OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "gpu/vulkan/vulkan_render_pass.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "gpu/vulkan/vulkan_command_buffer.h" |
| 9 #include "gpu/vulkan/vulkan_image_view.h" |
| 10 #include "gpu/vulkan/vulkan_implementation.h" |
| 11 #include "gpu/vulkan/vulkan_swap_chain.h" |
| 12 #include "ui/gfx/geometry/size.h" |
| 13 |
| 14 namespace gpu { |
| 15 |
| 16 VkImageLayout ConvertImageLayout( |
| 17 const VulkanImageView* image_view, |
| 18 VulkanRenderPass::ImageLayoutType layout_type) { |
| 19 switch (layout_type) { |
| 20 case VulkanRenderPass::ImageLayoutType::IMAGE_LAYOUT_UNDEFINED: |
| 21 return VK_IMAGE_LAYOUT_UNDEFINED; |
| 22 case VulkanRenderPass::ImageLayoutType::IMAGE_LAYOUT_TYPE_IMAGE_VIEW: |
| 23 switch (image_view->image_type()) { |
| 24 case VulkanImageView::ImageType::IMAGE_TYPE_COLOR: |
| 25 return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| 26 case VulkanImageView::ImageType::IMAGE_TYPE_DEPTH: |
| 27 case VulkanImageView::ImageType::IMAGE_TYPE_STENCIL: |
| 28 case VulkanImageView::ImageType::IMAGE_TYPE_DEPTH_STENCIL: |
| 29 return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; |
| 30 default: |
| 31 return VK_IMAGE_LAYOUT_UNDEFINED; |
| 32 } |
| 33 break; |
| 34 case VulkanRenderPass::ImageLayoutType::IMAGE_LAYOUT_TYPE_PRESENT: |
| 35 return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; |
| 36 } |
| 37 |
| 38 return VK_IMAGE_LAYOUT_UNDEFINED; |
| 39 } |
| 40 |
| 41 bool VulkanRenderPass::AttachmentData::ValidateData( |
| 42 const VulkanSwapChain* swap_chain) const { |
| 43 #if DCHECK_IS_ON() |
| 44 if (attachment_type < AttachmentType::ATTACHMENT_TYPE_SWAP_IMAGE || |
| 45 attachment_type > AttachmentType::ATTACHMENT_TYPE_ATTACHMENT_VIEW) { |
| 46 DLOG(ERROR) << "Invalid Attachment Type: " |
| 47 << static_cast<int>(attachment_type); |
| 48 return false; |
| 49 } |
| 50 |
| 51 if (sample_count & |
| 52 ~(VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_2_BIT | VK_SAMPLE_COUNT_4_BIT | |
| 53 VK_SAMPLE_COUNT_8_BIT | VK_SAMPLE_COUNT_16_BIT | |
| 54 VK_SAMPLE_COUNT_32_BIT | VK_SAMPLE_COUNT_64_BIT)) { |
| 55 DLOG(ERROR) << "Invalid Sample Count: " |
| 56 << static_cast<uint32_t>(sample_count); |
| 57 return false; |
| 58 } |
| 59 |
| 60 if (std::min(load_op, stencil_load_op) < VK_ATTACHMENT_LOAD_OP_LOAD || |
| 61 std::max(load_op, stencil_load_op) > VK_ATTACHMENT_LOAD_OP_DONT_CARE) { |
| 62 DLOG(ERROR) << "Invalid Load Op (" << static_cast<int>(load_op) |
| 63 << ") or Stencil Load Op (" << static_cast<int>(stencil_load_op) |
| 64 << ")."; |
| 65 return false; |
| 66 } |
| 67 |
| 68 if (std::min(store_op, stencil_store_op) < VK_ATTACHMENT_STORE_OP_STORE || |
| 69 std::max(store_op, stencil_store_op) > VK_ATTACHMENT_STORE_OP_DONT_CARE) { |
| 70 DLOG(ERROR) << "Invalid Store Op (" << static_cast<int>(store_op) |
| 71 << ") or Stencil Store Op (" |
| 72 << static_cast<int>(stencil_store_op) << ")."; |
| 73 return false; |
| 74 } |
| 75 |
| 76 if (start_layout < ImageLayoutType::IMAGE_LAYOUT_TYPE_IMAGE_VIEW || |
| 77 start_layout > ImageLayoutType::IMAGE_LAYOUT_TYPE_PRESENT) { |
| 78 DLOG(ERROR) << "Invalid Start Layout: " << static_cast<int>(start_layout); |
| 79 return false; |
| 80 } |
| 81 |
| 82 if (end_layout < ImageLayoutType::IMAGE_LAYOUT_TYPE_IMAGE_VIEW || |
| 83 end_layout > ImageLayoutType::IMAGE_LAYOUT_TYPE_PRESENT) { |
| 84 DLOG(ERROR) << "Invalid Start Layout: " << static_cast<int>(end_layout); |
| 85 return false; |
| 86 } |
| 87 |
| 88 if (attachment_type == AttachmentType::ATTACHMENT_TYPE_ATTACHMENT_VIEW) { |
| 89 if (nullptr == image_view) { |
| 90 DLOG(ERROR) << "Must specify image view for image view attachment"; |
| 91 return false; |
| 92 } |
| 93 } |
| 94 #endif |
| 95 |
| 96 return true; |
| 97 } |
| 98 |
| 99 VulkanRenderPass::SubpassData::SubpassData() {} |
| 100 |
| 101 VulkanRenderPass::SubpassData::~SubpassData() {} |
| 102 |
| 103 bool VulkanRenderPass::SubpassData::ValidateData( |
| 104 uint32_t num_attachments) const { |
| 105 #if DCHECK_IS_ON() |
| 106 for (const SubpassAttachment subpass_attachment : subpass_attachments) { |
| 107 if (subpass_attachment.attachment_index >= num_attachments) { |
| 108 DLOG(ERROR) << "Invalid attachment index: " |
| 109 << subpass_attachment.attachment_index << " < " |
| 110 << num_attachments; |
| 111 return false; |
| 112 } |
| 113 |
| 114 const ImageLayoutType layout = subpass_attachment.subpass_layout; |
| 115 if (layout < ImageLayoutType::IMAGE_LAYOUT_TYPE_IMAGE_VIEW || |
| 116 layout > ImageLayoutType::IMAGE_LAYOUT_TYPE_PRESENT) { |
| 117 DLOG(ERROR) << "Invalid subpass layout: " << static_cast<int>(layout); |
| 118 return false; |
| 119 } |
| 120 } |
| 121 #endif |
| 122 |
| 123 return true; |
| 124 } |
| 125 |
| 126 VulkanRenderPass::RenderPassData::RenderPassData() {} |
| 127 |
| 128 VulkanRenderPass::RenderPassData::~RenderPassData() {} |
| 129 |
| 130 VulkanRenderPass::VulkanRenderPass() {} |
| 131 |
| 132 VulkanRenderPass::~VulkanRenderPass() { |
| 133 DCHECK_EQ(static_cast<VkRenderPass>(VK_NULL_HANDLE), render_pass_); |
| 134 DCHECK(frame_buffers_.empty()); |
| 135 } |
| 136 |
| 137 bool VulkanRenderPass::RenderPassData::ValidateData( |
| 138 const VulkanSwapChain* swap_chain) const { |
| 139 #if DCHECK_IS_ON() |
| 140 for (const AttachmentData& attachment : attachments) { |
| 141 if (!attachment.ValidateData(swap_chain)) |
| 142 return false; |
| 143 } |
| 144 |
| 145 for (const SubpassData& subpass_data : subpass_datas) { |
| 146 if (!subpass_data.ValidateData(attachments.size())) |
| 147 return false; |
| 148 } |
| 149 #endif |
| 150 |
| 151 return true; |
| 152 } |
| 153 |
| 154 bool VulkanRenderPass::Initialize(const VulkanSwapChain* swap_chain, |
| 155 const RenderPassData& render_pass_data) { |
| 156 DCHECK(!executing_); |
| 157 DCHECK_EQ(static_cast<VkRenderPass>(VK_NULL_HANDLE), render_pass_); |
| 158 DCHECK(frame_buffers_.empty()); |
| 159 DCHECK(render_pass_data.ValidateData(swap_chain)); |
| 160 |
| 161 VkDevice device = GetVulkanDevice(); |
| 162 VkResult result = VK_SUCCESS; |
| 163 |
| 164 swap_chain_ = swap_chain; |
| 165 num_sub_passes_ = render_pass_data.subpass_datas.size(); |
| 166 current_sub_pass_ = 0; |
| 167 attachment_clear_values_.clear(); |
| 168 attachment_clear_indexes_.clear(); |
| 169 |
| 170 // Fill out attachment information. |
| 171 const uint32_t num_attachments = render_pass_data.attachments.size(); |
| 172 std::vector<VkAttachmentDescription> attachment_descs(num_attachments); |
| 173 std::vector<VulkanImageView*> attachment_image_view(num_attachments); |
| 174 for (uint32_t i = 0; i < num_attachments; ++i) { |
| 175 const AttachmentData& attachment_data = render_pass_data.attachments[i]; |
| 176 |
| 177 VulkanImageView* image_view = nullptr; |
| 178 switch (attachment_data.attachment_type) { |
| 179 case AttachmentType::ATTACHMENT_TYPE_SWAP_IMAGE: |
| 180 // All the image views in the swap chain all share the same format. |
| 181 image_view = swap_chain->GetCurrentImageView(); |
| 182 break; |
| 183 case AttachmentType::ATTACHMENT_TYPE_ATTACHMENT_VIEW: |
| 184 // All the image views in the attachment should have the same format. |
| 185 image_view = attachment_data.image_view; |
| 186 break; |
| 187 } |
| 188 DCHECK(image_view); |
| 189 attachment_image_view[i] = image_view; |
| 190 |
| 191 VkAttachmentDescription& attachment_desc = attachment_descs[i]; |
| 192 attachment_desc.format = image_view->format(); |
| 193 attachment_desc.samples = attachment_data.sample_count; |
| 194 attachment_desc.loadOp = attachment_data.load_op; |
| 195 attachment_desc.storeOp = attachment_data.store_op; |
| 196 attachment_desc.stencilLoadOp = attachment_data.stencil_load_op; |
| 197 attachment_desc.stencilStoreOp = attachment_data.stencil_store_op; |
| 198 attachment_desc.initialLayout = |
| 199 ConvertImageLayout(image_view, attachment_data.start_layout); |
| 200 attachment_desc.finalLayout = |
| 201 ConvertImageLayout(image_view, attachment_data.end_layout); |
| 202 |
| 203 if (attachment_desc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR || |
| 204 attachment_desc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) { |
| 205 attachment_clear_values_.push_back(attachment_data.clear_value); |
| 206 attachment_clear_indexes_.push_back(i); |
| 207 } |
| 208 } |
| 209 |
| 210 // Fill out subpass information. |
| 211 std::vector<VkSubpassDescription> subpass_descs( |
| 212 render_pass_data.subpass_datas.size()); |
| 213 std::vector<std::vector<VkAttachmentReference>> color_refs( |
| 214 render_pass_data.subpass_datas.size()); |
| 215 std::vector<VkAttachmentReference> depth_stencil_refs( |
| 216 render_pass_data.subpass_datas.size()); |
| 217 for (uint32_t i = 0; i < render_pass_data.subpass_datas.size(); ++i) { |
| 218 depth_stencil_refs[i].attachment = VK_ATTACHMENT_UNUSED; |
| 219 |
| 220 for (const VulkanRenderPass::SubpassAttachment& subpass_attachment : |
| 221 render_pass_data.subpass_datas[i].subpass_attachments) { |
| 222 const uint32_t index = subpass_attachment.attachment_index; |
| 223 VulkanImageView* image_view = attachment_image_view[index]; |
| 224 |
| 225 VkAttachmentReference attachment_reference = {}; |
| 226 attachment_reference.attachment = index; |
| 227 attachment_reference.layout = |
| 228 ConvertImageLayout(image_view, subpass_attachment.subpass_layout); |
| 229 |
| 230 switch (image_view->image_type()) { |
| 231 case VulkanImageView::ImageType::IMAGE_TYPE_COLOR: |
| 232 color_refs[i].push_back(attachment_reference); |
| 233 break; |
| 234 case VulkanImageView::ImageType::IMAGE_TYPE_DEPTH: |
| 235 case VulkanImageView::ImageType::IMAGE_TYPE_STENCIL: |
| 236 case VulkanImageView::ImageType::IMAGE_TYPE_DEPTH_STENCIL: |
| 237 if (VK_ATTACHMENT_UNUSED != depth_stencil_refs[i].attachment) { |
| 238 DLOG(ERROR) << "Subpass cannot have multiple depth/stencil refs."; |
| 239 return false; |
| 240 } |
| 241 depth_stencil_refs[i] = attachment_reference; |
| 242 break; |
| 243 default: |
| 244 DLOG(ERROR) << "Invalid image type: " |
| 245 << static_cast<int>(image_view->image_type()); |
| 246 return false; |
| 247 } |
| 248 } |
| 249 |
| 250 VkSubpassDescription& subpass_desc = subpass_descs[i]; |
| 251 subpass_desc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; |
| 252 subpass_desc.colorAttachmentCount = color_refs[i].size(); |
| 253 subpass_desc.pColorAttachments = color_refs[i].data(); |
| 254 subpass_desc.pDepthStencilAttachment = &depth_stencil_refs[i]; |
| 255 } |
| 256 |
| 257 // Create VkRenderPass; |
| 258 VkRenderPassCreateInfo render_pass_create_info = {}; |
| 259 render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; |
| 260 render_pass_create_info.attachmentCount = |
| 261 static_cast<uint32_t>(attachment_descs.size()); |
| 262 render_pass_create_info.pAttachments = attachment_descs.data(); |
| 263 render_pass_create_info.subpassCount = subpass_descs.size(); |
| 264 render_pass_create_info.pSubpasses = subpass_descs.data(); |
| 265 |
| 266 result = vkCreateRenderPass(device, &render_pass_create_info, nullptr, |
| 267 &render_pass_); |
| 268 if (VK_SUCCESS != result) { |
| 269 DLOG(ERROR) << "vkCreateRenderPass() failed: " << result; |
| 270 return false; |
| 271 } |
| 272 |
| 273 // Initialize frame buffers. |
| 274 const uint32_t num_frame_buffers = swap_chain->num_images(); |
| 275 frame_buffers_.resize(num_frame_buffers); |
| 276 for (uint32_t i = 0; i < num_frame_buffers; ++i) { |
| 277 std::vector<VkImageView> image_views(num_attachments); |
| 278 uint32_t width = 0; |
| 279 uint32_t height = 0; |
| 280 uint32_t layers = 0; |
| 281 |
| 282 for (uint32_t n = 0; n < num_attachments; ++n) { |
| 283 const AttachmentData& attachment_data = render_pass_data.attachments[n]; |
| 284 VulkanImageView* image_view = nullptr; |
| 285 |
| 286 switch (attachment_data.attachment_type) { |
| 287 case AttachmentType::ATTACHMENT_TYPE_SWAP_IMAGE: |
| 288 image_view = swap_chain->GetImageView(n); |
| 289 break; |
| 290 case AttachmentType::ATTACHMENT_TYPE_ATTACHMENT_VIEW: |
| 291 image_view = attachment_data.image_view; |
| 292 break; |
| 293 } |
| 294 DCHECK(image_view); |
| 295 |
| 296 if (n == 0) { |
| 297 width = image_view->width(); |
| 298 height = image_view->height(); |
| 299 layers = image_view->layers(); |
| 300 } else if (width != image_view->width() || |
| 301 height != image_view->height() || |
| 302 layers != image_view->layers()) { |
| 303 DLOG(ERROR) << "Images in a frame buffer must have same dimensions."; |
| 304 return false; |
| 305 } |
| 306 |
| 307 image_views[n] = image_view->handle(); |
| 308 } |
| 309 |
| 310 VkFramebufferCreateInfo framebuffer_create_info = {}; |
| 311 framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; |
| 312 framebuffer_create_info.renderPass = render_pass_; |
| 313 framebuffer_create_info.attachmentCount = image_views.size(); |
| 314 framebuffer_create_info.pAttachments = image_views.data(); |
| 315 framebuffer_create_info.width = width; |
| 316 framebuffer_create_info.height = height; |
| 317 framebuffer_create_info.layers = layers; |
| 318 |
| 319 result = vkCreateFramebuffer(device, &framebuffer_create_info, nullptr, |
| 320 &frame_buffers_[i]); |
| 321 if (VK_SUCCESS != result) { |
| 322 DLOG(ERROR) << "vkCreateFramebuffer() failed: " << result; |
| 323 return false; |
| 324 } |
| 325 } |
| 326 |
| 327 return true; |
| 328 } |
| 329 |
| 330 void VulkanRenderPass::Destroy() { |
| 331 VkDevice device = GetVulkanDevice(); |
| 332 |
| 333 for (VkFramebuffer frame_buffer : frame_buffers_) { |
| 334 vkDestroyFramebuffer(device, frame_buffer, nullptr); |
| 335 } |
| 336 frame_buffers_.clear(); |
| 337 |
| 338 if (VK_NULL_HANDLE != render_pass_) { |
| 339 vkDestroyRenderPass(device, render_pass_, nullptr); |
| 340 render_pass_ = VK_NULL_HANDLE; |
| 341 } |
| 342 |
| 343 swap_chain_ = nullptr; |
| 344 attachment_clear_values_.clear(); |
| 345 attachment_clear_indexes_.clear(); |
| 346 } |
| 347 |
| 348 void VulkanRenderPass::BeginRenderPass( |
| 349 const CommandBufferRecorderBase& recorder, |
| 350 bool exec_inline) { |
| 351 DCHECK(!executing_); |
| 352 DCHECK_NE(0u, num_sub_passes_); |
| 353 executing_ = true; |
| 354 execution_type_ = exec_inline ? VK_SUBPASS_CONTENTS_INLINE |
| 355 : VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS; |
| 356 current_sub_pass_ = 0; |
| 357 |
| 358 const gfx::Size& size = swap_chain_->size(); |
| 359 |
| 360 VkRenderPassBeginInfo begin_info = {}; |
| 361 begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; |
| 362 begin_info.renderPass = render_pass_; |
| 363 begin_info.framebuffer = frame_buffers_[swap_chain_->current_image()]; |
| 364 begin_info.renderArea.extent.width = size.width(); |
| 365 begin_info.renderArea.extent.height = size.height(); |
| 366 begin_info.clearValueCount = |
| 367 static_cast<uint32_t>(attachment_clear_values_.size()); |
| 368 begin_info.pClearValues = attachment_clear_values_.data(); |
| 369 |
| 370 vkCmdBeginRenderPass(recorder.handle(), &begin_info, execution_type_); |
| 371 } |
| 372 |
| 373 void VulkanRenderPass::NextSubPass(const CommandBufferRecorderBase& recorder) { |
| 374 DCHECK(executing_); |
| 375 DCHECK_LT(current_sub_pass_ + 1, num_sub_passes_); |
| 376 vkCmdNextSubpass(recorder.handle(), execution_type_); |
| 377 current_sub_pass_++; |
| 378 } |
| 379 |
| 380 void VulkanRenderPass::EndRenderPass( |
| 381 const CommandBufferRecorderBase& recorder) { |
| 382 DCHECK(executing_); |
| 383 vkCmdEndRenderPass(recorder.handle()); |
| 384 executing_ = false; |
| 385 } |
| 386 |
| 387 void VulkanRenderPass::SetClearValue(uint32_t attachment_index, |
| 388 VkClearValue clear_value) { |
| 389 DCHECK_EQ(attachment_clear_values_.size(), attachment_clear_indexes_.size()); |
| 390 auto iter = |
| 391 std::lower_bound(attachment_clear_indexes_.begin(), |
| 392 attachment_clear_indexes_.end(), attachment_index); |
| 393 if (iter != attachment_clear_indexes_.end() && *iter == attachment_index) { |
| 394 const uint32_t index = iter - attachment_clear_indexes_.begin(); |
| 395 attachment_clear_values_[index] = clear_value; |
| 396 } |
| 397 } |
| 398 |
| 399 } // namespace gpu |
OLD | NEW |