• 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 #ifndef RS_ENABLE_VK
10 #include "flutter/fml/logging.h"
11 #endif
12 #ifdef RS_ENABLE_VK
13 #include "flutter/vulkan/vulkan_hilog.h"
14 #endif
15 
16 #ifdef RS_ENABLE_VK
17 #define ACQUIRE_PROC(name, context)                          \
18   if (!(name = AcquireProc("vk" #name, context))) {          \
19     LOGE("Could not acquire proc: vk" #name);                \
20     return false;                                            \
21   }
22 #else
23 #define ACQUIRE_PROC(name, context)                          \
24   if (!(name = AcquireProc("vk" #name, context))) {          \
25     FML_DLOG(INFO) << "Could not acquire proc: vk" << #name; \
26     return false;                                            \
27   }
28 #endif
29 
30 namespace vulkan {
31 
VulkanProcTable()32 VulkanProcTable::VulkanProcTable()
33     : handle_(nullptr), acquired_mandatory_proc_addresses_(false) {
34   acquired_mandatory_proc_addresses_ =
35       OpenLibraryHandle() && SetupLoaderProcAddresses();
36 }
37 
~VulkanProcTable()38 VulkanProcTable::~VulkanProcTable() {
39   CloseLibraryHandle();
40 }
41 
HasAcquiredMandatoryProcAddresses() const42 bool VulkanProcTable::HasAcquiredMandatoryProcAddresses() const {
43   return acquired_mandatory_proc_addresses_;
44 }
45 
IsValid() const46 bool VulkanProcTable::IsValid() const {
47   return instance_ && device_;
48 }
49 
AreInstanceProcsSetup() const50 bool VulkanProcTable::AreInstanceProcsSetup() const {
51   return instance_;
52 }
53 
AreDeviceProcsSetup() const54 bool VulkanProcTable::AreDeviceProcsSetup() const {
55   return device_;
56 }
57 
SetupLoaderProcAddresses()58 bool VulkanProcTable::SetupLoaderProcAddresses() {
59   if (handle_ == nullptr) {
60     return true;
61   }
62 
63 #ifdef RS_ENABLE_VK
64   GetInstanceProcAddr =
65 #if VULKAN_LINK_STATICALLY
66       GetInstanceProcAddr = &vkGetInstanceProcAddr;
67 #else  // VULKAN_LINK_STATICALLY
68       reinterpret_cast<PFN_vkGetInstanceProcAddr>(dlsym(handle_, "vkGetInstanceProcAddr"));
69       GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(dlsym(handle_, "vkGetDeviceProcAddr"));
70       EnumerateInstanceExtensionProperties = reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(
71           dlsym(handle_, "vkEnumerateInstanceExtensionProperties"));
72       CreateInstance = reinterpret_cast<PFN_vkCreateInstance>(dlsym(handle_, "vkCreateInstance"));
73 #endif // VULKAN_LINK_STATICALLY
74 #else
75   GetInstanceProcAddr =
76 #if VULKAN_LINK_STATICALLY
77       GetInstanceProcAddr = &vkGetInstanceProcAddr;
78 #else   // VULKAN_LINK_STATICALLY
79       reinterpret_cast<PFN_vkGetInstanceProcAddr>(
80           dlsym(handle_, "vkGetInstanceProcAddr"));
81 #endif  // VULKAN_LINK_STATICALLY
82 #endif
83 
84   if (!GetInstanceProcAddr) {
85 #ifdef RS_ENABLE_VK
86     LOGE("Could not acquire vkGetInstanceProcAddr.");
87 #else
88     FML_DLOG(WARNING) << "Could not acquire vkGetInstanceProcAddr.";
89 #endif
90     return false;
91   }
92 
93   VulkanHandle<VkInstance> null_instance(VK_NULL_HANDLE, nullptr);
94 
95 #ifndef RS_ENABLE_VK
96   ACQUIRE_PROC(CreateInstance, null_instance);
97   ACQUIRE_PROC(EnumerateInstanceExtensionProperties, null_instance);
98 #endif
99   ACQUIRE_PROC(EnumerateInstanceLayerProperties, null_instance);
100 
101   return true;
102 }
103 
SetupInstanceProcAddresses(const VulkanHandle<VkInstance> & handle)104 bool VulkanProcTable::SetupInstanceProcAddresses(
105     const VulkanHandle<VkInstance>& handle) {
106   ACQUIRE_PROC(CreateDevice, handle);
107   ACQUIRE_PROC(DestroyDevice, handle);
108   ACQUIRE_PROC(DestroyInstance, handle);
109   ACQUIRE_PROC(EnumerateDeviceLayerProperties, handle);
110   ACQUIRE_PROC(EnumeratePhysicalDevices, handle);
111 #ifdef RS_ENABLE_VK
112   ACQUIRE_PROC(GetPhysicalDeviceFeatures, handle);
113   ACQUIRE_PROC(GetPhysicalDeviceQueueFamilyProperties, handle);
114   ACQUIRE_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR, handle);
115   ACQUIRE_PROC(GetPhysicalDeviceSurfaceFormatsKHR, handle);
116   ACQUIRE_PROC(GetPhysicalDeviceSurfacePresentModesKHR, handle);
117   ACQUIRE_PROC(GetPhysicalDeviceSurfaceSupportKHR, handle);
118   ACQUIRE_PROC(DestroySurfaceKHR, handle);
119   ACQUIRE_PROC(CreateOHOSSurfaceOpenHarmony, handle);
120 #else
121   ACQUIRE_PROC(GetDeviceProcAddr, handle);
122   ACQUIRE_PROC(GetPhysicalDeviceFeatures, handle);
123   ACQUIRE_PROC(GetPhysicalDeviceQueueFamilyProperties, handle);
124 #if OS_ANDROID
125   ACQUIRE_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR, handle);
126   ACQUIRE_PROC(GetPhysicalDeviceSurfaceFormatsKHR, handle);
127   ACQUIRE_PROC(GetPhysicalDeviceSurfacePresentModesKHR, handle);
128   ACQUIRE_PROC(GetPhysicalDeviceSurfaceSupportKHR, handle);
129   ACQUIRE_PROC(DestroySurfaceKHR, handle);
130   ACQUIRE_PROC(CreateAndroidSurfaceKHR, handle);
131 #endif  // OS_ANDROID
132 #endif // RS_ENABLE_VK
133 
134   // The debug report functions are optional. We don't want proc acquisition to
135   // fail here because the optional methods were not present (since ACQUIRE_PROC
136   // returns false on failure). Wrap the optional proc acquisitions in an
137   // anonymous lambda and invoke it. We don't really care about the result since
138   // users of Debug reporting functions check for their presence explicitly.
139 #ifndef RS_ENABLE_VK
140   [this, &handle]() -> bool {
141     ACQUIRE_PROC(CreateDebugReportCallbackEXT, handle);
142     ACQUIRE_PROC(DestroyDebugReportCallbackEXT, handle);
143     return true;
144   }();
145 #endif
146 
147   instance_ = {handle, nullptr};
148   return true;
149 }
150 
SetupDeviceProcAddresses(const VulkanHandle<VkDevice> & handle)151 bool VulkanProcTable::SetupDeviceProcAddresses(
152     const VulkanHandle<VkDevice>& handle) {
153   ACQUIRE_PROC(AllocateCommandBuffers, handle);
154   ACQUIRE_PROC(AllocateMemory, handle);
155   ACQUIRE_PROC(BeginCommandBuffer, handle);
156   ACQUIRE_PROC(BindImageMemory, handle);
157   ACQUIRE_PROC(CmdPipelineBarrier, handle);
158   ACQUIRE_PROC(CreateCommandPool, handle);
159   ACQUIRE_PROC(CreateFence, handle);
160   ACQUIRE_PROC(CreateImage, handle);
161   ACQUIRE_PROC(CreateSemaphore, handle);
162   ACQUIRE_PROC(DestroyCommandPool, handle);
163   ACQUIRE_PROC(DestroyFence, handle);
164   ACQUIRE_PROC(DestroyImage, handle);
165   ACQUIRE_PROC(DestroySemaphore, handle);
166   ACQUIRE_PROC(DeviceWaitIdle, handle);
167   ACQUIRE_PROC(EndCommandBuffer, handle);
168   ACQUIRE_PROC(FreeCommandBuffers, handle);
169   ACQUIRE_PROC(FreeMemory, handle);
170   ACQUIRE_PROC(GetDeviceQueue, handle);
171   ACQUIRE_PROC(GetImageMemoryRequirements, handle);
172   ACQUIRE_PROC(QueueSubmit, handle);
173   ACQUIRE_PROC(QueueWaitIdle, handle);
174   ACQUIRE_PROC(ResetCommandBuffer, handle);
175   ACQUIRE_PROC(ResetFences, handle);
176   ACQUIRE_PROC(WaitForFences, handle);
177 #ifdef RS_ENABLE_VK
178   ACQUIRE_PROC(AcquireNextImageKHR, handle);
179   ACQUIRE_PROC(CreateSwapchainKHR, handle);
180   ACQUIRE_PROC(DestroySwapchainKHR, handle);
181   ACQUIRE_PROC(GetSwapchainImagesKHR, handle);
182   ACQUIRE_PROC(QueuePresentKHR, handle);
183 #else
184 #if OS_ANDROID
185   ACQUIRE_PROC(AcquireNextImageKHR, handle);
186   ACQUIRE_PROC(CreateSwapchainKHR, handle);
187   ACQUIRE_PROC(DestroySwapchainKHR, handle);
188   ACQUIRE_PROC(GetSwapchainImagesKHR, handle);
189   ACQUIRE_PROC(QueuePresentKHR, handle);
190 #endif  // OS_ANDROID
191 #if OS_FUCHSIA
192   ACQUIRE_PROC(GetMemoryZirconHandleFUCHSIA, handle);
193   ACQUIRE_PROC(ImportSemaphoreZirconHandleFUCHSIA, handle);
194 #endif  // OS_FUCHSIA
195 #endif // RS_ENABLE_VK
196   device_ = {handle, nullptr};
197   return true;
198 }
199 
OpenLibraryHandle()200 bool VulkanProcTable::OpenLibraryHandle() {
201 #if VULKAN_LINK_STATICALLY
202   static char kDummyLibraryHandle = '\0';
203   handle_ = reinterpret_cast<decltype(handle_)>(&kDummyLibraryHandle);
204   return true;
205 #else   // VULKAN_LINK_STATICALLY
206   dlerror();  // clear existing errors on thread.
207   handle_ = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
208   if (handle_ == nullptr) {
209 #ifdef RS_ENABLE_VK
210     LOGE("Could not open the vulkan library: %s", dlerror());
211 #else
212     FML_DLOG(WARNING) << "Could not open the vulkan library: " << dlerror();
213 #endif
214     return false;
215   }
216   return true;
217 #endif  // VULKAN_LINK_STATICALLY
218 }
219 
CloseLibraryHandle()220 bool VulkanProcTable::CloseLibraryHandle() {
221 #if VULKAN_LINK_STATICALLY
222   handle_ = nullptr;
223   return true;
224 #else
225   if (handle_ != nullptr) {
226     dlerror();  // clear existing errors on thread.
227     if (dlclose(handle_) != 0) {
228 #ifdef RS_ENABLE_VK
229       LOGE("Could not close the vulkan library handle. This "
230                  "indicates a leak.");
231       LOGE("%s", dlerror());
232 #else
233       FML_DLOG(ERROR) << "Could not close the vulkan library handle. This "
234                          "indicates a leak.";
235       FML_DLOG(ERROR) << dlerror();
236 #endif
237     }
238     handle_ = nullptr;
239   }
240   return handle_ == nullptr;
241 #endif
242 }
243 
AcquireProc(const char * proc_name,const VulkanHandle<VkInstance> & instance) const244 PFN_vkVoidFunction VulkanProcTable::AcquireProc(
245     const char* proc_name,
246     const VulkanHandle<VkInstance>& instance) const {
247   if (proc_name == nullptr || !GetInstanceProcAddr) {
248     return nullptr;
249   }
250 
251   // A VK_NULL_HANDLE as the instance is an acceptable parameter.
252   return GetInstanceProcAddr(instance, proc_name);
253 }
254 
AcquireProc(const char * proc_name,const VulkanHandle<VkDevice> & device) const255 PFN_vkVoidFunction VulkanProcTable::AcquireProc(
256     const char* proc_name,
257     const VulkanHandle<VkDevice>& device) const {
258   if (proc_name == nullptr || !device || !GetDeviceProcAddr) {
259     return nullptr;
260   }
261 
262   return GetDeviceProcAddr(device, proc_name);
263 }
264 
CreateSkiaGetProc() const265 GrVkGetProc VulkanProcTable::CreateSkiaGetProc() const {
266   if (!IsValid()) {
267     return nullptr;
268   }
269 
270   return [this](const char* proc_name, VkInstance instance, VkDevice device) {
271     if (device != VK_NULL_HANDLE) {
272       auto result = AcquireProc(proc_name, {device, nullptr});
273       if (result != nullptr) {
274         return result;
275       }
276     }
277 
278     return AcquireProc(proc_name, {instance, nullptr});
279   };
280 }
281 
282 }  // namespace vulkan
283