blob: 5cf0310514f4ae14b4fb983f918403f745cd98a1 [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 Scobie0f539a72024-01-29 10:49:10 -050037#include <string>
Ian Elliott1f0911e2022-09-09 16:31:47 -060038#include <vector>
39
40#include <vulkan/vulkan.h>
41#include "log/log_main.h"
42
43namespace android {
44namespace renderengine {
45
46struct VulkanFuncs {
47 PFN_vkCreateSemaphore vkCreateSemaphore = nullptr;
48 PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR = nullptr;
49 PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR = nullptr;
50 PFN_vkDestroySemaphore vkDestroySemaphore = nullptr;
51
52 PFN_vkDeviceWaitIdle vkDeviceWaitIdle = nullptr;
53 PFN_vkDestroyDevice vkDestroyDevice = nullptr;
54 PFN_vkDestroyInstance vkDestroyInstance = nullptr;
55};
56
Ian Elliott98e87162023-04-14 14:05:19 -060057// Ref-Count a semaphore
58struct DestroySemaphoreInfo {
59 VkSemaphore mSemaphore;
60 // We need to make sure we don't delete the VkSemaphore until it is done being used by both Skia
61 // (including by the GPU) and inside SkiaVkRenderEngine. So we always start with two refs, one
62 // owned by Skia and one owned by the SkiaVkRenderEngine. The refs are decremented each time
63 // delete_semaphore* is called with this object. Skia will call destroy_semaphore* once it is
64 // done with the semaphore and the GPU has finished work on the semaphore. SkiaVkRenderEngine
65 // calls delete_semaphore* after sending the semaphore to Skia and exporting it if need be.
66 int mRefs = 2;
67
68 DestroySemaphoreInfo(VkSemaphore semaphore) : mSemaphore(semaphore) {}
69};
70
Nolan Scobie0f539a72024-01-29 10:49:10 -050071namespace {
72void onVkDeviceFault(void* callbackContext, const std::string& description,
73 const std::vector<VkDeviceFaultAddressInfoEXT>& addressInfos,
74 const std::vector<VkDeviceFaultVendorInfoEXT>& vendorInfos,
75 const std::vector<std::byte>& vendorBinaryData);
76} // anonymous namespace
77
Ian Elliott1f0911e2022-09-09 16:31:47 -060078struct VulkanInterface {
79 bool initialized = false;
80 VkInstance instance;
81 VkPhysicalDevice physicalDevice;
82 VkDevice device;
83 VkQueue queue;
84 int queueIndex;
85 uint32_t apiVersion;
86 GrVkExtensions grExtensions;
87 VkPhysicalDeviceFeatures2* physicalDeviceFeatures2 = nullptr;
88 VkPhysicalDeviceSamplerYcbcrConversionFeatures* samplerYcbcrConversionFeatures = nullptr;
Ian Elliottae0b8d12023-01-05 19:13:42 -070089 VkPhysicalDeviceProtectedMemoryFeatures* protectedMemoryFeatures = nullptr;
Nolan Scobie0f539a72024-01-29 10:49:10 -050090 VkPhysicalDeviceFaultFeaturesEXT* deviceFaultFeatures = nullptr;
Ian Elliott1f0911e2022-09-09 16:31:47 -060091 GrVkGetProc grGetProc;
92 bool isProtected;
93 bool isRealtimePriority;
94
95 VulkanFuncs funcs;
96
97 std::vector<std::string> instanceExtensionNames;
98 std::vector<std::string> deviceExtensionNames;
99
100 GrVkBackendContext getBackendContext() {
101 GrVkBackendContext backendContext;
102 backendContext.fInstance = instance;
103 backendContext.fPhysicalDevice = physicalDevice;
104 backendContext.fDevice = device;
105 backendContext.fQueue = queue;
106 backendContext.fGraphicsQueueIndex = queueIndex;
107 backendContext.fMaxAPIVersion = apiVersion;
108 backendContext.fVkExtensions = &grExtensions;
109 backendContext.fDeviceFeatures2 = physicalDeviceFeatures2;
110 backendContext.fGetProc = grGetProc;
111 backendContext.fProtectedContext = isProtected ? GrProtected::kYes : GrProtected::kNo;
Nolan Scobie0f539a72024-01-29 10:49:10 -0500112 backendContext.fDeviceLostContext = this; // VulkanInterface is long-lived
113 backendContext.fDeviceLostProc = onVkDeviceFault;
Ian Elliott1f0911e2022-09-09 16:31:47 -0600114 return backendContext;
115 };
116
117 VkSemaphore createExportableSemaphore() {
118 VkExportSemaphoreCreateInfo exportInfo;
119 exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
120 exportInfo.pNext = nullptr;
121 exportInfo.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
122
123 VkSemaphoreCreateInfo semaphoreInfo;
124 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
125 semaphoreInfo.pNext = &exportInfo;
126 semaphoreInfo.flags = 0;
127
128 VkSemaphore semaphore;
129 VkResult err = funcs.vkCreateSemaphore(device, &semaphoreInfo, nullptr, &semaphore);
130 if (VK_SUCCESS != err) {
131 ALOGE("%s: failed to create semaphore. err %d\n", __func__, err);
132 return VK_NULL_HANDLE;
133 }
134
135 return semaphore;
136 }
137
138 // syncFd cannot be <= 0
139 VkSemaphore importSemaphoreFromSyncFd(int syncFd) {
140 VkSemaphoreCreateInfo semaphoreInfo;
141 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
142 semaphoreInfo.pNext = nullptr;
143 semaphoreInfo.flags = 0;
144
145 VkSemaphore semaphore;
146 VkResult err = funcs.vkCreateSemaphore(device, &semaphoreInfo, nullptr, &semaphore);
147 if (VK_SUCCESS != err) {
148 ALOGE("%s: failed to create import semaphore", __func__);
149 return VK_NULL_HANDLE;
150 }
151
152 VkImportSemaphoreFdInfoKHR importInfo;
153 importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
154 importInfo.pNext = nullptr;
155 importInfo.semaphore = semaphore;
156 importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
157 importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
158 importInfo.fd = syncFd;
159
160 err = funcs.vkImportSemaphoreFdKHR(device, &importInfo);
161 if (VK_SUCCESS != err) {
162 funcs.vkDestroySemaphore(device, semaphore, nullptr);
163 ALOGE("%s: failed to import semaphore", __func__);
164 return VK_NULL_HANDLE;
165 }
166
167 return semaphore;
168 }
169
170 int exportSemaphoreSyncFd(VkSemaphore semaphore) {
171 int res;
172
173 VkSemaphoreGetFdInfoKHR getFdInfo;
174 getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
175 getFdInfo.pNext = nullptr;
176 getFdInfo.semaphore = semaphore;
177 getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
178
179 VkResult err = funcs.vkGetSemaphoreFdKHR(device, &getFdInfo, &res);
180 if (VK_SUCCESS != err) {
181 ALOGE("%s: failed to export semaphore, err: %d", __func__, err);
182 return -1;
183 }
184 return res;
185 }
186
187 void destroySemaphore(VkSemaphore semaphore) {
188 funcs.vkDestroySemaphore(device, semaphore, nullptr);
189 }
190};
191
Nolan Scobie0f539a72024-01-29 10:49:10 -0500192namespace {
193void onVkDeviceFault(void* callbackContext, const std::string& description,
194 const std::vector<VkDeviceFaultAddressInfoEXT>& addressInfos,
195 const std::vector<VkDeviceFaultVendorInfoEXT>& vendorInfos,
196 const std::vector<std::byte>& vendorBinaryData) {
197 VulkanInterface* interface = static_cast<VulkanInterface*>(callbackContext);
198 const string protectedStr = interface->isProtected ? "protected" : "non-protected";
199 // The final crash string should contain as much differentiating info as possible, up to 1024
200 // bytes. As this final message is constructed, the same information is also dumped to the logs
201 // but in a more verbose format. Building the crash string is unsightly, so the clearer logging
202 // statement is always placed first to give context.
203 ALOGE("VK_ERROR_DEVICE_LOST (%s context): %s", protectedStr.c_str(), description.c_str());
204 string crashStr = "VK_ERROR_DEVICE_LOST (" + protectedStr;
205
206 if (!addressInfos.empty()) {
207 ALOGE("%zu VkDeviceFaultAddressInfoEXT:", addressInfos.size());
208 crashStr += ", " + std::to_string(addressInfos.size()) + " address info (";
209 for (VkDeviceFaultAddressInfoEXT addressInfo : addressInfos) {
210 ALOGE(" addressType: %d", (int)addressInfo.addressType);
211 ALOGE(" reportedAddress: %" PRIu64, addressInfo.reportedAddress);
212 ALOGE(" addressPrecision: %" PRIu64, addressInfo.addressPrecision);
213 crashStr += std::to_string(addressInfo.addressType) + ":" +
214 std::to_string(addressInfo.reportedAddress) + ":" +
215 std::to_string(addressInfo.addressPrecision) + ", ";
216 }
217 crashStr.resize(crashStr.size() - 2); // Remove trailing ", "
218 crashStr += ")";
219 }
220
221 if (!vendorInfos.empty()) {
222 ALOGE("%zu VkDeviceFaultVendorInfoEXT:", vendorInfos.size());
223 crashStr += ", " + std::to_string(vendorInfos.size()) + " vendor info (";
224 for (VkDeviceFaultVendorInfoEXT vendorInfo : vendorInfos) {
225 ALOGE(" description: %s", vendorInfo.description);
226 ALOGE(" vendorFaultCode: %" PRIu64, vendorInfo.vendorFaultCode);
227 ALOGE(" vendorFaultData: %" PRIu64, vendorInfo.vendorFaultData);
228 // Omit descriptions for individual vendor info structs in the crash string, as the
229 // fault code and fault data fields should be enough for clustering, and the verbosity
230 // isn't worth it. Additionally, vendors may just set the general description field of
231 // the overall fault to the description of the first element in this list, and that
232 // overall description will be placed at the end of the crash string.
233 crashStr += std::to_string(vendorInfo.vendorFaultCode) + ":" +
234 std::to_string(vendorInfo.vendorFaultData) + ", ";
235 }
236 crashStr.resize(crashStr.size() - 2); // Remove trailing ", "
237 crashStr += ")";
238 }
239
240 if (!vendorBinaryData.empty()) {
241 // TODO: b/322830575 - Log in base64, or dump directly to a file that gets put in bugreports
242 ALOGE("%zu bytes of vendor-specific binary data (please notify Android's Core Graphics"
243 " Stack team if you observe this message).",
244 vendorBinaryData.size());
245 crashStr += ", " + std::to_string(vendorBinaryData.size()) + " bytes binary";
246 }
247
248 crashStr += "): " + description;
249 LOG_ALWAYS_FATAL("%s", crashStr.c_str());
250};
251} // anonymous namespace
252
Ian Elliott1f0911e2022-09-09 16:31:47 -0600253static GrVkGetProc sGetProc = [](const char* proc_name, VkInstance instance, VkDevice device) {
254 if (device != VK_NULL_HANDLE) {
255 return vkGetDeviceProcAddr(device, proc_name);
256 }
257 return vkGetInstanceProcAddr(instance, proc_name);
258};
259
260#define BAIL(fmt, ...) \
261 { \
262 ALOGE("%s: " fmt ", bailing", __func__, ##__VA_ARGS__); \
263 return interface; \
264 }
265
266#define CHECK_NONNULL(expr) \
267 if ((expr) == nullptr) { \
268 BAIL("[%s] null", #expr); \
269 }
270
271#define VK_CHECK(expr) \
272 if ((expr) != VK_SUCCESS) { \
273 BAIL("[%s] failed. err = %d", #expr, expr); \
274 return interface; \
275 }
276
277#define VK_GET_PROC(F) \
278 PFN_vk##F vk##F = (PFN_vk##F)vkGetInstanceProcAddr(VK_NULL_HANDLE, "vk" #F); \
279 CHECK_NONNULL(vk##F)
280#define VK_GET_INST_PROC(instance, F) \
281 PFN_vk##F vk##F = (PFN_vk##F)vkGetInstanceProcAddr(instance, "vk" #F); \
282 CHECK_NONNULL(vk##F)
283#define VK_GET_DEV_PROC(device, F) \
284 PFN_vk##F vk##F = (PFN_vk##F)vkGetDeviceProcAddr(device, "vk" #F); \
285 CHECK_NONNULL(vk##F)
286
287VulkanInterface initVulkanInterface(bool protectedContent = false) {
288 VulkanInterface interface;
289
290 VK_GET_PROC(EnumerateInstanceVersion);
291 uint32_t instanceVersion;
292 VK_CHECK(vkEnumerateInstanceVersion(&instanceVersion));
293
294 if (instanceVersion < VK_MAKE_VERSION(1, 1, 0)) {
295 return interface;
296 }
297
298 const VkApplicationInfo appInfo = {
299 VK_STRUCTURE_TYPE_APPLICATION_INFO, nullptr, "surfaceflinger", 0, "android platform", 0,
300 VK_MAKE_VERSION(1, 1, 0),
301 };
302
303 VK_GET_PROC(EnumerateInstanceExtensionProperties);
304
305 uint32_t extensionCount = 0;
306 VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr));
307 std::vector<VkExtensionProperties> instanceExtensions(extensionCount);
308 VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount,
309 instanceExtensions.data()));
310 std::vector<const char*> enabledInstanceExtensionNames;
311 enabledInstanceExtensionNames.reserve(instanceExtensions.size());
312 interface.instanceExtensionNames.reserve(instanceExtensions.size());
313 for (const auto& instExt : instanceExtensions) {
314 enabledInstanceExtensionNames.push_back(instExt.extensionName);
315 interface.instanceExtensionNames.push_back(instExt.extensionName);
316 }
317
318 const VkInstanceCreateInfo instanceCreateInfo = {
319 VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
320 nullptr,
321 0,
322 &appInfo,
323 0,
324 nullptr,
325 (uint32_t)enabledInstanceExtensionNames.size(),
326 enabledInstanceExtensionNames.data(),
327 };
328
329 VK_GET_PROC(CreateInstance);
330 VkInstance instance;
331 VK_CHECK(vkCreateInstance(&instanceCreateInfo, nullptr, &instance));
332
333 VK_GET_INST_PROC(instance, DestroyInstance);
334 interface.funcs.vkDestroyInstance = vkDestroyInstance;
335 VK_GET_INST_PROC(instance, EnumeratePhysicalDevices);
336 VK_GET_INST_PROC(instance, EnumerateDeviceExtensionProperties);
337 VK_GET_INST_PROC(instance, GetPhysicalDeviceProperties2);
338 VK_GET_INST_PROC(instance, GetPhysicalDeviceExternalSemaphoreProperties);
Ian Elliottd50658f2023-06-28 11:08:35 -0600339 VK_GET_INST_PROC(instance, GetPhysicalDeviceQueueFamilyProperties2);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600340 VK_GET_INST_PROC(instance, GetPhysicalDeviceFeatures2);
341 VK_GET_INST_PROC(instance, CreateDevice);
342
343 uint32_t physdevCount;
344 VK_CHECK(vkEnumeratePhysicalDevices(instance, &physdevCount, nullptr));
345 if (physdevCount == 0) {
346 BAIL("Could not find any physical devices");
347 }
348
349 physdevCount = 1;
350 VkPhysicalDevice physicalDevice;
351 VkResult enumeratePhysDevsErr =
352 vkEnumeratePhysicalDevices(instance, &physdevCount, &physicalDevice);
353 if (enumeratePhysDevsErr != VK_SUCCESS && VK_INCOMPLETE != enumeratePhysDevsErr) {
354 BAIL("vkEnumeratePhysicalDevices failed with non-VK_INCOMPLETE error: %d",
355 enumeratePhysDevsErr);
356 }
357
358 VkPhysicalDeviceProperties2 physDevProps = {
359 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
360 0,
361 {},
362 };
363 VkPhysicalDeviceProtectedMemoryProperties protMemProps = {
364 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES,
365 0,
366 {},
367 };
368
369 if (protectedContent) {
370 physDevProps.pNext = &protMemProps;
371 }
372
373 vkGetPhysicalDeviceProperties2(physicalDevice, &physDevProps);
374 if (physDevProps.properties.apiVersion < VK_MAKE_VERSION(1, 1, 0)) {
375 BAIL("Could not find a Vulkan 1.1+ physical device");
376 }
377
378 // Check for syncfd support. Bail if we cannot both import and export them.
379 VkPhysicalDeviceExternalSemaphoreInfo semInfo = {
380 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
381 nullptr,
382 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
383 };
384 VkExternalSemaphoreProperties semProps = {
385 VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, nullptr, 0, 0, 0,
386 };
387 vkGetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, &semInfo, &semProps);
388
389 bool sufficientSemaphoreSyncFdSupport = (semProps.exportFromImportedHandleTypes &
390 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) &&
391 (semProps.compatibleHandleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) &&
392 (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT) &&
393 (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
394
395 if (!sufficientSemaphoreSyncFdSupport) {
396 BAIL("Vulkan device does not support sufficient external semaphore sync fd features. "
397 "exportFromImportedHandleTypes 0x%x (needed 0x%x) "
398 "compatibleHandleTypes 0x%x (needed 0x%x) "
399 "externalSemaphoreFeatures 0x%x (needed 0x%x) ",
400 semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
401 semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
402 semProps.externalSemaphoreFeatures,
403 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
404 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
405 } else {
406 ALOGD("Vulkan device supports sufficient external semaphore sync fd features. "
407 "exportFromImportedHandleTypes 0x%x (needed 0x%x) "
408 "compatibleHandleTypes 0x%x (needed 0x%x) "
409 "externalSemaphoreFeatures 0x%x (needed 0x%x) ",
410 semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
411 semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
412 semProps.externalSemaphoreFeatures,
413 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
414 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
415 }
416
417 uint32_t queueCount;
Ian Elliottd50658f2023-06-28 11:08:35 -0600418 vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, nullptr);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600419 if (queueCount == 0) {
420 BAIL("Could not find queues for physical device");
421 }
422
Ian Elliottd50658f2023-06-28 11:08:35 -0600423 std::vector<VkQueueFamilyProperties2> queueProps(queueCount);
424 std::vector<VkQueueFamilyGlobalPriorityPropertiesEXT> queuePriorityProps(queueCount);
425 VkQueueGlobalPriorityKHR queuePriority = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR;
426 // Even though we don't yet know if the VK_EXT_global_priority extension is available,
427 // we can safely add the request to the pNext chain, and if the extension is not
428 // available, it will be ignored.
429 for (uint32_t i = 0; i < queueCount; ++i) {
430 queuePriorityProps[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT;
431 queuePriorityProps[i].pNext = nullptr;
432 queueProps[i].pNext = &queuePriorityProps[i];
433 }
434 vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, queueProps.data());
Ian Elliott1f0911e2022-09-09 16:31:47 -0600435
436 int graphicsQueueIndex = -1;
437 for (uint32_t i = 0; i < queueCount; ++i) {
Ian Elliottd50658f2023-06-28 11:08:35 -0600438 // Look at potential answers to the VK_EXT_global_priority query. If answers were
439 // provided, we may adjust the queuePriority.
440 if (queueProps[i].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
441 for (uint32_t j = 0; j < queuePriorityProps[i].priorityCount; j++) {
442 if (queuePriorityProps[i].priorities[j] > queuePriority) {
443 queuePriority = queuePriorityProps[i].priorities[j];
444 }
445 }
446 if (queuePriority == VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR) {
447 interface.isRealtimePriority = true;
448 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600449 graphicsQueueIndex = i;
450 break;
451 }
452 }
453
454 if (graphicsQueueIndex == -1) {
455 BAIL("Could not find a graphics queue family");
456 }
457
458 uint32_t deviceExtensionCount;
459 VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount,
460 nullptr));
461 std::vector<VkExtensionProperties> deviceExtensions(deviceExtensionCount);
462 VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount,
463 deviceExtensions.data()));
464
465 std::vector<const char*> enabledDeviceExtensionNames;
466 enabledDeviceExtensionNames.reserve(deviceExtensions.size());
467 interface.deviceExtensionNames.reserve(deviceExtensions.size());
468 for (const auto& devExt : deviceExtensions) {
469 enabledDeviceExtensionNames.push_back(devExt.extensionName);
470 interface.deviceExtensionNames.push_back(devExt.extensionName);
471 }
472
473 interface.grExtensions.init(sGetProc, instance, physicalDevice,
474 enabledInstanceExtensionNames.size(),
475 enabledInstanceExtensionNames.data(),
476 enabledDeviceExtensionNames.size(),
477 enabledDeviceExtensionNames.data());
478
479 if (!interface.grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
480 BAIL("Vulkan driver doesn't support external semaphore fd");
481 }
482
483 interface.physicalDeviceFeatures2 = new VkPhysicalDeviceFeatures2;
484 interface.physicalDeviceFeatures2->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
485 interface.physicalDeviceFeatures2->pNext = nullptr;
486
487 interface.samplerYcbcrConversionFeatures = new VkPhysicalDeviceSamplerYcbcrConversionFeatures;
488 interface.samplerYcbcrConversionFeatures->sType =
489 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
490 interface.samplerYcbcrConversionFeatures->pNext = nullptr;
491
492 interface.physicalDeviceFeatures2->pNext = interface.samplerYcbcrConversionFeatures;
493 void** tailPnext = &interface.samplerYcbcrConversionFeatures->pNext;
494
495 if (protectedContent) {
Ian Elliottae0b8d12023-01-05 19:13:42 -0700496 interface.protectedMemoryFeatures = new VkPhysicalDeviceProtectedMemoryFeatures;
Ian Elliott1f0911e2022-09-09 16:31:47 -0600497 interface.protectedMemoryFeatures->sType =
498 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
499 interface.protectedMemoryFeatures->pNext = nullptr;
500 *tailPnext = interface.protectedMemoryFeatures;
501 tailPnext = &interface.protectedMemoryFeatures->pNext;
502 }
503
Nolan Scobie0f539a72024-01-29 10:49:10 -0500504 if (interface.grExtensions.hasExtension(VK_EXT_DEVICE_FAULT_EXTENSION_NAME, 1)) {
505 interface.deviceFaultFeatures = new VkPhysicalDeviceFaultFeaturesEXT;
506 interface.deviceFaultFeatures->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
507 interface.deviceFaultFeatures->pNext = nullptr;
508 *tailPnext = interface.deviceFaultFeatures;
509 tailPnext = &interface.deviceFaultFeatures->pNext;
510 }
511
Ian Elliott1f0911e2022-09-09 16:31:47 -0600512 vkGetPhysicalDeviceFeatures2(physicalDevice, interface.physicalDeviceFeatures2);
513 // Looks like this would slow things down and we can't depend on it on all platforms
514 interface.physicalDeviceFeatures2->features.robustBufferAccess = VK_FALSE;
515
John Bauman1aab9922023-10-24 17:23:47 +0000516 if (protectedContent && !interface.protectedMemoryFeatures->protectedMemory) {
517 BAIL("Protected memory not supported");
518 }
519
Ian Elliott1f0911e2022-09-09 16:31:47 -0600520 float queuePriorities[1] = {0.0f};
521 void* queueNextPtr = nullptr;
522
523 VkDeviceQueueGlobalPriorityCreateInfoEXT queuePriorityCreateInfo = {
524 VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT,
525 nullptr,
526 // If queue priority is supported, RE should always have realtime priority.
Ian Elliottd50658f2023-06-28 11:08:35 -0600527 queuePriority,
Ian Elliott1f0911e2022-09-09 16:31:47 -0600528 };
529
530 if (interface.grExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) {
531 queueNextPtr = &queuePriorityCreateInfo;
Ian Elliott1f0911e2022-09-09 16:31:47 -0600532 }
533
534 VkDeviceQueueCreateFlags deviceQueueCreateFlags =
535 (VkDeviceQueueCreateFlags)(protectedContent ? VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT : 0);
536
537 const VkDeviceQueueCreateInfo queueInfo = {
538 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
539 queueNextPtr,
540 deviceQueueCreateFlags,
541 (uint32_t)graphicsQueueIndex,
542 1,
543 queuePriorities,
544 };
545
546 const VkDeviceCreateInfo deviceInfo = {
547 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
548 interface.physicalDeviceFeatures2,
549 0,
550 1,
551 &queueInfo,
552 0,
553 nullptr,
554 (uint32_t)enabledDeviceExtensionNames.size(),
555 enabledDeviceExtensionNames.data(),
556 nullptr,
557 };
558
559 ALOGD("Trying to create Vk device with protectedContent=%d", protectedContent);
560 VkDevice device;
561 VK_CHECK(vkCreateDevice(physicalDevice, &deviceInfo, nullptr, &device));
562 ALOGD("Trying to create Vk device with protectedContent=%d (success)", protectedContent);
563
564 VkQueue graphicsQueue;
Ian Elliott87e3dd82023-02-27 12:07:10 -0700565 VK_GET_DEV_PROC(device, GetDeviceQueue2);
566 const VkDeviceQueueInfo2 deviceQueueInfo2 = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2, nullptr,
567 deviceQueueCreateFlags,
568 (uint32_t)graphicsQueueIndex, 0};
569 vkGetDeviceQueue2(device, &deviceQueueInfo2, &graphicsQueue);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600570
571 VK_GET_DEV_PROC(device, DeviceWaitIdle);
572 VK_GET_DEV_PROC(device, DestroyDevice);
573 interface.funcs.vkDeviceWaitIdle = vkDeviceWaitIdle;
574 interface.funcs.vkDestroyDevice = vkDestroyDevice;
575
576 VK_GET_DEV_PROC(device, CreateSemaphore);
577 VK_GET_DEV_PROC(device, ImportSemaphoreFdKHR);
578 VK_GET_DEV_PROC(device, GetSemaphoreFdKHR);
579 VK_GET_DEV_PROC(device, DestroySemaphore);
580 interface.funcs.vkCreateSemaphore = vkCreateSemaphore;
581 interface.funcs.vkImportSemaphoreFdKHR = vkImportSemaphoreFdKHR;
582 interface.funcs.vkGetSemaphoreFdKHR = vkGetSemaphoreFdKHR;
583 interface.funcs.vkDestroySemaphore = vkDestroySemaphore;
584
585 // At this point, everything's succeeded and we can continue
586 interface.initialized = true;
587 interface.instance = instance;
588 interface.physicalDevice = physicalDevice;
589 interface.device = device;
590 interface.queue = graphicsQueue;
591 interface.queueIndex = graphicsQueueIndex;
592 interface.apiVersion = physDevProps.properties.apiVersion;
593 // grExtensions already constructed
594 // feature pointers already constructed
595 interface.grGetProc = sGetProc;
596 interface.isProtected = protectedContent;
597 // funcs already initialized
598
599 ALOGD("%s: Success init Vulkan interface", __func__);
600 return interface;
601}
602
603void teardownVulkanInterface(VulkanInterface* interface) {
604 interface->initialized = false;
605
606 if (interface->device != VK_NULL_HANDLE) {
607 interface->funcs.vkDeviceWaitIdle(interface->device);
608 interface->funcs.vkDestroyDevice(interface->device, nullptr);
609 interface->device = VK_NULL_HANDLE;
610 }
611 if (interface->instance != VK_NULL_HANDLE) {
612 interface->funcs.vkDestroyInstance(interface->instance, nullptr);
613 interface->instance = VK_NULL_HANDLE;
614 }
615
616 if (interface->protectedMemoryFeatures) {
617 delete interface->protectedMemoryFeatures;
618 }
619
620 if (interface->samplerYcbcrConversionFeatures) {
621 delete interface->samplerYcbcrConversionFeatures;
622 }
623
624 if (interface->physicalDeviceFeatures2) {
625 delete interface->physicalDeviceFeatures2;
626 }
627
Nolan Scobie0f539a72024-01-29 10:49:10 -0500628 if (interface->deviceFaultFeatures) {
629 delete interface->deviceFaultFeatures;
630 }
631
Ian Elliott1f0911e2022-09-09 16:31:47 -0600632 interface->samplerYcbcrConversionFeatures = nullptr;
633 interface->physicalDeviceFeatures2 = nullptr;
634 interface->protectedMemoryFeatures = nullptr;
635}
636
637static VulkanInterface sVulkanInterface;
638static VulkanInterface sProtectedContentVulkanInterface;
639
640static void sSetupVulkanInterface() {
641 if (!sVulkanInterface.initialized) {
642 sVulkanInterface = initVulkanInterface(false /* no protected content */);
643 // We will have to abort if non-protected VkDevice creation fails (then nothing works).
644 LOG_ALWAYS_FATAL_IF(!sVulkanInterface.initialized,
645 "Could not initialize Vulkan RenderEngine!");
646 }
647 if (!sProtectedContentVulkanInterface.initialized) {
648 sProtectedContentVulkanInterface = initVulkanInterface(true /* protected content */);
649 if (!sProtectedContentVulkanInterface.initialized) {
650 ALOGE("Could not initialize protected content Vulkan RenderEngine.");
651 }
652 }
653}
654
655namespace skia {
656
657using base::StringAppendF;
658
659bool SkiaVkRenderEngine::canSupportSkiaVkRenderEngine() {
660 VulkanInterface temp = initVulkanInterface(false /* no protected content */);
661 ALOGD("SkiaVkRenderEngine::canSupportSkiaVkRenderEngine(): initialized == %s.",
662 temp.initialized ? "true" : "false");
663 return temp.initialized;
664}
665
666std::unique_ptr<SkiaVkRenderEngine> SkiaVkRenderEngine::create(
667 const RenderEngineCreationArgs& args) {
668 std::unique_ptr<SkiaVkRenderEngine> engine(new SkiaVkRenderEngine(args));
669 engine->ensureGrContextsCreated();
670
671 if (sVulkanInterface.initialized) {
672 ALOGD("SkiaVkRenderEngine::%s: successfully initialized SkiaVkRenderEngine", __func__);
673 return engine;
674 } else {
675 ALOGD("SkiaVkRenderEngine::%s: could not create SkiaVkRenderEngine. "
676 "Likely insufficient Vulkan support",
677 __func__);
678 return {};
679 }
680}
681
682SkiaVkRenderEngine::SkiaVkRenderEngine(const RenderEngineCreationArgs& args)
Leon Scroggins III696bf932024-01-24 15:21:05 -0500683 : SkiaRenderEngine(args.threaded, static_cast<PixelFormat>(args.pixelFormat),
Alec Mouri47bcb072023-08-15 02:02:49 +0000684 args.supportsBackgroundBlur) {}
Ian Elliott1f0911e2022-09-09 16:31:47 -0600685
686SkiaVkRenderEngine::~SkiaVkRenderEngine() {
687 finishRenderingAndAbandonContext();
688}
689
690SkiaRenderEngine::Contexts SkiaVkRenderEngine::createDirectContexts(
691 const GrContextOptions& options) {
692 sSetupVulkanInterface();
693
694 SkiaRenderEngine::Contexts contexts;
Kevin Lubick2fc49112023-10-13 13:10:48 +0000695 contexts.first = GrDirectContexts::MakeVulkan(sVulkanInterface.getBackendContext(), options);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600696 if (supportsProtectedContentImpl()) {
697 contexts.second =
Kevin Lubick2fc49112023-10-13 13:10:48 +0000698 GrDirectContexts::MakeVulkan(sProtectedContentVulkanInterface.getBackendContext(),
699 options);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600700 }
701
702 return contexts;
703}
704
705bool SkiaVkRenderEngine::supportsProtectedContentImpl() const {
706 return sProtectedContentVulkanInterface.initialized;
707}
708
709bool SkiaVkRenderEngine::useProtectedContextImpl(GrProtected) {
710 return true;
711}
712
Ian Elliott98e87162023-04-14 14:05:19 -0600713static void delete_semaphore(void* semaphore) {
714 DestroySemaphoreInfo* info = reinterpret_cast<DestroySemaphoreInfo*>(semaphore);
715 --info->mRefs;
716 if (!info->mRefs) {
717 sVulkanInterface.destroySemaphore(info->mSemaphore);
718 delete info;
719 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600720}
721
Ian Elliott98e87162023-04-14 14:05:19 -0600722static void delete_semaphore_protected(void* semaphore) {
723 DestroySemaphoreInfo* info = reinterpret_cast<DestroySemaphoreInfo*>(semaphore);
724 --info->mRefs;
725 if (!info->mRefs) {
726 sProtectedContentVulkanInterface.destroySemaphore(info->mSemaphore);
727 delete info;
728 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600729}
730
731static VulkanInterface& getVulkanInterface(bool protectedContext) {
732 if (protectedContext) {
733 return sProtectedContentVulkanInterface;
734 }
735 return sVulkanInterface;
736}
737
738void SkiaVkRenderEngine::waitFence(GrDirectContext* grContext, base::borrowed_fd fenceFd) {
739 if (fenceFd.get() < 0) return;
740
741 int dupedFd = dup(fenceFd.get());
742 if (dupedFd < 0) {
743 ALOGE("failed to create duplicate fence fd: %d", dupedFd);
744 sync_wait(fenceFd.get(), -1);
745 return;
746 }
747
748 base::unique_fd fenceDup(dupedFd);
749 VkSemaphore waitSemaphore =
750 getVulkanInterface(isProtected()).importSemaphoreFromSyncFd(fenceDup.release());
751 GrBackendSemaphore beSemaphore;
752 beSemaphore.initVulkan(waitSemaphore);
753 grContext->wait(1, &beSemaphore, true /* delete after wait */);
754}
755
756base::unique_fd SkiaVkRenderEngine::flushAndSubmit(GrDirectContext* grContext) {
Ian Elliott98e87162023-04-14 14:05:19 -0600757 VulkanInterface& vi = getVulkanInterface(isProtected());
758 VkSemaphore semaphore = vi.createExportableSemaphore();
759
760 GrBackendSemaphore backendSemaphore;
761 backendSemaphore.initVulkan(semaphore);
762
Ian Elliott1f0911e2022-09-09 16:31:47 -0600763 GrFlushInfo flushInfo;
Ian Elliott98e87162023-04-14 14:05:19 -0600764 DestroySemaphoreInfo* destroySemaphoreInfo = nullptr;
765 if (semaphore != VK_NULL_HANDLE) {
766 destroySemaphoreInfo = new DestroySemaphoreInfo(semaphore);
767 flushInfo.fNumSemaphores = 1;
768 flushInfo.fSignalSemaphores = &backendSemaphore;
769 flushInfo.fFinishedProc = isProtected() ? delete_semaphore_protected : delete_semaphore;
770 flushInfo.fFinishedContext = destroySemaphoreInfo;
771 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600772 GrSemaphoresSubmitted submitted = grContext->flush(flushInfo);
Kevin Lubicka0efc342023-09-20 13:11:52 +0000773 grContext->submit(GrSyncCpu::kNo);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600774 int drawFenceFd = -1;
Ian Elliott98e87162023-04-14 14:05:19 -0600775 if (semaphore != VK_NULL_HANDLE) {
776 if (GrSemaphoresSubmitted::kYes == submitted) {
777 drawFenceFd = vi.exportSemaphoreSyncFd(semaphore);
778 }
779 // Now that drawFenceFd has been created, we can delete our reference to this semaphore
780 flushInfo.fFinishedProc(destroySemaphoreInfo);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600781 }
782 base::unique_fd res(drawFenceFd);
783 return res;
784}
785
786int SkiaVkRenderEngine::getContextPriority() {
787 // EGL_CONTEXT_PRIORITY_REALTIME_NV
788 constexpr int kRealtimePriority = 0x3357;
789 if (getVulkanInterface(isProtected()).isRealtimePriority) {
790 return kRealtimePriority;
791 } else {
792 return 0;
793 }
794}
795
796void SkiaVkRenderEngine::appendBackendSpecificInfoToDump(std::string& result) {
797 StringAppendF(&result, "\n ------------RE Vulkan----------\n");
798 StringAppendF(&result, "\n Vulkan device initialized: %d\n", sVulkanInterface.initialized);
799 StringAppendF(&result, "\n Vulkan protected device initialized: %d\n",
800 sProtectedContentVulkanInterface.initialized);
801
802 if (!sVulkanInterface.initialized) {
803 return;
804 }
805
806 StringAppendF(&result, "\n Instance extensions:\n");
807 for (const auto& name : sVulkanInterface.instanceExtensionNames) {
808 StringAppendF(&result, "\n %s\n", name.c_str());
809 }
810
811 StringAppendF(&result, "\n Device extensions:\n");
812 for (const auto& name : sVulkanInterface.deviceExtensionNames) {
813 StringAppendF(&result, "\n %s\n", name.c_str());
814 }
815}
816
817} // namespace skia
818} // namespace renderengine
819} // namespace android