Chromium Code Reviews| Index: gpu/vulkan/vulkan_surface.cc |
| diff --git a/gpu/vulkan/vulkan_surface.cc b/gpu/vulkan/vulkan_surface.cc |
| index b340a69d77af6e30c10ad08486483ed8603178c7..dc42bd4019641b4717d421872e285dbf1a444146 100644 |
| --- a/gpu/vulkan/vulkan_surface.cc |
| +++ b/gpu/vulkan/vulkan_surface.cc |
| @@ -4,11 +4,220 @@ |
| #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_implementation.h" |
| +#include "gpu/vulkan/vulkan_swap_chain.h" |
| + |
| +#if defined(VK_USE_PLATFORM_XLIB_KHR) |
| +#include "ui/gfx/x/x11_types.h" |
| +#endif // defined(VK_USE_PLATFORM_XLIB_KHR) |
| namespace gfx { |
| -VulkanSurface::VulkanSurface() {} |
| +namespace { |
| +const VkDeviceSize kFormatSize[] = { |
| + 4, // SURFACE_ARGB8888, |
| + 2, // SURFACE_RGB565, |
| + 4, // SURFACE_OSMESA_BGRA, |
| + 4, // SURFACE_OSMESA_RGBA, |
| +}; |
| +static_assert(arraysize(kFormatSize) == VulkanSurface::NUM_SURFACE_FORMATS, |
| + "Array size for kFormatSize must match surface formats."); |
| + |
| +const VkFormat kNativeVkFormat[] = { |
| + VK_FORMAT_B8G8R8A8_UNORM, // SURFACE_ARGB8888, |
| + VK_FORMAT_R5G6B5_UNORM_PACK16, // SURFACE_RGB565, |
| + VK_FORMAT_B8G8R8A8_UNORM, // SURFACE_OSMESA_BGRA, |
| + VK_FORMAT_B8G8R8A8_UNORM, // SURFACE_OSMESA_RGBA, |
| +}; |
| +static_assert(arraysize(kNativeVkFormat) == VulkanSurface::NUM_SURFACE_FORMATS, |
| + "Array size for kNativeVkFormat must match surface formats."); |
| + |
| +const VkComponentMapping kFormatMapping[] = { |
| + // SURFACE_ARGB8888, |
| + {VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, |
| + VK_COMPONENT_SWIZZLE_B}, |
| + |
| + // SURFACE_RGB565, |
| + {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, |
| + VK_COMPONENT_SWIZZLE_ONE}, |
| + |
| + // SURFACE_OSMESA_BGRA, |
| + {VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, |
| + VK_COMPONENT_SWIZZLE_A}, |
| + |
| + // SURFACE_OSMESA_RGBA, |
| + {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, |
| + VK_COMPONENT_SWIZZLE_A}, |
| +}; |
| +static_assert(arraysize(kFormatMapping) == VulkanSurface::NUM_SURFACE_FORMATS, |
| + "Array size for kFormatMapping must match surface formats."); |
| + |
| +} // namespace |
| + |
| +class VulkanWSISurface : public VulkanSurface { |
| + public: |
| + VulkanWSISurface(gfx::AcceleratedWidget window) : window_(window) {} |
|
piman
2016/03/09 01:25:34
nit: explicit
David Yen
2016/03/10 01:39:49
Done.
|
| + |
| + ~VulkanWSISurface() override { |
| + DCHECK_EQ(static_cast<VkSurfaceKHR>(VK_NULL_HANDLE), surface_); |
| + } |
| + |
| + bool Initialize(VulkanSurface::Format format) override { |
| + DCHECK(format >= 0 && format < NUM_SURFACE_FORMATS); |
| +#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_; |
| + vkCreateXlibSurfaceKHR(GetVulkanInstance(), &surface_create_info, nullptr, |
| + &surface_); |
| +#else |
| +#error Unsupported Vulkan Platform. |
| +#endif |
| + |
| + // Get list of supported formats. |
| + uint32_t format_count = 0; |
| + VkResult result = vkGetPhysicalDeviceSurfaceFormatsKHR( |
| + GetVulkanPhysicalDevice(), surface_, &format_count, nullptr); |
| + if (VK_SUCCESS != result) { |
| + LOG(ERROR) << "vkGetPhysicalDeviceSurfaceFormatsKHR() failed: " << result; |
|
piman
2016/03/09 01:25:34
nit: DLOG
David Yen
2016/03/10 01:39:48
Done.
|
| + return false; |
| + } |
| + |
| + std::vector<VkSurfaceFormatKHR> formats(format_count); |
| + result = vkGetPhysicalDeviceSurfaceFormatsKHR( |
| + GetVulkanPhysicalDevice(), surface_, &format_count, formats.data()); |
| + if (VK_SUCCESS != result) { |
| + LOG(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; |
| + format_set = true; |
| + break; |
| + } |
| + } |
| + if (!format_set) { |
| + surface_format_.format = VK_FORMAT_B8G8R8A8_UNORM; |
|
piman
2016/03/09 01:25:34
There's no guarantee that this is supported. If we
David Yen
2016/03/10 01:39:49
Done.
|
| + surface_format_.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; |
| + } |
| + } |
| + |
| + // Get Surface Information. |
| + VkSurfaceCapabilitiesKHR surface_caps; |
| + result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR( |
| + GetVulkanPhysicalDevice(), surface_, &surface_caps); |
| + if (VK_SUCCESS != result) { |
| + LOG(ERROR) << "vkGetPhysicalDeviceSurfaceCapabilitiesKHR() failed: " |
|
piman
2016/03/09 01:25:34
nit: DLOG
David Yen
2016/03/10 01:39:49
Done.
|
| + << 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); |
| + |
| + // The next part of the setup process needs to submit commands, we create |
| + // a temporary command buffer to do these submissions. |
| + scoped_ptr<VulkanCommandBuffer> command_buffer = |
| + CreatePrimaryCommandBuffer(); |
| + |
| + bool success = false; |
| + do { |
| + { |
| + ScopedSingleUseCommandBufferRecorder recorder(*command_buffer); |
| + |
| + // Create Swapchain. |
| + if (!swap_chain_.Initialize(recorder.handle(), surface_, surface_caps, |
| + surface_format_, kFormatMapping[format])) { |
| + break; |
| + } |
| + } |
| + |
| + if (!command_buffer->Submit()) { |
| + LOG(ERROR) << "Failed to submit command buffer commands."; |
|
piman
2016/03/09 01:25:34
nit: DLOG
David Yen
2016/03/10 01:39:49
Done.
|
| + break; |
| + } |
| + |
| + // TODO(dyen): Look into if it's worth inserting a fence or event here |
| + // and keeping around the command buffer until it's done. |
|
piman
2016/03/09 01:25:34
We'll definitely want some facility to do that - d
David Yen
2016/03/10 01:39:48
After thinking through this more, I now have this
|
| + result = vkQueueWaitIdle(GetVulkanQueue()); |
| + if (VK_SUCCESS != result) { |
| + LOG(ERROR) << "vkQueueWaitIdle() failed: " << result; |
|
piman
2016/03/09 01:25:34
nit: DLOG
David Yen
2016/03/10 01:39:49
Done.
|
| + break; |
| + } |
| + |
| + success = true; |
| + } while (false); |
| + |
| + command_buffer->Destroy(); |
| + return success; |
| + } |
| + |
| + void Destroy() override { |
| + swap_chain_.Destroy(); |
| + vkDestroySurfaceKHR(GetVulkanInstance(), surface_, nullptr); |
| + surface_ = VK_NULL_HANDLE; |
| + } |
| + |
| + protected: |
| + gfx::AcceleratedWidget window_; |
| + gfx::Size size_; |
| + VkSurfaceKHR surface_ = VK_NULL_HANDLE; |
| + VkSurfaceFormatKHR surface_format_ = {}; |
| + VulkanSwapChain swap_chain_; |
| +}; |
| + |
| +class VulkanBufferSurface : public VulkanSurface { |
|
piman
2016/03/09 01:25:34
I don't think this is useful - you can't use a VkB
David Yen
2016/03/10 01:39:48
Deleted.
|
| + public: |
| + VulkanBufferSurface(const gfx::Size& size) : size_(size) {} |
| + |
| + ~VulkanBufferSurface() override { |
| + DCHECK_EQ(static_cast<VkBuffer>(VK_NULL_HANDLE), buffer_); |
| + } |
| + |
| + bool Initialize(VulkanSurface::Format format) override { |
| + VkBufferCreateInfo buffer_create_info = {}; |
| + buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
| + buffer_create_info.size = kFormatSize[format] * size_.GetArea(); |
| + buffer_create_info.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | |
| + VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; |
| + buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| + |
| + VkResult result = vkCreateBuffer(GetVulkanDevice(), &buffer_create_info, |
| + nullptr, &buffer_); |
| + if (VK_SUCCESS != result) { |
| + LOG(ERROR) << "Could not create VkBuffer (" << size_.width() << "x" |
| + << size_.height() << "x" << kFormatSize[format] |
| + << "): " << result; |
| + return false; |
| + } |
| + return true; |
| + } |
| + |
| + void Destroy() override { |
| + vkDestroyBuffer(GetVulkanDevice(), buffer_, nullptr); |
| + buffer_ = VK_NULL_HANDLE; |
| + } |
| + |
| + protected: |
| + gfx::Size size_; |
| + VkBuffer buffer_ = VK_NULL_HANDLE; |
| +}; |
| // static |
| bool VulkanSurface::InitializeOneOff() { |
| @@ -20,4 +229,18 @@ bool VulkanSurface::InitializeOneOff() { |
| VulkanSurface::~VulkanSurface() {} |
| +// static |
| +scoped_ptr<gfx::VulkanSurface> VulkanSurface::CreateViewSurface( |
| + gfx::AcceleratedWidget window) { |
| + return scoped_ptr<gfx::VulkanSurface>(new VulkanWSISurface(window)); |
| +} |
| + |
| +// static |
| +scoped_ptr<gfx::VulkanSurface> VulkanSurface::CreateOffscreenSurface( |
| + const gfx::Size& size) { |
| + return scoped_ptr<gfx::VulkanSurface>(new VulkanBufferSurface(size)); |
| +} |
| + |
| +VulkanSurface::VulkanSurface() {} |
| + |
| } // namespace gfx |