blob: b43ab6c9df3c5faa0086e9f8c17f7e478db5993d [file] [log] [blame]
Ian Elliott1f0911e2022-09-09 16:31:47 -06001/*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// #define LOG_NDEBUG 0
18#undef LOG_TAG
19#define LOG_TAG "RenderEngine"
20#define ATRACE_TAG ATRACE_TAG_GRAPHICS
21
22#include "SkiaVkRenderEngine.h"
23
24#include <GrBackendSemaphore.h>
25#include <GrContextOptions.h>
26#include <vk/GrVkExtensions.h>
27#include <vk/GrVkTypes.h>
Kevin Lubick2fc49112023-10-13 13:10:48 +000028#include <include/gpu/ganesh/vk/GrVkDirectContext.h>
Ian Elliott1f0911e2022-09-09 16:31:47 -060029
30#include <android-base/stringprintf.h>
31#include <gui/TraceUtils.h>
32#include <sync/sync.h>
33#include <utils/Trace.h>
34
35#include <cstdint>
36#include <memory>
Nolan Scobie9e9ebf82024-01-31 14:16:16 -050037#include <sstream>
Nolan Scobie0f539a72024-01-29 10:49:10 -050038#include <string>
Ian Elliott1f0911e2022-09-09 16:31:47 -060039#include <vector>
40
41#include <vulkan/vulkan.h>
42#include "log/log_main.h"
43
44namespace android {
45namespace renderengine {
46
47struct VulkanFuncs {
48 PFN_vkCreateSemaphore vkCreateSemaphore = nullptr;
49 PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR = nullptr;
50 PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR = nullptr;
51 PFN_vkDestroySemaphore vkDestroySemaphore = nullptr;
52
53 PFN_vkDeviceWaitIdle vkDeviceWaitIdle = nullptr;
54 PFN_vkDestroyDevice vkDestroyDevice = nullptr;
55 PFN_vkDestroyInstance vkDestroyInstance = nullptr;
56};
57
Ian Elliott98e87162023-04-14 14:05:19 -060058// Ref-Count a semaphore
59struct DestroySemaphoreInfo {
60 VkSemaphore mSemaphore;
61 // We need to make sure we don't delete the VkSemaphore until it is done being used by both Skia
62 // (including by the GPU) and inside SkiaVkRenderEngine. So we always start with two refs, one
63 // owned by Skia and one owned by the SkiaVkRenderEngine. The refs are decremented each time
64 // delete_semaphore* is called with this object. Skia will call destroy_semaphore* once it is
65 // done with the semaphore and the GPU has finished work on the semaphore. SkiaVkRenderEngine
66 // calls delete_semaphore* after sending the semaphore to Skia and exporting it if need be.
67 int mRefs = 2;
68
69 DestroySemaphoreInfo(VkSemaphore semaphore) : mSemaphore(semaphore) {}
70};
71
Nolan Scobie0f539a72024-01-29 10:49:10 -050072namespace {
73void onVkDeviceFault(void* callbackContext, const std::string& description,
74 const std::vector<VkDeviceFaultAddressInfoEXT>& addressInfos,
75 const std::vector<VkDeviceFaultVendorInfoEXT>& vendorInfos,
76 const std::vector<std::byte>& vendorBinaryData);
77} // anonymous namespace
78
Ian Elliott1f0911e2022-09-09 16:31:47 -060079struct VulkanInterface {
80 bool initialized = false;
81 VkInstance instance;
82 VkPhysicalDevice physicalDevice;
83 VkDevice device;
84 VkQueue queue;
85 int queueIndex;
86 uint32_t apiVersion;
87 GrVkExtensions grExtensions;
88 VkPhysicalDeviceFeatures2* physicalDeviceFeatures2 = nullptr;
89 VkPhysicalDeviceSamplerYcbcrConversionFeatures* samplerYcbcrConversionFeatures = nullptr;
Ian Elliottae0b8d12023-01-05 19:13:42 -070090 VkPhysicalDeviceProtectedMemoryFeatures* protectedMemoryFeatures = nullptr;
Nolan Scobie0f539a72024-01-29 10:49:10 -050091 VkPhysicalDeviceFaultFeaturesEXT* deviceFaultFeatures = nullptr;
Ian Elliott1f0911e2022-09-09 16:31:47 -060092 GrVkGetProc grGetProc;
93 bool isProtected;
94 bool isRealtimePriority;
95
96 VulkanFuncs funcs;
97
98 std::vector<std::string> instanceExtensionNames;
99 std::vector<std::string> deviceExtensionNames;
100
101 GrVkBackendContext getBackendContext() {
102 GrVkBackendContext backendContext;
103 backendContext.fInstance = instance;
104 backendContext.fPhysicalDevice = physicalDevice;
105 backendContext.fDevice = device;
106 backendContext.fQueue = queue;
107 backendContext.fGraphicsQueueIndex = queueIndex;
108 backendContext.fMaxAPIVersion = apiVersion;
109 backendContext.fVkExtensions = &grExtensions;
110 backendContext.fDeviceFeatures2 = physicalDeviceFeatures2;
111 backendContext.fGetProc = grGetProc;
112 backendContext.fProtectedContext = isProtected ? GrProtected::kYes : GrProtected::kNo;
Nolan Scobie0f539a72024-01-29 10:49:10 -0500113 backendContext.fDeviceLostContext = this; // VulkanInterface is long-lived
114 backendContext.fDeviceLostProc = onVkDeviceFault;
Ian Elliott1f0911e2022-09-09 16:31:47 -0600115 return backendContext;
116 };
117
118 VkSemaphore createExportableSemaphore() {
119 VkExportSemaphoreCreateInfo exportInfo;
120 exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
121 exportInfo.pNext = nullptr;
122 exportInfo.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
123
124 VkSemaphoreCreateInfo semaphoreInfo;
125 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
126 semaphoreInfo.pNext = &exportInfo;
127 semaphoreInfo.flags = 0;
128
129 VkSemaphore semaphore;
130 VkResult err = funcs.vkCreateSemaphore(device, &semaphoreInfo, nullptr, &semaphore);
131 if (VK_SUCCESS != err) {
132 ALOGE("%s: failed to create semaphore. err %d\n", __func__, err);
133 return VK_NULL_HANDLE;
134 }
135
136 return semaphore;
137 }
138
139 // syncFd cannot be <= 0
140 VkSemaphore importSemaphoreFromSyncFd(int syncFd) {
141 VkSemaphoreCreateInfo semaphoreInfo;
142 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
143 semaphoreInfo.pNext = nullptr;
144 semaphoreInfo.flags = 0;
145
146 VkSemaphore semaphore;
147 VkResult err = funcs.vkCreateSemaphore(device, &semaphoreInfo, nullptr, &semaphore);
148 if (VK_SUCCESS != err) {
149 ALOGE("%s: failed to create import semaphore", __func__);
150 return VK_NULL_HANDLE;
151 }
152
153 VkImportSemaphoreFdInfoKHR importInfo;
154 importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
155 importInfo.pNext = nullptr;
156 importInfo.semaphore = semaphore;
157 importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
158 importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
159 importInfo.fd = syncFd;
160
161 err = funcs.vkImportSemaphoreFdKHR(device, &importInfo);
162 if (VK_SUCCESS != err) {
163 funcs.vkDestroySemaphore(device, semaphore, nullptr);
164 ALOGE("%s: failed to import semaphore", __func__);
165 return VK_NULL_HANDLE;
166 }
167
168 return semaphore;
169 }
170
171 int exportSemaphoreSyncFd(VkSemaphore semaphore) {
172 int res;
173
174 VkSemaphoreGetFdInfoKHR getFdInfo;
175 getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
176 getFdInfo.pNext = nullptr;
177 getFdInfo.semaphore = semaphore;
178 getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
179
180 VkResult err = funcs.vkGetSemaphoreFdKHR(device, &getFdInfo, &res);
181 if (VK_SUCCESS != err) {
182 ALOGE("%s: failed to export semaphore, err: %d", __func__, err);
183 return -1;
184 }
185 return res;
186 }
187
188 void destroySemaphore(VkSemaphore semaphore) {
189 funcs.vkDestroySemaphore(device, semaphore, nullptr);
190 }
191};
192
Nolan Scobie0f539a72024-01-29 10:49:10 -0500193namespace {
194void onVkDeviceFault(void* callbackContext, const std::string& description,
195 const std::vector<VkDeviceFaultAddressInfoEXT>& addressInfos,
196 const std::vector<VkDeviceFaultVendorInfoEXT>& vendorInfos,
197 const std::vector<std::byte>& vendorBinaryData) {
198 VulkanInterface* interface = static_cast<VulkanInterface*>(callbackContext);
Nolan Scobie9e9ebf82024-01-31 14:16:16 -0500199 const std::string protectedStr = interface->isProtected ? "protected" : "non-protected";
Nolan Scobie0f539a72024-01-29 10:49:10 -0500200 // The final crash string should contain as much differentiating info as possible, up to 1024
201 // bytes. As this final message is constructed, the same information is also dumped to the logs
202 // but in a more verbose format. Building the crash string is unsightly, so the clearer logging
203 // statement is always placed first to give context.
204 ALOGE("VK_ERROR_DEVICE_LOST (%s context): %s", protectedStr.c_str(), description.c_str());
Nolan Scobie9e9ebf82024-01-31 14:16:16 -0500205 std::stringstream crashMsg;
206 crashMsg << "VK_ERROR_DEVICE_LOST (" << protectedStr;
Nolan Scobie0f539a72024-01-29 10:49:10 -0500207
208 if (!addressInfos.empty()) {
209 ALOGE("%zu VkDeviceFaultAddressInfoEXT:", addressInfos.size());
Nolan Scobie9e9ebf82024-01-31 14:16:16 -0500210 crashMsg << ", " << addressInfos.size() << " address info (";
Nolan Scobie0f539a72024-01-29 10:49:10 -0500211 for (VkDeviceFaultAddressInfoEXT addressInfo : addressInfos) {
212 ALOGE(" addressType: %d", (int)addressInfo.addressType);
213 ALOGE(" reportedAddress: %" PRIu64, addressInfo.reportedAddress);
214 ALOGE(" addressPrecision: %" PRIu64, addressInfo.addressPrecision);
Nolan Scobie9e9ebf82024-01-31 14:16:16 -0500215 crashMsg << addressInfo.addressType << ":"
216 << addressInfo.reportedAddress << ":"
217 << addressInfo.addressPrecision << ", ";
Nolan Scobie0f539a72024-01-29 10:49:10 -0500218 }
Nolan Scobie9e9ebf82024-01-31 14:16:16 -0500219 crashMsg.seekp(-2, crashMsg.cur); // Move back to overwrite trailing ", "
220 crashMsg << ")";
Nolan Scobie0f539a72024-01-29 10:49:10 -0500221 }
222
223 if (!vendorInfos.empty()) {
224 ALOGE("%zu VkDeviceFaultVendorInfoEXT:", vendorInfos.size());
Nolan Scobie9e9ebf82024-01-31 14:16:16 -0500225 crashMsg << ", " << vendorInfos.size() << " vendor info (";
Nolan Scobie0f539a72024-01-29 10:49:10 -0500226 for (VkDeviceFaultVendorInfoEXT vendorInfo : vendorInfos) {
227 ALOGE(" description: %s", vendorInfo.description);
228 ALOGE(" vendorFaultCode: %" PRIu64, vendorInfo.vendorFaultCode);
229 ALOGE(" vendorFaultData: %" PRIu64, vendorInfo.vendorFaultData);
230 // Omit descriptions for individual vendor info structs in the crash string, as the
231 // fault code and fault data fields should be enough for clustering, and the verbosity
232 // isn't worth it. Additionally, vendors may just set the general description field of
233 // the overall fault to the description of the first element in this list, and that
234 // overall description will be placed at the end of the crash string.
Nolan Scobie9e9ebf82024-01-31 14:16:16 -0500235 crashMsg << vendorInfo.vendorFaultCode << ":"
236 << vendorInfo.vendorFaultData << ", ";
Nolan Scobie0f539a72024-01-29 10:49:10 -0500237 }
Nolan Scobie9e9ebf82024-01-31 14:16:16 -0500238 crashMsg.seekp(-2, crashMsg.cur); // Move back to overwrite trailing ", "
239 crashMsg << ")";
Nolan Scobie0f539a72024-01-29 10:49:10 -0500240 }
241
242 if (!vendorBinaryData.empty()) {
243 // TODO: b/322830575 - Log in base64, or dump directly to a file that gets put in bugreports
244 ALOGE("%zu bytes of vendor-specific binary data (please notify Android's Core Graphics"
245 " Stack team if you observe this message).",
246 vendorBinaryData.size());
Nolan Scobie9e9ebf82024-01-31 14:16:16 -0500247 crashMsg << ", " << vendorBinaryData.size() << " bytes binary";
Nolan Scobie0f539a72024-01-29 10:49:10 -0500248 }
249
Nolan Scobie9e9ebf82024-01-31 14:16:16 -0500250 crashMsg << "): " << description;
251 LOG_ALWAYS_FATAL("%s", crashMsg.str().c_str());
Nolan Scobie0f539a72024-01-29 10:49:10 -0500252};
253} // anonymous namespace
254
Ian Elliott1f0911e2022-09-09 16:31:47 -0600255static GrVkGetProc sGetProc = [](const char* proc_name, VkInstance instance, VkDevice device) {
256 if (device != VK_NULL_HANDLE) {
257 return vkGetDeviceProcAddr(device, proc_name);
258 }
259 return vkGetInstanceProcAddr(instance, proc_name);
260};
261
262#define BAIL(fmt, ...) \
263 { \
264 ALOGE("%s: " fmt ", bailing", __func__, ##__VA_ARGS__); \
265 return interface; \
266 }
267
268#define CHECK_NONNULL(expr) \
269 if ((expr) == nullptr) { \
270 BAIL("[%s] null", #expr); \
271 }
272
273#define VK_CHECK(expr) \
274 if ((expr) != VK_SUCCESS) { \
275 BAIL("[%s] failed. err = %d", #expr, expr); \
276 return interface; \
277 }
278
279#define VK_GET_PROC(F) \
280 PFN_vk##F vk##F = (PFN_vk##F)vkGetInstanceProcAddr(VK_NULL_HANDLE, "vk" #F); \
281 CHECK_NONNULL(vk##F)
282#define VK_GET_INST_PROC(instance, F) \
283 PFN_vk##F vk##F = (PFN_vk##F)vkGetInstanceProcAddr(instance, "vk" #F); \
284 CHECK_NONNULL(vk##F)
285#define VK_GET_DEV_PROC(device, F) \
286 PFN_vk##F vk##F = (PFN_vk##F)vkGetDeviceProcAddr(device, "vk" #F); \
287 CHECK_NONNULL(vk##F)
288
289VulkanInterface initVulkanInterface(bool protectedContent = false) {
Leon Scroggins IIIf3369ed2024-02-16 17:52:42 -0500290 const nsecs_t timeBefore = systemTime();
Ian Elliott1f0911e2022-09-09 16:31:47 -0600291 VulkanInterface interface;
292
293 VK_GET_PROC(EnumerateInstanceVersion);
294 uint32_t instanceVersion;
295 VK_CHECK(vkEnumerateInstanceVersion(&instanceVersion));
296
297 if (instanceVersion < VK_MAKE_VERSION(1, 1, 0)) {
298 return interface;
299 }
300
301 const VkApplicationInfo appInfo = {
302 VK_STRUCTURE_TYPE_APPLICATION_INFO, nullptr, "surfaceflinger", 0, "android platform", 0,
303 VK_MAKE_VERSION(1, 1, 0),
304 };
305
306 VK_GET_PROC(EnumerateInstanceExtensionProperties);
307
308 uint32_t extensionCount = 0;
309 VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr));
310 std::vector<VkExtensionProperties> instanceExtensions(extensionCount);
311 VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount,
312 instanceExtensions.data()));
313 std::vector<const char*> enabledInstanceExtensionNames;
314 enabledInstanceExtensionNames.reserve(instanceExtensions.size());
315 interface.instanceExtensionNames.reserve(instanceExtensions.size());
316 for (const auto& instExt : instanceExtensions) {
317 enabledInstanceExtensionNames.push_back(instExt.extensionName);
318 interface.instanceExtensionNames.push_back(instExt.extensionName);
319 }
320
321 const VkInstanceCreateInfo instanceCreateInfo = {
322 VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
323 nullptr,
324 0,
325 &appInfo,
326 0,
327 nullptr,
328 (uint32_t)enabledInstanceExtensionNames.size(),
329 enabledInstanceExtensionNames.data(),
330 };
331
332 VK_GET_PROC(CreateInstance);
333 VkInstance instance;
334 VK_CHECK(vkCreateInstance(&instanceCreateInfo, nullptr, &instance));
335
336 VK_GET_INST_PROC(instance, DestroyInstance);
337 interface.funcs.vkDestroyInstance = vkDestroyInstance;
338 VK_GET_INST_PROC(instance, EnumeratePhysicalDevices);
339 VK_GET_INST_PROC(instance, EnumerateDeviceExtensionProperties);
340 VK_GET_INST_PROC(instance, GetPhysicalDeviceProperties2);
341 VK_GET_INST_PROC(instance, GetPhysicalDeviceExternalSemaphoreProperties);
Ian Elliottd50658f2023-06-28 11:08:35 -0600342 VK_GET_INST_PROC(instance, GetPhysicalDeviceQueueFamilyProperties2);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600343 VK_GET_INST_PROC(instance, GetPhysicalDeviceFeatures2);
344 VK_GET_INST_PROC(instance, CreateDevice);
345
346 uint32_t physdevCount;
347 VK_CHECK(vkEnumeratePhysicalDevices(instance, &physdevCount, nullptr));
348 if (physdevCount == 0) {
349 BAIL("Could not find any physical devices");
350 }
351
352 physdevCount = 1;
353 VkPhysicalDevice physicalDevice;
354 VkResult enumeratePhysDevsErr =
355 vkEnumeratePhysicalDevices(instance, &physdevCount, &physicalDevice);
356 if (enumeratePhysDevsErr != VK_SUCCESS && VK_INCOMPLETE != enumeratePhysDevsErr) {
357 BAIL("vkEnumeratePhysicalDevices failed with non-VK_INCOMPLETE error: %d",
358 enumeratePhysDevsErr);
359 }
360
361 VkPhysicalDeviceProperties2 physDevProps = {
362 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
363 0,
364 {},
365 };
366 VkPhysicalDeviceProtectedMemoryProperties protMemProps = {
367 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES,
368 0,
369 {},
370 };
371
372 if (protectedContent) {
373 physDevProps.pNext = &protMemProps;
374 }
375
376 vkGetPhysicalDeviceProperties2(physicalDevice, &physDevProps);
377 if (physDevProps.properties.apiVersion < VK_MAKE_VERSION(1, 1, 0)) {
378 BAIL("Could not find a Vulkan 1.1+ physical device");
379 }
380
381 // Check for syncfd support. Bail if we cannot both import and export them.
382 VkPhysicalDeviceExternalSemaphoreInfo semInfo = {
383 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
384 nullptr,
385 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
386 };
387 VkExternalSemaphoreProperties semProps = {
388 VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, nullptr, 0, 0, 0,
389 };
390 vkGetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, &semInfo, &semProps);
391
392 bool sufficientSemaphoreSyncFdSupport = (semProps.exportFromImportedHandleTypes &
393 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) &&
394 (semProps.compatibleHandleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) &&
395 (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT) &&
396 (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
397
398 if (!sufficientSemaphoreSyncFdSupport) {
399 BAIL("Vulkan device does not support sufficient external semaphore sync fd features. "
400 "exportFromImportedHandleTypes 0x%x (needed 0x%x) "
401 "compatibleHandleTypes 0x%x (needed 0x%x) "
402 "externalSemaphoreFeatures 0x%x (needed 0x%x) ",
403 semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
404 semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
405 semProps.externalSemaphoreFeatures,
406 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
407 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
408 } else {
409 ALOGD("Vulkan device supports sufficient external semaphore sync fd features. "
410 "exportFromImportedHandleTypes 0x%x (needed 0x%x) "
411 "compatibleHandleTypes 0x%x (needed 0x%x) "
412 "externalSemaphoreFeatures 0x%x (needed 0x%x) ",
413 semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
414 semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
415 semProps.externalSemaphoreFeatures,
416 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
417 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
418 }
419
420 uint32_t queueCount;
Ian Elliottd50658f2023-06-28 11:08:35 -0600421 vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, nullptr);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600422 if (queueCount == 0) {
423 BAIL("Could not find queues for physical device");
424 }
425
Ian Elliottd50658f2023-06-28 11:08:35 -0600426 std::vector<VkQueueFamilyProperties2> queueProps(queueCount);
427 std::vector<VkQueueFamilyGlobalPriorityPropertiesEXT> queuePriorityProps(queueCount);
428 VkQueueGlobalPriorityKHR queuePriority = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR;
429 // Even though we don't yet know if the VK_EXT_global_priority extension is available,
430 // we can safely add the request to the pNext chain, and if the extension is not
431 // available, it will be ignored.
432 for (uint32_t i = 0; i < queueCount; ++i) {
433 queuePriorityProps[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT;
434 queuePriorityProps[i].pNext = nullptr;
435 queueProps[i].pNext = &queuePriorityProps[i];
436 }
437 vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, queueProps.data());
Ian Elliott1f0911e2022-09-09 16:31:47 -0600438
439 int graphicsQueueIndex = -1;
440 for (uint32_t i = 0; i < queueCount; ++i) {
Ian Elliottd50658f2023-06-28 11:08:35 -0600441 // Look at potential answers to the VK_EXT_global_priority query. If answers were
442 // provided, we may adjust the queuePriority.
443 if (queueProps[i].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
444 for (uint32_t j = 0; j < queuePriorityProps[i].priorityCount; j++) {
445 if (queuePriorityProps[i].priorities[j] > queuePriority) {
446 queuePriority = queuePriorityProps[i].priorities[j];
447 }
448 }
449 if (queuePriority == VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR) {
450 interface.isRealtimePriority = true;
451 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600452 graphicsQueueIndex = i;
453 break;
454 }
455 }
456
457 if (graphicsQueueIndex == -1) {
458 BAIL("Could not find a graphics queue family");
459 }
460
461 uint32_t deviceExtensionCount;
462 VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount,
463 nullptr));
464 std::vector<VkExtensionProperties> deviceExtensions(deviceExtensionCount);
465 VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount,
466 deviceExtensions.data()));
467
468 std::vector<const char*> enabledDeviceExtensionNames;
469 enabledDeviceExtensionNames.reserve(deviceExtensions.size());
470 interface.deviceExtensionNames.reserve(deviceExtensions.size());
471 for (const auto& devExt : deviceExtensions) {
472 enabledDeviceExtensionNames.push_back(devExt.extensionName);
473 interface.deviceExtensionNames.push_back(devExt.extensionName);
474 }
475
476 interface.grExtensions.init(sGetProc, instance, physicalDevice,
477 enabledInstanceExtensionNames.size(),
478 enabledInstanceExtensionNames.data(),
479 enabledDeviceExtensionNames.size(),
480 enabledDeviceExtensionNames.data());
481
482 if (!interface.grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
483 BAIL("Vulkan driver doesn't support external semaphore fd");
484 }
485
486 interface.physicalDeviceFeatures2 = new VkPhysicalDeviceFeatures2;
487 interface.physicalDeviceFeatures2->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
488 interface.physicalDeviceFeatures2->pNext = nullptr;
489
490 interface.samplerYcbcrConversionFeatures = new VkPhysicalDeviceSamplerYcbcrConversionFeatures;
491 interface.samplerYcbcrConversionFeatures->sType =
492 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
493 interface.samplerYcbcrConversionFeatures->pNext = nullptr;
494
495 interface.physicalDeviceFeatures2->pNext = interface.samplerYcbcrConversionFeatures;
496 void** tailPnext = &interface.samplerYcbcrConversionFeatures->pNext;
497
498 if (protectedContent) {
Ian Elliottae0b8d12023-01-05 19:13:42 -0700499 interface.protectedMemoryFeatures = new VkPhysicalDeviceProtectedMemoryFeatures;
Ian Elliott1f0911e2022-09-09 16:31:47 -0600500 interface.protectedMemoryFeatures->sType =
501 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
502 interface.protectedMemoryFeatures->pNext = nullptr;
503 *tailPnext = interface.protectedMemoryFeatures;
504 tailPnext = &interface.protectedMemoryFeatures->pNext;
505 }
506
Nolan Scobie0f539a72024-01-29 10:49:10 -0500507 if (interface.grExtensions.hasExtension(VK_EXT_DEVICE_FAULT_EXTENSION_NAME, 1)) {
508 interface.deviceFaultFeatures = new VkPhysicalDeviceFaultFeaturesEXT;
509 interface.deviceFaultFeatures->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
510 interface.deviceFaultFeatures->pNext = nullptr;
511 *tailPnext = interface.deviceFaultFeatures;
512 tailPnext = &interface.deviceFaultFeatures->pNext;
513 }
514
Ian Elliott1f0911e2022-09-09 16:31:47 -0600515 vkGetPhysicalDeviceFeatures2(physicalDevice, interface.physicalDeviceFeatures2);
516 // Looks like this would slow things down and we can't depend on it on all platforms
517 interface.physicalDeviceFeatures2->features.robustBufferAccess = VK_FALSE;
518
John Bauman1aab9922023-10-24 17:23:47 +0000519 if (protectedContent && !interface.protectedMemoryFeatures->protectedMemory) {
520 BAIL("Protected memory not supported");
521 }
522
Ian Elliott1f0911e2022-09-09 16:31:47 -0600523 float queuePriorities[1] = {0.0f};
524 void* queueNextPtr = nullptr;
525
526 VkDeviceQueueGlobalPriorityCreateInfoEXT queuePriorityCreateInfo = {
527 VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT,
528 nullptr,
529 // If queue priority is supported, RE should always have realtime priority.
Ian Elliottd50658f2023-06-28 11:08:35 -0600530 queuePriority,
Ian Elliott1f0911e2022-09-09 16:31:47 -0600531 };
532
533 if (interface.grExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) {
534 queueNextPtr = &queuePriorityCreateInfo;
Ian Elliott1f0911e2022-09-09 16:31:47 -0600535 }
536
537 VkDeviceQueueCreateFlags deviceQueueCreateFlags =
538 (VkDeviceQueueCreateFlags)(protectedContent ? VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT : 0);
539
540 const VkDeviceQueueCreateInfo queueInfo = {
541 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
542 queueNextPtr,
543 deviceQueueCreateFlags,
544 (uint32_t)graphicsQueueIndex,
545 1,
546 queuePriorities,
547 };
548
549 const VkDeviceCreateInfo deviceInfo = {
550 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
551 interface.physicalDeviceFeatures2,
552 0,
553 1,
554 &queueInfo,
555 0,
556 nullptr,
557 (uint32_t)enabledDeviceExtensionNames.size(),
558 enabledDeviceExtensionNames.data(),
559 nullptr,
560 };
561
562 ALOGD("Trying to create Vk device with protectedContent=%d", protectedContent);
563 VkDevice device;
564 VK_CHECK(vkCreateDevice(physicalDevice, &deviceInfo, nullptr, &device));
565 ALOGD("Trying to create Vk device with protectedContent=%d (success)", protectedContent);
566
567 VkQueue graphicsQueue;
Ian Elliott87e3dd82023-02-27 12:07:10 -0700568 VK_GET_DEV_PROC(device, GetDeviceQueue2);
569 const VkDeviceQueueInfo2 deviceQueueInfo2 = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2, nullptr,
570 deviceQueueCreateFlags,
571 (uint32_t)graphicsQueueIndex, 0};
572 vkGetDeviceQueue2(device, &deviceQueueInfo2, &graphicsQueue);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600573
574 VK_GET_DEV_PROC(device, DeviceWaitIdle);
575 VK_GET_DEV_PROC(device, DestroyDevice);
576 interface.funcs.vkDeviceWaitIdle = vkDeviceWaitIdle;
577 interface.funcs.vkDestroyDevice = vkDestroyDevice;
578
579 VK_GET_DEV_PROC(device, CreateSemaphore);
580 VK_GET_DEV_PROC(device, ImportSemaphoreFdKHR);
581 VK_GET_DEV_PROC(device, GetSemaphoreFdKHR);
582 VK_GET_DEV_PROC(device, DestroySemaphore);
583 interface.funcs.vkCreateSemaphore = vkCreateSemaphore;
584 interface.funcs.vkImportSemaphoreFdKHR = vkImportSemaphoreFdKHR;
585 interface.funcs.vkGetSemaphoreFdKHR = vkGetSemaphoreFdKHR;
586 interface.funcs.vkDestroySemaphore = vkDestroySemaphore;
587
588 // At this point, everything's succeeded and we can continue
589 interface.initialized = true;
590 interface.instance = instance;
591 interface.physicalDevice = physicalDevice;
592 interface.device = device;
593 interface.queue = graphicsQueue;
594 interface.queueIndex = graphicsQueueIndex;
595 interface.apiVersion = physDevProps.properties.apiVersion;
596 // grExtensions already constructed
597 // feature pointers already constructed
598 interface.grGetProc = sGetProc;
599 interface.isProtected = protectedContent;
600 // funcs already initialized
601
Leon Scroggins IIIf3369ed2024-02-16 17:52:42 -0500602 const nsecs_t timeAfter = systemTime();
603 const float initTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
604 ALOGD("%s: Success init Vulkan interface in %f ms", __func__, initTimeMs);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600605 return interface;
606}
607
608void teardownVulkanInterface(VulkanInterface* interface) {
609 interface->initialized = false;
610
611 if (interface->device != VK_NULL_HANDLE) {
612 interface->funcs.vkDeviceWaitIdle(interface->device);
613 interface->funcs.vkDestroyDevice(interface->device, nullptr);
614 interface->device = VK_NULL_HANDLE;
615 }
616 if (interface->instance != VK_NULL_HANDLE) {
617 interface->funcs.vkDestroyInstance(interface->instance, nullptr);
618 interface->instance = VK_NULL_HANDLE;
619 }
620
621 if (interface->protectedMemoryFeatures) {
622 delete interface->protectedMemoryFeatures;
623 }
624
625 if (interface->samplerYcbcrConversionFeatures) {
626 delete interface->samplerYcbcrConversionFeatures;
627 }
628
629 if (interface->physicalDeviceFeatures2) {
630 delete interface->physicalDeviceFeatures2;
631 }
632
Nolan Scobie0f539a72024-01-29 10:49:10 -0500633 if (interface->deviceFaultFeatures) {
634 delete interface->deviceFaultFeatures;
635 }
636
Ian Elliott1f0911e2022-09-09 16:31:47 -0600637 interface->samplerYcbcrConversionFeatures = nullptr;
638 interface->physicalDeviceFeatures2 = nullptr;
639 interface->protectedMemoryFeatures = nullptr;
640}
641
642static VulkanInterface sVulkanInterface;
643static VulkanInterface sProtectedContentVulkanInterface;
644
645static void sSetupVulkanInterface() {
646 if (!sVulkanInterface.initialized) {
647 sVulkanInterface = initVulkanInterface(false /* no protected content */);
648 // We will have to abort if non-protected VkDevice creation fails (then nothing works).
649 LOG_ALWAYS_FATAL_IF(!sVulkanInterface.initialized,
650 "Could not initialize Vulkan RenderEngine!");
651 }
652 if (!sProtectedContentVulkanInterface.initialized) {
653 sProtectedContentVulkanInterface = initVulkanInterface(true /* protected content */);
654 if (!sProtectedContentVulkanInterface.initialized) {
655 ALOGE("Could not initialize protected content Vulkan RenderEngine.");
656 }
657 }
658}
659
Leon Scroggins IIIf3369ed2024-02-16 17:52:42 -0500660bool RenderEngine::canSupport(GraphicsApi graphicsApi) {
661 switch (graphicsApi) {
662 case GraphicsApi::GL:
663 return true;
664 case GraphicsApi::VK: {
665 if (!sVulkanInterface.initialized) {
666 sVulkanInterface = initVulkanInterface(false /* no protected content */);
667 ALOGD("%s: initialized == %s.", __func__,
668 sVulkanInterface.initialized ? "true" : "false");
669 }
670 return sVulkanInterface.initialized;
671 }
672 }
673}
674
Ian Elliott1f0911e2022-09-09 16:31:47 -0600675namespace skia {
676
677using base::StringAppendF;
678
Ian Elliott1f0911e2022-09-09 16:31:47 -0600679std::unique_ptr<SkiaVkRenderEngine> SkiaVkRenderEngine::create(
680 const RenderEngineCreationArgs& args) {
681 std::unique_ptr<SkiaVkRenderEngine> engine(new SkiaVkRenderEngine(args));
682 engine->ensureGrContextsCreated();
683
684 if (sVulkanInterface.initialized) {
685 ALOGD("SkiaVkRenderEngine::%s: successfully initialized SkiaVkRenderEngine", __func__);
686 return engine;
687 } else {
688 ALOGD("SkiaVkRenderEngine::%s: could not create SkiaVkRenderEngine. "
689 "Likely insufficient Vulkan support",
690 __func__);
691 return {};
692 }
693}
694
695SkiaVkRenderEngine::SkiaVkRenderEngine(const RenderEngineCreationArgs& args)
Leon Scroggins III696bf932024-01-24 15:21:05 -0500696 : SkiaRenderEngine(args.threaded, static_cast<PixelFormat>(args.pixelFormat),
Alec Mouri47bcb072023-08-15 02:02:49 +0000697 args.supportsBackgroundBlur) {}
Ian Elliott1f0911e2022-09-09 16:31:47 -0600698
699SkiaVkRenderEngine::~SkiaVkRenderEngine() {
700 finishRenderingAndAbandonContext();
701}
702
703SkiaRenderEngine::Contexts SkiaVkRenderEngine::createDirectContexts(
704 const GrContextOptions& options) {
705 sSetupVulkanInterface();
706
707 SkiaRenderEngine::Contexts contexts;
Kevin Lubick2fc49112023-10-13 13:10:48 +0000708 contexts.first = GrDirectContexts::MakeVulkan(sVulkanInterface.getBackendContext(), options);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600709 if (supportsProtectedContentImpl()) {
710 contexts.second =
Kevin Lubick2fc49112023-10-13 13:10:48 +0000711 GrDirectContexts::MakeVulkan(sProtectedContentVulkanInterface.getBackendContext(),
712 options);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600713 }
714
715 return contexts;
716}
717
718bool SkiaVkRenderEngine::supportsProtectedContentImpl() const {
719 return sProtectedContentVulkanInterface.initialized;
720}
721
722bool SkiaVkRenderEngine::useProtectedContextImpl(GrProtected) {
723 return true;
724}
725
Ian Elliott98e87162023-04-14 14:05:19 -0600726static void delete_semaphore(void* semaphore) {
727 DestroySemaphoreInfo* info = reinterpret_cast<DestroySemaphoreInfo*>(semaphore);
728 --info->mRefs;
729 if (!info->mRefs) {
730 sVulkanInterface.destroySemaphore(info->mSemaphore);
731 delete info;
732 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600733}
734
Ian Elliott98e87162023-04-14 14:05:19 -0600735static void delete_semaphore_protected(void* semaphore) {
736 DestroySemaphoreInfo* info = reinterpret_cast<DestroySemaphoreInfo*>(semaphore);
737 --info->mRefs;
738 if (!info->mRefs) {
739 sProtectedContentVulkanInterface.destroySemaphore(info->mSemaphore);
740 delete info;
741 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600742}
743
744static VulkanInterface& getVulkanInterface(bool protectedContext) {
745 if (protectedContext) {
746 return sProtectedContentVulkanInterface;
747 }
748 return sVulkanInterface;
749}
750
751void SkiaVkRenderEngine::waitFence(GrDirectContext* grContext, base::borrowed_fd fenceFd) {
752 if (fenceFd.get() < 0) return;
753
754 int dupedFd = dup(fenceFd.get());
755 if (dupedFd < 0) {
756 ALOGE("failed to create duplicate fence fd: %d", dupedFd);
757 sync_wait(fenceFd.get(), -1);
758 return;
759 }
760
761 base::unique_fd fenceDup(dupedFd);
762 VkSemaphore waitSemaphore =
763 getVulkanInterface(isProtected()).importSemaphoreFromSyncFd(fenceDup.release());
764 GrBackendSemaphore beSemaphore;
765 beSemaphore.initVulkan(waitSemaphore);
766 grContext->wait(1, &beSemaphore, true /* delete after wait */);
767}
768
769base::unique_fd SkiaVkRenderEngine::flushAndSubmit(GrDirectContext* grContext) {
Ian Elliott98e87162023-04-14 14:05:19 -0600770 VulkanInterface& vi = getVulkanInterface(isProtected());
771 VkSemaphore semaphore = vi.createExportableSemaphore();
772
773 GrBackendSemaphore backendSemaphore;
774 backendSemaphore.initVulkan(semaphore);
775
Ian Elliott1f0911e2022-09-09 16:31:47 -0600776 GrFlushInfo flushInfo;
Ian Elliott98e87162023-04-14 14:05:19 -0600777 DestroySemaphoreInfo* destroySemaphoreInfo = nullptr;
778 if (semaphore != VK_NULL_HANDLE) {
779 destroySemaphoreInfo = new DestroySemaphoreInfo(semaphore);
780 flushInfo.fNumSemaphores = 1;
781 flushInfo.fSignalSemaphores = &backendSemaphore;
782 flushInfo.fFinishedProc = isProtected() ? delete_semaphore_protected : delete_semaphore;
783 flushInfo.fFinishedContext = destroySemaphoreInfo;
784 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600785 GrSemaphoresSubmitted submitted = grContext->flush(flushInfo);
Kevin Lubicka0efc342023-09-20 13:11:52 +0000786 grContext->submit(GrSyncCpu::kNo);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600787 int drawFenceFd = -1;
Ian Elliott98e87162023-04-14 14:05:19 -0600788 if (semaphore != VK_NULL_HANDLE) {
789 if (GrSemaphoresSubmitted::kYes == submitted) {
790 drawFenceFd = vi.exportSemaphoreSyncFd(semaphore);
791 }
792 // Now that drawFenceFd has been created, we can delete our reference to this semaphore
793 flushInfo.fFinishedProc(destroySemaphoreInfo);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600794 }
795 base::unique_fd res(drawFenceFd);
796 return res;
797}
798
799int SkiaVkRenderEngine::getContextPriority() {
800 // EGL_CONTEXT_PRIORITY_REALTIME_NV
801 constexpr int kRealtimePriority = 0x3357;
802 if (getVulkanInterface(isProtected()).isRealtimePriority) {
803 return kRealtimePriority;
804 } else {
805 return 0;
806 }
807}
808
809void SkiaVkRenderEngine::appendBackendSpecificInfoToDump(std::string& result) {
810 StringAppendF(&result, "\n ------------RE Vulkan----------\n");
811 StringAppendF(&result, "\n Vulkan device initialized: %d\n", sVulkanInterface.initialized);
812 StringAppendF(&result, "\n Vulkan protected device initialized: %d\n",
813 sProtectedContentVulkanInterface.initialized);
814
815 if (!sVulkanInterface.initialized) {
816 return;
817 }
818
819 StringAppendF(&result, "\n Instance extensions:\n");
820 for (const auto& name : sVulkanInterface.instanceExtensionNames) {
821 StringAppendF(&result, "\n %s\n", name.c_str());
822 }
823
824 StringAppendF(&result, "\n Device extensions:\n");
825 for (const auto& name : sVulkanInterface.deviceExtensionNames) {
826 StringAppendF(&result, "\n %s\n", name.c_str());
827 }
828}
829
830} // namespace skia
831} // namespace renderengine
832} // namespace android