Vulkan: Add vk_icdInitializeConnectToServiceCallback()

This entry point is a private implementation detail between
the Fuchsia Vulkan loader and the Vulkan ICDs on this platform.

It is called by the loader early on to pass the address of a global
function pointer, that can later be used by extensions to connect
to Fuchsia FIDL services.

This is equivalent to the Fuchsia fdio_service_connect() function,
except that this scheme prevents adding libfdio as a dependency
into the ICD shared library.

Bug: fxb/13095
Bug: fxb/13074

Change-Id: Idd2a0a9b78495fff4bdb17d9f6afc446b067d7e0
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/44019
Tested-by: Nicolas Capens <nicolascapens@google.com>
Presubmit-Ready: David Turner <digit@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f973cba..c26ffac 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -257,10 +257,18 @@
             set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-undefined,error")
         endif()
     elseif(LINUX OR FUCHSIA)
+        # NOTE: The Fuchsia linker script is needed to export the vk_icdInitializeConnectToServiceCallback
+        # entry point (a private implementation detail betwen the Fuchsia Vulkan loader and the ICD).
+        if ((FUCHSIA) AND ("${TARGET}" STREQUAL "vk_swiftshader"))
+          set(LINKER_VERSION_SCRIPT "fuchsia_vk_swiftshader.lds")
+        else()
+          set(LINKER_VERSION_SCRIPT "${TARGET}.lds")
+        endif()
+
         # The version script only exports the API functions and
         # hides all the others.
-        set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--version-script=${DIR}/${TARGET}.lds")
-        set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_DEPENDS "${DIR}/${TARGET}.lds;")
+        set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--version-script=${DIR}/${LINKER_VERSION_SCRIPT}")
+        set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_DEPENDS "${DIR}/${LINKER_VERSION_SCRIPT};")
 
         # -Bsymbolic binds symbol references to their global definitions within
         # a shared object, thereby preventing symbol preemption.
diff --git a/src/Vulkan/VkGetProcAddress.cpp b/src/Vulkan/VkGetProcAddress.cpp
index 95310d3..2c762b8 100644
--- a/src/Vulkan/VkGetProcAddress.cpp
+++ b/src/Vulkan/VkGetProcAddress.cpp
@@ -517,4 +517,8 @@
 	}
 };
 
+#endif  // __ANDROID__
+
+#if VK_USE_PLATFORM_FUCHSIA
+PFN_vkConnectToService vk::icdFuchsiaServiceConnectCallback = nullptr;
 #endif
diff --git a/src/Vulkan/VkGetProcAddress.h b/src/Vulkan/VkGetProcAddress.h
index 6eb017f..5918673 100644
--- a/src/Vulkan/VkGetProcAddress.h
+++ b/src/Vulkan/VkGetProcAddress.h
@@ -27,4 +27,16 @@
 
 }  // namespace vk
 
-#endif // VK_UTILS_HPP_
\ No newline at end of file
+#if VK_USE_PLATFORM_FUCHSIA
+// See vk_icdInitializeServiceConnectCallback() in libVulkan.cpp for details
+// about this global pointer. Since this is a private implementation detail
+// between the Vulkan loader and the ICDs, this type will never be part of
+// the <vulkan/vulkan_fuchsia.h> headers, so define the type here.
+typedef VkResult(VKAPI_PTR* PFN_vkConnectToService)(const char* pName, uint32_t handle);
+
+namespace vk {
+extern PFN_vkConnectToService icdFuchsiaServiceConnectCallback;
+}
+#endif  // VK_USE_PLATFORM_FUCHSIA
+
+#endif // VK_UTILS_HPP_
diff --git a/src/Vulkan/fuchsia_vk_swiftshader.lds b/src/Vulkan/fuchsia_vk_swiftshader.lds
new file mode 100644
index 0000000..b235a69
--- /dev/null
+++ b/src/Vulkan/fuchsia_vk_swiftshader.lds
@@ -0,0 +1,20 @@
+# For Fuchsia, we must not export anything other than loader-related API
+# There is also the vk_icdInitializeConnectToServiceCallback entry point
+# that is specific to the Fuchsia Vulkan loader implementation.
+{
+global:
+	vkGetInstanceProcAddr;
+
+	# Loader-ICD interface functions
+	vk_icdGetInstanceProcAddr;
+	vk_icdNegotiateLoaderICDInterfaceVersion;
+	vk_icdInitializeConnectToServiceCallback;
+
+	# Type-strings and type-infos required by sanitizers
+	_ZTS*;
+	_ZTI*;
+
+local:
+	*;
+};
+
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 54273a6..f235a6f 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -275,6 +275,26 @@
 	return VK_SUCCESS;
 }
 
+#if VK_USE_PLATFORM_FUCHSIA
+
+// This symbol must be exported by a Fuchsia Vulkan ICD. The Vulkan loader will
+// call it, passing the address of a global function pointer that can later be
+// used at runtime to connect to Fuchsia FIDL services, as required by certain
+// extensions. See https://fxbug.dev/13095 for more details.
+//
+// NOTE: This entry point has not been upstreamed to Khronos yet, which reserves
+//       all symbols starting with vk_icd. See https://fxbug.dev/13074 which
+//       tracks upstreaming progress.
+VK_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vk_icdInitializeConnectToServiceCallback(
+    PFN_vkConnectToService callback)
+{
+	TRACE("(callback = %p)", callback);
+	vk::icdFuchsiaServiceConnectCallback = callback;
+	return VK_SUCCESS;
+}
+
+#endif  // VK_USE_PLATFORM_FUCHSIA
+
 static const VkExtensionProperties instanceExtensionProperties[] = {
 	{ VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME, VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION },
 	{ VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION },