blob: eb7a9d5bfa203a202356229bc68e1e3ca5f2f538 [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
Serdar Kocdemir415c59e2024-02-27 12:36:09 +0000381 if (physDevProps.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
382 // TODO: b/326633110 - SkiaVK is not working correctly on swiftshader path.
383 BAIL("CPU implementations of Vulkan is not supported");
384 }
385
Ian Elliott1f0911e2022-09-09 16:31:47 -0600386 // Check for syncfd support. Bail if we cannot both import and export them.
387 VkPhysicalDeviceExternalSemaphoreInfo semInfo = {
388 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
389 nullptr,
390 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
391 };
392 VkExternalSemaphoreProperties semProps = {
393 VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, nullptr, 0, 0, 0,
394 };
395 vkGetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, &semInfo, &semProps);
396
397 bool sufficientSemaphoreSyncFdSupport = (semProps.exportFromImportedHandleTypes &
398 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) &&
399 (semProps.compatibleHandleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) &&
400 (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT) &&
401 (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
402
403 if (!sufficientSemaphoreSyncFdSupport) {
404 BAIL("Vulkan device does not support sufficient external semaphore sync fd features. "
405 "exportFromImportedHandleTypes 0x%x (needed 0x%x) "
406 "compatibleHandleTypes 0x%x (needed 0x%x) "
407 "externalSemaphoreFeatures 0x%x (needed 0x%x) ",
408 semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
409 semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
410 semProps.externalSemaphoreFeatures,
411 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
412 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
413 } else {
414 ALOGD("Vulkan device supports sufficient external semaphore sync fd features. "
415 "exportFromImportedHandleTypes 0x%x (needed 0x%x) "
416 "compatibleHandleTypes 0x%x (needed 0x%x) "
417 "externalSemaphoreFeatures 0x%x (needed 0x%x) ",
418 semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
419 semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
420 semProps.externalSemaphoreFeatures,
421 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
422 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
423 }
424
425 uint32_t queueCount;
Ian Elliottd50658f2023-06-28 11:08:35 -0600426 vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, nullptr);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600427 if (queueCount == 0) {
428 BAIL("Could not find queues for physical device");
429 }
430
Ian Elliottd50658f2023-06-28 11:08:35 -0600431 std::vector<VkQueueFamilyProperties2> queueProps(queueCount);
432 std::vector<VkQueueFamilyGlobalPriorityPropertiesEXT> queuePriorityProps(queueCount);
433 VkQueueGlobalPriorityKHR queuePriority = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR;
434 // Even though we don't yet know if the VK_EXT_global_priority extension is available,
435 // we can safely add the request to the pNext chain, and if the extension is not
436 // available, it will be ignored.
437 for (uint32_t i = 0; i < queueCount; ++i) {
438 queuePriorityProps[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT;
439 queuePriorityProps[i].pNext = nullptr;
440 queueProps[i].pNext = &queuePriorityProps[i];
441 }
442 vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, queueProps.data());
Ian Elliott1f0911e2022-09-09 16:31:47 -0600443
444 int graphicsQueueIndex = -1;
445 for (uint32_t i = 0; i < queueCount; ++i) {
Ian Elliottd50658f2023-06-28 11:08:35 -0600446 // Look at potential answers to the VK_EXT_global_priority query. If answers were
447 // provided, we may adjust the queuePriority.
448 if (queueProps[i].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
449 for (uint32_t j = 0; j < queuePriorityProps[i].priorityCount; j++) {
450 if (queuePriorityProps[i].priorities[j] > queuePriority) {
451 queuePriority = queuePriorityProps[i].priorities[j];
452 }
453 }
454 if (queuePriority == VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR) {
455 interface.isRealtimePriority = true;
456 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600457 graphicsQueueIndex = i;
458 break;
459 }
460 }
461
462 if (graphicsQueueIndex == -1) {
463 BAIL("Could not find a graphics queue family");
464 }
465
466 uint32_t deviceExtensionCount;
467 VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount,
468 nullptr));
469 std::vector<VkExtensionProperties> deviceExtensions(deviceExtensionCount);
470 VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount,
471 deviceExtensions.data()));
472
473 std::vector<const char*> enabledDeviceExtensionNames;
474 enabledDeviceExtensionNames.reserve(deviceExtensions.size());
475 interface.deviceExtensionNames.reserve(deviceExtensions.size());
476 for (const auto& devExt : deviceExtensions) {
477 enabledDeviceExtensionNames.push_back(devExt.extensionName);
478 interface.deviceExtensionNames.push_back(devExt.extensionName);
479 }
480
481 interface.grExtensions.init(sGetProc, instance, physicalDevice,
482 enabledInstanceExtensionNames.size(),
483 enabledInstanceExtensionNames.data(),
484 enabledDeviceExtensionNames.size(),
485 enabledDeviceExtensionNames.data());
486
487 if (!interface.grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
488 BAIL("Vulkan driver doesn't support external semaphore fd");
489 }
490
491 interface.physicalDeviceFeatures2 = new VkPhysicalDeviceFeatures2;
492 interface.physicalDeviceFeatures2->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
493 interface.physicalDeviceFeatures2->pNext = nullptr;
494
495 interface.samplerYcbcrConversionFeatures = new VkPhysicalDeviceSamplerYcbcrConversionFeatures;
496 interface.samplerYcbcrConversionFeatures->sType =
497 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
498 interface.samplerYcbcrConversionFeatures->pNext = nullptr;
499
500 interface.physicalDeviceFeatures2->pNext = interface.samplerYcbcrConversionFeatures;
501 void** tailPnext = &interface.samplerYcbcrConversionFeatures->pNext;
502
503 if (protectedContent) {
Ian Elliottae0b8d12023-01-05 19:13:42 -0700504 interface.protectedMemoryFeatures = new VkPhysicalDeviceProtectedMemoryFeatures;
Ian Elliott1f0911e2022-09-09 16:31:47 -0600505 interface.protectedMemoryFeatures->sType =
506 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
507 interface.protectedMemoryFeatures->pNext = nullptr;
508 *tailPnext = interface.protectedMemoryFeatures;
509 tailPnext = &interface.protectedMemoryFeatures->pNext;
510 }
511
Nolan Scobie0f539a72024-01-29 10:49:10 -0500512 if (interface.grExtensions.hasExtension(VK_EXT_DEVICE_FAULT_EXTENSION_NAME, 1)) {
513 interface.deviceFaultFeatures = new VkPhysicalDeviceFaultFeaturesEXT;
514 interface.deviceFaultFeatures->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
515 interface.deviceFaultFeatures->pNext = nullptr;
516 *tailPnext = interface.deviceFaultFeatures;
517 tailPnext = &interface.deviceFaultFeatures->pNext;
518 }
519
Ian Elliott1f0911e2022-09-09 16:31:47 -0600520 vkGetPhysicalDeviceFeatures2(physicalDevice, interface.physicalDeviceFeatures2);
521 // Looks like this would slow things down and we can't depend on it on all platforms
522 interface.physicalDeviceFeatures2->features.robustBufferAccess = VK_FALSE;
523
John Bauman1aab9922023-10-24 17:23:47 +0000524 if (protectedContent && !interface.protectedMemoryFeatures->protectedMemory) {
525 BAIL("Protected memory not supported");
526 }
527
Ian Elliott1f0911e2022-09-09 16:31:47 -0600528 float queuePriorities[1] = {0.0f};
529 void* queueNextPtr = nullptr;
530
531 VkDeviceQueueGlobalPriorityCreateInfoEXT queuePriorityCreateInfo = {
532 VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT,
533 nullptr,
534 // If queue priority is supported, RE should always have realtime priority.
Ian Elliottd50658f2023-06-28 11:08:35 -0600535 queuePriority,
Ian Elliott1f0911e2022-09-09 16:31:47 -0600536 };
537
538 if (interface.grExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) {
539 queueNextPtr = &queuePriorityCreateInfo;
Ian Elliott1f0911e2022-09-09 16:31:47 -0600540 }
541
542 VkDeviceQueueCreateFlags deviceQueueCreateFlags =
543 (VkDeviceQueueCreateFlags)(protectedContent ? VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT : 0);
544
545 const VkDeviceQueueCreateInfo queueInfo = {
546 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
547 queueNextPtr,
548 deviceQueueCreateFlags,
549 (uint32_t)graphicsQueueIndex,
550 1,
551 queuePriorities,
552 };
553
554 const VkDeviceCreateInfo deviceInfo = {
555 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
556 interface.physicalDeviceFeatures2,
557 0,
558 1,
559 &queueInfo,
560 0,
561 nullptr,
562 (uint32_t)enabledDeviceExtensionNames.size(),
563 enabledDeviceExtensionNames.data(),
564 nullptr,
565 };
566
567 ALOGD("Trying to create Vk device with protectedContent=%d", protectedContent);
568 VkDevice device;
569 VK_CHECK(vkCreateDevice(physicalDevice, &deviceInfo, nullptr, &device));
570 ALOGD("Trying to create Vk device with protectedContent=%d (success)", protectedContent);
571
572 VkQueue graphicsQueue;
Ian Elliott87e3dd82023-02-27 12:07:10 -0700573 VK_GET_DEV_PROC(device, GetDeviceQueue2);
574 const VkDeviceQueueInfo2 deviceQueueInfo2 = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2, nullptr,
575 deviceQueueCreateFlags,
576 (uint32_t)graphicsQueueIndex, 0};
577 vkGetDeviceQueue2(device, &deviceQueueInfo2, &graphicsQueue);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600578
579 VK_GET_DEV_PROC(device, DeviceWaitIdle);
580 VK_GET_DEV_PROC(device, DestroyDevice);
581 interface.funcs.vkDeviceWaitIdle = vkDeviceWaitIdle;
582 interface.funcs.vkDestroyDevice = vkDestroyDevice;
583
584 VK_GET_DEV_PROC(device, CreateSemaphore);
585 VK_GET_DEV_PROC(device, ImportSemaphoreFdKHR);
586 VK_GET_DEV_PROC(device, GetSemaphoreFdKHR);
587 VK_GET_DEV_PROC(device, DestroySemaphore);
588 interface.funcs.vkCreateSemaphore = vkCreateSemaphore;
589 interface.funcs.vkImportSemaphoreFdKHR = vkImportSemaphoreFdKHR;
590 interface.funcs.vkGetSemaphoreFdKHR = vkGetSemaphoreFdKHR;
591 interface.funcs.vkDestroySemaphore = vkDestroySemaphore;
592
593 // At this point, everything's succeeded and we can continue
594 interface.initialized = true;
595 interface.instance = instance;
596 interface.physicalDevice = physicalDevice;
597 interface.device = device;
598 interface.queue = graphicsQueue;
599 interface.queueIndex = graphicsQueueIndex;
600 interface.apiVersion = physDevProps.properties.apiVersion;
601 // grExtensions already constructed
602 // feature pointers already constructed
603 interface.grGetProc = sGetProc;
604 interface.isProtected = protectedContent;
605 // funcs already initialized
606
Leon Scroggins IIIf3369ed2024-02-16 17:52:42 -0500607 const nsecs_t timeAfter = systemTime();
608 const float initTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
609 ALOGD("%s: Success init Vulkan interface in %f ms", __func__, initTimeMs);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600610 return interface;
611}
612
613void teardownVulkanInterface(VulkanInterface* interface) {
614 interface->initialized = false;
615
616 if (interface->device != VK_NULL_HANDLE) {
617 interface->funcs.vkDeviceWaitIdle(interface->device);
618 interface->funcs.vkDestroyDevice(interface->device, nullptr);
619 interface->device = VK_NULL_HANDLE;
620 }
621 if (interface->instance != VK_NULL_HANDLE) {
622 interface->funcs.vkDestroyInstance(interface->instance, nullptr);
623 interface->instance = VK_NULL_HANDLE;
624 }
625
626 if (interface->protectedMemoryFeatures) {
627 delete interface->protectedMemoryFeatures;
628 }
629
630 if (interface->samplerYcbcrConversionFeatures) {
631 delete interface->samplerYcbcrConversionFeatures;
632 }
633
634 if (interface->physicalDeviceFeatures2) {
635 delete interface->physicalDeviceFeatures2;
636 }
637
Nolan Scobie0f539a72024-01-29 10:49:10 -0500638 if (interface->deviceFaultFeatures) {
639 delete interface->deviceFaultFeatures;
640 }
641
Ian Elliott1f0911e2022-09-09 16:31:47 -0600642 interface->samplerYcbcrConversionFeatures = nullptr;
643 interface->physicalDeviceFeatures2 = nullptr;
644 interface->protectedMemoryFeatures = nullptr;
645}
646
647static VulkanInterface sVulkanInterface;
648static VulkanInterface sProtectedContentVulkanInterface;
649
650static void sSetupVulkanInterface() {
651 if (!sVulkanInterface.initialized) {
652 sVulkanInterface = initVulkanInterface(false /* no protected content */);
653 // We will have to abort if non-protected VkDevice creation fails (then nothing works).
654 LOG_ALWAYS_FATAL_IF(!sVulkanInterface.initialized,
655 "Could not initialize Vulkan RenderEngine!");
656 }
657 if (!sProtectedContentVulkanInterface.initialized) {
658 sProtectedContentVulkanInterface = initVulkanInterface(true /* protected content */);
659 if (!sProtectedContentVulkanInterface.initialized) {
660 ALOGE("Could not initialize protected content Vulkan RenderEngine.");
661 }
662 }
663}
664
Leon Scroggins IIIf3369ed2024-02-16 17:52:42 -0500665bool RenderEngine::canSupport(GraphicsApi graphicsApi) {
666 switch (graphicsApi) {
667 case GraphicsApi::GL:
668 return true;
669 case GraphicsApi::VK: {
670 if (!sVulkanInterface.initialized) {
671 sVulkanInterface = initVulkanInterface(false /* no protected content */);
672 ALOGD("%s: initialized == %s.", __func__,
673 sVulkanInterface.initialized ? "true" : "false");
674 }
675 return sVulkanInterface.initialized;
676 }
677 }
678}
679
Ian Elliott1f0911e2022-09-09 16:31:47 -0600680namespace skia {
681
682using base::StringAppendF;
683
Ian Elliott1f0911e2022-09-09 16:31:47 -0600684std::unique_ptr<SkiaVkRenderEngine> SkiaVkRenderEngine::create(
685 const RenderEngineCreationArgs& args) {
686 std::unique_ptr<SkiaVkRenderEngine> engine(new SkiaVkRenderEngine(args));
687 engine->ensureGrContextsCreated();
688
689 if (sVulkanInterface.initialized) {
690 ALOGD("SkiaVkRenderEngine::%s: successfully initialized SkiaVkRenderEngine", __func__);
691 return engine;
692 } else {
693 ALOGD("SkiaVkRenderEngine::%s: could not create SkiaVkRenderEngine. "
694 "Likely insufficient Vulkan support",
695 __func__);
696 return {};
697 }
698}
699
700SkiaVkRenderEngine::SkiaVkRenderEngine(const RenderEngineCreationArgs& args)
Leon Scroggins III696bf932024-01-24 15:21:05 -0500701 : SkiaRenderEngine(args.threaded, static_cast<PixelFormat>(args.pixelFormat),
Alec Mouri47bcb072023-08-15 02:02:49 +0000702 args.supportsBackgroundBlur) {}
Ian Elliott1f0911e2022-09-09 16:31:47 -0600703
704SkiaVkRenderEngine::~SkiaVkRenderEngine() {
705 finishRenderingAndAbandonContext();
706}
707
708SkiaRenderEngine::Contexts SkiaVkRenderEngine::createDirectContexts(
709 const GrContextOptions& options) {
710 sSetupVulkanInterface();
711
712 SkiaRenderEngine::Contexts contexts;
Kevin Lubick2fc49112023-10-13 13:10:48 +0000713 contexts.first = GrDirectContexts::MakeVulkan(sVulkanInterface.getBackendContext(), options);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600714 if (supportsProtectedContentImpl()) {
715 contexts.second =
Kevin Lubick2fc49112023-10-13 13:10:48 +0000716 GrDirectContexts::MakeVulkan(sProtectedContentVulkanInterface.getBackendContext(),
717 options);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600718 }
719
720 return contexts;
721}
722
723bool SkiaVkRenderEngine::supportsProtectedContentImpl() const {
724 return sProtectedContentVulkanInterface.initialized;
725}
726
727bool SkiaVkRenderEngine::useProtectedContextImpl(GrProtected) {
728 return true;
729}
730
Ian Elliott98e87162023-04-14 14:05:19 -0600731static void delete_semaphore(void* semaphore) {
732 DestroySemaphoreInfo* info = reinterpret_cast<DestroySemaphoreInfo*>(semaphore);
733 --info->mRefs;
734 if (!info->mRefs) {
735 sVulkanInterface.destroySemaphore(info->mSemaphore);
736 delete info;
737 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600738}
739
Ian Elliott98e87162023-04-14 14:05:19 -0600740static void delete_semaphore_protected(void* semaphore) {
741 DestroySemaphoreInfo* info = reinterpret_cast<DestroySemaphoreInfo*>(semaphore);
742 --info->mRefs;
743 if (!info->mRefs) {
744 sProtectedContentVulkanInterface.destroySemaphore(info->mSemaphore);
745 delete info;
746 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600747}
748
749static VulkanInterface& getVulkanInterface(bool protectedContext) {
750 if (protectedContext) {
751 return sProtectedContentVulkanInterface;
752 }
753 return sVulkanInterface;
754}
755
756void SkiaVkRenderEngine::waitFence(GrDirectContext* grContext, base::borrowed_fd fenceFd) {
757 if (fenceFd.get() < 0) return;
758
759 int dupedFd = dup(fenceFd.get());
760 if (dupedFd < 0) {
761 ALOGE("failed to create duplicate fence fd: %d", dupedFd);
762 sync_wait(fenceFd.get(), -1);
763 return;
764 }
765
766 base::unique_fd fenceDup(dupedFd);
767 VkSemaphore waitSemaphore =
768 getVulkanInterface(isProtected()).importSemaphoreFromSyncFd(fenceDup.release());
769 GrBackendSemaphore beSemaphore;
770 beSemaphore.initVulkan(waitSemaphore);
771 grContext->wait(1, &beSemaphore, true /* delete after wait */);
772}
773
774base::unique_fd SkiaVkRenderEngine::flushAndSubmit(GrDirectContext* grContext) {
Ian Elliott98e87162023-04-14 14:05:19 -0600775 VulkanInterface& vi = getVulkanInterface(isProtected());
776 VkSemaphore semaphore = vi.createExportableSemaphore();
777
778 GrBackendSemaphore backendSemaphore;
779 backendSemaphore.initVulkan(semaphore);
780
Ian Elliott1f0911e2022-09-09 16:31:47 -0600781 GrFlushInfo flushInfo;
Ian Elliott98e87162023-04-14 14:05:19 -0600782 DestroySemaphoreInfo* destroySemaphoreInfo = nullptr;
783 if (semaphore != VK_NULL_HANDLE) {
784 destroySemaphoreInfo = new DestroySemaphoreInfo(semaphore);
785 flushInfo.fNumSemaphores = 1;
786 flushInfo.fSignalSemaphores = &backendSemaphore;
787 flushInfo.fFinishedProc = isProtected() ? delete_semaphore_protected : delete_semaphore;
788 flushInfo.fFinishedContext = destroySemaphoreInfo;
789 }
Ian Elliott1f0911e2022-09-09 16:31:47 -0600790 GrSemaphoresSubmitted submitted = grContext->flush(flushInfo);
Kevin Lubicka0efc342023-09-20 13:11:52 +0000791 grContext->submit(GrSyncCpu::kNo);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600792 int drawFenceFd = -1;
Ian Elliott98e87162023-04-14 14:05:19 -0600793 if (semaphore != VK_NULL_HANDLE) {
794 if (GrSemaphoresSubmitted::kYes == submitted) {
795 drawFenceFd = vi.exportSemaphoreSyncFd(semaphore);
796 }
797 // Now that drawFenceFd has been created, we can delete our reference to this semaphore
798 flushInfo.fFinishedProc(destroySemaphoreInfo);
Ian Elliott1f0911e2022-09-09 16:31:47 -0600799 }
800 base::unique_fd res(drawFenceFd);
801 return res;
802}
803
804int SkiaVkRenderEngine::getContextPriority() {
805 // EGL_CONTEXT_PRIORITY_REALTIME_NV
806 constexpr int kRealtimePriority = 0x3357;
807 if (getVulkanInterface(isProtected()).isRealtimePriority) {
808 return kRealtimePriority;
809 } else {
810 return 0;
811 }
812}
813
814void SkiaVkRenderEngine::appendBackendSpecificInfoToDump(std::string& result) {
815 StringAppendF(&result, "\n ------------RE Vulkan----------\n");
816 StringAppendF(&result, "\n Vulkan device initialized: %d\n", sVulkanInterface.initialized);
817 StringAppendF(&result, "\n Vulkan protected device initialized: %d\n",
818 sProtectedContentVulkanInterface.initialized);
819
820 if (!sVulkanInterface.initialized) {
821 return;
822 }
823
824 StringAppendF(&result, "\n Instance extensions:\n");
825 for (const auto& name : sVulkanInterface.instanceExtensionNames) {
826 StringAppendF(&result, "\n %s\n", name.c_str());
827 }
828
829 StringAppendF(&result, "\n Device extensions:\n");
830 for (const auto& name : sVulkanInterface.deviceExtensionNames) {
831 StringAppendF(&result, "\n %s\n", name.c_str());
832 }
833}
834
835} // namespace skia
836} // namespace renderengine
837} // namespace android