blob: bff12ce7ff8f5a8054950d3c3af2b93431bdf0aa [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) {
290 VulkanInterface interface;
291
292 VK_GET_PROC(EnumerateInstanceVersion);
293 uint32_t instanceVersion;
294 VK_CHECK(vkEnumerateInstanceVersion(&instanceVersion));
295
296 if (instanceVersion < VK_MAKE_VERSION(1, 1, 0)) {
297 return interface;
298 }
299
300 const VkApplicationInfo appInfo = {
301 VK_STRUCTURE_TYPE_APPLICATION_INFO, nullptr, "surfaceflinger", 0, "android platform", 0,
302 VK_MAKE_VERSION(1, 1, 0),
303 };
304
305 VK_GET_PROC(EnumerateInstanceExtensionProperties);
306
307 uint32_t extensionCount = 0;
308 VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr));
309 std::vector<VkExtensionProperties> instanceExtensions(extensionCount);
310 VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount,
311 instanceExtensions.data()));
312 std::vector<const char*> enabledInstanceExtensionNames;
313 enabledInstanceExtensionNames.reserve(instanceExtensions.size());
314 interface.instanceExtensionNames.reserve(instanceExtensions.size());
315 for (const auto& instExt : instanceExtensions) {
316 enabledInstanceExtensionNames.push_back(instExt.extensionName);
317 interface.instanceExtensionNames.push_back(instExt.extensionName);
318 }
319
320 const VkInstanceCreateInfo instanceCreateInfo = {
321 VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
322 nullptr,
323 0,
324 &appInfo,
325 0,
326 nullptr,
327 (uint32_t)enabledInstanceExtensionNames.size(),
328 enabledInstanceExtensionNames.data(),
329 };
330
331 VK_GET_PROC(CreateInstance);
332 VkInstance instance;
333 VK_CHECK(vkCreateInstance(&instanceCreateInfo, nullptr, &instance));
334
335 VK_GET_INST_PROC(instance, DestroyInstance);
336 interface.funcs.vkDestroyInstance = vkDestroyInstance;
337 VK_GET_INST_PROC(instance, EnumeratePhysicalDevices);
338 VK_GET_INST_PROC(instance, EnumerateDeviceExtensionProperties);
339 VK_GET_INST_PROC(instance, GetPhysicalDeviceProperties2);
340 VK_GET_INST_PROC(instance, GetPhysicalDeviceExternalSemaphoreProperties);
Ian Elliottd50658f2023-06-28 11:08:35 -0600341 VK_GET_INST_PROC(instance, GetPhysicalDeviceQueueFamilyProperties2);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600342 VK_GET_INST_PROC(instance, GetPhysicalDeviceFeatures2);
343 VK_GET_INST_PROC(instance, CreateDevice);
344
345 uint32_t physdevCount;
346 VK_CHECK(vkEnumeratePhysicalDevices(instance, &physdevCount, nullptr));
347 if (physdevCount == 0) {
348 BAIL("Could not find any physical devices");
349 }
350
351 physdevCount = 1;
352 VkPhysicalDevice physicalDevice;
353 VkResult enumeratePhysDevsErr =
354 vkEnumeratePhysicalDevices(instance, &physdevCount, &physicalDevice);
355 if (enumeratePhysDevsErr != VK_SUCCESS && VK_INCOMPLETE != enumeratePhysDevsErr) {
356 BAIL("vkEnumeratePhysicalDevices failed with non-VK_INCOMPLETE error: %d",
357 enumeratePhysDevsErr);
358 }
359
360 VkPhysicalDeviceProperties2 physDevProps = {
361 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
362 0,
363 {},
364 };
365 VkPhysicalDeviceProtectedMemoryProperties protMemProps = {
366 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES,
367 0,
368 {},
369 };
370
371 if (protectedContent) {
372 physDevProps.pNext = &protMemProps;
373 }
374
375 vkGetPhysicalDeviceProperties2(physicalDevice, &physDevProps);
376 if (physDevProps.properties.apiVersion < VK_MAKE_VERSION(1, 1, 0)) {
377 BAIL("Could not find a Vulkan 1.1+ physical device");
378 }
379
380 // Check for syncfd support. Bail if we cannot both import and export them.
381 VkPhysicalDeviceExternalSemaphoreInfo semInfo = {
382 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
383 nullptr,
384 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
385 };
386 VkExternalSemaphoreProperties semProps = {
387 VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, nullptr, 0, 0, 0,
388 };
389 vkGetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, &semInfo, &semProps);
390
391 bool sufficientSemaphoreSyncFdSupport = (semProps.exportFromImportedHandleTypes &
392 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) &&
393 (semProps.compatibleHandleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) &&
394 (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT) &&
395 (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
396
397 if (!sufficientSemaphoreSyncFdSupport) {
398 BAIL("Vulkan device does not support sufficient external semaphore sync fd features. "
399 "exportFromImportedHandleTypes 0x%x (needed 0x%x) "
400 "compatibleHandleTypes 0x%x (needed 0x%x) "
401 "externalSemaphoreFeatures 0x%x (needed 0x%x) ",
402 semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
403 semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
404 semProps.externalSemaphoreFeatures,
405 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
406 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
407 } else {
408 ALOGD("Vulkan device supports sufficient external semaphore sync fd features. "
409 "exportFromImportedHandleTypes 0x%x (needed 0x%x) "
410 "compatibleHandleTypes 0x%x (needed 0x%x) "
411 "externalSemaphoreFeatures 0x%x (needed 0x%x) ",
412 semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
413 semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
414 semProps.externalSemaphoreFeatures,
415 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
416 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
417 }
418
419 uint32_t queueCount;
Ian Elliottd50658f2023-06-28 11:08:35 -0600420 vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, nullptr);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600421 if (queueCount == 0) {
422 BAIL("Could not find queues for physical device");
423 }
424
Ian Elliottd50658f2023-06-28 11:08:35 -0600425 std::vector<VkQueueFamilyProperties2> queueProps(queueCount);
426 std::vector<VkQueueFamilyGlobalPriorityPropertiesEXT> queuePriorityProps(queueCount);
427 VkQueueGlobalPriorityKHR queuePriority = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR;
428 // Even though we don't yet know if the VK_EXT_global_priority extension is available,
429 // we can safely add the request to the pNext chain, and if the extension is not
430 // available, it will be ignored.
431 for (uint32_t i = 0; i < queueCount; ++i) {
432 queuePriorityProps[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT;
433 queuePriorityProps[i].pNext = nullptr;
434 queueProps[i].pNext = &queuePriorityProps[i];
435 }
436 vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, queueProps.data());
Ian Elliott1f0911e2022-09-09 16:31:47 -0600437
438 int graphicsQueueIndex = -1;
439 for (uint32_t i = 0; i < queueCount; ++i) {
Ian Elliottd50658f2023-06-28 11:08:35 -0600440 // Look at potential answers to the VK_EXT_global_priority query. If answers were
441 // provided, we may adjust the queuePriority.
442 if (queueProps[i].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
443 for (uint32_t j = 0; j < queuePriorityProps[i].priorityCount; j++) {
444 if (queuePriorityProps[i].priorities[j] > queuePriority) {
445 queuePriority = queuePriorityProps[i].priorities[j];
446 }
447 }
448 if (queuePriority == VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR) {
449 interface.isRealtimePriority = true;
450 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600451 graphicsQueueIndex = i;
452 break;
453 }
454 }
455
456 if (graphicsQueueIndex == -1) {
457 BAIL("Could not find a graphics queue family");
458 }
459
460 uint32_t deviceExtensionCount;
461 VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount,
462 nullptr));
463 std::vector<VkExtensionProperties> deviceExtensions(deviceExtensionCount);
464 VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount,
465 deviceExtensions.data()));
466
467 std::vector<const char*> enabledDeviceExtensionNames;
468 enabledDeviceExtensionNames.reserve(deviceExtensions.size());
469 interface.deviceExtensionNames.reserve(deviceExtensions.size());
470 for (const auto& devExt : deviceExtensions) {
471 enabledDeviceExtensionNames.push_back(devExt.extensionName);
472 interface.deviceExtensionNames.push_back(devExt.extensionName);
473 }
474
475 interface.grExtensions.init(sGetProc, instance, physicalDevice,
476 enabledInstanceExtensionNames.size(),
477 enabledInstanceExtensionNames.data(),
478 enabledDeviceExtensionNames.size(),
479 enabledDeviceExtensionNames.data());
480
481 if (!interface.grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
482 BAIL("Vulkan driver doesn't support external semaphore fd");
483 }
484
485 interface.physicalDeviceFeatures2 = new VkPhysicalDeviceFeatures2;
486 interface.physicalDeviceFeatures2->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
487 interface.physicalDeviceFeatures2->pNext = nullptr;
488
489 interface.samplerYcbcrConversionFeatures = new VkPhysicalDeviceSamplerYcbcrConversionFeatures;
490 interface.samplerYcbcrConversionFeatures->sType =
491 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
492 interface.samplerYcbcrConversionFeatures->pNext = nullptr;
493
494 interface.physicalDeviceFeatures2->pNext = interface.samplerYcbcrConversionFeatures;
495 void** tailPnext = &interface.samplerYcbcrConversionFeatures->pNext;
496
497 if (protectedContent) {
Ian Elliottae0b8d12023-01-05 19:13:42 -0700498 interface.protectedMemoryFeatures = new VkPhysicalDeviceProtectedMemoryFeatures;
Ian Elliott1f0911e2022-09-09 16:31:47 -0600499 interface.protectedMemoryFeatures->sType =
500 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
501 interface.protectedMemoryFeatures->pNext = nullptr;
502 *tailPnext = interface.protectedMemoryFeatures;
503 tailPnext = &interface.protectedMemoryFeatures->pNext;
504 }
505
Nolan Scobie0f539a72024-01-29 10:49:10 -0500506 if (interface.grExtensions.hasExtension(VK_EXT_DEVICE_FAULT_EXTENSION_NAME, 1)) {
507 interface.deviceFaultFeatures = new VkPhysicalDeviceFaultFeaturesEXT;
508 interface.deviceFaultFeatures->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
509 interface.deviceFaultFeatures->pNext = nullptr;
510 *tailPnext = interface.deviceFaultFeatures;
511 tailPnext = &interface.deviceFaultFeatures->pNext;
512 }
513
Ian Elliott1f0911e2022-09-09 16:31:47 -0600514 vkGetPhysicalDeviceFeatures2(physicalDevice, interface.physicalDeviceFeatures2);
515 // Looks like this would slow things down and we can't depend on it on all platforms
516 interface.physicalDeviceFeatures2->features.robustBufferAccess = VK_FALSE;
517
John Bauman1aab9922023-10-24 17:23:47 +0000518 if (protectedContent && !interface.protectedMemoryFeatures->protectedMemory) {
519 BAIL("Protected memory not supported");
520 }
521
Ian Elliott1f0911e2022-09-09 16:31:47 -0600522 float queuePriorities[1] = {0.0f};
523 void* queueNextPtr = nullptr;
524
525 VkDeviceQueueGlobalPriorityCreateInfoEXT queuePriorityCreateInfo = {
526 VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT,
527 nullptr,
528 // If queue priority is supported, RE should always have realtime priority.
Ian Elliottd50658f2023-06-28 11:08:35 -0600529 queuePriority,
Ian Elliott1f0911e2022-09-09 16:31:47 -0600530 };
531
532 if (interface.grExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) {
533 queueNextPtr = &queuePriorityCreateInfo;
Ian Elliott1f0911e2022-09-09 16:31:47 -0600534 }
535
536 VkDeviceQueueCreateFlags deviceQueueCreateFlags =
537 (VkDeviceQueueCreateFlags)(protectedContent ? VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT : 0);
538
539 const VkDeviceQueueCreateInfo queueInfo = {
540 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
541 queueNextPtr,
542 deviceQueueCreateFlags,
543 (uint32_t)graphicsQueueIndex,
544 1,
545 queuePriorities,
546 };
547
548 const VkDeviceCreateInfo deviceInfo = {
549 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
550 interface.physicalDeviceFeatures2,
551 0,
552 1,
553 &queueInfo,
554 0,
555 nullptr,
556 (uint32_t)enabledDeviceExtensionNames.size(),
557 enabledDeviceExtensionNames.data(),
558 nullptr,
559 };
560
561 ALOGD("Trying to create Vk device with protectedContent=%d", protectedContent);
562 VkDevice device;
563 VK_CHECK(vkCreateDevice(physicalDevice, &deviceInfo, nullptr, &device));
564 ALOGD("Trying to create Vk device with protectedContent=%d (success)", protectedContent);
565
566 VkQueue graphicsQueue;
Ian Elliott87e3dd82023-02-27 12:07:10 -0700567 VK_GET_DEV_PROC(device, GetDeviceQueue2);
568 const VkDeviceQueueInfo2 deviceQueueInfo2 = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2, nullptr,
569 deviceQueueCreateFlags,
570 (uint32_t)graphicsQueueIndex, 0};
571 vkGetDeviceQueue2(device, &deviceQueueInfo2, &graphicsQueue);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600572
573 VK_GET_DEV_PROC(device, DeviceWaitIdle);
574 VK_GET_DEV_PROC(device, DestroyDevice);
575 interface.funcs.vkDeviceWaitIdle = vkDeviceWaitIdle;
576 interface.funcs.vkDestroyDevice = vkDestroyDevice;
577
578 VK_GET_DEV_PROC(device, CreateSemaphore);
579 VK_GET_DEV_PROC(device, ImportSemaphoreFdKHR);
580 VK_GET_DEV_PROC(device, GetSemaphoreFdKHR);
581 VK_GET_DEV_PROC(device, DestroySemaphore);
582 interface.funcs.vkCreateSemaphore = vkCreateSemaphore;
583 interface.funcs.vkImportSemaphoreFdKHR = vkImportSemaphoreFdKHR;
584 interface.funcs.vkGetSemaphoreFdKHR = vkGetSemaphoreFdKHR;
585 interface.funcs.vkDestroySemaphore = vkDestroySemaphore;
586
587 // At this point, everything's succeeded and we can continue
588 interface.initialized = true;
589 interface.instance = instance;
590 interface.physicalDevice = physicalDevice;
591 interface.device = device;
592 interface.queue = graphicsQueue;
593 interface.queueIndex = graphicsQueueIndex;
594 interface.apiVersion = physDevProps.properties.apiVersion;
595 // grExtensions already constructed
596 // feature pointers already constructed
597 interface.grGetProc = sGetProc;
598 interface.isProtected = protectedContent;
599 // funcs already initialized
600
601 ALOGD("%s: Success init Vulkan interface", __func__);
602 return interface;
603}
604
605void teardownVulkanInterface(VulkanInterface* interface) {
606 interface->initialized = false;
607
608 if (interface->device != VK_NULL_HANDLE) {
609 interface->funcs.vkDeviceWaitIdle(interface->device);
610 interface->funcs.vkDestroyDevice(interface->device, nullptr);
611 interface->device = VK_NULL_HANDLE;
612 }
613 if (interface->instance != VK_NULL_HANDLE) {
614 interface->funcs.vkDestroyInstance(interface->instance, nullptr);
615 interface->instance = VK_NULL_HANDLE;
616 }
617
618 if (interface->protectedMemoryFeatures) {
619 delete interface->protectedMemoryFeatures;
620 }
621
622 if (interface->samplerYcbcrConversionFeatures) {
623 delete interface->samplerYcbcrConversionFeatures;
624 }
625
626 if (interface->physicalDeviceFeatures2) {
627 delete interface->physicalDeviceFeatures2;
628 }
629
Nolan Scobie0f539a72024-01-29 10:49:10 -0500630 if (interface->deviceFaultFeatures) {
631 delete interface->deviceFaultFeatures;
632 }
633
Ian Elliott1f0911e2022-09-09 16:31:47 -0600634 interface->samplerYcbcrConversionFeatures = nullptr;
635 interface->physicalDeviceFeatures2 = nullptr;
636 interface->protectedMemoryFeatures = nullptr;
637}
638
639static VulkanInterface sVulkanInterface;
640static VulkanInterface sProtectedContentVulkanInterface;
641
642static void sSetupVulkanInterface() {
643 if (!sVulkanInterface.initialized) {
644 sVulkanInterface = initVulkanInterface(false /* no protected content */);
645 // We will have to abort if non-protected VkDevice creation fails (then nothing works).
646 LOG_ALWAYS_FATAL_IF(!sVulkanInterface.initialized,
647 "Could not initialize Vulkan RenderEngine!");
648 }
649 if (!sProtectedContentVulkanInterface.initialized) {
650 sProtectedContentVulkanInterface = initVulkanInterface(true /* protected content */);
651 if (!sProtectedContentVulkanInterface.initialized) {
652 ALOGE("Could not initialize protected content Vulkan RenderEngine.");
653 }
654 }
655}
656
657namespace skia {
658
659using base::StringAppendF;
660
661bool SkiaVkRenderEngine::canSupportSkiaVkRenderEngine() {
662 VulkanInterface temp = initVulkanInterface(false /* no protected content */);
663 ALOGD("SkiaVkRenderEngine::canSupportSkiaVkRenderEngine(): initialized == %s.",
664 temp.initialized ? "true" : "false");
665 return temp.initialized;
666}
667
668std::unique_ptr<SkiaVkRenderEngine> SkiaVkRenderEngine::create(
669 const RenderEngineCreationArgs& args) {
670 std::unique_ptr<SkiaVkRenderEngine> engine(new SkiaVkRenderEngine(args));
671 engine->ensureGrContextsCreated();
672
673 if (sVulkanInterface.initialized) {
674 ALOGD("SkiaVkRenderEngine::%s: successfully initialized SkiaVkRenderEngine", __func__);
675 return engine;
676 } else {
677 ALOGD("SkiaVkRenderEngine::%s: could not create SkiaVkRenderEngine. "
678 "Likely insufficient Vulkan support",
679 __func__);
680 return {};
681 }
682}
683
684SkiaVkRenderEngine::SkiaVkRenderEngine(const RenderEngineCreationArgs& args)
Leon Scroggins III696bf932024-01-24 15:21:05 -0500685 : SkiaRenderEngine(args.threaded, static_cast<PixelFormat>(args.pixelFormat),
Alec Mouri47bcb072023-08-15 02:02:49 +0000686 args.supportsBackgroundBlur) {}
Ian Elliott1f0911e2022-09-09 16:31:47 -0600687
688SkiaVkRenderEngine::~SkiaVkRenderEngine() {
689 finishRenderingAndAbandonContext();
690}
691
692SkiaRenderEngine::Contexts SkiaVkRenderEngine::createDirectContexts(
693 const GrContextOptions& options) {
694 sSetupVulkanInterface();
695
696 SkiaRenderEngine::Contexts contexts;
Kevin Lubick2fc49112023-10-13 13:10:48 +0000697 contexts.first = GrDirectContexts::MakeVulkan(sVulkanInterface.getBackendContext(), options);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600698 if (supportsProtectedContentImpl()) {
699 contexts.second =
Kevin Lubick2fc49112023-10-13 13:10:48 +0000700 GrDirectContexts::MakeVulkan(sProtectedContentVulkanInterface.getBackendContext(),
701 options);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600702 }
703
704 return contexts;
705}
706
707bool SkiaVkRenderEngine::supportsProtectedContentImpl() const {
708 return sProtectedContentVulkanInterface.initialized;
709}
710
711bool SkiaVkRenderEngine::useProtectedContextImpl(GrProtected) {
712 return true;
713}
714
Ian Elliott98e87162023-04-14 14:05:19 -0600715static void delete_semaphore(void* semaphore) {
716 DestroySemaphoreInfo* info = reinterpret_cast<DestroySemaphoreInfo*>(semaphore);
717 --info->mRefs;
718 if (!info->mRefs) {
719 sVulkanInterface.destroySemaphore(info->mSemaphore);
720 delete info;
721 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600722}
723
Ian Elliott98e87162023-04-14 14:05:19 -0600724static void delete_semaphore_protected(void* semaphore) {
725 DestroySemaphoreInfo* info = reinterpret_cast<DestroySemaphoreInfo*>(semaphore);
726 --info->mRefs;
727 if (!info->mRefs) {
728 sProtectedContentVulkanInterface.destroySemaphore(info->mSemaphore);
729 delete info;
730 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600731}
732
733static VulkanInterface& getVulkanInterface(bool protectedContext) {
734 if (protectedContext) {
735 return sProtectedContentVulkanInterface;
736 }
737 return sVulkanInterface;
738}
739
740void SkiaVkRenderEngine::waitFence(GrDirectContext* grContext, base::borrowed_fd fenceFd) {
741 if (fenceFd.get() < 0) return;
742
743 int dupedFd = dup(fenceFd.get());
744 if (dupedFd < 0) {
745 ALOGE("failed to create duplicate fence fd: %d", dupedFd);
746 sync_wait(fenceFd.get(), -1);
747 return;
748 }
749
750 base::unique_fd fenceDup(dupedFd);
751 VkSemaphore waitSemaphore =
752 getVulkanInterface(isProtected()).importSemaphoreFromSyncFd(fenceDup.release());
753 GrBackendSemaphore beSemaphore;
754 beSemaphore.initVulkan(waitSemaphore);
755 grContext->wait(1, &beSemaphore, true /* delete after wait */);
756}
757
758base::unique_fd SkiaVkRenderEngine::flushAndSubmit(GrDirectContext* grContext) {
Ian Elliott98e87162023-04-14 14:05:19 -0600759 VulkanInterface& vi = getVulkanInterface(isProtected());
760 VkSemaphore semaphore = vi.createExportableSemaphore();
761
762 GrBackendSemaphore backendSemaphore;
763 backendSemaphore.initVulkan(semaphore);
764
Ian Elliott1f0911e2022-09-09 16:31:47 -0600765 GrFlushInfo flushInfo;
Ian Elliott98e87162023-04-14 14:05:19 -0600766 DestroySemaphoreInfo* destroySemaphoreInfo = nullptr;
767 if (semaphore != VK_NULL_HANDLE) {
768 destroySemaphoreInfo = new DestroySemaphoreInfo(semaphore);
769 flushInfo.fNumSemaphores = 1;
770 flushInfo.fSignalSemaphores = &backendSemaphore;
771 flushInfo.fFinishedProc = isProtected() ? delete_semaphore_protected : delete_semaphore;
772 flushInfo.fFinishedContext = destroySemaphoreInfo;
773 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600774 GrSemaphoresSubmitted submitted = grContext->flush(flushInfo);
Kevin Lubicka0efc342023-09-20 13:11:52 +0000775 grContext->submit(GrSyncCpu::kNo);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600776 int drawFenceFd = -1;
Ian Elliott98e87162023-04-14 14:05:19 -0600777 if (semaphore != VK_NULL_HANDLE) {
778 if (GrSemaphoresSubmitted::kYes == submitted) {
779 drawFenceFd = vi.exportSemaphoreSyncFd(semaphore);
780 }
781 // Now that drawFenceFd has been created, we can delete our reference to this semaphore
782 flushInfo.fFinishedProc(destroySemaphoreInfo);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600783 }
784 base::unique_fd res(drawFenceFd);
785 return res;
786}
787
788int SkiaVkRenderEngine::getContextPriority() {
789 // EGL_CONTEXT_PRIORITY_REALTIME_NV
790 constexpr int kRealtimePriority = 0x3357;
791 if (getVulkanInterface(isProtected()).isRealtimePriority) {
792 return kRealtimePriority;
793 } else {
794 return 0;
795 }
796}
797
798void SkiaVkRenderEngine::appendBackendSpecificInfoToDump(std::string& result) {
799 StringAppendF(&result, "\n ------------RE Vulkan----------\n");
800 StringAppendF(&result, "\n Vulkan device initialized: %d\n", sVulkanInterface.initialized);
801 StringAppendF(&result, "\n Vulkan protected device initialized: %d\n",
802 sProtectedContentVulkanInterface.initialized);
803
804 if (!sVulkanInterface.initialized) {
805 return;
806 }
807
808 StringAppendF(&result, "\n Instance extensions:\n");
809 for (const auto& name : sVulkanInterface.instanceExtensionNames) {
810 StringAppendF(&result, "\n %s\n", name.c_str());
811 }
812
813 StringAppendF(&result, "\n Device extensions:\n");
814 for (const auto& name : sVulkanInterface.deviceExtensionNames) {
815 StringAppendF(&result, "\n %s\n", name.c_str());
816 }
817}
818
819} // namespace skia
820} // namespace renderengine
821} // namespace android