blob: 4344362ed9f981ecee23bf55aebe25d91ce65ed4 [file] [log] [blame]
// 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