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