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 |