| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "flutter/vulkan/procs/vulkan_proc_table.h" |
| |
| #include <utility> |
| |
| #include "flutter/fml/logging.h" |
| |
| #define ACQUIRE_PROC(name, context) \ |
| if (!(name = AcquireProc("vk" #name, context))) { \ |
| return false; \ |
| } |
| |
| #define ACQUIRE_PROC_EITHER(name, name2, context) \ |
| if (!(name = AcquireProc("vk" #name, context)) && \ |
| !(name2 = AcquireProc("vk" #name2, context))) { \ |
| return false; \ |
| } |
| |
| namespace vulkan { |
| |
| VulkanProcTable::VulkanProcTable() : VulkanProcTable("libvulkan.so"){}; |
| |
| VulkanProcTable::VulkanProcTable(const char* so_path) |
| : handle_(nullptr), acquired_mandatory_proc_addresses_(false) { |
| acquired_mandatory_proc_addresses_ = OpenLibraryHandle(so_path) && |
| SetupGetInstanceProcAddress() && |
| SetupLoaderProcAddresses(); |
| } |
| |
| VulkanProcTable::VulkanProcTable( |
| PFN_vkGetInstanceProcAddr get_instance_proc_addr) |
| : handle_(nullptr), acquired_mandatory_proc_addresses_(false) { |
| GetInstanceProcAddr = get_instance_proc_addr; |
| acquired_mandatory_proc_addresses_ = SetupLoaderProcAddresses(); |
| } |
| |
| VulkanProcTable::~VulkanProcTable() { |
| CloseLibraryHandle(); |
| } |
| |
| bool VulkanProcTable::HasAcquiredMandatoryProcAddresses() const { |
| return acquired_mandatory_proc_addresses_; |
| } |
| |
| bool VulkanProcTable::IsValid() const { |
| return instance_ && device_; |
| } |
| |
| bool VulkanProcTable::AreInstanceProcsSetup() const { |
| return instance_; |
| } |
| |
| bool VulkanProcTable::AreDeviceProcsSetup() const { |
| return device_; |
| } |
| |
| bool VulkanProcTable::SetupGetInstanceProcAddress() { |
| if (!handle_) { |
| return true; |
| } |
| |
| GetInstanceProcAddr = NativeGetInstanceProcAddr(); |
| if (!GetInstanceProcAddr) { |
| FML_DLOG(WARNING) << "Could not acquire vkGetInstanceProcAddr."; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| PFN_vkGetInstanceProcAddr VulkanProcTable::NativeGetInstanceProcAddr() const { |
| if (GetInstanceProcAddr) { |
| return GetInstanceProcAddr; |
| } |
| |
| #if VULKAN_LINK_STATICALLY |
| return &vkGetInstanceProcAddr; |
| #else // VULKAN_LINK_STATICALLY |
| auto instance_proc = |
| const_cast<uint8_t*>(handle_->ResolveSymbol("vkGetInstanceProcAddr")); |
| return reinterpret_cast<PFN_vkGetInstanceProcAddr>(instance_proc); |
| #endif // VULKAN_LINK_STATICALLY |
| } |
| |
| bool VulkanProcTable::SetupLoaderProcAddresses() { |
| VulkanHandle<VkInstance> null_instance(VK_NULL_HANDLE, nullptr); |
| |
| ACQUIRE_PROC(CreateInstance, null_instance); |
| ACQUIRE_PROC(EnumerateInstanceExtensionProperties, null_instance); |
| ACQUIRE_PROC(EnumerateInstanceLayerProperties, null_instance); |
| |
| return true; |
| } |
| |
| bool VulkanProcTable::SetupInstanceProcAddresses( |
| const VulkanHandle<VkInstance>& handle) { |
| ACQUIRE_PROC(CreateDevice, handle); |
| ACQUIRE_PROC(DestroyDevice, handle); |
| ACQUIRE_PROC(DestroyInstance, handle); |
| ACQUIRE_PROC(EnumerateDeviceLayerProperties, handle); |
| ACQUIRE_PROC(EnumeratePhysicalDevices, handle); |
| ACQUIRE_PROC(GetDeviceProcAddr, handle); |
| ACQUIRE_PROC(GetPhysicalDeviceFeatures, handle); |
| ACQUIRE_PROC(GetPhysicalDeviceQueueFamilyProperties, handle); |
| ACQUIRE_PROC(GetPhysicalDeviceProperties, handle); |
| ACQUIRE_PROC(GetPhysicalDeviceMemoryProperties, handle); |
| ACQUIRE_PROC_EITHER(GetPhysicalDeviceMemoryProperties2, |
| GetPhysicalDeviceMemoryProperties2KHR, handle); |
| |
| #if FML_OS_ANDROID |
| ACQUIRE_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR, handle); |
| ACQUIRE_PROC(GetPhysicalDeviceSurfaceFormatsKHR, handle); |
| ACQUIRE_PROC(GetPhysicalDeviceSurfacePresentModesKHR, handle); |
| ACQUIRE_PROC(GetPhysicalDeviceSurfaceSupportKHR, handle); |
| ACQUIRE_PROC(DestroySurfaceKHR, handle); |
| ACQUIRE_PROC(CreateAndroidSurfaceKHR, handle); |
| #endif // FML_OS_ANDROID |
| |
| // The debug report functions are optional. We don't want proc acquisition to |
| // fail here because the optional methods were not present (since ACQUIRE_PROC |
| // returns false on failure). Wrap the optional proc acquisitions in an |
| // anonymous lambda and invoke it. We don't really care about the result since |
| // users of Debug reporting functions check for their presence explicitly. |
| [this, &handle]() -> bool { |
| ACQUIRE_PROC(CreateDebugReportCallbackEXT, handle); |
| ACQUIRE_PROC(DestroyDebugReportCallbackEXT, handle); |
| return true; |
| }(); |
| |
| instance_ = VulkanHandle<VkInstance>{handle, nullptr}; |
| return true; |
| } |
| |
| bool VulkanProcTable::SetupDeviceProcAddresses( |
| const VulkanHandle<VkDevice>& handle) { |
| ACQUIRE_PROC(AllocateCommandBuffers, handle); |
| ACQUIRE_PROC(AllocateMemory, handle); |
| ACQUIRE_PROC(BeginCommandBuffer, handle); |
| ACQUIRE_PROC(BindImageMemory, handle); |
| ACQUIRE_PROC(CmdPipelineBarrier, handle); |
| ACQUIRE_PROC(CreateCommandPool, handle); |
| ACQUIRE_PROC(CreateFence, handle); |
| ACQUIRE_PROC(CreateImage, handle); |
| ACQUIRE_PROC(CreateSemaphore, handle); |
| ACQUIRE_PROC(DestroyCommandPool, handle); |
| ACQUIRE_PROC(DestroyFence, handle); |
| ACQUIRE_PROC(DestroyImage, handle); |
| ACQUIRE_PROC(DestroySemaphore, handle); |
| ACQUIRE_PROC(DeviceWaitIdle, handle); |
| ACQUIRE_PROC(EndCommandBuffer, handle); |
| ACQUIRE_PROC(FreeCommandBuffers, handle); |
| ACQUIRE_PROC(FreeMemory, handle); |
| ACQUIRE_PROC(GetDeviceQueue, handle); |
| ACQUIRE_PROC(GetImageMemoryRequirements, handle); |
| ACQUIRE_PROC(QueueSubmit, handle); |
| ACQUIRE_PROC(QueueWaitIdle, handle); |
| ACQUIRE_PROC(ResetCommandBuffer, handle); |
| ACQUIRE_PROC(ResetFences, handle); |
| ACQUIRE_PROC(WaitForFences, handle); |
| ACQUIRE_PROC(MapMemory, handle); |
| ACQUIRE_PROC(UnmapMemory, handle); |
| ACQUIRE_PROC(FlushMappedMemoryRanges, handle); |
| ACQUIRE_PROC(InvalidateMappedMemoryRanges, handle); |
| ACQUIRE_PROC(BindBufferMemory, handle); |
| ACQUIRE_PROC(GetBufferMemoryRequirements, handle); |
| ACQUIRE_PROC(CreateBuffer, handle); |
| ACQUIRE_PROC(DestroyBuffer, handle); |
| ACQUIRE_PROC(CmdCopyBuffer, handle); |
| |
| ACQUIRE_PROC_EITHER(GetBufferMemoryRequirements2, |
| GetBufferMemoryRequirements2KHR, handle); |
| ACQUIRE_PROC_EITHER(GetImageMemoryRequirements2, |
| GetImageMemoryRequirements2KHR, handle); |
| ACQUIRE_PROC_EITHER(BindBufferMemory2, BindBufferMemory2KHR, handle); |
| ACQUIRE_PROC_EITHER(BindImageMemory2, BindImageMemory2KHR, handle); |
| |
| #ifndef TEST_VULKAN_PROCS |
| #if FML_OS_ANDROID |
| ACQUIRE_PROC(AcquireNextImageKHR, handle); |
| ACQUIRE_PROC(CreateSwapchainKHR, handle); |
| ACQUIRE_PROC(DestroySwapchainKHR, handle); |
| ACQUIRE_PROC(GetSwapchainImagesKHR, handle); |
| ACQUIRE_PROC(QueuePresentKHR, handle); |
| #endif // FML_OS_ANDROID |
| #if OS_FUCHSIA |
| ACQUIRE_PROC(ImportSemaphoreZirconHandleFUCHSIA, handle); |
| ACQUIRE_PROC(GetSemaphoreZirconHandleFUCHSIA, handle); |
| ACQUIRE_PROC(GetMemoryZirconHandleFUCHSIA, handle); |
| ACQUIRE_PROC(CreateBufferCollectionFUCHSIA, handle); |
| ACQUIRE_PROC(DestroyBufferCollectionFUCHSIA, handle); |
| ACQUIRE_PROC(SetBufferCollectionImageConstraintsFUCHSIA, handle); |
| ACQUIRE_PROC(GetBufferCollectionPropertiesFUCHSIA, handle); |
| #endif // OS_FUCHSIA |
| #endif // TEST_VULKAN_PROCS |
| device_ = VulkanHandle<VkDevice>{handle, nullptr}; |
| return true; |
| } |
| |
| bool VulkanProcTable::OpenLibraryHandle(const char* path) { |
| #if VULKAN_LINK_STATICALLY |
| handle_ = fml::NativeLibrary::CreateForCurrentProcess(); |
| #else // VULKAN_LINK_STATICALLY |
| handle_ = fml::NativeLibrary::Create(path); |
| #endif // VULKAN_LINK_STATICALLY |
| if (!handle_) { |
| FML_DLOG(ERROR) << "Could not open Vulkan library handle: " << path; |
| return false; |
| } |
| return true; |
| } |
| |
| bool VulkanProcTable::CloseLibraryHandle() { |
| handle_ = nullptr; |
| return true; |
| } |
| |
| PFN_vkVoidFunction VulkanProcTable::AcquireProc( |
| const char* proc_name, |
| const VulkanHandle<VkInstance>& instance) const { |
| if (proc_name == nullptr || !GetInstanceProcAddr) { |
| return nullptr; |
| } |
| |
| // A VK_NULL_HANDLE as the instance is an acceptable parameter. |
| return reinterpret_cast<PFN_vkVoidFunction>( |
| GetInstanceProcAddr(instance, proc_name)); |
| } |
| |
| PFN_vkVoidFunction VulkanProcTable::AcquireProc( |
| const char* proc_name, |
| const VulkanHandle<VkDevice>& device) const { |
| if (proc_name == nullptr || !device || !GetDeviceProcAddr) { |
| return nullptr; |
| } |
| |
| return GetDeviceProcAddr(device, proc_name); |
| } |
| |
| } // namespace vulkan |