// 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 #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 kNativeVkFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, // FORMAT_BGRA8888, VK_FORMAT_R5G6B5_UNORM_PACK16, // FORMAT_RGB565, }; static_assert(arraysize(kNativeVkFormat) == VulkanSurface::NUM_SURFACE_FORMATS, "Array size for kNativeVkFormat must match surface formats."); } // namespace class VulkanWSISurface : public VulkanSurface { public: explicit VulkanWSISurface(gfx::AcceleratedWidget window) : window_(window) {} ~VulkanWSISurface() override { DCHECK_EQ(static_cast(VK_NULL_HANDLE), surface_); } bool Initialize(VulkanDeviceQueue* device_queue, VulkanSurface::Format format) override { DCHECK(format >= 0 && format < NUM_SURFACE_FORMATS); DCHECK_EQ(static_cast(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; } #else #error Unsupported Vulkan Platform. #endif DCHECK_NE(static_cast(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 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_format = kNativeVkFormat[format]; if (formats.size() == 1 && VK_FORMAT_UNDEFINED == formats[0].format) { surface_format_.format = preferred_format; surface_format_.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; } else { bool format_set = false; for (VkSurfaceFormatKHR supported_format : formats) { if (supported_format.format == preferred_format) { surface_format_ = supported_format; surface_format_.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; format_set = true; 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_; }; // static bool VulkanSurface::InitializeOneOff() { if (!InitializeVulkan()) return false; return true; } VulkanSurface::~VulkanSurface() {} // static scoped_ptr VulkanSurface::CreateViewSurface( gfx::AcceleratedWidget window) { return scoped_ptr(new VulkanWSISurface(window)); } VulkanSurface::VulkanSurface() {} } // namespace gpu