/* * Copyright 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // #define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "RenderEngine" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "SkiaVkRenderEngine.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "log/log_main.h" namespace android { namespace renderengine { struct VulkanFuncs { PFN_vkCreateSemaphore vkCreateSemaphore = nullptr; PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR = nullptr; PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR = nullptr; PFN_vkDestroySemaphore vkDestroySemaphore = nullptr; PFN_vkDeviceWaitIdle vkDeviceWaitIdle = nullptr; PFN_vkDestroyDevice vkDestroyDevice = nullptr; PFN_vkDestroyInstance vkDestroyInstance = nullptr; }; // Ref-Count a semaphore struct DestroySemaphoreInfo { VkSemaphore mSemaphore; // We need to make sure we don't delete the VkSemaphore until it is done being used by both Skia // (including by the GPU) and inside SkiaVkRenderEngine. So we always start with two refs, one // owned by Skia and one owned by the SkiaVkRenderEngine. The refs are decremented each time // delete_semaphore* is called with this object. Skia will call destroy_semaphore* once it is // done with the semaphore and the GPU has finished work on the semaphore. SkiaVkRenderEngine // calls delete_semaphore* after sending the semaphore to Skia and exporting it if need be. int mRefs = 2; DestroySemaphoreInfo(VkSemaphore semaphore) : mSemaphore(semaphore) {} }; struct VulkanInterface { bool initialized = false; VkInstance instance; VkPhysicalDevice physicalDevice; VkDevice device; VkQueue queue; int queueIndex; uint32_t apiVersion; GrVkExtensions grExtensions; VkPhysicalDeviceFeatures2* physicalDeviceFeatures2 = nullptr; VkPhysicalDeviceSamplerYcbcrConversionFeatures* samplerYcbcrConversionFeatures = nullptr; VkPhysicalDeviceProtectedMemoryFeatures* protectedMemoryFeatures = nullptr; GrVkGetProc grGetProc; bool isProtected; bool isRealtimePriority; VulkanFuncs funcs; std::vector instanceExtensionNames; std::vector deviceExtensionNames; GrVkBackendContext getBackendContext() { GrVkBackendContext backendContext; backendContext.fInstance = instance; backendContext.fPhysicalDevice = physicalDevice; backendContext.fDevice = device; backendContext.fQueue = queue; backendContext.fGraphicsQueueIndex = queueIndex; backendContext.fMaxAPIVersion = apiVersion; backendContext.fVkExtensions = &grExtensions; backendContext.fDeviceFeatures2 = physicalDeviceFeatures2; backendContext.fGetProc = grGetProc; backendContext.fProtectedContext = isProtected ? GrProtected::kYes : GrProtected::kNo; return backendContext; }; VkSemaphore createExportableSemaphore() { VkExportSemaphoreCreateInfo exportInfo; exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO; exportInfo.pNext = nullptr; exportInfo.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; VkSemaphoreCreateInfo semaphoreInfo; semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; semaphoreInfo.pNext = &exportInfo; semaphoreInfo.flags = 0; VkSemaphore semaphore; VkResult err = funcs.vkCreateSemaphore(device, &semaphoreInfo, nullptr, &semaphore); if (VK_SUCCESS != err) { ALOGE("%s: failed to create semaphore. err %d\n", __func__, err); return VK_NULL_HANDLE; } return semaphore; } // syncFd cannot be <= 0 VkSemaphore importSemaphoreFromSyncFd(int syncFd) { VkSemaphoreCreateInfo semaphoreInfo; semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; semaphoreInfo.pNext = nullptr; semaphoreInfo.flags = 0; VkSemaphore semaphore; VkResult err = funcs.vkCreateSemaphore(device, &semaphoreInfo, nullptr, &semaphore); if (VK_SUCCESS != err) { ALOGE("%s: failed to create import semaphore", __func__); return VK_NULL_HANDLE; } VkImportSemaphoreFdInfoKHR importInfo; importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR; importInfo.pNext = nullptr; importInfo.semaphore = semaphore; importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT; importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; importInfo.fd = syncFd; err = funcs.vkImportSemaphoreFdKHR(device, &importInfo); if (VK_SUCCESS != err) { funcs.vkDestroySemaphore(device, semaphore, nullptr); ALOGE("%s: failed to import semaphore", __func__); return VK_NULL_HANDLE; } return semaphore; } int exportSemaphoreSyncFd(VkSemaphore semaphore) { int res; VkSemaphoreGetFdInfoKHR getFdInfo; getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR; getFdInfo.pNext = nullptr; getFdInfo.semaphore = semaphore; getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; VkResult err = funcs.vkGetSemaphoreFdKHR(device, &getFdInfo, &res); if (VK_SUCCESS != err) { ALOGE("%s: failed to export semaphore, err: %d", __func__, err); return -1; } return res; } void destroySemaphore(VkSemaphore semaphore) { funcs.vkDestroySemaphore(device, semaphore, nullptr); } }; static GrVkGetProc sGetProc = [](const char* proc_name, VkInstance instance, VkDevice device) { if (device != VK_NULL_HANDLE) { return vkGetDeviceProcAddr(device, proc_name); } return vkGetInstanceProcAddr(instance, proc_name); }; #define BAIL(fmt, ...) \ { \ ALOGE("%s: " fmt ", bailing", __func__, ##__VA_ARGS__); \ return interface; \ } #define CHECK_NONNULL(expr) \ if ((expr) == nullptr) { \ BAIL("[%s] null", #expr); \ } #define VK_CHECK(expr) \ if ((expr) != VK_SUCCESS) { \ BAIL("[%s] failed. err = %d", #expr, expr); \ return interface; \ } #define VK_GET_PROC(F) \ PFN_vk##F vk##F = (PFN_vk##F)vkGetInstanceProcAddr(VK_NULL_HANDLE, "vk" #F); \ CHECK_NONNULL(vk##F) #define VK_GET_INST_PROC(instance, F) \ PFN_vk##F vk##F = (PFN_vk##F)vkGetInstanceProcAddr(instance, "vk" #F); \ CHECK_NONNULL(vk##F) #define VK_GET_DEV_PROC(device, F) \ PFN_vk##F vk##F = (PFN_vk##F)vkGetDeviceProcAddr(device, "vk" #F); \ CHECK_NONNULL(vk##F) VulkanInterface initVulkanInterface(bool protectedContent = false) { VulkanInterface interface; VK_GET_PROC(EnumerateInstanceVersion); uint32_t instanceVersion; VK_CHECK(vkEnumerateInstanceVersion(&instanceVersion)); if (instanceVersion < VK_MAKE_VERSION(1, 1, 0)) { return interface; } const VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO, nullptr, "surfaceflinger", 0, "android platform", 0, VK_MAKE_VERSION(1, 1, 0), }; VK_GET_PROC(EnumerateInstanceExtensionProperties); uint32_t extensionCount = 0; VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr)); std::vector instanceExtensions(extensionCount); VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, instanceExtensions.data())); std::vector enabledInstanceExtensionNames; enabledInstanceExtensionNames.reserve(instanceExtensions.size()); interface.instanceExtensionNames.reserve(instanceExtensions.size()); for (const auto& instExt : instanceExtensions) { enabledInstanceExtensionNames.push_back(instExt.extensionName); interface.instanceExtensionNames.push_back(instExt.extensionName); } const VkInstanceCreateInfo instanceCreateInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, nullptr, 0, &appInfo, 0, nullptr, (uint32_t)enabledInstanceExtensionNames.size(), enabledInstanceExtensionNames.data(), }; VK_GET_PROC(CreateInstance); VkInstance instance; VK_CHECK(vkCreateInstance(&instanceCreateInfo, nullptr, &instance)); VK_GET_INST_PROC(instance, DestroyInstance); interface.funcs.vkDestroyInstance = vkDestroyInstance; VK_GET_INST_PROC(instance, EnumeratePhysicalDevices); VK_GET_INST_PROC(instance, EnumerateDeviceExtensionProperties); VK_GET_INST_PROC(instance, GetPhysicalDeviceProperties2); VK_GET_INST_PROC(instance, GetPhysicalDeviceExternalSemaphoreProperties); VK_GET_INST_PROC(instance, GetPhysicalDeviceQueueFamilyProperties2); VK_GET_INST_PROC(instance, GetPhysicalDeviceFeatures2); VK_GET_INST_PROC(instance, CreateDevice); uint32_t physdevCount; VK_CHECK(vkEnumeratePhysicalDevices(instance, &physdevCount, nullptr)); if (physdevCount == 0) { BAIL("Could not find any physical devices"); } physdevCount = 1; VkPhysicalDevice physicalDevice; VkResult enumeratePhysDevsErr = vkEnumeratePhysicalDevices(instance, &physdevCount, &physicalDevice); if (enumeratePhysDevsErr != VK_SUCCESS && VK_INCOMPLETE != enumeratePhysDevsErr) { BAIL("vkEnumeratePhysicalDevices failed with non-VK_INCOMPLETE error: %d", enumeratePhysDevsErr); } VkPhysicalDeviceProperties2 physDevProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, 0, {}, }; VkPhysicalDeviceProtectedMemoryProperties protMemProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES, 0, {}, }; if (protectedContent) { physDevProps.pNext = &protMemProps; } vkGetPhysicalDeviceProperties2(physicalDevice, &physDevProps); if (physDevProps.properties.apiVersion < VK_MAKE_VERSION(1, 1, 0)) { BAIL("Could not find a Vulkan 1.1+ physical device"); } // Check for syncfd support. Bail if we cannot both import and export them. VkPhysicalDeviceExternalSemaphoreInfo semInfo = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, nullptr, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, }; VkExternalSemaphoreProperties semProps = { VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, nullptr, 0, 0, 0, }; vkGetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, &semInfo, &semProps); bool sufficientSemaphoreSyncFdSupport = (semProps.exportFromImportedHandleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) && (semProps.compatibleHandleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) && (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT) && (semProps.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT); if (!sufficientSemaphoreSyncFdSupport) { BAIL("Vulkan device does not support sufficient external semaphore sync fd features. " "exportFromImportedHandleTypes 0x%x (needed 0x%x) " "compatibleHandleTypes 0x%x (needed 0x%x) " "externalSemaphoreFeatures 0x%x (needed 0x%x) ", semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, semProps.externalSemaphoreFeatures, VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT); } else { ALOGD("Vulkan device supports sufficient external semaphore sync fd features. " "exportFromImportedHandleTypes 0x%x (needed 0x%x) " "compatibleHandleTypes 0x%x (needed 0x%x) " "externalSemaphoreFeatures 0x%x (needed 0x%x) ", semProps.exportFromImportedHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, semProps.compatibleHandleTypes, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, semProps.externalSemaphoreFeatures, VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT); } uint32_t queueCount; vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, nullptr); if (queueCount == 0) { BAIL("Could not find queues for physical device"); } std::vector queueProps(queueCount); std::vector queuePriorityProps(queueCount); VkQueueGlobalPriorityKHR queuePriority = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR; // Even though we don't yet know if the VK_EXT_global_priority extension is available, // we can safely add the request to the pNext chain, and if the extension is not // available, it will be ignored. for (uint32_t i = 0; i < queueCount; ++i) { queuePriorityProps[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT; queuePriorityProps[i].pNext = nullptr; queueProps[i].pNext = &queuePriorityProps[i]; } vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queueCount, queueProps.data()); int graphicsQueueIndex = -1; for (uint32_t i = 0; i < queueCount; ++i) { // Look at potential answers to the VK_EXT_global_priority query. If answers were // provided, we may adjust the queuePriority. if (queueProps[i].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) { for (uint32_t j = 0; j < queuePriorityProps[i].priorityCount; j++) { if (queuePriorityProps[i].priorities[j] > queuePriority) { queuePriority = queuePriorityProps[i].priorities[j]; } } if (queuePriority == VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR) { interface.isRealtimePriority = true; } graphicsQueueIndex = i; break; } } if (graphicsQueueIndex == -1) { BAIL("Could not find a graphics queue family"); } uint32_t deviceExtensionCount; VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount, nullptr)); std::vector deviceExtensions(deviceExtensionCount); VK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &deviceExtensionCount, deviceExtensions.data())); std::vector enabledDeviceExtensionNames; enabledDeviceExtensionNames.reserve(deviceExtensions.size()); interface.deviceExtensionNames.reserve(deviceExtensions.size()); for (const auto& devExt : deviceExtensions) { enabledDeviceExtensionNames.push_back(devExt.extensionName); interface.deviceExtensionNames.push_back(devExt.extensionName); } interface.grExtensions.init(sGetProc, instance, physicalDevice, enabledInstanceExtensionNames.size(), enabledInstanceExtensionNames.data(), enabledDeviceExtensionNames.size(), enabledDeviceExtensionNames.data()); if (!interface.grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) { BAIL("Vulkan driver doesn't support external semaphore fd"); } interface.physicalDeviceFeatures2 = new VkPhysicalDeviceFeatures2; interface.physicalDeviceFeatures2->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; interface.physicalDeviceFeatures2->pNext = nullptr; interface.samplerYcbcrConversionFeatures = new VkPhysicalDeviceSamplerYcbcrConversionFeatures; interface.samplerYcbcrConversionFeatures->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; interface.samplerYcbcrConversionFeatures->pNext = nullptr; interface.physicalDeviceFeatures2->pNext = interface.samplerYcbcrConversionFeatures; void** tailPnext = &interface.samplerYcbcrConversionFeatures->pNext; if (protectedContent) { interface.protectedMemoryFeatures = new VkPhysicalDeviceProtectedMemoryFeatures; interface.protectedMemoryFeatures->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES; interface.protectedMemoryFeatures->pNext = nullptr; *tailPnext = interface.protectedMemoryFeatures; tailPnext = &interface.protectedMemoryFeatures->pNext; } vkGetPhysicalDeviceFeatures2(physicalDevice, interface.physicalDeviceFeatures2); // Looks like this would slow things down and we can't depend on it on all platforms interface.physicalDeviceFeatures2->features.robustBufferAccess = VK_FALSE; float queuePriorities[1] = {0.0f}; void* queueNextPtr = nullptr; VkDeviceQueueGlobalPriorityCreateInfoEXT queuePriorityCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT, nullptr, // If queue priority is supported, RE should always have realtime priority. queuePriority, }; if (interface.grExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) { queueNextPtr = &queuePriorityCreateInfo; } VkDeviceQueueCreateFlags deviceQueueCreateFlags = (VkDeviceQueueCreateFlags)(protectedContent ? VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT : 0); const VkDeviceQueueCreateInfo queueInfo = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, queueNextPtr, deviceQueueCreateFlags, (uint32_t)graphicsQueueIndex, 1, queuePriorities, }; const VkDeviceCreateInfo deviceInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, interface.physicalDeviceFeatures2, 0, 1, &queueInfo, 0, nullptr, (uint32_t)enabledDeviceExtensionNames.size(), enabledDeviceExtensionNames.data(), nullptr, }; ALOGD("Trying to create Vk device with protectedContent=%d", protectedContent); VkDevice device; VK_CHECK(vkCreateDevice(physicalDevice, &deviceInfo, nullptr, &device)); ALOGD("Trying to create Vk device with protectedContent=%d (success)", protectedContent); VkQueue graphicsQueue; VK_GET_DEV_PROC(device, GetDeviceQueue2); const VkDeviceQueueInfo2 deviceQueueInfo2 = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2, nullptr, deviceQueueCreateFlags, (uint32_t)graphicsQueueIndex, 0}; vkGetDeviceQueue2(device, &deviceQueueInfo2, &graphicsQueue); VK_GET_DEV_PROC(device, DeviceWaitIdle); VK_GET_DEV_PROC(device, DestroyDevice); interface.funcs.vkDeviceWaitIdle = vkDeviceWaitIdle; interface.funcs.vkDestroyDevice = vkDestroyDevice; VK_GET_DEV_PROC(device, CreateSemaphore); VK_GET_DEV_PROC(device, ImportSemaphoreFdKHR); VK_GET_DEV_PROC(device, GetSemaphoreFdKHR); VK_GET_DEV_PROC(device, DestroySemaphore); interface.funcs.vkCreateSemaphore = vkCreateSemaphore; interface.funcs.vkImportSemaphoreFdKHR = vkImportSemaphoreFdKHR; interface.funcs.vkGetSemaphoreFdKHR = vkGetSemaphoreFdKHR; interface.funcs.vkDestroySemaphore = vkDestroySemaphore; // At this point, everything's succeeded and we can continue interface.initialized = true; interface.instance = instance; interface.physicalDevice = physicalDevice; interface.device = device; interface.queue = graphicsQueue; interface.queueIndex = graphicsQueueIndex; interface.apiVersion = physDevProps.properties.apiVersion; // grExtensions already constructed // feature pointers already constructed interface.grGetProc = sGetProc; interface.isProtected = protectedContent; // funcs already initialized ALOGD("%s: Success init Vulkan interface", __func__); return interface; } void teardownVulkanInterface(VulkanInterface* interface) { interface->initialized = false; if (interface->device != VK_NULL_HANDLE) { interface->funcs.vkDeviceWaitIdle(interface->device); interface->funcs.vkDestroyDevice(interface->device, nullptr); interface->device = VK_NULL_HANDLE; } if (interface->instance != VK_NULL_HANDLE) { interface->funcs.vkDestroyInstance(interface->instance, nullptr); interface->instance = VK_NULL_HANDLE; } if (interface->protectedMemoryFeatures) { delete interface->protectedMemoryFeatures; } if (interface->samplerYcbcrConversionFeatures) { delete interface->samplerYcbcrConversionFeatures; } if (interface->physicalDeviceFeatures2) { delete interface->physicalDeviceFeatures2; } interface->samplerYcbcrConversionFeatures = nullptr; interface->physicalDeviceFeatures2 = nullptr; interface->protectedMemoryFeatures = nullptr; } static VulkanInterface sVulkanInterface; static VulkanInterface sProtectedContentVulkanInterface; static void sSetupVulkanInterface() { if (!sVulkanInterface.initialized) { sVulkanInterface = initVulkanInterface(false /* no protected content */); // We will have to abort if non-protected VkDevice creation fails (then nothing works). LOG_ALWAYS_FATAL_IF(!sVulkanInterface.initialized, "Could not initialize Vulkan RenderEngine!"); } if (!sProtectedContentVulkanInterface.initialized) { sProtectedContentVulkanInterface = initVulkanInterface(true /* protected content */); if (!sProtectedContentVulkanInterface.initialized) { ALOGE("Could not initialize protected content Vulkan RenderEngine."); } } } namespace skia { using base::StringAppendF; bool SkiaVkRenderEngine::canSupportSkiaVkRenderEngine() { VulkanInterface temp = initVulkanInterface(false /* no protected content */); ALOGD("SkiaVkRenderEngine::canSupportSkiaVkRenderEngine(): initialized == %s.", temp.initialized ? "true" : "false"); return temp.initialized; } std::unique_ptr SkiaVkRenderEngine::create( const RenderEngineCreationArgs& args) { std::unique_ptr engine(new SkiaVkRenderEngine(args)); engine->ensureGrContextsCreated(); if (sVulkanInterface.initialized) { ALOGD("SkiaVkRenderEngine::%s: successfully initialized SkiaVkRenderEngine", __func__); return engine; } else { ALOGD("SkiaVkRenderEngine::%s: could not create SkiaVkRenderEngine. " "Likely insufficient Vulkan support", __func__); return {}; } } SkiaVkRenderEngine::SkiaVkRenderEngine(const RenderEngineCreationArgs& args) : SkiaRenderEngine(args.renderEngineType, static_cast(args.pixelFormat), args.useColorManagement, args.supportsBackgroundBlur) {} SkiaVkRenderEngine::~SkiaVkRenderEngine() { finishRenderingAndAbandonContext(); } SkiaRenderEngine::Contexts SkiaVkRenderEngine::createDirectContexts( const GrContextOptions& options) { sSetupVulkanInterface(); SkiaRenderEngine::Contexts contexts; contexts.first = GrDirectContext::MakeVulkan(sVulkanInterface.getBackendContext(), options); if (supportsProtectedContentImpl()) { contexts.second = GrDirectContext::MakeVulkan(sProtectedContentVulkanInterface.getBackendContext(), options); } return contexts; } bool SkiaVkRenderEngine::supportsProtectedContentImpl() const { return sProtectedContentVulkanInterface.initialized; } bool SkiaVkRenderEngine::useProtectedContextImpl(GrProtected) { return true; } static void delete_semaphore(void* semaphore) { DestroySemaphoreInfo* info = reinterpret_cast(semaphore); --info->mRefs; if (!info->mRefs) { sVulkanInterface.destroySemaphore(info->mSemaphore); delete info; } } static void delete_semaphore_protected(void* semaphore) { DestroySemaphoreInfo* info = reinterpret_cast(semaphore); --info->mRefs; if (!info->mRefs) { sProtectedContentVulkanInterface.destroySemaphore(info->mSemaphore); delete info; } } static VulkanInterface& getVulkanInterface(bool protectedContext) { if (protectedContext) { return sProtectedContentVulkanInterface; } return sVulkanInterface; } void SkiaVkRenderEngine::waitFence(GrDirectContext* grContext, base::borrowed_fd fenceFd) { if (fenceFd.get() < 0) return; int dupedFd = dup(fenceFd.get()); if (dupedFd < 0) { ALOGE("failed to create duplicate fence fd: %d", dupedFd); sync_wait(fenceFd.get(), -1); return; } base::unique_fd fenceDup(dupedFd); VkSemaphore waitSemaphore = getVulkanInterface(isProtected()).importSemaphoreFromSyncFd(fenceDup.release()); GrBackendSemaphore beSemaphore; beSemaphore.initVulkan(waitSemaphore); grContext->wait(1, &beSemaphore, true /* delete after wait */); } base::unique_fd SkiaVkRenderEngine::flushAndSubmit(GrDirectContext* grContext) { VulkanInterface& vi = getVulkanInterface(isProtected()); VkSemaphore semaphore = vi.createExportableSemaphore(); GrBackendSemaphore backendSemaphore; backendSemaphore.initVulkan(semaphore); GrFlushInfo flushInfo; DestroySemaphoreInfo* destroySemaphoreInfo = nullptr; if (semaphore != VK_NULL_HANDLE) { destroySemaphoreInfo = new DestroySemaphoreInfo(semaphore); flushInfo.fNumSemaphores = 1; flushInfo.fSignalSemaphores = &backendSemaphore; flushInfo.fFinishedProc = isProtected() ? delete_semaphore_protected : delete_semaphore; flushInfo.fFinishedContext = destroySemaphoreInfo; } GrSemaphoresSubmitted submitted = grContext->flush(flushInfo); grContext->submit(false /* no cpu sync */); int drawFenceFd = -1; if (semaphore != VK_NULL_HANDLE) { if (GrSemaphoresSubmitted::kYes == submitted) { drawFenceFd = vi.exportSemaphoreSyncFd(semaphore); } // Now that drawFenceFd has been created, we can delete our reference to this semaphore flushInfo.fFinishedProc(destroySemaphoreInfo); } base::unique_fd res(drawFenceFd); return res; } int SkiaVkRenderEngine::getContextPriority() { // EGL_CONTEXT_PRIORITY_REALTIME_NV constexpr int kRealtimePriority = 0x3357; if (getVulkanInterface(isProtected()).isRealtimePriority) { return kRealtimePriority; } else { return 0; } } void SkiaVkRenderEngine::appendBackendSpecificInfoToDump(std::string& result) { StringAppendF(&result, "\n ------------RE Vulkan----------\n"); StringAppendF(&result, "\n Vulkan device initialized: %d\n", sVulkanInterface.initialized); StringAppendF(&result, "\n Vulkan protected device initialized: %d\n", sProtectedContentVulkanInterface.initialized); if (!sVulkanInterface.initialized) { return; } StringAppendF(&result, "\n Instance extensions:\n"); for (const auto& name : sVulkanInterface.instanceExtensionNames) { StringAppendF(&result, "\n %s\n", name.c_str()); } StringAppendF(&result, "\n Device extensions:\n"); for (const auto& name : sVulkanInterface.deviceExtensionNames) { StringAppendF(&result, "\n %s\n", name.c_str()); } } } // namespace skia } // namespace renderengine } // namespace android