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

Side by Side 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: removed unnecessary dependency 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 unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698