| // Copyright (c) 2016 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_surface.h" |
| |
| #include <vulkan/vulkan.h> |
| |
| #include "base/macros.h" |
| #include "gpu/vulkan/vulkan_command_buffer.h" |
| #include "gpu/vulkan/vulkan_device_queue.h" |
| #include "gpu/vulkan/vulkan_implementation.h" |
| #include "gpu/vulkan/vulkan_platform.h" |
| #include "gpu/vulkan/vulkan_swap_chain.h" |
| |
| #if defined(USE_X11) |
| #include "ui/gfx/x/x11_types.h" |
| #endif // defined(USE_X11) |
| |
| namespace gpu { |
| |
| namespace { |
| const VkFormat kPreferredVkFormats32[] = { |
| VK_FORMAT_B8G8R8A8_UNORM, // FORMAT_BGRA8888, |
| VK_FORMAT_R8G8B8A8_UNORM, // FORMAT_RGBA8888, |
| }; |
| |
| const VkFormat kPreferredVkFormats16[] = { |
| VK_FORMAT_R5G6B5_UNORM_PACK16, // FORMAT_RGB565, |
| }; |
| |
| } // namespace |
| |
| class VulkanWSISurface : public VulkanSurface { |
| public: |
| explicit VulkanWSISurface(gfx::AcceleratedWidget window) : window_(window) {} |
| |
| ~VulkanWSISurface() override { |
| DCHECK_EQ(static_cast<VkSurfaceKHR>(VK_NULL_HANDLE), surface_); |
| } |
| |
| bool Initialize(VulkanDeviceQueue* device_queue, |
| VulkanSurface::Format format) override { |
| DCHECK(format >= 0 && format < NUM_SURFACE_FORMATS); |
| DCHECK_EQ(static_cast<VkSurfaceKHR>(VK_NULL_HANDLE), surface_); |
| VkResult result = VK_SUCCESS; |
| |
| #if defined(VK_USE_PLATFORM_XLIB_KHR) |
| VkXlibSurfaceCreateInfoKHR surface_create_info = {}; |
| surface_create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; |
| surface_create_info.dpy = gfx::GetXDisplay(); |
| surface_create_info.window = window_; |
| result = vkCreateXlibSurfaceKHR(GetVulkanInstance(), &surface_create_info, |
| nullptr, &surface_); |
| if (VK_SUCCESS != result) { |
| DLOG(ERROR) << "vkCreateXlibSurfaceKHR() failed: " << result; |
| return false; |
| } |
| #elif defined(VK_USE_PLATFORM_ANDROID_KHR) |
| VkAndroidSurfaceCreateInfoKHR surface_create_info = {}; |
| surface_create_info.sType = |
| VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; |
| surface_create_info.window = window_; |
| result = vkCreateAndroidSurfaceKHR( |
| GetVulkanInstance(), &surface_create_info, nullptr, &surface_); |
| if (VK_SUCCESS != result) { |
| DLOG(ERROR) << "vkCreateAndroidSurfaceKHR() failed: " << result; |
| return false; |
| } |
| #else |
| #error Unsupported Vulkan Platform. |
| #endif |
| |
| DCHECK_NE(static_cast<VkSurfaceKHR>(VK_NULL_HANDLE), surface_); |
| DCHECK(device_queue); |
| device_queue_ = device_queue; |
| |
| // Get list of supported formats. |
| uint32_t format_count = 0; |
| result = vkGetPhysicalDeviceSurfaceFormatsKHR( |
| device_queue_->GetVulkanPhysicalDevice(), surface_, &format_count, |
| nullptr); |
| if (VK_SUCCESS != result) { |
| DLOG(ERROR) << "vkGetPhysicalDeviceSurfaceFormatsKHR() failed: " |
| << result; |
| return false; |
| } |
| |
| std::vector<VkSurfaceFormatKHR> formats(format_count); |
| result = vkGetPhysicalDeviceSurfaceFormatsKHR( |
| device_queue_->GetVulkanPhysicalDevice(), surface_, &format_count, |
| formats.data()); |
| if (VK_SUCCESS != result) { |
| DLOG(ERROR) << "vkGetPhysicalDeviceSurfaceFormatsKHR() failed: " |
| << result; |
| return false; |
| } |
| |
| const VkFormat* preferred_formats = (format == FORMAT_RGBA_32) |
| ? kPreferredVkFormats32 |
| : kPreferredVkFormats16; |
| unsigned int size = (format == FORMAT_RGBA_32) |
| ? arraysize(kPreferredVkFormats32) |
| : arraysize(kPreferredVkFormats16); |
| |
| if (formats.size() == 1 && VK_FORMAT_UNDEFINED == formats[0].format) { |
| surface_format_.format = preferred_formats[0]; |
| surface_format_.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; |
| } else { |
| bool format_set = false; |
| for (VkSurfaceFormatKHR supported_format : formats) { |
| unsigned int counter = 0; |
| while (counter < size && format_set == false) { |
| if (supported_format.format == preferred_formats[counter]) { |
| surface_format_ = supported_format; |
| surface_format_.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; |
| format_set = true; |
| } |
| counter++; |
| } |
| if (format_set) |
| break; |
| } |
| if (!format_set) { |
| DLOG(ERROR) << "Format not supported."; |
| return false; |
| } |
| } |
| |
| // Get Surface Information. |
| VkSurfaceCapabilitiesKHR surface_caps; |
| result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR( |
| device_queue_->GetVulkanPhysicalDevice(), surface_, &surface_caps); |
| if (VK_SUCCESS != result) { |
| DLOG(ERROR) << "vkGetPhysicalDeviceSurfaceCapabilitiesKHR() failed: " |
| << result; |
| return false; |
| } |
| |
| // These are actual surfaces so the current extent should be defined. |
| DCHECK_NE(UINT_MAX, surface_caps.currentExtent.width); |
| DCHECK_NE(UINT_MAX, surface_caps.currentExtent.height); |
| size_ = gfx::Size(surface_caps.currentExtent.width, |
| surface_caps.currentExtent.height); |
| |
| // Create Swapchain. |
| if (!swap_chain_.Initialize(device_queue_, surface_, surface_caps, |
| surface_format_)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void Destroy() override { |
| swap_chain_.Destroy(); |
| vkDestroySurfaceKHR(GetVulkanInstance(), surface_, nullptr); |
| surface_ = VK_NULL_HANDLE; |
| } |
| |
| gfx::SwapResult SwapBuffers() override { return swap_chain_.SwapBuffers(); } |
| VulkanSwapChain* GetSwapChain() override { return &swap_chain_; } |
| void Finish() override { vkQueueWaitIdle(device_queue_->GetVulkanQueue()); } |
| |
| protected: |
| gfx::AcceleratedWidget window_; |
| gfx::Size size_; |
| VkSurfaceKHR surface_ = VK_NULL_HANDLE; |
| VkSurfaceFormatKHR surface_format_ = {}; |
| VulkanDeviceQueue* device_queue_ = nullptr; |
| VulkanSwapChain swap_chain_; |
| }; |
| |
| VulkanSurface::~VulkanSurface() {} |
| |
| // static |
| std::unique_ptr<VulkanSurface> VulkanSurface::CreateViewSurface( |
| gfx::AcceleratedWidget window) { |
| return std::unique_ptr<VulkanSurface>(new VulkanWSISurface(window)); |
| } |
| |
| VulkanSurface::VulkanSurface() {} |
| |
| } // namespace gpu |