From ff8d9992c99aca394b1218692cd94909fc1405aa Mon Sep 17 00:00:00 2001 From: Craig Stout Date: Wed, 30 Sep 2020 22:59:30 -0400 Subject: [PATCH] Add Fuchsia support Fuchsia (fuchsia.dev) builds with GN and uses a loader service to load the ICD into the application's address space. ANGLE builds have been verified. Reemoves unused variable is_icd. --- BUILD.gn | 81 ++++++++++++-- BUILD.md | 10 ++ fuchsia/dlopen_fuchsia.c | 87 +++++++++++++++ fuchsia/dlopen_fuchsia.h | 29 +++++ loader/loader.c | 11 +- loader/vk_loader_platform.h | 32 +++++- vulkan.symbols.api | 207 ++++++++++++++++++++++++++++++++++++ 7 files changed, 444 insertions(+), 13 deletions(-) create mode 100644 fuchsia/dlopen_fuchsia.c create mode 100644 fuchsia/dlopen_fuchsia.h create mode 100644 vulkan.symbols.api diff --git a/BUILD.gn b/BUILD.gn index 121b436b..671295fc 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -13,11 +13,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +import("//build_overrides/build.gni") import("//build_overrides/vulkan_loader.gni") -# Fuchsia has non-upstream changes to the vulkan loader, so we don't want -# to build it from upstream sources. -assert(!is_fuchsia) +if (is_fuchsia) { + import("//build/cpp/sdk_shared_library.gni") + import("//build/sdk/sdk_documentation.gni") +} if (!is_android) { vulkan_undefine_configs = [] @@ -32,7 +34,20 @@ if (is_win) { config("vulkan_internal_config") { defines = [ "VULKAN_NON_CMAKE_BUILD" ] if (is_clang || !is_win) { - cflags = [ "-Wno-unused-function" ] + cflags = [ + "-Wno-conversion", + "-Wno-extra-semi", + "-Wno-sign-compare", + "-Wno-unreachable-code", + "-Wno-unused-function", + "-Wno-unused-variable", + ] + } + if (is_fuchsia) { + defines += [ + "SYSCONFDIR=\"/config\"", + "EXTRASYSCONFDIR=\"/pkg/data\"", + ] } if (is_linux || is_mac) { defines += [ @@ -66,7 +81,9 @@ config("vulkan_loader_config") { } if (!is_android) { - if (vulkan_loader_shared) { + if (is_fuchsia) { + library_type = "sdk_shared_library" + } else if (vulkan_loader_shared) { library_type = "shared_library" } else { library_type = "static_library" @@ -133,11 +150,29 @@ if (!is_android) { frameworks = [ "CoreFoundation.framework" ] } public_deps = [ "$vulkan_headers_dir:vulkan_headers" ] - configs -= [ "//build/config/compiler:chromium_code" ] - configs += [ "//build/config/compiler:no_chromium_code" ] + if (build_with_chromium) { + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + } configs += [ ":vulkan_internal_config" ] public_configs = [ ":vulkan_loader_config" ] configs -= vulkan_undefine_configs + + if (is_fuchsia) { + output_name = "vulkan" + category = "partner" + + # The Vulkan loader's interface is defined by standard Khronos vulkan headers + # which can be obtained separately from the loader implementation itself. + no_headers = true + + deps = [ + ":dlopen_fuchsia", + "//sdk/lib/fdio", + ] + + runtime_deps = [ "//sdk/lib/fdio:fdio_sdk" ] + } } if (is_linux && vulkan_loader_shared) { @@ -149,3 +184,35 @@ if (!is_android) { } } } + +if (is_fuchsia) { + config("fuchsia_config") { + include_dirs = [ "fuchsia" ] + } + + source_set("dlopen_fuchsia") { + public_configs = [ ":fuchsia_config" ] + + sources = [ + "fuchsia/dlopen_fuchsia.c", + "fuchsia/dlopen_fuchsia.h", + ] + + deps = [ + "//sdk/fidl/fuchsia.vulkan.loader:fuchsia.vulkan.loader_c_client", + "//sdk/lib/fdio", + ] + } + + sdk_documentation("vulkan_license") { + name = "vulkan_license" + category = "public" + + files = [ + { + source = "LICENSE.txt" + dest = "LICENSE.vulkan" + }, + ] + } +} diff --git a/BUILD.md b/BUILD.md index 0bfc03e6..8ccf7907 100644 --- a/BUILD.md +++ b/BUILD.md @@ -10,6 +10,7 @@ Instructions for building this repository on Linux, Windows, and MacOS. 1. [Windows Build](#building-on-windows) 1. [Linux Build](#building-on-linux) 1. [MacOS build](#building-on-macos) +1. [Fuchsia build](#building-on-fuchsia) ## Contributing to the Repository @@ -677,3 +678,12 @@ To run the loader test script, change to the `build/tests` directory in your Vulkan-Loader repository, and run: ./vk_loader_validation_tests + +## Building on Fuchsia + +Fuchsia uses the project's GN build system to integrate with the Fuchsia platform build. + +### SDK Symbols + +The Vulkan Loader is a component of the Fuchsia SDK, so it must explicitly declare its exported symbols in +the file vulkan.symbols.api; see [SDK](https://fuchsia.dev/fuchsia-src/development/sdk). diff --git a/fuchsia/dlopen_fuchsia.c b/fuchsia/dlopen_fuchsia.c new file mode 100644 index 00000000..c973b352 --- /dev/null +++ b/fuchsia/dlopen_fuchsia.c @@ -0,0 +1,87 @@ +/* + * + * Copyright (c) 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "dlopen_fuchsia.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char g_error[128] = {}; + +const char *dlerror_fuchsia(void) { return g_error; } + +static zx_handle_t vulkan_loader_svc = ZX_HANDLE_INVALID; +void connect_to_vulkan_loader_svc(void) { + zx_handle_t svc1, svc2; + if (zx_channel_create(0, &svc1, &svc2) != ZX_OK) return; + + if (fdio_service_connect("/svc/" fuchsia_vulkan_loader_Loader_Name, svc1) != ZX_OK) { + zx_handle_close(svc2); + return; + } + + vulkan_loader_svc = svc2; +} + +static once_flag svc_connect_once_flag = ONCE_FLAG_INIT; + +void *dlopen_fuchsia(const char *name, int mode, bool driver) { + // First try to just dlopen() from our own namespace. This will succeed for + // any layers that are packaged with the application, but will fail for + // client drivers loaded from the system. + void *result; + if (!driver) { + result = dlopen(name, mode); + if (result != NULL) return result; + } + + // If we couldn't find the library in our own namespace, connect to the + // loader service to request this library. + call_once(&svc_connect_once_flag, connect_to_vulkan_loader_svc); + + if (vulkan_loader_svc == ZX_HANDLE_INVALID) { + snprintf(g_error, sizeof(g_error), "libvulkan.so:dlopen_fuchsia: no connection to loader svc\n"); + return NULL; + } + + zx_handle_t vmo = ZX_HANDLE_INVALID; + zx_status_t st = fuchsia_vulkan_loader_LoaderGet(vulkan_loader_svc, name, strlen(name), &vmo); + if (st != ZX_OK) { + snprintf(g_error, sizeof(g_error), "libvulkan.so:dlopen_fuchsia: Get() failed: %d\n", st); + return NULL; + } + + if (vmo == ZX_HANDLE_INVALID) { + snprintf(g_error, sizeof(g_error), "libvulkan.so:dlopen_fuchsia: Get() returned invalid vmo\n"); + return NULL; + } + + result = dlopen_vmo(vmo, mode); + zx_handle_close(vmo); + if (!result) { + snprintf(g_error, sizeof(g_error), "%s", dlerror()); + } + return result; +} diff --git a/fuchsia/dlopen_fuchsia.h b/fuchsia/dlopen_fuchsia.h new file mode 100644 index 00000000..a674b8db --- /dev/null +++ b/fuchsia/dlopen_fuchsia.h @@ -0,0 +1,29 @@ +/* + * + * Copyright (c) 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#pragma once + +#include +#include + +__BEGIN_CDECLS + +// If not |driver|, then the request is to load a layer. +void *dlopen_fuchsia(const char *name, int mode, bool driver); +const char *dlerror_fuchsia(void); + +__END_CDECLS diff --git a/loader/loader.c b/loader/loader.c index e78b1397..7c7e1cdf 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -253,7 +253,7 @@ void *loader_device_heap_realloc(const struct loader_device *device, void *pMemo } // Environment variables -#if defined(__linux__) || defined(__APPLE__) +#if defined(__linux__) || defined(__APPLE__) || defined(__Fuchsia__) static inline bool IsHighIntegrity() { return geteuid() != getuid() || getegid() != getgid(); @@ -277,6 +277,8 @@ static inline char *loader_secure_getenv(const char *name, const struct loader_i // This algorithm is derived from glibc code that sets an internal // variable (__libc_enable_secure) if the process is running under setuid or setgid. return IsHighIntegrity() ? NULL : loader_getenv(name, inst); +#elif defined(__Fuchsia__) + return loader_getenv(name, inst); #else // Linux #if defined(HAVE_SECURE_GETENV) && !defined(USE_UNSAFE_FILE_SEARCH) @@ -2317,7 +2319,11 @@ static VkResult loader_scanned_icd_add(const struct loader_instance *inst, struc // TODO implement smarter opening/closing of libraries. For now this // function leaves libraries open and the scanned_icd_clear closes them +#if defined(__Fuchsia__) + handle = loader_platform_open_driver(filename); +#else handle = loader_platform_open_library(filename); +#endif if (NULL == handle) { loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, loader_platform_open_library_error(filename)); goto out; @@ -3955,12 +3961,14 @@ static VkResult ReadDataFilesInSearchPaths(const struct loader_instance *inst, e if (xdgdatadirs == NULL) { xdgdata_alloc = false; } +#if !defined(__Fuchsia__) if (xdgconfdirs == NULL || xdgconfdirs[0] == '\0') { xdgconfdirs = FALLBACK_CONFIG_DIRS; } if (xdgdatadirs == NULL || xdgdatadirs[0] == '\0') { xdgdatadirs = FALLBACK_DATA_DIRS; } +#endif // Only use HOME if XDG_DATA_HOME is not present on the system if (NULL == xdgdatahome) { @@ -4308,7 +4316,6 @@ out: static VkResult ReadDataFilesInRegistry(const struct loader_instance *inst, enum loader_data_files_type data_file_type, bool warn_if_not_present, char *registry_location, struct loader_data_files *out_files) { VkResult vk_result = VK_SUCCESS; - bool is_icd = (data_file_type == LOADER_DATA_FILE_MANIFEST_ICD); char *search_path = NULL; // These calls look at the PNP/Device section of the registry. diff --git a/loader/vk_loader_platform.h b/loader/vk_loader_platform.h index e227bf07..abf078c2 100644 --- a/loader/vk_loader_platform.h +++ b/loader/vk_loader_platform.h @@ -28,10 +28,14 @@ #include #endif // _WIN32 +#if defined(__Fuchsia__) +#include "dlopen_fuchsia.h" +#endif // defined(__Fuchsia__) + #include "vulkan/vk_platform.h" #include "vulkan/vk_sdk_platform.h" -#if defined(__linux__) || defined(__APPLE__) +#if defined(__linux__) || defined(__APPLE__) || defined(__Fuchsia__) /* Linux-specific common code: */ // Headers: @@ -118,6 +122,8 @@ static inline char *loader_platform_executable_path(char *buffer, size_t size) { buffer[ret] = '\0'; return buffer; } +#elif defined(__Fuchsia__) +static inline char *loader_platform_executable_path(char *buffer, size_t size) { return NULL; } #endif // defined (__APPLE__) // Compatability with compilers that don't support __has_feature @@ -131,14 +137,32 @@ static inline char *loader_platform_executable_path(char *buffer, size_t size) { // Dynamic Loading of libraries: typedef void *loader_platform_dl_handle; -static inline loader_platform_dl_handle loader_platform_open_library(const char *libPath) { // When loading the library, we use RTLD_LAZY so that not all symbols have to be // resolved at this time (which improves performance). Note that if not all symbols // can be resolved, this could cause crashes later. Use the LD_BIND_NOW environment // variable to force all symbols to be resolved here. - return dlopen(libPath, RTLD_LAZY | RTLD_LOCAL); +#define LOADER_DLOPEN_MODE (RTLD_LAZY | RTLD_LOCAL) + +#if defined(__Fuchsia__) +static inline loader_platform_dl_handle loader_platform_open_driver(const char *libPath) { + return dlopen_fuchsia(libPath, LOADER_DLOPEN_MODE, true); +} +static inline loader_platform_dl_handle loader_platform_open_library(const char *libPath) { + return dlopen_fuchsia(libPath, LOADER_DLOPEN_MODE, false); +} +#else +static inline loader_platform_dl_handle loader_platform_open_library(const char *libPath) { + return dlopen(libPath, LOADER_DLOPEN_MODE); +} +#endif + +static inline const char *loader_platform_open_library_error(const char *libPath) { +#ifdef __Fuchsia__ + return dlerror_fuchsia(); +#else + return dlerror(); +#endif } -static inline const char *loader_platform_open_library_error(const char *libPath) { return dlerror(); } static inline void loader_platform_close_library(loader_platform_dl_handle library) { dlclose(library); } static inline void *loader_platform_get_proc_address(loader_platform_dl_handle library, const char *name) { assert(library); diff --git a/vulkan.symbols.api b/vulkan.symbols.api new file mode 100644 index 00000000..b1b74e85 --- /dev/null +++ b/vulkan.symbols.api @@ -0,0 +1,207 @@ +vkAcquireNextImage2KHR +vkAcquireNextImageKHR +vkAllocateCommandBuffers +vkAllocateDescriptorSets +vkAllocateMemory +vkBeginCommandBuffer +vkBindBufferMemory +vkBindBufferMemory2 +vkBindImageMemory +vkBindImageMemory2 +vkCmdBeginQuery +vkCmdBeginRenderPass +vkCmdBeginRenderPass2 +vkCmdBindDescriptorSets +vkCmdBindIndexBuffer +vkCmdBindPipeline +vkCmdBindVertexBuffers +vkCmdBlitImage +vkCmdClearAttachments +vkCmdClearColorImage +vkCmdClearDepthStencilImage +vkCmdCopyBuffer +vkCmdCopyBufferToImage +vkCmdCopyImage +vkCmdCopyImageToBuffer +vkCmdCopyQueryPoolResults +vkCmdDispatch +vkCmdDispatchBase +vkCmdDispatchIndirect +vkCmdDraw +vkCmdDrawIndexed +vkCmdDrawIndexedIndirect +vkCmdDrawIndexedIndirectCount +vkCmdDrawIndirect +vkCmdDrawIndirectCount +vkCmdEndQuery +vkCmdEndRenderPass +vkCmdEndRenderPass2 +vkCmdExecuteCommands +vkCmdFillBuffer +vkCmdNextSubpass +vkCmdNextSubpass2 +vkCmdPipelineBarrier +vkCmdPushConstants +vkCmdResetEvent +vkCmdResetQueryPool +vkCmdResolveImage +vkCmdSetBlendConstants +vkCmdSetDepthBias +vkCmdSetDepthBounds +vkCmdSetDeviceMask +vkCmdSetEvent +vkCmdSetLineWidth +vkCmdSetScissor +vkCmdSetStencilCompareMask +vkCmdSetStencilReference +vkCmdSetStencilWriteMask +vkCmdSetViewport +vkCmdUpdateBuffer +vkCmdWaitEvents +vkCmdWriteTimestamp +vkCreateBuffer +vkCreateBufferView +vkCreateCommandPool +vkCreateComputePipelines +vkCreateDescriptorPool +vkCreateDescriptorSetLayout +vkCreateDescriptorUpdateTemplate +vkCreateDevice +vkCreateDisplayModeKHR +vkCreateDisplayPlaneSurfaceKHR +vkCreateEvent +vkCreateFence +vkCreateFramebuffer +vkCreateGraphicsPipelines +vkCreateImage +vkCreateImagePipeSurfaceFUCHSIA +vkCreateImageView +vkCreateInstance +vkCreatePipelineCache +vkCreatePipelineLayout +vkCreateQueryPool +vkCreateRenderPass +vkCreateRenderPass2 +vkCreateSampler +vkCreateSamplerYcbcrConversion +vkCreateSemaphore +vkCreateShaderModule +vkCreateSharedSwapchainsKHR +vkCreateSwapchainKHR +vkDestroyBuffer +vkDestroyBufferView +vkDestroyCommandPool +vkDestroyDescriptorPool +vkDestroyDescriptorSetLayout +vkDestroyDescriptorUpdateTemplate +vkDestroyDevice +vkDestroyEvent +vkDestroyFence +vkDestroyFramebuffer +vkDestroyImage +vkDestroyImageView +vkDestroyInstance +vkDestroyPipeline +vkDestroyPipelineCache +vkDestroyPipelineLayout +vkDestroyQueryPool +vkDestroyRenderPass +vkDestroySampler +vkDestroySamplerYcbcrConversion +vkDestroySemaphore +vkDestroyShaderModule +vkDestroySurfaceKHR +vkDestroySwapchainKHR +vkDeviceWaitIdle +vkEndCommandBuffer +vkEnumerateDeviceExtensionProperties +vkEnumerateDeviceLayerProperties +vkEnumerateInstanceExtensionProperties +vkEnumerateInstanceLayerProperties +vkEnumerateInstanceVersion +vkEnumeratePhysicalDeviceGroups +vkEnumeratePhysicalDevices +vkFlushMappedMemoryRanges +vkFreeCommandBuffers +vkFreeDescriptorSets +vkFreeMemory +vkGetBufferDeviceAddress +vkGetBufferMemoryRequirements +vkGetBufferMemoryRequirements2 +vkGetBufferOpaqueCaptureAddress +vkGetDescriptorSetLayoutSupport +vkGetDeviceGroupPeerMemoryFeatures +vkGetDeviceGroupPresentCapabilitiesKHR +vkGetDeviceGroupSurfacePresentModesKHR +vkGetDeviceMemoryCommitment +vkGetDeviceMemoryOpaqueCaptureAddress +vkGetDeviceProcAddr +vkGetDeviceQueue +vkGetDeviceQueue2 +vkGetDisplayModeProperties2KHR +vkGetDisplayModePropertiesKHR +vkGetDisplayPlaneCapabilities2KHR +vkGetDisplayPlaneCapabilitiesKHR +vkGetDisplayPlaneSupportedDisplaysKHR +vkGetEventStatus +vkGetFenceStatus +vkGetImageMemoryRequirements +vkGetImageMemoryRequirements2 +vkGetImageSparseMemoryRequirements +vkGetImageSparseMemoryRequirements2 +vkGetImageSubresourceLayout +vkGetInstanceProcAddr +vkGetPhysicalDeviceDisplayPlaneProperties2KHR +vkGetPhysicalDeviceDisplayPlanePropertiesKHR +vkGetPhysicalDeviceDisplayProperties2KHR +vkGetPhysicalDeviceDisplayPropertiesKHR +vkGetPhysicalDeviceExternalBufferProperties +vkGetPhysicalDeviceExternalFenceProperties +vkGetPhysicalDeviceExternalSemaphoreProperties +vkGetPhysicalDeviceFeatures +vkGetPhysicalDeviceFeatures2 +vkGetPhysicalDeviceFormatProperties +vkGetPhysicalDeviceFormatProperties2 +vkGetPhysicalDeviceImageFormatProperties +vkGetPhysicalDeviceImageFormatProperties2 +vkGetPhysicalDeviceMemoryProperties +vkGetPhysicalDeviceMemoryProperties2 +vkGetPhysicalDevicePresentRectanglesKHR +vkGetPhysicalDeviceProperties +vkGetPhysicalDeviceProperties2 +vkGetPhysicalDeviceQueueFamilyProperties +vkGetPhysicalDeviceQueueFamilyProperties2 +vkGetPhysicalDeviceSparseImageFormatProperties +vkGetPhysicalDeviceSparseImageFormatProperties2 +vkGetPhysicalDeviceSurfaceCapabilities2KHR +vkGetPhysicalDeviceSurfaceCapabilitiesKHR +vkGetPhysicalDeviceSurfaceFormats2KHR +vkGetPhysicalDeviceSurfaceFormatsKHR +vkGetPhysicalDeviceSurfacePresentModesKHR +vkGetPhysicalDeviceSurfaceSupportKHR +vkGetPipelineCacheData +vkGetQueryPoolResults +vkGetRenderAreaGranularity +vkGetSemaphoreCounterValue +vkGetSwapchainImagesKHR +vkInvalidateMappedMemoryRanges +vkMapMemory +vkMergePipelineCaches +vkQueueBindSparse +vkQueuePresentKHR +vkQueueSubmit +vkQueueWaitIdle +vkResetCommandBuffer +vkResetCommandPool +vkResetDescriptorPool +vkResetEvent +vkResetFences +vkResetQueryPool +vkSetEvent +vkSignalSemaphore +vkTrimCommandPool +vkUnmapMemory +vkUpdateDescriptorSetWithTemplate +vkUpdateDescriptorSets +vkWaitForFences +vkWaitSemaphores