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

Unified Diff: gpu/vulkan/vulkan_render_pass.cc

Issue 1776453003: Added initial implementation of Vulkan Render Passes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@gn_vulkan
Patch Set: Adding logging/macros headers 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
« no previous file with comments | « gpu/vulkan/vulkan_render_pass.h ('k') | gpu/vulkan/vulkan_surface.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: gpu/vulkan/vulkan_render_pass.cc
diff --git a/gpu/vulkan/vulkan_render_pass.cc b/gpu/vulkan/vulkan_render_pass.cc
new file mode 100644
index 0000000000000000000000000000000000000000..84f630f6a54d8e0d14114b42fa8427feb79a8ec2
--- /dev/null
+++ b/gpu/vulkan/vulkan_render_pass.cc
@@ -0,0 +1,399 @@
+// 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_render_pass.h"
+
+#include "base/logging.h"
+#include "gpu/vulkan/vulkan_command_buffer.h"
+#include "gpu/vulkan/vulkan_image_view.h"
+#include "gpu/vulkan/vulkan_implementation.h"
+#include "gpu/vulkan/vulkan_swap_chain.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace gpu {
+
+VkImageLayout ConvertImageLayout(
+ const VulkanImageView* image_view,
+ VulkanRenderPass::ImageLayoutType layout_type) {
+ switch (layout_type) {
+ case VulkanRenderPass::ImageLayoutType::IMAGE_LAYOUT_UNDEFINED:
+ return VK_IMAGE_LAYOUT_UNDEFINED;
+ case VulkanRenderPass::ImageLayoutType::IMAGE_LAYOUT_TYPE_IMAGE_VIEW:
+ switch (image_view->image_type()) {
+ case VulkanImageView::ImageType::IMAGE_TYPE_COLOR:
+ return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ case VulkanImageView::ImageType::IMAGE_TYPE_DEPTH:
+ case VulkanImageView::ImageType::IMAGE_TYPE_STENCIL:
+ case VulkanImageView::ImageType::IMAGE_TYPE_DEPTH_STENCIL:
+ return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ default:
+ return VK_IMAGE_LAYOUT_UNDEFINED;
+ }
+ break;
+ case VulkanRenderPass::ImageLayoutType::IMAGE_LAYOUT_TYPE_PRESENT:
+ return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ }
+
+ return VK_IMAGE_LAYOUT_UNDEFINED;
+}
+
+bool VulkanRenderPass::AttachmentData::ValidateData(
+ const VulkanSwapChain* swap_chain) const {
+#if DCHECK_IS_ON()
+ if (attachment_type < AttachmentType::ATTACHMENT_TYPE_SWAP_IMAGE ||
+ attachment_type > AttachmentType::ATTACHMENT_TYPE_ATTACHMENT_VIEW) {
+ DLOG(ERROR) << "Invalid Attachment Type: "
+ << static_cast<int>(attachment_type);
+ return false;
+ }
+
+ if (sample_count &
+ ~(VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_2_BIT | VK_SAMPLE_COUNT_4_BIT |
+ VK_SAMPLE_COUNT_8_BIT | VK_SAMPLE_COUNT_16_BIT |
+ VK_SAMPLE_COUNT_32_BIT | VK_SAMPLE_COUNT_64_BIT)) {
+ DLOG(ERROR) << "Invalid Sample Count: "
+ << static_cast<uint32_t>(sample_count);
+ return false;
+ }
+
+ if (std::min(load_op, stencil_load_op) < VK_ATTACHMENT_LOAD_OP_LOAD ||
+ std::max(load_op, stencil_load_op) > VK_ATTACHMENT_LOAD_OP_DONT_CARE) {
+ DLOG(ERROR) << "Invalid Load Op (" << static_cast<int>(load_op)
+ << ") or Stencil Load Op (" << static_cast<int>(stencil_load_op)
+ << ").";
+ return false;
+ }
+
+ if (std::min(store_op, stencil_store_op) < VK_ATTACHMENT_STORE_OP_STORE ||
+ std::max(store_op, stencil_store_op) > VK_ATTACHMENT_STORE_OP_DONT_CARE) {
+ DLOG(ERROR) << "Invalid Store Op (" << static_cast<int>(store_op)
+ << ") or Stencil Store Op ("
+ << static_cast<int>(stencil_store_op) << ").";
+ return false;
+ }
+
+ if (start_layout < ImageLayoutType::IMAGE_LAYOUT_TYPE_IMAGE_VIEW ||
+ start_layout > ImageLayoutType::IMAGE_LAYOUT_TYPE_PRESENT) {
+ DLOG(ERROR) << "Invalid Start Layout: " << static_cast<int>(start_layout);
+ return false;
+ }
+
+ if (end_layout < ImageLayoutType::IMAGE_LAYOUT_TYPE_IMAGE_VIEW ||
+ end_layout > ImageLayoutType::IMAGE_LAYOUT_TYPE_PRESENT) {
+ DLOG(ERROR) << "Invalid Start Layout: " << static_cast<int>(end_layout);
+ return false;
+ }
+
+ if (attachment_type == AttachmentType::ATTACHMENT_TYPE_ATTACHMENT_VIEW) {
+ if (nullptr == image_view) {
+ DLOG(ERROR) << "Must specify image view for image view attachment";
+ return false;
+ }
+ }
+#endif
+
+ return true;
+}
+
+VulkanRenderPass::SubpassData::SubpassData() {}
+
+VulkanRenderPass::SubpassData::~SubpassData() {}
+
+bool VulkanRenderPass::SubpassData::ValidateData(
+ uint32_t num_attachments) const {
+#if DCHECK_IS_ON()
+ for (const SubpassAttachment subpass_attachment : subpass_attachments) {
+ if (subpass_attachment.attachment_index >= num_attachments) {
+ DLOG(ERROR) << "Invalid attachment index: "
+ << subpass_attachment.attachment_index << " < "
+ << num_attachments;
+ return false;
+ }
+
+ const ImageLayoutType layout = subpass_attachment.subpass_layout;
+ if (layout < ImageLayoutType::IMAGE_LAYOUT_TYPE_IMAGE_VIEW ||
+ layout > ImageLayoutType::IMAGE_LAYOUT_TYPE_PRESENT) {
+ DLOG(ERROR) << "Invalid subpass layout: " << static_cast<int>(layout);
+ return false;
+ }
+ }
+#endif
+
+ return true;
+}
+
+VulkanRenderPass::RenderPassData::RenderPassData() {}
+
+VulkanRenderPass::RenderPassData::~RenderPassData() {}
+
+VulkanRenderPass::VulkanRenderPass() {}
+
+VulkanRenderPass::~VulkanRenderPass() {
+ DCHECK_EQ(static_cast<VkRenderPass>(VK_NULL_HANDLE), render_pass_);
+ DCHECK(frame_buffers_.empty());
+}
+
+bool VulkanRenderPass::RenderPassData::ValidateData(
+ const VulkanSwapChain* swap_chain) const {
+#if DCHECK_IS_ON()
+ for (const AttachmentData& attachment : attachments) {
+ if (!attachment.ValidateData(swap_chain))
+ return false;
+ }
+
+ for (const SubpassData& subpass_data : subpass_datas) {
+ if (!subpass_data.ValidateData(attachments.size()))
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+bool VulkanRenderPass::Initialize(const VulkanSwapChain* swap_chain,
+ const RenderPassData& render_pass_data) {
+ DCHECK(!executing_);
+ DCHECK_EQ(static_cast<VkRenderPass>(VK_NULL_HANDLE), render_pass_);
+ DCHECK(frame_buffers_.empty());
+ DCHECK(render_pass_data.ValidateData(swap_chain));
+
+ VkDevice device = GetVulkanDevice();
+ VkResult result = VK_SUCCESS;
+
+ swap_chain_ = swap_chain;
+ num_sub_passes_ = render_pass_data.subpass_datas.size();
+ current_sub_pass_ = 0;
+ attachment_clear_values_.clear();
+ attachment_clear_indexes_.clear();
+
+ // Fill out attachment information.
+ const uint32_t num_attachments = render_pass_data.attachments.size();
+ std::vector<VkAttachmentDescription> attachment_descs(num_attachments);
+ std::vector<VulkanImageView*> attachment_image_view(num_attachments);
+ for (uint32_t i = 0; i < num_attachments; ++i) {
+ const AttachmentData& attachment_data = render_pass_data.attachments[i];
+
+ VulkanImageView* image_view = nullptr;
+ switch (attachment_data.attachment_type) {
+ case AttachmentType::ATTACHMENT_TYPE_SWAP_IMAGE:
+ // All the image views in the swap chain all share the same format.
+ image_view = swap_chain->GetCurrentImageView();
+ break;
+ case AttachmentType::ATTACHMENT_TYPE_ATTACHMENT_VIEW:
+ // All the image views in the attachment should have the same format.
+ image_view = attachment_data.image_view;
+ break;
+ }
+ DCHECK(image_view);
+ attachment_image_view[i] = image_view;
+
+ VkAttachmentDescription& attachment_desc = attachment_descs[i];
+ attachment_desc.format = image_view->format();
+ attachment_desc.samples = attachment_data.sample_count;
+ attachment_desc.loadOp = attachment_data.load_op;
+ attachment_desc.storeOp = attachment_data.store_op;
+ attachment_desc.stencilLoadOp = attachment_data.stencil_load_op;
+ attachment_desc.stencilStoreOp = attachment_data.stencil_store_op;
+ attachment_desc.initialLayout =
+ ConvertImageLayout(image_view, attachment_data.start_layout);
+ attachment_desc.finalLayout =
+ ConvertImageLayout(image_view, attachment_data.end_layout);
+
+ if (attachment_desc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ||
+ attachment_desc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
+ attachment_clear_values_.push_back(attachment_data.clear_value);
+ attachment_clear_indexes_.push_back(i);
+ }
+ }
+
+ // Fill out subpass information.
+ std::vector<VkSubpassDescription> subpass_descs(
+ render_pass_data.subpass_datas.size());
+ std::vector<std::vector<VkAttachmentReference>> color_refs(
+ render_pass_data.subpass_datas.size());
+ std::vector<VkAttachmentReference> depth_stencil_refs(
+ render_pass_data.subpass_datas.size());
+ for (uint32_t i = 0; i < render_pass_data.subpass_datas.size(); ++i) {
+ depth_stencil_refs[i].attachment = VK_ATTACHMENT_UNUSED;
+
+ for (const VulkanRenderPass::SubpassAttachment& subpass_attachment :
+ render_pass_data.subpass_datas[i].subpass_attachments) {
+ const uint32_t index = subpass_attachment.attachment_index;
+ VulkanImageView* image_view = attachment_image_view[index];
+
+ VkAttachmentReference attachment_reference = {};
+ attachment_reference.attachment = index;
+ attachment_reference.layout =
+ ConvertImageLayout(image_view, subpass_attachment.subpass_layout);
+
+ switch (image_view->image_type()) {
+ case VulkanImageView::ImageType::IMAGE_TYPE_COLOR:
+ color_refs[i].push_back(attachment_reference);
+ break;
+ case VulkanImageView::ImageType::IMAGE_TYPE_DEPTH:
+ case VulkanImageView::ImageType::IMAGE_TYPE_STENCIL:
+ case VulkanImageView::ImageType::IMAGE_TYPE_DEPTH_STENCIL:
+ if (VK_ATTACHMENT_UNUSED != depth_stencil_refs[i].attachment) {
+ DLOG(ERROR) << "Subpass cannot have multiple depth/stencil refs.";
+ return false;
+ }
+ depth_stencil_refs[i] = attachment_reference;
+ break;
+ default:
+ DLOG(ERROR) << "Invalid image type: "
+ << static_cast<int>(image_view->image_type());
+ return false;
+ }
+ }
+
+ VkSubpassDescription& subpass_desc = subpass_descs[i];
+ subpass_desc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass_desc.colorAttachmentCount = color_refs[i].size();
+ subpass_desc.pColorAttachments = color_refs[i].data();
+ subpass_desc.pDepthStencilAttachment = &depth_stencil_refs[i];
+ }
+
+ // Create VkRenderPass;
+ VkRenderPassCreateInfo render_pass_create_info = {};
+ render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ render_pass_create_info.attachmentCount =
+ static_cast<uint32_t>(attachment_descs.size());
+ render_pass_create_info.pAttachments = attachment_descs.data();
+ render_pass_create_info.subpassCount = subpass_descs.size();
+ render_pass_create_info.pSubpasses = subpass_descs.data();
+
+ result = vkCreateRenderPass(device, &render_pass_create_info, nullptr,
+ &render_pass_);
+ if (VK_SUCCESS != result) {
+ DLOG(ERROR) << "vkCreateRenderPass() failed: " << result;
+ return false;
+ }
+
+ // Initialize frame buffers.
+ const uint32_t num_frame_buffers = swap_chain->num_images();
+ frame_buffers_.resize(num_frame_buffers);
+ for (uint32_t i = 0; i < num_frame_buffers; ++i) {
+ std::vector<VkImageView> image_views(num_attachments);
+ uint32_t width = 0;
+ uint32_t height = 0;
+ uint32_t layers = 0;
+
+ for (uint32_t n = 0; n < num_attachments; ++n) {
+ const AttachmentData& attachment_data = render_pass_data.attachments[n];
+ VulkanImageView* image_view = nullptr;
+
+ switch (attachment_data.attachment_type) {
+ case AttachmentType::ATTACHMENT_TYPE_SWAP_IMAGE:
+ image_view = swap_chain->GetImageView(n);
+ break;
+ case AttachmentType::ATTACHMENT_TYPE_ATTACHMENT_VIEW:
+ image_view = attachment_data.image_view;
+ break;
+ }
+ DCHECK(image_view);
+
+ if (n == 0) {
+ width = image_view->width();
+ height = image_view->height();
+ layers = image_view->layers();
+ } else if (width != image_view->width() ||
+ height != image_view->height() ||
+ layers != image_view->layers()) {
+ DLOG(ERROR) << "Images in a frame buffer must have same dimensions.";
+ return false;
+ }
+
+ image_views[n] = image_view->handle();
+ }
+
+ VkFramebufferCreateInfo framebuffer_create_info = {};
+ framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ framebuffer_create_info.renderPass = render_pass_;
+ framebuffer_create_info.attachmentCount = image_views.size();
+ framebuffer_create_info.pAttachments = image_views.data();
+ framebuffer_create_info.width = width;
+ framebuffer_create_info.height = height;
+ framebuffer_create_info.layers = layers;
+
+ result = vkCreateFramebuffer(device, &framebuffer_create_info, nullptr,
+ &frame_buffers_[i]);
+ if (VK_SUCCESS != result) {
+ DLOG(ERROR) << "vkCreateFramebuffer() failed: " << result;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void VulkanRenderPass::Destroy() {
+ VkDevice device = GetVulkanDevice();
+
+ for (VkFramebuffer frame_buffer : frame_buffers_) {
+ vkDestroyFramebuffer(device, frame_buffer, nullptr);
+ }
+ frame_buffers_.clear();
+
+ if (VK_NULL_HANDLE != render_pass_) {
+ vkDestroyRenderPass(device, render_pass_, nullptr);
+ render_pass_ = VK_NULL_HANDLE;
+ }
+
+ swap_chain_ = nullptr;
+ attachment_clear_values_.clear();
+ attachment_clear_indexes_.clear();
+}
+
+void VulkanRenderPass::BeginRenderPass(
+ const CommandBufferRecorderBase& recorder,
+ bool exec_inline) {
+ DCHECK(!executing_);
+ DCHECK_NE(0u, num_sub_passes_);
+ executing_ = true;
+ execution_type_ = exec_inline ? VK_SUBPASS_CONTENTS_INLINE
+ : VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
+ current_sub_pass_ = 0;
+
+ const gfx::Size& size = swap_chain_->size();
+
+ VkRenderPassBeginInfo begin_info = {};
+ begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ begin_info.renderPass = render_pass_;
+ begin_info.framebuffer = frame_buffers_[swap_chain_->current_image()];
+ begin_info.renderArea.extent.width = size.width();
+ begin_info.renderArea.extent.height = size.height();
+ begin_info.clearValueCount =
+ static_cast<uint32_t>(attachment_clear_values_.size());
+ begin_info.pClearValues = attachment_clear_values_.data();
+
+ vkCmdBeginRenderPass(recorder.handle(), &begin_info, execution_type_);
+}
+
+void VulkanRenderPass::NextSubPass(const CommandBufferRecorderBase& recorder) {
+ DCHECK(executing_);
+ DCHECK_LT(current_sub_pass_ + 1, num_sub_passes_);
+ vkCmdNextSubpass(recorder.handle(), execution_type_);
+ current_sub_pass_++;
+}
+
+void VulkanRenderPass::EndRenderPass(
+ const CommandBufferRecorderBase& recorder) {
+ DCHECK(executing_);
+ vkCmdEndRenderPass(recorder.handle());
+ executing_ = false;
+}
+
+void VulkanRenderPass::SetClearValue(uint32_t attachment_index,
+ VkClearValue clear_value) {
+ DCHECK_EQ(attachment_clear_values_.size(), attachment_clear_indexes_.size());
+ auto iter =
+ std::lower_bound(attachment_clear_indexes_.begin(),
+ attachment_clear_indexes_.end(), attachment_index);
+ if (iter != attachment_clear_indexes_.end() && *iter == attachment_index) {
+ const uint32_t index = iter - attachment_clear_indexes_.begin();
+ attachment_clear_values_[index] = clear_value;
+ }
+}
+
+} // namespace gpu
« no previous file with comments | « gpu/vulkan/vulkan_render_pass.h ('k') | gpu/vulkan/vulkan_surface.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698