Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(435)

Unified Diff: gpu/vulkan/vulkan_swap_chain.cc

Issue 1776453003: Added initial implementation of Vulkan Render Passes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@gn_vulkan
Patch Set: Fix SwapBuffers() present layout, test in unittests instead of injections Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« gpu/vulkan/vulkan_surface.h ('K') | « gpu/vulkan/vulkan_swap_chain.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: gpu/vulkan/vulkan_swap_chain.cc
diff --git a/gpu/vulkan/vulkan_swap_chain.cc b/gpu/vulkan/vulkan_swap_chain.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3f32f43a52c5067a0103c8edc044e7c126319425
--- /dev/null
+++ b/gpu/vulkan/vulkan_swap_chain.cc
@@ -0,0 +1,404 @@
+// 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_swap_chain.h"
+
+#include "gpu/vulkan/vulkan_command_buffer.h"
+#include "gpu/vulkan/vulkan_command_pool.h"
+#include "gpu/vulkan/vulkan_implementation.h"
+
+namespace gpu {
+
+VulkanSwapChain::VulkanSwapChain() {}
+
+VulkanSwapChain::~VulkanSwapChain() {
+ DCHECK(images_.empty());
+ DCHECK_EQ(static_cast<VkSwapchainKHR>(VK_NULL_HANDLE), swap_chain_);
+}
+
+bool VulkanSwapChain::Initialize(VkSurfaceKHR surface,
+ const VkSurfaceCapabilitiesKHR& surface_caps,
+ const VkSurfaceFormatKHR& surface_format) {
+ return InitializeSwapChain(surface, surface_caps, surface_format) &&
+ InitializeImageLayoutCommandBuffer() &&
+ InitializeSwapImages(surface_caps, surface_format) &&
+ InitializeInitialBuffer();
+}
+
+void VulkanSwapChain::Destroy() {
+ DestroySwapImages();
+ DestroyImageLayoutCommandBuffer();
+ DestroySwapChain();
+}
+
+gfx::SwapResult VulkanSwapChain::SwapBuffers() {
+ VkResult result = VK_SUCCESS;
+
+ scoped_ptr<ImageData>& current_image_data = images_[current_image_];
+
+ // Default image subresource range.
+ VkImageSubresourceRange image_subresource_range = {};
+ image_subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ image_subresource_range.baseMipLevel = 0;
+ image_subresource_range.levelCount = 1;
+ image_subresource_range.baseArrayLayer = 0;
+ image_subresource_range.layerCount = 1;
+
+ // Submit our command buffer for the current buffer.
+ if (!current_image_data->command_buffer->Submit(
+ GetVulkanQueue(), 1, &current_image_data->render_layout_semaphore, 1,
+ &current_image_data->render_semaphore)) {
piman 2016/03/11 03:07:52 You don't need a semaphore to order command buffer
David Yen 2016/03/21 18:26:31 That would make things easier. I wasn't sure becau
+ return gfx::SwapResult::SWAP_FAILED;
+ }
+
+ // Prepare the image layout to present.
+ {
+ ScopedSingleUseCommandBufferRecorder recorder(
piman 2016/03/11 03:07:53 2 things: 1- you can't reuse the command buffer un
David Yen 2016/03/21 18:26:31 Done. To make how this is suppose to be done clear
+ *image_layout_command_buffer_);
+
+ VkImageMemoryBarrier image_memory_barrier = {};
+ image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ image_memory_barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.subresourceRange = image_subresource_range;
+ image_memory_barrier.image = current_image_data->image;
+
+ vkCmdPipelineBarrier(recorder.handle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
+ nullptr, 1, &image_memory_barrier);
+ }
+ if (!image_layout_command_buffer_->Submit(
+ GetVulkanQueue(), 1, &current_image_data->render_semaphore, 1,
+ &current_image_data->present_layout_semaphore)) {
+ return gfx::SwapResult::SWAP_FAILED;
+ }
+
+ // Queue the present.
+ VkPresentInfoKHR present_info = {};
+ present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
+ present_info.waitSemaphoreCount = 1;
+ present_info.pWaitSemaphores = &current_image_data->present_layout_semaphore;
+ present_info.swapchainCount = 1;
+ present_info.pSwapchains = &swap_chain_;
+ present_info.pImageIndices = &current_image_;
+
+ result = vkQueuePresentKHR(GetVulkanQueue(), &present_info);
+ if (VK_SUCCESS != result) {
+ return gfx::SwapResult::SWAP_FAILED;
+ }
+
+ // Setup for the next available buffer.
+ // TODO(dyen): Look into if this does what I'm expecting. More studying of
+ // the spec is required here. It doesn't seem clear if "success" when timeout
+ // is 0 means it will give you a buffer even before it's done presenting. That
+ // is probably what we want and the present/render_layout semaphore will
+ // do the synchronization for us.
piman 2016/03/11 03:07:53 vkAcquireNextImageKHR needs to be able to block, r
David Yen 2016/03/21 18:26:31 Done.
+ result = vkAcquireNextImageKHR(GetVulkanDevice(), swap_chain_, 0,
+ current_image_data->present_semaphore,
+ VK_NULL_HANDLE, &current_image_);
+ if (VK_SUCCESS != result) {
+ return gfx::SwapResult::SWAP_FAILED;
+ }
+
+ scoped_ptr<ImageData>& next_image_data = images_[current_image_];
+
+ // The present semaphore actually is associated with the new image data, but
+ // the previous one is guaranteed to be unused to swap it to the correct one.
+ std::swap(next_image_data->present_semaphore,
+ current_image_data->present_semaphore);
+
+ // Setup the previous layout back to the render layout after presentation.
+ {
+ ScopedSingleUseCommandBufferRecorder recorder(
piman 2016/03/11 03:07:52 Same points as above.
David Yen 2016/03/21 18:26:31 Done.
+ *image_layout_command_buffer_);
+
+ VkImageMemoryBarrier image_memory_barrier = {};
+ image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ image_memory_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.subresourceRange = image_subresource_range;
+ image_memory_barrier.image = next_image_data->image;
+
+ vkCmdPipelineBarrier(recorder.handle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
+ nullptr, 1, &image_memory_barrier);
+ }
+ // TODO(dyen): This signals render_layout_semaphore which is waited upon
+ // above. When this submit is called it is possible the render layout
+ // semaphore is in an unsignalled state, however by the time the present
+ // semaphore is signalled it is guaranteed to be in an unsignalled state.
+ // We need to make sure this is ok, the spec doesn't specify any constraints
+ // here.
piman 2016/03/11 03:07:53 This should be ok (note that I don't think you nee
David Yen 2016/03/21 18:26:31 Acknowledged.
+ if (!image_layout_command_buffer_->Submit(
+ GetVulkanQueue(), 1, &next_image_data->present_semaphore, 1,
+ &next_image_data->render_layout_semaphore)) {
+ return gfx::SwapResult::SWAP_FAILED;
+ }
+
+ return gfx::SwapResult::SWAP_ACK;
+}
+
+bool VulkanSwapChain::InitializeSwapChain(
+ VkSurfaceKHR surface,
+ const VkSurfaceCapabilitiesKHR& surface_caps,
+ const VkSurfaceFormatKHR& surface_format) {
+ VkDevice device = GetVulkanDevice();
+ VkResult result = VK_SUCCESS;
+
+ VkSwapchainCreateInfoKHR swap_chain_create_info = {};
+ swap_chain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+ swap_chain_create_info.surface = surface;
+ swap_chain_create_info.minImageCount =
+ std::min(2u, surface_caps.maxImageCount);
piman 2016/03/11 03:07:53 It does have to be more than surface_caps.minImage
David Yen 2016/03/21 18:26:31 Done.
+ swap_chain_create_info.imageFormat = surface_format.format;
+ swap_chain_create_info.imageColorSpace = surface_format.colorSpace;
+ swap_chain_create_info.imageExtent = surface_caps.currentExtent;
+ swap_chain_create_info.imageArrayLayers = 1;
+ swap_chain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ swap_chain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ swap_chain_create_info.preTransform = surface_caps.currentTransform;
+ swap_chain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+ swap_chain_create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
+ swap_chain_create_info.clipped = true;
+ swap_chain_create_info.oldSwapchain = swap_chain_;
+
+ VkSwapchainKHR new_swap_chain = VK_NULL_HANDLE;
+ result = vkCreateSwapchainKHR(device, &swap_chain_create_info, nullptr,
+ &new_swap_chain);
+ if (VK_SUCCESS != result) {
+ DLOG(ERROR) << "vkCreateSwapchainKHR() failed: " << result;
+ return false;
+ }
+
+ // Destroy the old swap chain and buffers.
+ // TODO(dyen): Look into how to do this safely while commands in flight.
+ Destroy();
+
+ swap_chain_ = new_swap_chain;
+ return true;
+}
+
+void VulkanSwapChain::DestroySwapChain() {
+ VkDevice device = GetVulkanDevice();
+
+ if (swap_chain_ != VK_NULL_HANDLE) {
+ vkDestroySwapchainKHR(device, swap_chain_, nullptr);
+ swap_chain_ = VK_NULL_HANDLE;
+ }
+}
+
+bool VulkanSwapChain::InitializeImageLayoutCommandBuffer() {
+ command_pool_ = CreateCommandPool();
+ if (!command_pool_)
+ return false;
+
+ image_layout_command_buffer_ = command_pool_->CreatePrimaryCommandBuffer();
+ if (!image_layout_command_buffer_)
+ return false;
+
+ return true;
+}
+
+void VulkanSwapChain::DestroyImageLayoutCommandBuffer() {
+ if (image_layout_command_buffer_) {
+ image_layout_command_buffer_->Destroy();
+ image_layout_command_buffer_.reset();
+ }
+
+ if (command_pool_) {
+ command_pool_->Destroy();
+ command_pool_.reset();
+ }
+}
+
+bool VulkanSwapChain::InitializeSwapImages(
+ const VkSurfaceCapabilitiesKHR& surface_caps,
+ const VkSurfaceFormatKHR& surface_format) {
+ VkDevice device = GetVulkanDevice();
+ VkResult result = VK_SUCCESS;
+
+ uint32_t image_count = 0;
+ result = vkGetSwapchainImagesKHR(device, swap_chain_, &image_count, nullptr);
+ if (VK_SUCCESS != result) {
+ DLOG(ERROR) << "vkGetSwapchainImagesKHR(NULL) failed: " << result;
+ return false;
+ }
+
+ std::vector<VkImage> images(image_count);
+ result =
+ vkGetSwapchainImagesKHR(device, swap_chain_, &image_count, images.data());
+ if (VK_SUCCESS != result) {
+ DLOG(ERROR) << "vkGetSwapchainImagesKHR(images) failed: " << result;
+ return false;
+ }
+
+ // Generic semaphore creation structure.
+ VkSemaphoreCreateInfo semaphore_create_info = {};
+ semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+
+ // Default image subresource range.
+ VkImageSubresourceRange image_subresource_range = {};
+ image_subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ image_subresource_range.baseMipLevel = 0;
+ image_subresource_range.levelCount = 1;
+ image_subresource_range.baseArrayLayer = 0;
+ image_subresource_range.layerCount = 1;
+
+ // The image memory barrier is used to setup the image layout.
+ VkImageMemoryBarrier image_memory_barrier = {};
+ image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ image_memory_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ image_memory_barrier.subresourceRange = image_subresource_range;
+
+ // We must create an image view for each image.
+ VkImageViewCreateInfo image_view_create_info = {};
+ image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ image_view_create_info.format = surface_format.format;
+ image_view_create_info.components = {
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
+ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY};
+ image_view_create_info.subresourceRange = image_subresource_range;
+
+ {
+ ScopedSingleUseCommandBufferRecorder recorder(
+ *image_layout_command_buffer_);
+ images_.resize(image_count);
+ for (uint32_t i = 0; i < image_count; ++i) {
+ images_[i].reset(new ImageData);
+ scoped_ptr<ImageData>& image_data = images_[i];
+ image_data->image = images[i];
+
+ // Setup semaphores.
+ result = vkCreateSemaphore(device, &semaphore_create_info, nullptr,
+ &image_data->render_layout_semaphore);
+ if (VK_SUCCESS != result) {
+ DLOG(ERROR) << "vkCreateSemaphore(render_layout) failed: " << result;
+ return false;
+ }
+ result = vkCreateSemaphore(device, &semaphore_create_info, nullptr,
+ &image_data->render_semaphore);
+ if (VK_SUCCESS != result) {
+ DLOG(ERROR) << "vkCreateSemaphore(render) failed: " << result;
+ return false;
+ }
+
+ result = vkCreateSemaphore(device, &semaphore_create_info, nullptr,
+ &image_data->present_layout_semaphore);
+ if (VK_SUCCESS != result) {
+ DLOG(ERROR) << "vkCreateSemaphore(present_layout) failed: " << result;
+ return false;
+ }
+
+ result = vkCreateSemaphore(device, &semaphore_create_info, nullptr,
+ &image_data->present_semaphore);
+ if (VK_SUCCESS != result) {
+ DLOG(ERROR) << "vkCreateSemaphore(present) failed: " << result;
+ return false;
+ }
+
+ // Setup the Image Layout.
+ image_memory_barrier.image = images[i];
+ vkCmdPipelineBarrier(recorder.handle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
+ nullptr, 1, &image_memory_barrier);
+
+ // Create the image view.
+ image_view_create_info.image = images[i];
+ result = vkCreateImageView(device, &image_view_create_info, nullptr,
+ &image_data->image_view);
+ if (VK_SUCCESS != result) {
+ DLOG(ERROR) << "vkCreateImageView() failed: " << result;
+ return false;
+ }
+
+ // Initialize the command buffer for this buffer data.
+ image_data->command_buffer = command_pool_->CreatePrimaryCommandBuffer();
+ }
+ }
+
+ // Submit the image layout commands, and tie them all to the render layout.
+ std::vector<VkSemaphore> initial_render_layout_semaphores(image_count);
+ for (uint32_t i = 0; i < image_count; ++i) {
+ initial_render_layout_semaphores[i] = images_[i]->render_layout_semaphore;
+ }
+ if (!image_layout_command_buffer_->Submit(
+ GetVulkanQueue(), 0, nullptr, image_count,
+ initial_render_layout_semaphores.data())) {
+ return false;
+ }
+
+ return true;
+}
+
+void VulkanSwapChain::DestroySwapImages() {
+ VkDevice device = GetVulkanDevice();
+
+ for (const scoped_ptr<ImageData>& image_data : images_) {
+ if (image_data->command_buffer) {
+ image_data->command_buffer->Destroy();
+ image_data->command_buffer.reset();
+ }
+
+ // Destroy Image View.
+ if (VK_NULL_HANDLE != image_data->image_view) {
+ vkDestroyImageView(device, image_data->image_view, nullptr);
+ image_data->image_view = VK_NULL_HANDLE;
+ }
+
+ // Destroy Semaphores.
+ if (VK_NULL_HANDLE != image_data->present_semaphore) {
+ vkDestroySemaphore(device, image_data->present_semaphore, nullptr);
+ image_data->present_semaphore = VK_NULL_HANDLE;
+ }
+
+ if (VK_NULL_HANDLE != image_data->present_layout_semaphore) {
+ vkDestroySemaphore(device, image_data->present_layout_semaphore, nullptr);
+ image_data->present_layout_semaphore = VK_NULL_HANDLE;
+ }
+
+ if (VK_NULL_HANDLE != image_data->render_semaphore) {
+ vkDestroySemaphore(device, image_data->render_semaphore, nullptr);
+ image_data->render_semaphore = VK_NULL_HANDLE;
+ }
+
+ if (VK_NULL_HANDLE != image_data->render_layout_semaphore) {
+ vkDestroySemaphore(device, image_data->render_layout_semaphore, nullptr);
+ image_data->render_layout_semaphore = VK_NULL_HANDLE;
+ }
+
+ image_data->image = VK_NULL_HANDLE;
+ }
+ images_.clear();
+}
+
+bool VulkanSwapChain::InitializeInitialBuffer() {
+ // Acquire the initial buffer, all the buffers have their initial render
+ // layout semaphore setup so this is a special case.
+ const VkResult result =
+ vkAcquireNextImageKHR(GetVulkanDevice(), swap_chain_, 0, VK_NULL_HANDLE,
+ VK_NULL_HANDLE, &current_image_);
+ if (VK_SUCCESS != result) {
+ DLOG(ERROR) << "vkAcquireNextImageKHR() failed: " << result;
+ return false;
+ }
+
+ return true;
+}
+
+VulkanSwapChain::ImageData::ImageData() {}
+
+VulkanSwapChain::ImageData::~ImageData() {}
+
+} // namespace gpu
« gpu/vulkan/vulkan_surface.h ('K') | « gpu/vulkan/vulkan_swap_chain.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698