// Copyright 2020 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "gpu/vulkan/vulkan_image.h" #include "base/logging.h" #include "build/build_config.h" #include "gpu/config/gpu_info_collector.h" #include "gpu/config/gpu_test_config.h" #include "gpu/ipc/service/gpu_memory_buffer_factory.h" #include "gpu/vulkan/tests/basic_vulkan_test.h" #include "gpu/vulkan/vulkan_device_queue.h" #include "gpu/vulkan/vulkan_function_pointers.h" #include "ui/gfx/geometry/rect.h" #if BUILDFLAG(IS_ANDROID) #include "base/android/android_hardware_buffer_compat.h" #endif namespace gpu { namespace { // TODO(penghuang): add more formats used by chrome. const VkFormat kFormats[] = { VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM, }; } // namespace using VulkanImageTest = BasicVulkanTest; TEST_F(VulkanImageTest, Create) { constexpr gfx::Size size(100, 100); constexpr VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; auto* device_queue = GetDeviceQueue(); for (auto format : kFormats) { auto image = VulkanImage::Create(device_queue, size, format, usage); EXPECT_TRUE(image); EXPECT_EQ(image->size(), size); EXPECT_EQ(image->format(), format); EXPECT_GT(image->device_size(), 0u); EXPECT_EQ(image->image_tiling(), VK_IMAGE_TILING_OPTIMAL); EXPECT_NE(image->image(), static_cast(VK_NULL_HANDLE)); EXPECT_NE(image->device_memory(), static_cast(VK_NULL_HANDLE)); EXPECT_EQ(image->handle_types(), 0u); image->Destroy(); } } TEST_F(VulkanImageTest, CreateWithExternalMemory) { { // TODO(crbug.com/1069516) : Fails on current driver version on this bot. if (GPUTestBotConfig::CurrentConfigMatches("Win10")) return; } constexpr gfx::Size size(100, 100); constexpr VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; auto* device_queue = GetDeviceQueue(); for (auto format : kFormats) { auto image = VulkanImage::CreateWithExternalMemory(device_queue, size, format, usage); EXPECT_TRUE(image); EXPECT_EQ(image->size(), size); EXPECT_EQ(image->format(), format); EXPECT_GT(image->device_size(), 0u); EXPECT_EQ(image->image_tiling(), VK_IMAGE_TILING_OPTIMAL); EXPECT_NE(image->image(), static_cast(VK_NULL_HANDLE)); EXPECT_NE(image->device_memory(), static_cast(VK_NULL_HANDLE)); #if BUILDFLAG(IS_POSIX) EXPECT_TRUE(image->handle_types() & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) << std::hex << "handle_types = 0x" << image->handle_types(); const VkExternalMemoryHandleTypeFlagBits kHandleTypes[] = { VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, }; // Get fd for all supported types. for (auto handle_type : kHandleTypes) { if ((image->handle_types() & handle_type) == 0) continue; base::ScopedFD scoped_fd = image->GetMemoryFd(handle_type); EXPECT_TRUE(scoped_fd.is_valid()) << std::hex << " handle_types = 0x" << image->handle_types() << " handle_type = 0x" << handle_type; } #elif BUILDFLAG(IS_WIN) EXPECT_TRUE(image->handle_types() & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) << std::hex << "handle_types = 0x" << image->handle_types(); const VkExternalMemoryHandleTypeFlagBits kHandleTypes[] = { VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT, }; // Get fd for all supported types. for (auto handle_type : kHandleTypes) { if ((image->handle_types() & handle_type) == 0) continue; base::win::ScopedHandle scoped_handle = image->GetMemoryHandle( static_cast(handle_type)); EXPECT_TRUE(scoped_handle.IsValid()) << std::hex << " handle_types = 0x" << image->handle_types() << " handle_type = 0x" << handle_type; } #elif BUILDFLAG(IS_FUCHSIA) EXPECT_TRUE(image->handle_types() & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA); zx::vmo handle = image->GetMemoryZirconHandle(); EXPECT_TRUE(handle); #endif image->Destroy(); } } #if BUILDFLAG(IS_ANDROID) TEST_F(VulkanImageTest, CreateFromGpuMemoryBufferHandle) { if (!base::AndroidHardwareBufferCompat::IsSupportAvailable()) { LOG(ERROR) << "AndroidHardwareBuffer is not supported"; return; } auto* device_queue = GetDeviceQueue(); if (!gfx::HasExtension( device_queue->enabled_extensions(), VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) { LOG(ERROR) << "Vulkan extension " "VK_ANDROID_external_memory_android_hardware_buffer is not " "supported"; return; } auto factory = GpuMemoryBufferFactory::CreateNativeType( /*viz::VulkanContextProvider=*/nullptr); EXPECT_TRUE(factory); constexpr gfx::Size size(100, 100); constexpr VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; const struct { gfx::BufferFormat buffer; VkFormat vk; } formats[] = { {gfx::BufferFormat::RGBA_8888, VK_FORMAT_R8G8B8A8_UNORM}, {gfx::BufferFormat::BGR_565, VK_FORMAT_R5G6B5_UNORM_PACK16}, {gfx::BufferFormat::RGBA_F16, VK_FORMAT_R16G16B16A16_SFLOAT}, {gfx::BufferFormat::RGBX_8888, VK_FORMAT_R8G8B8A8_UNORM}, {gfx::BufferFormat::RGBA_1010102, VK_FORMAT_A2B10G10R10_UNORM_PACK32}, }; for (const auto format : formats) { gfx::GpuMemoryBufferId id(1); gfx::BufferUsage buffer_usage = gfx::BufferUsage::SCANOUT; int client_id = 1; auto gmb_handle = factory->CreateGpuMemoryBuffer( id, size, /*framebuffer_size=*/size, format.buffer, buffer_usage, client_id, kNullSurfaceHandle); EXPECT_TRUE(!gmb_handle.is_null()); EXPECT_EQ(gmb_handle.type, gfx::GpuMemoryBufferType::ANDROID_HARDWARE_BUFFER); auto image = VulkanImage::CreateFromGpuMemoryBufferHandle( device_queue, std::move(gmb_handle), size, format.vk, usage, /*flags=*/0, /*image_tiling=*/VK_IMAGE_TILING_OPTIMAL, /*queue_family_index=*/VK_QUEUE_FAMILY_EXTERNAL); EXPECT_TRUE(image); EXPECT_EQ(image->size(), size); EXPECT_EQ(image->format(), format.vk); EXPECT_GT(image->device_size(), 0u); EXPECT_EQ(image->image_tiling(), VK_IMAGE_TILING_OPTIMAL); EXPECT_NE(image->image(), static_cast(VK_NULL_HANDLE)); EXPECT_NE(image->device_memory(), static_cast(VK_NULL_HANDLE)); image->Destroy(); factory->DestroyGpuMemoryBuffer(id, client_id); } } #endif } // namespace gpu