Chromium Code Reviews| 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 (num_image_views != 1 && num_image_views != swap_chain->num_images()) { | |
| 90 DLOG(ERROR) << "Invalid number of image views: " << num_image_views; | |
| 91 return false; | |
| 92 } | |
| 93 | |
| 94 if (nullptr == image_views) { | |
| 95 DLOG(ERROR) << "Must specify image view for image view attachment"; | |
| 96 return false; | |
| 97 } | |
| 98 | |
| 99 // All image views must match the same format if not sharing. | |
| 100 for (uint32_t i = 1; i < num_image_views; ++i) { | |
| 101 if (image_views[i].format() != image_views[0].format()) { | |
| 102 DLOG(ERROR) << "Image views in attachment must have the same format."; | |
| 103 return false; | |
| 104 } | |
| 105 } | |
| 106 } | |
| 107 #endif | |
| 108 | |
| 109 return true; | |
| 110 } | |
| 111 | |
| 112 VulkanRenderPass::SubpassData::SubpassData() {} | |
| 113 | |
| 114 VulkanRenderPass::SubpassData::~SubpassData() {} | |
| 115 | |
| 116 bool VulkanRenderPass::SubpassData::ValidateData( | |
| 117 uint32_t num_attachments) const { | |
| 118 #if DCHECK_IS_ON() | |
| 119 for (const SubpassAttachment subpass_attachment : subpass_attachments) { | |
| 120 if (subpass_attachment.attachment_index >= num_attachments) { | |
| 121 DLOG(ERROR) << "Invalid attachment index: " | |
| 122 << subpass_attachment.attachment_index << " < " | |
| 123 << num_attachments; | |
| 124 return false; | |
| 125 } | |
| 126 | |
| 127 const ImageLayoutType layout = subpass_attachment.subpass_layout; | |
| 128 if (layout < ImageLayoutType::IMAGE_LAYOUT_TYPE_IMAGE_VIEW || | |
| 129 layout > ImageLayoutType::IMAGE_LAYOUT_TYPE_PRESENT) { | |
| 130 DLOG(ERROR) << "Invalid subpass layout: " << static_cast<int>(layout); | |
| 131 return false; | |
| 132 } | |
| 133 } | |
| 134 #endif | |
| 135 | |
| 136 return true; | |
| 137 } | |
| 138 | |
| 139 VulkanRenderPass::RenderPassData::RenderPassData() {} | |
| 140 | |
| 141 VulkanRenderPass::RenderPassData::~RenderPassData() {} | |
| 142 | |
| 143 VulkanRenderPass::VulkanRenderPass() {} | |
| 144 | |
| 145 VulkanRenderPass::~VulkanRenderPass() { | |
| 146 DCHECK_EQ(static_cast<VkRenderPass>(VK_NULL_HANDLE), render_pass_); | |
| 147 DCHECK(frame_buffers_.empty()); | |
| 148 } | |
| 149 | |
| 150 bool VulkanRenderPass::RenderPassData::ValidateData( | |
| 151 const VulkanSwapChain* swap_chain) const { | |
| 152 #if DCHECK_IS_ON() | |
| 153 for (const AttachmentData& attachment : attachments) { | |
| 154 if (!attachment.ValidateData(swap_chain)) | |
| 155 return false; | |
| 156 } | |
| 157 | |
| 158 for (const SubpassData& subpass_data : subpass_datas) { | |
| 159 if (!subpass_data.ValidateData(attachments.size())) | |
| 160 return false; | |
| 161 } | |
| 162 #endif | |
| 163 | |
| 164 return true; | |
| 165 } | |
| 166 | |
| 167 bool VulkanRenderPass::Initialize(const VulkanSwapChain* swap_chain, | |
| 168 const RenderPassData& render_pass_data) { | |
| 169 DCHECK(!executing_); | |
| 170 DCHECK_EQ(static_cast<VkRenderPass>(VK_NULL_HANDLE), render_pass_); | |
| 171 DCHECK(frame_buffers_.empty()); | |
| 172 DCHECK(render_pass_data.ValidateData(swap_chain)); | |
| 173 | |
| 174 VkDevice device = GetVulkanDevice(); | |
| 175 VkResult result = VK_SUCCESS; | |
| 176 | |
| 177 swap_chain_ = swap_chain; | |
| 178 num_sub_passes_ = render_pass_data.subpass_datas.size(); | |
| 179 current_sub_pass_ = 0; | |
| 180 attachment_clear_values_.clear(); | |
| 181 attachment_clear_indexes_.clear(); | |
| 182 | |
| 183 // Fill out attachment information. | |
| 184 const uint32_t num_attachments = render_pass_data.attachments.size(); | |
| 185 std::vector<VkAttachmentDescription> attachment_descs(num_attachments); | |
| 186 std::vector<VulkanImageView*> attachment_image_view(num_attachments); | |
| 187 for (uint32_t i = 0; i < num_attachments; ++i) { | |
| 188 const AttachmentData& attachment_data = render_pass_data.attachments[i]; | |
| 189 | |
| 190 VulkanImageView* image_view = nullptr; | |
| 191 switch (attachment_data.attachment_type) { | |
| 192 case AttachmentType::ATTACHMENT_TYPE_SWAP_IMAGE: | |
| 193 // All the image views in the swap chain all share the same format. | |
| 194 image_view = swap_chain->GetCurrentImageView(); | |
| 195 break; | |
| 196 case AttachmentType::ATTACHMENT_TYPE_ATTACHMENT_VIEW: | |
| 197 // All the image views in the attachment should have the same format. | |
| 198 image_view = attachment_data.image_views; | |
| 199 break; | |
| 200 } | |
| 201 DCHECK(image_view); | |
| 202 attachment_image_view[i] = image_view; | |
| 203 | |
| 204 VkAttachmentDescription& attachment_desc = attachment_descs[i]; | |
| 205 attachment_desc.format = image_view->format(); | |
| 206 attachment_desc.samples = attachment_data.sample_count; | |
| 207 attachment_desc.loadOp = attachment_data.load_op; | |
| 208 attachment_desc.storeOp = attachment_data.store_op; | |
| 209 attachment_desc.stencilLoadOp = attachment_data.stencil_load_op; | |
| 210 attachment_desc.stencilStoreOp = attachment_data.stencil_store_op; | |
| 211 attachment_desc.initialLayout = | |
| 212 ConvertImageLayout(image_view, attachment_data.start_layout); | |
| 213 attachment_desc.finalLayout = | |
| 214 ConvertImageLayout(image_view, attachment_data.end_layout); | |
| 215 | |
| 216 if (attachment_desc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR || | |
| 217 attachment_desc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) { | |
| 218 attachment_clear_values_.push_back(attachment_data.clear_value); | |
| 219 attachment_clear_indexes_.push_back(i); | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 // Fill out subpass information. | |
| 224 std::vector<VkSubpassDescription> subpass_descs( | |
| 225 render_pass_data.subpass_datas.size()); | |
| 226 std::vector<std::vector<VkAttachmentReference>> color_refs( | |
| 227 render_pass_data.subpass_datas.size()); | |
| 228 for (uint32_t i = 0; i < render_pass_data.subpass_datas.size(); ++i) { | |
| 229 VkAttachmentReference depth_stencil_ref = {}; | |
| 230 depth_stencil_ref.attachment = VK_ATTACHMENT_UNUSED; | |
| 231 | |
| 232 for (const VulkanRenderPass::SubpassAttachment& subpass_attachment : | |
| 233 render_pass_data.subpass_datas[i].subpass_attachments) { | |
| 234 const uint32_t index = subpass_attachment.attachment_index; | |
| 235 VulkanImageView* image_view = attachment_image_view[index]; | |
| 236 | |
| 237 VkAttachmentReference attachment_reference = {}; | |
| 238 attachment_reference.attachment = index; | |
| 239 attachment_reference.layout = | |
| 240 ConvertImageLayout(image_view, subpass_attachment.subpass_layout); | |
| 241 | |
| 242 switch (image_view->image_type()) { | |
| 243 case VulkanImageView::ImageType::IMAGE_TYPE_COLOR: | |
| 244 color_refs[i].push_back(attachment_reference); | |
| 245 break; | |
| 246 case VulkanImageView::ImageType::IMAGE_TYPE_DEPTH: | |
| 247 case VulkanImageView::ImageType::IMAGE_TYPE_STENCIL: | |
| 248 case VulkanImageView::ImageType::IMAGE_TYPE_DEPTH_STENCIL: | |
| 249 if (VK_ATTACHMENT_UNUSED != depth_stencil_ref.attachment) { | |
| 250 DLOG(ERROR) << "Subpass cannot have multiple depth/stencil refs."; | |
| 251 return false; | |
| 252 } | |
| 253 depth_stencil_ref = attachment_reference; | |
| 254 break; | |
| 255 default: | |
| 256 DLOG(ERROR) << "Invalid image type: " | |
| 257 << static_cast<int>(image_view->image_type()); | |
| 258 return false; | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 VkSubpassDescription& subpass_desc = subpass_descs[i]; | |
| 263 subpass_desc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; | |
| 264 subpass_desc.colorAttachmentCount = color_refs[i].size(); | |
| 265 subpass_desc.pColorAttachments = color_refs[i].data(); | |
| 266 subpass_desc.pDepthStencilAttachment = &depth_stencil_ref; | |
|
piman
2016/03/25 02:01:26
depth_stencil_ref is a local variable. Its pointer
David Yen
2016/03/25 17:36:14
Fixed the reference. According to the docs both wo
piman
2016/03/25 21:13:22
Ah, ok, you're right.
| |
| 267 } | |
| 268 | |
| 269 // Create VkRenderPass; | |
| 270 VkRenderPassCreateInfo render_pass_create_info = {}; | |
| 271 render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; | |
| 272 render_pass_create_info.attachmentCount = | |
| 273 static_cast<uint32_t>(attachment_descs.size()); | |
| 274 render_pass_create_info.pAttachments = attachment_descs.data(); | |
| 275 render_pass_create_info.subpassCount = subpass_descs.size(); | |
| 276 render_pass_create_info.pSubpasses = subpass_descs.data(); | |
| 277 | |
| 278 result = vkCreateRenderPass(device, &render_pass_create_info, nullptr, | |
| 279 &render_pass_); | |
| 280 if (VK_SUCCESS != result) { | |
| 281 DLOG(ERROR) << "vkCreateRenderPass() failed: " << result; | |
| 282 return false; | |
| 283 } | |
| 284 | |
| 285 // Initialize frame buffers. | |
| 286 const uint32_t num_frame_buffers = swap_chain->num_images(); | |
| 287 frame_buffers_.resize(num_frame_buffers); | |
| 288 for (uint32_t i = 0; i < num_frame_buffers; ++i) { | |
| 289 std::vector<VkImageView> image_views(num_attachments); | |
| 290 uint32_t width = 0; | |
| 291 uint32_t height = 0; | |
| 292 uint32_t layers = 0; | |
| 293 | |
| 294 for (uint32_t n = 0; n < num_attachments; ++n) { | |
| 295 const AttachmentData& attachment_data = render_pass_data.attachments[n]; | |
| 296 VulkanImageView* image_view = nullptr; | |
| 297 | |
| 298 switch (attachment_data.attachment_type) { | |
| 299 case AttachmentType::ATTACHMENT_TYPE_SWAP_IMAGE: | |
| 300 image_view = swap_chain->GetImageView(n); | |
| 301 break; | |
| 302 case AttachmentType::ATTACHMENT_TYPE_ATTACHMENT_VIEW: | |
| 303 if (attachment_data.num_image_views == 1) { | |
| 304 image_view = attachment_data.image_views; | |
| 305 } else if (attachment_data.num_image_views == num_attachments) { | |
| 306 image_view = &attachment_data.image_views[n]; | |
| 307 } else { | |
| 308 DLOG(ERROR) << "Invalid attachment image view count: " | |
| 309 << attachment_data.num_image_views; | |
| 310 return false; | |
| 311 } | |
| 312 break; | |
| 313 } | |
| 314 DCHECK(image_view); | |
| 315 | |
| 316 if (n == 0) { | |
| 317 width = image_view->width(); | |
| 318 height = image_view->height(); | |
| 319 layers = image_view->layers(); | |
| 320 } else if (width != image_view->width() || | |
| 321 height != image_view->height() || | |
| 322 layers != image_view->layers()) { | |
| 323 DLOG(ERROR) << "Images in a frame buffer must have same dimensions."; | |
| 324 return false; | |
| 325 } | |
| 326 | |
| 327 image_views[n] = image_view->handle(); | |
| 328 } | |
| 329 | |
| 330 VkFramebufferCreateInfo framebuffer_create_info = {}; | |
| 331 framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; | |
| 332 framebuffer_create_info.renderPass = render_pass_; | |
| 333 framebuffer_create_info.attachmentCount = image_views.size(); | |
| 334 framebuffer_create_info.pAttachments = image_views.data(); | |
| 335 framebuffer_create_info.width = width; | |
| 336 framebuffer_create_info.height = height; | |
| 337 framebuffer_create_info.layers = layers; | |
| 338 | |
| 339 result = vkCreateFramebuffer(device, &framebuffer_create_info, nullptr, | |
| 340 &frame_buffers_[i]); | |
| 341 if (VK_SUCCESS != result) { | |
| 342 DLOG(ERROR) << "vkCreateFramebuffer() failed: " << result; | |
| 343 return false; | |
| 344 } | |
| 345 } | |
| 346 | |
| 347 return true; | |
| 348 } | |
| 349 | |
| 350 void VulkanRenderPass::Destroy() { | |
| 351 VkDevice device = GetVulkanDevice(); | |
| 352 | |
| 353 for (VkFramebuffer frame_buffer : frame_buffers_) { | |
| 354 vkDestroyFramebuffer(device, frame_buffer, nullptr); | |
| 355 } | |
| 356 frame_buffers_.clear(); | |
| 357 | |
| 358 if (VK_NULL_HANDLE != render_pass_) { | |
| 359 vkDestroyRenderPass(device, render_pass_, nullptr); | |
| 360 render_pass_ = VK_NULL_HANDLE; | |
| 361 } | |
| 362 | |
| 363 swap_chain_ = nullptr; | |
| 364 attachment_clear_values_.clear(); | |
| 365 attachment_clear_indexes_.clear(); | |
| 366 } | |
| 367 | |
| 368 void VulkanRenderPass::BeginRenderPass( | |
| 369 const CommandBufferRecorderBase& recorder, | |
| 370 bool exec_inline) { | |
| 371 DCHECK(!executing_); | |
| 372 DCHECK_NE(0u, num_sub_passes_); | |
| 373 executing_ = true; | |
| 374 execution_type_ = exec_inline ? VK_SUBPASS_CONTENTS_INLINE | |
| 375 : VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS; | |
| 376 current_sub_pass_ = 0; | |
| 377 | |
| 378 const gfx::Size& size = swap_chain_->size(); | |
| 379 | |
| 380 VkRenderPassBeginInfo begin_info = {}; | |
| 381 begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; | |
| 382 begin_info.renderPass = render_pass_; | |
| 383 begin_info.framebuffer = frame_buffers_[swap_chain_->current_image()]; | |
| 384 begin_info.renderArea.extent.width = size.width(); | |
| 385 begin_info.renderArea.extent.height = size.height(); | |
| 386 begin_info.clearValueCount = | |
| 387 static_cast<uint32_t>(attachment_clear_values_.size()); | |
| 388 begin_info.pClearValues = attachment_clear_values_.data(); | |
| 389 | |
| 390 vkCmdBeginRenderPass(recorder.handle(), &begin_info, execution_type_); | |
| 391 } | |
| 392 | |
| 393 void VulkanRenderPass::NextSubPass(const CommandBufferRecorderBase& recorder) { | |
| 394 DCHECK(executing_); | |
| 395 DCHECK_LT(current_sub_pass_ + 1, num_sub_passes_); | |
| 396 vkCmdNextSubpass(recorder.handle(), execution_type_); | |
| 397 current_sub_pass_++; | |
| 398 } | |
| 399 | |
| 400 void VulkanRenderPass::EndRenderPass( | |
| 401 const CommandBufferRecorderBase& recorder) { | |
| 402 DCHECK(executing_); | |
| 403 vkCmdEndRenderPass(recorder.handle()); | |
| 404 executing_ = false; | |
| 405 } | |
| 406 | |
| 407 void VulkanRenderPass::SetClearValue(uint32_t attachment_index, | |
| 408 VkClearValue clear_value) { | |
| 409 DCHECK_EQ(attachment_clear_values_.size(), attachment_clear_indexes_.size()); | |
| 410 auto iter = | |
| 411 std::lower_bound(attachment_clear_indexes_.begin(), | |
| 412 attachment_clear_indexes_.end(), attachment_index); | |
| 413 if (iter != attachment_clear_indexes_.end() && *iter == attachment_index) { | |
| 414 const uint32_t index = iter - attachment_clear_indexes_.begin(); | |
| 415 attachment_clear_values_[index] = clear_value; | |
| 416 } | |
| 417 } | |
| 418 | |
| 419 } // namespace gpu | |
| OLD | NEW |