// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "gpu/vulkan/vulkan_util.h" #include "base/callback_helpers.h" #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/strings/pattern.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "gpu/config/gpu_info.h" // nogncheck #include "gpu/config/vulkan_info.h" #include "gpu/vulkan/vulkan_function_pointers.h" #include "ui/gl/gl_switches.h" #if BUILDFLAG(IS_ANDROID) #include "base/android/build_info.h" #endif #define GL_NONE 0x00 #define GL_LAYOUT_GENERAL_EXT 0x958D #define GL_LAYOUT_COLOR_ATTACHMENT_EXT 0x958E #define GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT 0x958F #define GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT 0x9590 #define GL_LAYOUT_SHADER_READ_ONLY_EXT 0x9591 #define GL_LAYOUT_TRANSFER_SRC_EXT 0x9592 #define GL_LAYOUT_TRANSFER_DST_EXT 0x9593 #define GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT 0x9530 #define GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT 0x9531 namespace gpu { namespace { #if BUILDFLAG(IS_ANDROID) int GetEMUIVersion() { const auto* build_info = base::android::BuildInfo::GetInstance(); base::StringPiece manufacturer(build_info->manufacturer()); // TODO(crbug.com/1096222): check Honor devices as well. if (manufacturer != "HUAWEI") return -1; // Huawei puts EMUI version in the build version incremental. // Example: 11.0.0.130C00 int version = 0; if (sscanf(build_info->version_incremental(), "%d.", &version) != 1) return -1; return version; } #endif } bool SubmitSignalVkSemaphores(VkQueue vk_queue, const base::span& vk_semaphores, VkFence vk_fence) { // Structure specifying a queue submit operation. VkSubmitInfo submit_info = {VK_STRUCTURE_TYPE_SUBMIT_INFO}; submit_info.signalSemaphoreCount = vk_semaphores.size(); submit_info.pSignalSemaphores = vk_semaphores.data(); const unsigned int submit_count = 1; return vkQueueSubmit(vk_queue, submit_count, &submit_info, vk_fence) == VK_SUCCESS; } bool SubmitSignalVkSemaphore(VkQueue vk_queue, VkSemaphore vk_semaphore, VkFence vk_fence) { return SubmitSignalVkSemaphores( vk_queue, base::span(&vk_semaphore, 1), vk_fence); } bool SubmitWaitVkSemaphores(VkQueue vk_queue, const base::span& vk_semaphores, VkFence vk_fence) { DCHECK(!vk_semaphores.empty()); std::vector semaphore_stages(vk_semaphores.size()); std::fill(semaphore_stages.begin(), semaphore_stages.end(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); // Structure specifying a queue submit operation. VkSubmitInfo submit_info = {VK_STRUCTURE_TYPE_SUBMIT_INFO}; submit_info.waitSemaphoreCount = vk_semaphores.size(); submit_info.pWaitSemaphores = vk_semaphores.data(); submit_info.pWaitDstStageMask = semaphore_stages.data(); const unsigned int submit_count = 1; return vkQueueSubmit(vk_queue, submit_count, &submit_info, vk_fence) == VK_SUCCESS; } bool SubmitWaitVkSemaphore(VkQueue vk_queue, VkSemaphore vk_semaphore, VkFence vk_fence) { return SubmitWaitVkSemaphores( vk_queue, base::span(&vk_semaphore, 1), vk_fence); } VkSemaphore CreateExternalVkSemaphore( VkDevice vk_device, VkExternalSemaphoreHandleTypeFlags handle_types) { VkExportSemaphoreCreateInfo export_info = {VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO}; export_info.handleTypes = handle_types; VkSemaphoreCreateInfo sem_info = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; sem_info.pNext = &export_info; VkSemaphore semaphore = VK_NULL_HANDLE; VkResult result = vkCreateSemaphore(vk_device, &sem_info, nullptr, &semaphore); if (result != VK_SUCCESS) { DLOG(ERROR) << "Failed to create VkSemaphore: " << result; return VK_NULL_HANDLE; } return semaphore; } std::string VkVersionToString(uint32_t version) { return base::StringPrintf("%u.%u.%u", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), VK_VERSION_PATCH(version)); } VkResult CreateGraphicsPipelinesHook( VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines) { base::ScopedClosureRunner uma_runner(base::BindOnce( [](base::Time time) { UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( "GPU.Vulkan.PipelineCache.vkCreateGraphicsPipelines", base::Time::Now() - time, base::Microseconds(100), base::Microseconds(50000), 50); }, base::Time::Now())); return vkCreateGraphicsPipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); } VkResult VulkanQueueSubmitHook(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence) { TRACE_EVENT0("gpu", "VulkanQueueSubmitHook"); return vkQueueSubmit(queue, submitCount, pSubmits, fence); } VkResult VulkanQueueWaitIdleHook(VkQueue queue) { TRACE_EVENT0("gpu", "VulkanQueueWaitIdleHook"); return vkQueueWaitIdle(queue); } VkResult VulkanQueuePresentKHRHook(VkQueue queue, const VkPresentInfoKHR* pPresentInfo) { TRACE_EVENT0("gpu", "VulkanQueuePresentKHRHook"); return vkQueuePresentKHR(queue, pPresentInfo); } bool CheckVulkanCompabilities(const VulkanInfo& vulkan_info, const GPUInfo& gpu_info, std::string enable_by_device_name) { // Android uses AHB and SyncFD for interop. They are imported into GL with other // API. #if !BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_WIN) constexpr char kMemoryObjectExtension[] = "GL_EXT_memory_object_win32"; constexpr char kSemaphoreExtension[] = "GL_EXT_semaphore_win32"; #elif BUILDFLAG(IS_FUCHSIA) constexpr char kMemoryObjectExtension[] = "GL_ANGLE_memory_object_fuchsia"; constexpr char kSemaphoreExtension[] = "GL_ANGLE_semaphore_fuchsia"; #else constexpr char kMemoryObjectExtension[] = "GL_EXT_memory_object_fd"; constexpr char kSemaphoreExtension[] = "GL_EXT_semaphore_fd"; #endif // If Chrome and ANGLE share the same VkQueue, they can share vulkan // resource without those extensions. if (!base::FeatureList::IsEnabled(features::kVulkanFromANGLE)) { // If both Vulkan and GL are using native GPU (non swiftshader), check // necessary extensions for GL and Vulkan interop. const auto extensions = gfx::MakeExtensionSet(gpu_info.gl_extensions); if (!gfx::HasExtension(extensions, kMemoryObjectExtension) || !gfx::HasExtension(extensions, kSemaphoreExtension)) { DLOG(ERROR) << kMemoryObjectExtension << " or " << kSemaphoreExtension << " is not supported."; return false; } } #endif // !BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_ANDROID) if (vulkan_info.physical_devices.empty()) return false; const auto& device_info = vulkan_info.physical_devices.front(); auto enable_patterns = base::SplitString( enable_by_device_name, "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); for (const auto& enable_pattern : enable_patterns) { if (base::MatchPattern(device_info.properties.deviceName, enable_pattern)) return true; } if (device_info.properties.vendorID == kVendorARM) { int emui_version = GetEMUIVersion(); // TODO(crbug.com/1096222) Display problem with Huawei EMUI < 11 and Honor // devices with Mali GPU. The Mali driver version is < 19.0.0. if (device_info.properties.driverVersion < VK_MAKE_VERSION(19, 0, 0) && emui_version < 11) { return false; } // Remove "Mali-" prefix. base::StringPiece device_name(device_info.properties.deviceName); if (!base::StartsWith(device_name, "Mali-")) { LOG(ERROR) << "Unexpected device_name " << device_name; return false; } device_name.remove_prefix(5); // Remove anything trailing a space (e.g. "G76 MC4" => "G76"). device_name = device_name.substr(0, device_name.find(" ")); // Older Mali GPUs are not performant with Vulkan -- this blocks all Utgard // gen, Midgard gen, and some Bifrost 1st & 2nd gen. std::vector slow_gpus = {"2??", "3??", "4??", "T???", "G31", "G51", "G52"}; for (base::StringPiece slow_gpu : slow_gpus) { if (base::MatchPattern(device_name, slow_gpu)) return false; } } // https:://crbug.com/1165783: Performance is not yet as good as GL. if (device_info.properties.vendorID == kVendorQualcomm) { if (device_info.properties.deviceName == base::StringPiece("Adreno (TM) 630")) return true; return false; } // https://crbug.com/1122650: Poor performance and untriaged crashes with // Imagination GPUs. if (device_info.properties.vendorID == kVendorImagination) return false; #endif // BUILDFLAG(IS_ANDROID) return true; } VkImageLayout GLImageLayoutToVkImageLayout(uint32_t layout) { switch (layout) { case GL_NONE: return VK_IMAGE_LAYOUT_UNDEFINED; case GL_LAYOUT_GENERAL_EXT: return VK_IMAGE_LAYOUT_GENERAL; case GL_LAYOUT_COLOR_ATTACHMENT_EXT: return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; case GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT: return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; case GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT: return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; case GL_LAYOUT_SHADER_READ_ONLY_EXT: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; case GL_LAYOUT_TRANSFER_SRC_EXT: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; case GL_LAYOUT_TRANSFER_DST_EXT: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; case GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT: return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR; case GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT: return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR; default: break; } NOTREACHED() << "Invalid image layout " << layout; return VK_IMAGE_LAYOUT_UNDEFINED; } uint32_t VkImageLayoutToGLImageLayout(VkImageLayout layout) { switch (layout) { case VK_IMAGE_LAYOUT_UNDEFINED: return GL_NONE; case VK_IMAGE_LAYOUT_GENERAL: return GL_LAYOUT_GENERAL_EXT; case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: return GL_LAYOUT_COLOR_ATTACHMENT_EXT; case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: return GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT; case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: return GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT; case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: return GL_LAYOUT_SHADER_READ_ONLY_EXT; case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: return GL_LAYOUT_TRANSFER_SRC_EXT; case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: return GL_LAYOUT_TRANSFER_DST_EXT; case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR: return GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT; case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR: return GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT; default: NOTREACHED() << "Invalid image layout " << layout; return GL_NONE; } } } // namespace gpu