• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "flutter/vulkan/vulkan_proc_table.h"
6 
7 #include <dlfcn.h>
8 
9 #include "flutter/fml/logging.h"
10 
11 #define ACQUIRE_PROC(name, context)                          \
12   if (!(name = AcquireProc("vk" #name, context))) {          \
13     FML_DLOG(INFO) << "Could not acquire proc: vk" << #name; \
14     return false;                                            \
15   }
16 
17 namespace vulkan {
18 
VulkanProcTable()19 VulkanProcTable::VulkanProcTable()
20     : handle_(nullptr), acquired_mandatory_proc_addresses_(false) {
21   acquired_mandatory_proc_addresses_ =
22       OpenLibraryHandle() && SetupLoaderProcAddresses();
23 }
24 
~VulkanProcTable()25 VulkanProcTable::~VulkanProcTable() {
26   CloseLibraryHandle();
27 }
28 
HasAcquiredMandatoryProcAddresses() const29 bool VulkanProcTable::HasAcquiredMandatoryProcAddresses() const {
30   return acquired_mandatory_proc_addresses_;
31 }
32 
IsValid() const33 bool VulkanProcTable::IsValid() const {
34   return instance_ && device_;
35 }
36 
AreInstanceProcsSetup() const37 bool VulkanProcTable::AreInstanceProcsSetup() const {
38   return instance_;
39 }
40 
AreDeviceProcsSetup() const41 bool VulkanProcTable::AreDeviceProcsSetup() const {
42   return device_;
43 }
44 
SetupLoaderProcAddresses()45 bool VulkanProcTable::SetupLoaderProcAddresses() {
46   if (handle_ == nullptr) {
47     return true;
48   }
49 
50   GetInstanceProcAddr =
51 #if VULKAN_LINK_STATICALLY
52       GetInstanceProcAddr = &vkGetInstanceProcAddr;
53 #else   // VULKAN_LINK_STATICALLY
54       reinterpret_cast<PFN_vkGetInstanceProcAddr>(
55           dlsym(handle_, "vkGetInstanceProcAddr"));
56 #endif  // VULKAN_LINK_STATICALLY
57 
58   if (!GetInstanceProcAddr) {
59     FML_DLOG(WARNING) << "Could not acquire vkGetInstanceProcAddr.";
60     return false;
61   }
62 
63   VulkanHandle<VkInstance> null_instance(VK_NULL_HANDLE, nullptr);
64 
65   ACQUIRE_PROC(CreateInstance, null_instance);
66   ACQUIRE_PROC(EnumerateInstanceExtensionProperties, null_instance);
67   ACQUIRE_PROC(EnumerateInstanceLayerProperties, null_instance);
68 
69   return true;
70 }
71 
SetupInstanceProcAddresses(const VulkanHandle<VkInstance> & handle)72 bool VulkanProcTable::SetupInstanceProcAddresses(
73     const VulkanHandle<VkInstance>& handle) {
74   ACQUIRE_PROC(CreateDevice, handle);
75   ACQUIRE_PROC(DestroyDevice, handle);
76   ACQUIRE_PROC(DestroyInstance, handle);
77   ACQUIRE_PROC(EnumerateDeviceLayerProperties, handle);
78   ACQUIRE_PROC(EnumeratePhysicalDevices, handle);
79   ACQUIRE_PROC(GetDeviceProcAddr, handle);
80   ACQUIRE_PROC(GetPhysicalDeviceFeatures, handle);
81   ACQUIRE_PROC(GetPhysicalDeviceQueueFamilyProperties, handle);
82 #if OS_ANDROID
83   ACQUIRE_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR, handle);
84   ACQUIRE_PROC(GetPhysicalDeviceSurfaceFormatsKHR, handle);
85   ACQUIRE_PROC(GetPhysicalDeviceSurfacePresentModesKHR, handle);
86   ACQUIRE_PROC(GetPhysicalDeviceSurfaceSupportKHR, handle);
87   ACQUIRE_PROC(DestroySurfaceKHR, handle);
88   ACQUIRE_PROC(CreateAndroidSurfaceKHR, handle);
89 #endif  // OS_ANDROID
90 
91   // The debug report functions are optional. We don't want proc acquisition to
92   // fail here because the optional methods were not present (since ACQUIRE_PROC
93   // returns false on failure). Wrap the optional proc acquisitions in an
94   // anonymous lambda and invoke it. We don't really care about the result since
95   // users of Debug reporting functions check for their presence explicitly.
96   [this, &handle]() -> bool {
97     ACQUIRE_PROC(CreateDebugReportCallbackEXT, handle);
98     ACQUIRE_PROC(DestroyDebugReportCallbackEXT, handle);
99     return true;
100   }();
101 
102   instance_ = {handle, nullptr};
103   return true;
104 }
105 
SetupDeviceProcAddresses(const VulkanHandle<VkDevice> & handle)106 bool VulkanProcTable::SetupDeviceProcAddresses(
107     const VulkanHandle<VkDevice>& handle) {
108   ACQUIRE_PROC(AllocateCommandBuffers, handle);
109   ACQUIRE_PROC(AllocateMemory, handle);
110   ACQUIRE_PROC(BeginCommandBuffer, handle);
111   ACQUIRE_PROC(BindImageMemory, handle);
112   ACQUIRE_PROC(CmdPipelineBarrier, handle);
113   ACQUIRE_PROC(CreateCommandPool, handle);
114   ACQUIRE_PROC(CreateFence, handle);
115   ACQUIRE_PROC(CreateImage, handle);
116   ACQUIRE_PROC(CreateSemaphore, handle);
117   ACQUIRE_PROC(DestroyCommandPool, handle);
118   ACQUIRE_PROC(DestroyFence, handle);
119   ACQUIRE_PROC(DestroyImage, handle);
120   ACQUIRE_PROC(DestroySemaphore, handle);
121   ACQUIRE_PROC(DeviceWaitIdle, handle);
122   ACQUIRE_PROC(EndCommandBuffer, handle);
123   ACQUIRE_PROC(FreeCommandBuffers, handle);
124   ACQUIRE_PROC(FreeMemory, handle);
125   ACQUIRE_PROC(GetDeviceQueue, handle);
126   ACQUIRE_PROC(GetImageMemoryRequirements, handle);
127   ACQUIRE_PROC(QueueSubmit, handle);
128   ACQUIRE_PROC(QueueWaitIdle, handle);
129   ACQUIRE_PROC(ResetCommandBuffer, handle);
130   ACQUIRE_PROC(ResetFences, handle);
131   ACQUIRE_PROC(WaitForFences, handle);
132 #if OS_ANDROID
133   ACQUIRE_PROC(AcquireNextImageKHR, handle);
134   ACQUIRE_PROC(CreateSwapchainKHR, handle);
135   ACQUIRE_PROC(DestroySwapchainKHR, handle);
136   ACQUIRE_PROC(GetSwapchainImagesKHR, handle);
137   ACQUIRE_PROC(QueuePresentKHR, handle);
138 #endif  // OS_ANDROID
139 #if OS_FUCHSIA
140   ACQUIRE_PROC(GetMemoryZirconHandleFUCHSIA, handle);
141   ACQUIRE_PROC(ImportSemaphoreZirconHandleFUCHSIA, handle);
142 #endif  // OS_FUCHSIA
143   device_ = {handle, nullptr};
144   return true;
145 }
146 
OpenLibraryHandle()147 bool VulkanProcTable::OpenLibraryHandle() {
148 #if VULKAN_LINK_STATICALLY
149   static char kDummyLibraryHandle = '\0';
150   handle_ = reinterpret_cast<decltype(handle_)>(&kDummyLibraryHandle);
151   return true;
152 #else   // VULKAN_LINK_STATICALLY
153   dlerror();  // clear existing errors on thread.
154   handle_ = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
155   if (handle_ == nullptr) {
156     FML_DLOG(WARNING) << "Could not open the vulkan library: " << dlerror();
157     return false;
158   }
159   return true;
160 #endif  // VULKAN_LINK_STATICALLY
161 }
162 
CloseLibraryHandle()163 bool VulkanProcTable::CloseLibraryHandle() {
164 #if VULKAN_LINK_STATICALLY
165   handle_ = nullptr;
166   return true;
167 #else
168   if (handle_ != nullptr) {
169     dlerror();  // clear existing errors on thread.
170     if (dlclose(handle_) != 0) {
171       FML_DLOG(ERROR) << "Could not close the vulkan library handle. This "
172                          "indicates a leak.";
173       FML_DLOG(ERROR) << dlerror();
174     }
175     handle_ = nullptr;
176   }
177   return handle_ == nullptr;
178 #endif
179 }
180 
AcquireProc(const char * proc_name,const VulkanHandle<VkInstance> & instance) const181 PFN_vkVoidFunction VulkanProcTable::AcquireProc(
182     const char* proc_name,
183     const VulkanHandle<VkInstance>& instance) const {
184   if (proc_name == nullptr || !GetInstanceProcAddr) {
185     return nullptr;
186   }
187 
188   // A VK_NULL_HANDLE as the instance is an acceptable parameter.
189   return GetInstanceProcAddr(instance, proc_name);
190 }
191 
AcquireProc(const char * proc_name,const VulkanHandle<VkDevice> & device) const192 PFN_vkVoidFunction VulkanProcTable::AcquireProc(
193     const char* proc_name,
194     const VulkanHandle<VkDevice>& device) const {
195   if (proc_name == nullptr || !device || !GetDeviceProcAddr) {
196     return nullptr;
197   }
198 
199   return GetDeviceProcAddr(device, proc_name);
200 }
201 
CreateSkiaGetProc() const202 GrVkGetProc VulkanProcTable::CreateSkiaGetProc() const {
203   if (!IsValid()) {
204     return nullptr;
205   }
206 
207   return [this](const char* proc_name, VkInstance instance, VkDevice device) {
208     if (device != VK_NULL_HANDLE) {
209       auto result = AcquireProc(proc_name, {device, nullptr});
210       if (result != nullptr) {
211         return result;
212       }
213     }
214 
215     return AcquireProc(proc_name, {instance, nullptr});
216   };
217 }
218 
219 }  // namespace vulkan
220