Blender V4.5
vk_framebuffer.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "vk_framebuffer.hh"
10#include "vk_backend.hh"
11#include "vk_context.hh"
12#include "vk_state_manager.hh"
13#include "vk_texture.hh"
14
15namespace blender::gpu {
16
21{
22 return {GPU_LOADACTION_LOAD, GPU_STOREACTION_STORE, {0.0f, 0.0f, 0.0f, 0.0f}};
23}
24
25/* -------------------------------------------------------------------- */
28
30 : FrameBuffer(name),
33{
34 size_set(1, 1);
35 srgb_ = false;
36 enabled_srgb_ = false;
37}
38
40{
41 VKContext *context = VKContext::get();
42 if (context && context->active_framebuffer_get() == this) {
43 context->deactivate_framebuffer();
44 }
45 render_pass_free();
46}
47
48void VKFrameBuffer::render_pass_free()
49{
51 if (vk_framebuffer != VK_NULL_HANDLE) {
52 discard_pool.discard_framebuffer(vk_framebuffer);
53 vk_framebuffer = VK_NULL_HANDLE;
54 }
55 if (vk_render_pass != VK_NULL_HANDLE) {
57 vk_render_pass = VK_NULL_HANDLE;
58 }
59}
60
62
63void VKFrameBuffer::bind(bool enabled_srgb)
64{
65 VKContext &context = *VKContext::get();
66 /* Updating attachments can issue pipeline barriers, this should be done outside the render pass.
67 * When done inside a render pass there should be a self-dependency between sub-passes on the
68 * active render pass. As the active render pass isn't aware of the new render pass (and should
69 * not) it is better to deactivate it before updating the attachments. For more information check
70 * `VkSubpassDependency`. */
71 if (context.has_active_framebuffer()) {
72 context.deactivate_framebuffer();
73 }
74
75 context.activate_framebuffer(*this);
79
80 enabled_srgb_ = enabled_srgb;
81 Shader::set_framebuffer_srgb_target(enabled_srgb && srgb_);
82 load_stores.fill(default_load_store());
83 attachment_states_.fill(GPU_ATTACHMENT_WRITE);
84}
85
87{
88 BLI_assert(r_viewports.is_empty());
89 for (int64_t index : IndexRange(this->multi_viewport_ ? GPU_MAX_VIEWPORTS : 1)) {
90 VkViewport viewport;
91 viewport.x = viewport_[index][0];
92 viewport.y = viewport_[index][1];
93 viewport.width = viewport_[index][2];
94 viewport.height = viewport_[index][3];
95 viewport.minDepth = 0.0f;
96 viewport.maxDepth = 1.0f;
97 r_viewports.append(viewport);
98 }
99}
100
101void VKFrameBuffer::render_area_update(VkRect2D &render_area) const
102{
103 if (scissor_test_get()) {
104 int scissor_rect[4];
105 scissor_get(scissor_rect);
106 render_area.offset.x = clamp_i(scissor_rect[0], 0, width_);
107 render_area.offset.y = clamp_i(scissor_rect[1], 0, height_);
108 render_area.extent.width = clamp_i(scissor_rect[2], 1, width_ - scissor_rect[0]);
109 render_area.extent.height = clamp_i(scissor_rect[3], 1, height_ - scissor_rect[1]);
110 }
111 else {
112 render_area.offset.x = 0;
113 render_area.offset.y = 0;
114 render_area.extent.width = width_;
115 render_area.extent.height = height_;
116 }
117}
118
120{
121 BLI_assert(r_render_areas.is_empty());
122 VkRect2D render_area;
123 render_area_update(render_area);
124 r_render_areas.append_n_times(render_area, this->multi_viewport_ ? GPU_MAX_VIEWPORTS : 1);
125}
126
127bool VKFrameBuffer::check(char err_out[256])
128{
129 bool success = true;
130
131 if (has_gaps_between_color_attachments()) {
132 success = false;
133
134 BLI_snprintf(err_out,
135 256,
136 "Framebuffer '%s' has gaps between color attachments. This is not supported by "
137 "legacy devices using VkRenderPass natively.\n",
138 name_);
139 }
140
141 return success;
142}
143
144bool VKFrameBuffer::has_gaps_between_color_attachments() const
145{
146 bool empty_slot = false;
148 const GPUAttachment &attachment = attachments_[attachment_index];
149 if (attachment.tex == nullptr) {
150 empty_slot = true;
151 }
152 else if (empty_slot) {
153 return true;
154 }
155 }
156 return false;
157}
158
159void VKFrameBuffer::build_clear_attachments_depth_stencil(
161 float clear_depth,
162 uint32_t clear_stencil,
164{
165 VkImageAspectFlags aspect_mask = (buffers & GPU_DEPTH_BIT ? VK_IMAGE_ASPECT_DEPTH_BIT : 0) |
166 (buffers & GPU_STENCIL_BIT ? VK_IMAGE_ASPECT_STENCIL_BIT : 0);
167
168 VkClearAttachment &clear_attachment =
169 clear_attachments.attachments[clear_attachments.attachment_count++];
170 clear_attachment.aspectMask = aspect_mask;
171 clear_attachment.clearValue.depthStencil.depth = clear_depth;
172 clear_attachment.clearValue.depthStencil.stencil = clear_stencil;
173 clear_attachment.colorAttachment = 0;
174}
175
176void VKFrameBuffer::build_clear_attachments_color(
177 const float (*clear_colors)[4],
178 const bool multi_clear_colors,
180{
181 int color_index = 0;
182 for (int color_slot = 0; color_slot < GPU_FB_MAX_COLOR_ATTACHMENT; color_slot++) {
183 const GPUAttachment &attachment = attachments_[GPU_FB_COLOR_ATTACHMENT0 + color_slot];
184 if (attachment.tex == nullptr) {
185 continue;
186 }
187 VkClearAttachment &clear_attachment =
188 clear_attachments.attachments[clear_attachments.attachment_count++];
189 clear_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
190 clear_attachment.colorAttachment = color_slot;
191 eGPUDataFormat data_format = to_data_format(GPU_texture_format(attachment.tex));
192 clear_attachment.clearValue.color = to_vk_clear_color_value(data_format,
193 &clear_colors[color_index]);
194
195 color_index += multi_clear_colors ? 1 : 0;
196 }
197}
198
199/* -------------------------------------------------------------------- */
202
204{
205 VKContext &context = *VKContext::get();
206 rendering_ensure(context);
207 context.render_graph().add_node(clear_attachments);
208}
209
211 const float clear_color[4],
212 float clear_depth,
213 uint clear_stencil)
214{
216 render_area_update(clear_attachments.vk_clear_rect.rect);
217 clear_attachments.vk_clear_rect.baseArrayLayer = 0;
218 clear_attachments.vk_clear_rect.layerCount = 1;
219
221 VKContext &context = *VKContext::get();
222 eGPUWriteMask needed_mask = GPU_WRITE_NONE;
223 if (buffers & GPU_DEPTH_BIT) {
224 needed_mask |= GPU_WRITE_DEPTH;
225 }
226 if (buffers & GPU_STENCIL_BIT) {
227 needed_mask |= GPU_WRITE_STENCIL;
228 }
229
230 /* Clearing depth via #vkCmdClearAttachments requires a render pass with write depth or stencil
231 * enabled. When not enabled, clearing should be done via texture directly. */
232 /* WORKAROUND: Clearing depth attachment when using dynamic rendering are not working on AMD
233 * official drivers.
234 * See #129265 */
235 if ((context.state_manager_get().state.write_mask & needed_mask) == needed_mask &&
237 {
238 build_clear_attachments_depth_stencil(
239 buffers, clear_depth, clear_stencil, clear_attachments);
240 }
241 else {
242 const GPUAttachment &attachment = depth_attachment();
243 VKTexture *depth_texture = unwrap(unwrap(attachment.tex));
244 if (depth_texture != nullptr) {
245 depth_texture->clear_depth_stencil(
246 buffers,
247 clear_depth,
248 clear_stencil,
249 attachment.layer == -1 ? std::nullopt : std::make_optional(attachment.layer));
250 }
251 }
252 }
253 if (buffers & GPU_COLOR_BIT) {
254 float clear_color_single[4];
255 copy_v4_v4(clear_color_single, clear_color);
256 build_clear_attachments_color(&clear_color_single, false, clear_attachments);
257 }
258
259 if (clear_attachments.attachment_count) {
260 clear(clear_attachments);
261 }
262}
263
264void VKFrameBuffer::clear_multi(const float (*clear_color)[4])
265{
267 render_area_update(clear_attachments.vk_clear_rect.rect);
268 clear_attachments.vk_clear_rect.baseArrayLayer = 0;
269 clear_attachments.vk_clear_rect.layerCount = 1;
270
271 build_clear_attachments_color(clear_color, true, clear_attachments);
272 if (clear_attachments.attachment_count) {
273 clear(clear_attachments);
274 }
275}
276
278 eGPUDataFormat /*data_format*/,
279 const void * /*clear_value*/)
280{
281 /* Clearing of a single attachment was added to implement `clear_multi` in OpenGL. As
282 * `clear_multi` is supported in Vulkan it isn't needed to implement this method.
283 */
285}
286
288
289/* -------------------------------------------------------------------- */
292
294{
295 load_stores[type] = ls;
296}
297
298static VkAttachmentLoadOp to_vk_attachment_load_op(eGPULoadOp load_op)
299{
300 switch (load_op) {
302 return VK_ATTACHMENT_LOAD_OP_DONT_CARE;
304 return VK_ATTACHMENT_LOAD_OP_CLEAR;
306 return VK_ATTACHMENT_LOAD_OP_LOAD;
307 }
309 return VK_ATTACHMENT_LOAD_OP_LOAD;
310}
311
312static VkAttachmentStoreOp to_vk_attachment_store_op(eGPUStoreOp store_op)
313{
314 switch (store_op) {
316 return VK_ATTACHMENT_STORE_OP_DONT_CARE;
318 return VK_ATTACHMENT_STORE_OP_STORE;
319 }
321 return VK_ATTACHMENT_STORE_OP_STORE;
322}
323
324static void set_load_store(VkRenderingAttachmentInfo &r_rendering_attachment,
325 const GPULoadStore &ls)
326{
327 copy_v4_v4(r_rendering_attachment.clearValue.color.float32, ls.clear_value);
328 r_rendering_attachment.loadOp = to_vk_attachment_load_op(ls.load_action);
329 r_rendering_attachment.storeOp = to_vk_attachment_store_op(ls.store_action);
330}
331
333
334/* -------------------------------------------------------------------- */
337
339 Span<GPUAttachmentState> color_attachment_states)
340{
341 const VKDevice &device = VKBackend::get().device;
342 const bool supports_local_read = device.extensions_get().dynamic_rendering_local_read;
343
344 attachment_states_[GPU_FB_DEPTH_ATTACHMENT] = depth_attachment_state;
345 attachment_states_.as_mutable_span()
346 .slice(GPU_FB_COLOR_ATTACHMENT0, color_attachment_states.size())
347 .copy_from(color_attachment_states);
348
349 if (supports_local_read) {
350 VKContext &context = *VKContext::get();
351
352 for (int index : IndexRange(color_attachment_states.size())) {
353 if (color_attachment_states[index] == GPU_ATTACHMENT_READ) {
355 if (texture) {
356 context.state_manager_get().image_bind(texture, index);
357 }
358 }
359 }
360 if (is_rendering_) {
361 is_rendering_ = false;
362 load_stores.fill(default_load_store());
363 }
364 }
365 else {
366 VKContext &context = *VKContext::get();
367 if (is_rendering_) {
368 rendering_end(context);
369
370 /* TODO: this might need a better implementation:
371 * READ -> DONTCARE
372 * WRITE -> LOAD, STORE based on previous value.
373 * IGNORE -> DONTCARE -> IGNORE */
374 load_stores.fill(default_load_store());
375 }
376
377 for (int index : IndexRange(color_attachment_states.size())) {
378 if (color_attachment_states[index] == GPU_ATTACHMENT_READ) {
380 if (texture) {
381 context.state_manager_get().texture_bind(
383 }
384 }
385 }
386 }
387}
388
390
391/* -------------------------------------------------------------------- */
394
397 const int area[4],
398 int /*channel_len*/,
399 int slot,
400 void *r_data)
401{
402 GPUAttachment *attachment = nullptr;
403 switch (plane) {
404 case GPU_COLOR_BIT:
405 attachment = &attachments_[GPU_FB_COLOR_ATTACHMENT0 + slot];
406 break;
407
408 case GPU_DEPTH_BIT:
409 attachment = attachments_[GPU_FB_DEPTH_ATTACHMENT].tex ?
412 break;
413
414 default:
416 return;
417 }
418
419 VKTexture *texture = unwrap(unwrap(attachment->tex));
421 "Trying to read back texture from framebuffer, but no texture is available in "
422 "requested slot.");
423 if (texture == nullptr) {
424 return;
425 }
426 const int region[6] = {area[0], area[1], 0, area[0] + area[2], area[1] + area[3], 1};
427 IndexRange layers(max_ii(attachment->layer, 0), 1);
428 texture->read_sub(0, format, region, layers, r_data);
429}
430
432
433/* -------------------------------------------------------------------- */
436
437static void blit_aspect(VKContext &context,
438 VKTexture &dst_texture,
439 VKTexture &src_texture,
440 int dst_offset_x,
441 int dst_offset_y,
442 VkImageAspectFlags image_aspect)
443{
444 /* Prefer texture copy, as some platforms don't support using D32_SFLOAT_S8_UINT to be used as
445 * a blit destination. */
446 if (dst_offset_x == 0 && dst_offset_y == 0 &&
447 dst_texture.device_format_get() == src_texture.device_format_get() &&
448 src_texture.width_get() == dst_texture.width_get() &&
449 src_texture.height_get() == dst_texture.height_get())
450 {
451 src_texture.copy_to(dst_texture, image_aspect);
452 return;
453 }
454
456
457 blit_image.src_image = src_texture.vk_image_handle();
458 blit_image.dst_image = dst_texture.vk_image_handle();
459 blit_image.filter = VK_FILTER_NEAREST;
460
461 VkImageBlit &region = blit_image.region;
462 region.srcSubresource.aspectMask = image_aspect;
463 region.srcSubresource.mipLevel = 0;
464 region.srcSubresource.baseArrayLayer = 0;
465 region.srcSubresource.layerCount = 1;
466 region.srcOffsets[0].x = 0;
467 region.srcOffsets[0].y = 0;
468 region.srcOffsets[0].z = 0;
469 region.srcOffsets[1].x = src_texture.width_get();
470 region.srcOffsets[1].y = src_texture.height_get();
471 region.srcOffsets[1].z = 1;
472
473 region.dstSubresource.aspectMask = image_aspect;
474 region.dstSubresource.mipLevel = 0;
475 region.dstSubresource.baseArrayLayer = 0;
476 region.dstSubresource.layerCount = 1;
477 region.dstOffsets[0].x = clamp_i(dst_offset_x, 0, dst_texture.width_get());
478 region.dstOffsets[0].y = clamp_i(dst_offset_y, 0, dst_texture.height_get());
479 region.dstOffsets[0].z = 0;
480 region.dstOffsets[1].x = clamp_i(
481 dst_offset_x + src_texture.width_get(), 0, dst_texture.width_get());
482 region.dstOffsets[1].y = clamp_i(
483 dst_offset_y + src_texture.height_get(), 0, dst_texture.height_get());
484 region.dstOffsets[1].z = 1;
485
486 context.render_graph().add_node(blit_image);
487}
488
490 int src_slot,
491 FrameBuffer *dst,
492 int dst_slot,
493 int dst_offset_x,
494 int dst_offset_y)
495{
496 BLI_assert(dst);
498 "VKFrameBuffer::blit_to only supports a single color or depth aspect.");
499 UNUSED_VARS_NDEBUG(planes);
500
501 VKContext &context = *VKContext::get();
502 if (!context.has_active_framebuffer()) {
504 return;
505 }
506
507 VKFrameBuffer &dst_framebuffer = *unwrap(dst);
508 if (planes & GPU_COLOR_BIT) {
509 const GPUAttachment &src_attachment = attachments_[GPU_FB_COLOR_ATTACHMENT0 + src_slot];
510 const GPUAttachment &dst_attachment =
511 dst_framebuffer.attachments_[GPU_FB_COLOR_ATTACHMENT0 + dst_slot];
512 if (src_attachment.tex && dst_attachment.tex) {
513 VKTexture &src_texture = *unwrap(unwrap(src_attachment.tex));
514 VKTexture &dst_texture = *unwrap(unwrap(dst_attachment.tex));
515 blit_aspect(context,
516 dst_texture,
517 src_texture,
518 dst_offset_x,
519 dst_offset_y,
520 VK_IMAGE_ASPECT_COLOR_BIT);
521 }
522 }
523
524 if (planes & GPU_DEPTH_BIT) {
525 /* Retrieve source texture. */
526 const GPUAttachment &src_attachment = attachments_[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex ?
529 const GPUAttachment &dst_attachment =
532 dst_framebuffer.attachments_[GPU_FB_DEPTH_ATTACHMENT];
533 if (src_attachment.tex && dst_attachment.tex) {
534 VKTexture &src_texture = *unwrap(unwrap(src_attachment.tex));
535 VKTexture &dst_texture = *unwrap(unwrap(dst_attachment.tex));
536 blit_aspect(context,
537 dst_texture,
538 src_texture,
539 dst_offset_x,
540 dst_offset_y,
541 VK_IMAGE_ASPECT_DEPTH_BIT);
542 }
543 }
544}
545
547
548/* -------------------------------------------------------------------- */
551
553{
554 if (!dirty_attachments_) {
555 return;
556 }
557
558 for (int i = 0; i < GPU_FB_MAX_ATTACHMENT; i++) {
559 GPUAttachment &attachment = attachments_[i];
560 if (attachment.tex) {
561 int size[3];
562 GPU_texture_get_mipmap_size(attachment.tex, attachment.mip, size);
563 size_set(size[0], size[1]);
564 return;
565 }
566 }
567}
568
570{
573 if (texture) {
574 srgb_ = (texture->format_flag_get() & GPU_FORMAT_SRGB) != 0;
575 return;
576 }
577 }
578}
579
581{
582 int size = 0;
583 for (int color_slot : IndexRange(GPU_FB_MAX_COLOR_ATTACHMENT)) {
584 if (color_tex(color_slot) != nullptr) {
585 size = max_ii(color_slot + 1, size);
586 }
587 }
588 return size;
589}
590
592
594{
595 is_rendering_ = false;
596}
597
599{
600 render_pass_free();
601
602 depth_attachment_format_ = VK_FORMAT_UNDEFINED;
603 stencil_attachment_format_ = VK_FORMAT_UNDEFINED;
604
606 Vector<VkAttachmentDescription> vk_attachment_descriptions;
607 Vector<VkAttachmentReference> color_attachments;
608 Vector<VkAttachmentReference> input_attachments;
609 Vector<VkImageView> vk_image_views;
610
611 uint32_t max_layer_count = 1;
612
613 /* Color attachments */
614 VkAttachmentReference depth_attachment_reference = {0u};
615 for (int color_attachment_index :
617 {
618 const GPUAttachment &attachment = attachments_[color_attachment_index];
619 if (attachment.tex == nullptr) {
620 continue;
621 }
622 VKTexture &color_texture = *unwrap(unwrap(attachment.tex));
624 "Texture is used as an attachment, but doesn't have the "
625 "GPU_TEXTURE_USAGE_ATTACHMENT flag.");
626 GPUAttachmentState attachment_state = attachment_states_[color_attachment_index];
627 uint32_t layer_base = max_ii(attachment.layer, 0);
628 int layer_count = color_texture.layer_count();
629 if (attachment.layer == -1 && layer_count != 1) {
630 max_layer_count = max_ii(max_layer_count, layer_count);
631 }
632
633 VKImageViewInfo image_view_info = {
635 IndexRange(layer_base,
636 layer_count != 1 ? max_ii(layer_count - layer_base, 1) : layer_count),
637 IndexRange(attachment.mip, 1),
638 {{'r', 'g', 'b', 'a'}},
639 false,
640 srgb_ && enabled_srgb_,
642 const VKImageView &image_view = color_texture.image_view_get(image_view_info);
643 // TODO: Use VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL for readonly attachments.
644 VkImageLayout vk_image_layout = (attachment_state == GPU_ATTACHMENT_READ) ?
645 VK_IMAGE_LAYOUT_GENERAL :
646 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
647 uint32_t attachment_reference = color_attachment_index - GPU_FB_COLOR_ATTACHMENT0;
648 /* Depth attachment should always be right after the last color attachment. If not shaders
649 * cannot be reused between frame-buffers with and without depth/stencil attachment. */
650 depth_attachment_reference.attachment = attachment_reference + 1;
651
652 VkAttachmentDescription vk_attachment_description = {};
653 vk_attachment_description.format = image_view.vk_format();
654 vk_attachment_description.samples = VK_SAMPLE_COUNT_1_BIT;
655 vk_attachment_description.initialLayout = vk_image_layout;
656 vk_attachment_description.finalLayout = vk_image_layout;
657 vk_attachment_descriptions.append(std::move(vk_attachment_description));
658 vk_image_views.append(image_view.vk_handle());
659
660 switch (attachment_state) {
662 color_attachments.append({attachment_reference, vk_image_layout});
663
664 access_info.images.append(
665 {color_texture.vk_image_handle(),
666 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
667 VK_IMAGE_ASPECT_COLOR_BIT,
668 layer_base});
669 break;
670 }
671
672 case GPU_ATTACHMENT_READ: {
673 input_attachments.append({attachment_reference, vk_image_layout});
674 access_info.images.append({color_texture.vk_image_handle(),
675 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
676 VK_IMAGE_ASPECT_COLOR_BIT,
677 layer_base});
678 break;
679 }
680
682 input_attachments.append({VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED});
683 break;
684 }
685 }
686 }
687
688 /* Update the color attachment size attribute. This is used to generate the correct amount of
689 * color blend states in the graphics pipeline. */
690 color_attachment_size = color_attachments.size();
691
692 /* Depth attachment */
693 bool has_depth_attachment = false;
694 for (int depth_attachment_index : IndexRange(GPU_FB_DEPTH_ATTACHMENT, 2)) {
695 const GPUAttachment &attachment = attachments_[depth_attachment_index];
696
697 if (attachment.tex == nullptr) {
698 continue;
699 }
700 has_depth_attachment = true;
701 bool is_stencil_attachment = depth_attachment_index == GPU_FB_DEPTH_STENCIL_ATTACHMENT;
702 VKTexture &depth_texture = *unwrap(unwrap(attachment.tex));
704 "Texture is used as an attachment, but doesn't have the "
705 "GPU_TEXTURE_USAGE_ATTACHMENT flag.");
706 VkImageAspectFlags depth_texture_aspect = to_vk_image_aspect_flag_bits(
707 depth_texture.device_format_get());
708 bool is_depth_stencil_attachment = depth_texture_aspect & VK_IMAGE_ASPECT_STENCIL_BIT;
709 VkImageLayout vk_image_layout = is_depth_stencil_attachment ?
710 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
711 VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
712 GPUAttachmentState attachment_state = attachment_states_[GPU_FB_DEPTH_ATTACHMENT];
713 VkImageView depth_image_view = VK_NULL_HANDLE;
714 uint32_t layer_base = max_ii(attachment.layer, 0);
715 if (attachment_state == GPU_ATTACHMENT_WRITE) {
717 IndexRange(layer_base, 1),
718 IndexRange(attachment.mip, 1),
719 {{'r', 'g', 'b', 'a'}},
720 is_stencil_attachment,
721 false,
723 depth_image_view = depth_texture.image_view_get(image_view_info).vk_handle();
724 }
725 VkAttachmentDescription vk_attachment_description = {};
726 vk_attachment_description.format = to_vk_format(depth_texture.device_format_get());
727 vk_attachment_description.samples = VK_SAMPLE_COUNT_1_BIT;
728 vk_attachment_description.initialLayout = vk_image_layout;
729 vk_attachment_description.finalLayout = vk_image_layout;
730 vk_attachment_descriptions.append(std::move(vk_attachment_description));
731 depth_attachment_reference.layout = vk_image_layout;
732 vk_image_views.append(depth_image_view);
733 access_info.images.append({depth_texture.vk_image_handle(),
734 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
735 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
736 is_stencil_attachment ?
737 static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT |
738 VK_IMAGE_ASPECT_STENCIL_BIT) :
739 static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT),
740 0});
741
742 VkFormat vk_format = to_vk_format(depth_texture.device_format_get());
743 depth_attachment_format_ = vk_format;
744 if (is_stencil_attachment) {
745 stencil_attachment_format_ = vk_format;
746 }
747 }
748
749 /* Sub-pass description. */
750 VkSubpassDescription vk_subpass_description = {};
751 vk_subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
752 vk_subpass_description.colorAttachmentCount = color_attachments.size();
753 vk_subpass_description.pColorAttachments = color_attachments.data();
754 vk_subpass_description.inputAttachmentCount = input_attachments.size();
755 vk_subpass_description.pInputAttachments = input_attachments.data();
756 if (has_depth_attachment) {
757 vk_subpass_description.pDepthStencilAttachment = &depth_attachment_reference;
758 }
759
760 VKDevice &device = VKBackend::get().device;
761 /* Render-pass create info. */
762 VkRenderPassCreateInfo vk_render_pass_create_info = {};
763 vk_render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
764 vk_render_pass_create_info.subpassCount = 1;
765 vk_render_pass_create_info.pSubpasses = &vk_subpass_description;
766 vk_render_pass_create_info.attachmentCount = vk_attachment_descriptions.size();
767 vk_render_pass_create_info.pAttachments = vk_attachment_descriptions.data();
768 vkCreateRenderPass(device.vk_handle(), &vk_render_pass_create_info, nullptr, &vk_render_pass);
770
771 /* Frame buffer create info */
772 VkFramebufferCreateInfo vk_framebuffer_create_info = {};
773 vk_framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
774 vk_framebuffer_create_info.renderPass = vk_render_pass;
775 vk_framebuffer_create_info.attachmentCount = vk_image_views.size();
776 vk_framebuffer_create_info.pAttachments = vk_image_views.data();
777 vk_framebuffer_create_info.width = width_;
778 vk_framebuffer_create_info.height = height_;
779 vk_framebuffer_create_info.layers = max_layer_count;
780 vkCreateFramebuffer(device.vk_handle(), &vk_framebuffer_create_info, nullptr, &vk_framebuffer);
781 debug::object_label(vk_framebuffer, name_);
782
783 /* Begin rendering */
784 render_graph::VKBeginRenderingNode::CreateInfo begin_rendering(access_info);
785 VkRenderPassBeginInfo &begin_info = begin_rendering.node_data.vk_render_pass_begin_info;
786 begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
787 begin_info.renderPass = vk_render_pass;
788 begin_info.framebuffer = vk_framebuffer;
789 render_area_update(begin_info.renderArea);
790
791 context.render_graph().add_node(begin_rendering);
792
793 /* Load store operations are not supported inside a render pass.
794 * It requires duplicating render passes and frame-buffers to support suspend/resume rendering.
795 * After suspension all the graphics pipelines needs to be created using the resume handles.
796 * Due to command reordering it is unclear when this switch needs to be made and would require
797 * to double the graphics pipelines.
798 *
799 * This all adds a lot of complexity just to support clearing ops on legacy platforms. An easier
800 * solution is to use #vkCmdClearAttachments right after the begin rendering.
801 */
804 for (int attachment_index : IndexRange(GPU_FB_MAX_ATTACHMENT)) {
805 GPULoadStore &load_store = load_stores[attachment_index];
806 if (load_store.load_action != GPU_LOADACTION_CLEAR) {
807 continue;
808 }
809
810 bool is_depth = attachment_index < GPU_FB_COLOR_ATTACHMENT0;
811 if (is_depth) {
812 build_clear_attachments_depth_stencil(
813 GPU_DEPTH_BIT, load_store.clear_value[0], 0, clear_attachments);
814 }
815 else {
816 build_clear_attachments_color(&load_store.clear_value, false, clear_attachments);
817 }
818 }
819
820 if (clear_attachments.attachment_count != 0) {
821 render_area_update(clear_attachments.vk_clear_rect.rect);
822 clear_attachments.vk_clear_rect.baseArrayLayer = 0;
823 clear_attachments.vk_clear_rect.layerCount = 1;
824 context.render_graph().add_node(clear_attachments);
825 }
826 }
827}
828
830 const VKExtensions &extensions)
831{
832 const VKDevice &device = VKBackend::get().device;
833 const bool supports_local_read = device.extensions_get().dynamic_rendering_local_read;
834
835 depth_attachment_format_ = VK_FORMAT_UNDEFINED;
836 stencil_attachment_format_ = VK_FORMAT_UNDEFINED;
837
839 render_graph::VKBeginRenderingNode::CreateInfo begin_rendering(access_info);
840 begin_rendering.node_data.vk_rendering_info.sType = VK_STRUCTURE_TYPE_RENDERING_INFO;
841 begin_rendering.node_data.vk_rendering_info.layerCount = 1;
842 render_area_update(begin_rendering.node_data.vk_rendering_info.renderArea);
843
844 color_attachment_formats_.clear();
845 for (int color_attachment_index :
847 {
848 const GPUAttachment &attachment = attachments_[color_attachment_index];
849 if (attachment.tex == nullptr) {
850 continue;
851 }
852
853 VKTexture &color_texture = *unwrap(unwrap(attachment.tex));
855 "Texture is used as an attachment, but doesn't have the "
856 "GPU_TEXTURE_USAGE_ATTACHMENT flag.");
857 /* To support `gpu_Layer` we need to set the layerCount to the number of layers it can
858 * access.
859 */
860 int layer_count = color_texture.layer_count();
861 if (attachment.layer == -1 && layer_count != 1) {
862 begin_rendering.node_data.vk_rendering_info.layerCount = max_ii(
863 begin_rendering.node_data.vk_rendering_info.layerCount, layer_count);
864 }
865
866 VkRenderingAttachmentInfo &attachment_info =
867 begin_rendering.node_data
868 .color_attachments[begin_rendering.node_data.vk_rendering_info.colorAttachmentCount++];
869 attachment_info.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
870
871 VkImageView vk_image_view = VK_NULL_HANDLE;
872 uint32_t layer_base = max_ii(attachment.layer, 0);
873 GPUAttachmentState attachment_state = attachment_states_[color_attachment_index];
874 VkFormat vk_format = to_vk_format(color_texture.device_format_get());
875 if (attachment_state == GPU_ATTACHMENT_WRITE) {
876 VKImageViewInfo image_view_info = {
878 IndexRange(layer_base,
879 layer_count != 1 ? max_ii(layer_count - layer_base, 1) : layer_count),
880 IndexRange(attachment.mip, 1),
881 {{'r', 'g', 'b', 'a'}},
882 false,
883 srgb_ && enabled_srgb_,
885 const VKImageView &image_view = color_texture.image_view_get(image_view_info);
886 vk_image_view = image_view.vk_handle();
887 vk_format = image_view.vk_format();
888 }
889 attachment_info.imageView = vk_image_view;
890 attachment_info.imageLayout = supports_local_read ? VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR :
891 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
892 set_load_store(attachment_info, load_stores[color_attachment_index]);
893
894 access_info.images.append(
895 {color_texture.vk_image_handle(),
896 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
897 VK_IMAGE_ASPECT_COLOR_BIT,
898 layer_base});
899 color_attachment_formats_.append(
900 (!extensions.dynamic_rendering_unused_attachments && vk_image_view == VK_NULL_HANDLE) ?
901 VK_FORMAT_UNDEFINED :
902 vk_format);
903
904 begin_rendering.node_data.vk_rendering_info.pColorAttachments =
905 begin_rendering.node_data.color_attachments;
906 }
907 color_attachment_size = color_attachment_formats_.size();
908
909 for (int depth_attachment_index : IndexRange(GPU_FB_DEPTH_ATTACHMENT, 2)) {
910 const GPUAttachment &attachment = attachments_[depth_attachment_index];
911
912 if (attachment.tex == nullptr) {
913 continue;
914 }
915 bool is_stencil_attachment = depth_attachment_index == GPU_FB_DEPTH_STENCIL_ATTACHMENT;
916 VKTexture &depth_texture = *unwrap(unwrap(attachment.tex));
918 "Texture is used as an attachment, but doesn't have the "
919 "GPU_TEXTURE_USAGE_ATTACHMENT flag.");
920 bool is_depth_stencil_attachment = to_vk_image_aspect_flag_bits(
921 depth_texture.device_format_get()) &
922 VK_IMAGE_ASPECT_STENCIL_BIT;
923 VkImageLayout vk_image_layout = is_depth_stencil_attachment ?
924 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
925 VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
926 GPUAttachmentState attachment_state = attachment_states_[GPU_FB_DEPTH_ATTACHMENT];
927 VkImageView depth_image_view = VK_NULL_HANDLE;
928 if (attachment_state == GPU_ATTACHMENT_WRITE) {
930 IndexRange(max_ii(attachment.layer, 0), 1),
931 IndexRange(attachment.mip, 1),
932 {{'r', 'g', 'b', 'a'}},
933 is_stencil_attachment,
934 false,
936 depth_image_view = depth_texture.image_view_get(image_view_info).vk_handle();
937 }
938 VkFormat vk_format = (!extensions.dynamic_rendering_unused_attachments &&
939 depth_image_view == VK_NULL_HANDLE) ?
940 VK_FORMAT_UNDEFINED :
941 to_vk_format(depth_texture.device_format_get());
942
943 /* TODO: we should be able to use a single attachment info and only set the
944 * #pDepthAttachment/#pStencilAttachment to the same struct.
945 * But perhaps the stencil clear op might be different. */
946 {
947 VkRenderingAttachmentInfo &attachment_info = begin_rendering.node_data.depth_attachment;
948 attachment_info.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
949 attachment_info.imageView = depth_image_view;
950 attachment_info.imageLayout = vk_image_layout;
951
952 set_load_store(attachment_info, load_stores[depth_attachment_index]);
953 depth_attachment_format_ = vk_format;
954 begin_rendering.node_data.vk_rendering_info.pDepthAttachment =
955 &begin_rendering.node_data.depth_attachment;
956 }
957
958 if (is_stencil_attachment) {
959 VkRenderingAttachmentInfo &attachment_info = begin_rendering.node_data.stencil_attachment;
960 attachment_info.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
961 attachment_info.imageView = depth_image_view;
962 attachment_info.imageLayout = vk_image_layout;
963
964 set_load_store(attachment_info, load_stores[depth_attachment_index]);
965 stencil_attachment_format_ = vk_format;
966 begin_rendering.node_data.vk_rendering_info.pStencilAttachment =
967 &begin_rendering.node_data.stencil_attachment;
968 }
969
970 access_info.images.append({depth_texture.vk_image_handle(),
971 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
972 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
973 is_stencil_attachment ?
974 static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT |
975 VK_IMAGE_ASPECT_STENCIL_BIT) :
976 static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT),
977 0});
978 break;
979 }
980
981 context.render_graph().add_node(begin_rendering);
982}
983
985{
986 if (!dirty_state_ && is_rendering_) {
987 return;
988 }
989
990 if (is_rendering_) {
991 rendering_end(context);
992 }
993
994#ifndef NDEBUG
995 if (G.debug & G_DEBUG_GPU) {
996 char message[256];
997 message[0] = '\0';
998 BLI_assert_msg(this->check(message), message);
999 }
1000#endif
1001
1002 const VKExtensions &extensions = VKBackend::get().device.extensions_get();
1003 is_rendering_ = true;
1004 if (extensions.dynamic_rendering) {
1005 rendering_ensure_dynamic_rendering(context, extensions);
1006 }
1007 else {
1009 }
1010 dirty_attachments_ = false;
1011 dirty_state_ = false;
1012}
1013
1015{
1016 return depth_attachment_format_;
1017}
1019{
1020 return stencil_attachment_format_;
1021};
1023{
1024 return color_attachment_formats_;
1025}
1026
1028{
1029 if (!is_rendering_ && use_explicit_load_store_) {
1030 rendering_ensure(context);
1031 }
1032
1033 if (is_rendering_) {
1034 const VKExtensions &extensions = VKBackend::get().device.extensions_get();
1036 end_rendering.vk_render_pass = VK_NULL_HANDLE;
1037 if (!extensions.dynamic_rendering) {
1039 end_rendering.vk_render_pass = vk_render_pass;
1040 }
1041 context.render_graph().add_node(end_rendering);
1042 is_rendering_ = false;
1043 }
1044}
1045
1046} // namespace blender::gpu
@ G_DEBUG_GPU
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
MINLINE int max_ii(int a, int b)
MINLINE int clamp_i(int value, int min, int max)
MINLINE void copy_v4_v4(float r[4], const float a[4])
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
#define UNUSED_VARS_NDEBUG(...)
#define ELEM(...)
@ GPU_LOADACTION_LOAD
@ GPU_LOADACTION_DONT_CARE
@ GPU_LOADACTION_CLEAR
eGPUStoreOp
@ GPU_STOREACTION_STORE
@ GPU_STOREACTION_DONT_CARE
GPUAttachmentState
@ GPU_ATTACHMENT_WRITE
@ GPU_ATTACHMENT_READ
@ GPU_ATTACHMENT_IGNORE
eGPUFrameBufferBits
@ GPU_DEPTH_BIT
@ GPU_STENCIL_BIT
@ GPU_COLOR_BIT
static constexpr int GPU_MAX_VIEWPORTS
@ GPU_DRIVER_OFFICIAL
@ GPU_OS_ANY
@ GPU_DEVICE_ATI
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
eGPUWriteMask
Definition GPU_state.hh:16
@ GPU_WRITE_STENCIL
Definition GPU_state.hh:23
@ GPU_WRITE_NONE
Definition GPU_state.hh:17
@ GPU_WRITE_DEPTH
Definition GPU_state.hh:22
eGPUDataFormat
@ GPU_TEXTURE_USAGE_ATTACHMENT
void GPU_texture_get_mipmap_size(GPUTexture *texture, int mip_level, int *r_size)
eGPUTextureFormat GPU_texture_format(const GPUTexture *texture)
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
constexpr int64_t size() const
Definition BLI_span.hh:252
int64_t size() const
void append(const T &value)
bool is_empty() const
void append_n_times(const T &value, const int64_t n)
void size_set(int width, int height)
const GPUAttachment & depth_attachment() const
void scissor_get(int r_scissor[4]) const
GPUTexture * color_tex(int slot) const
FrameBuffer(const char *name)
GPUAttachment attachments_[GPU_FB_MAX_ATTACHMENT]
int viewport_[GPU_MAX_VIEWPORTS][4]
static void set_framebuffer_srgb_target(int use_srgb_to_linear)
eGPUTextureUsage usage_get() const
static VKBackend & get()
Definition vk_backend.hh:91
static VKContext * get()
VkDevice vk_handle() const
Definition vk_device.hh:336
const VKExtensions & extensions_get() const
Definition vk_device.hh:396
void discard_framebuffer(VkFramebuffer vk_framebuffer)
static VKDiscardPool & discard_pool_get()
void discard_render_pass(VkRenderPass vk_render_pass)
void rendering_ensure_dynamic_rendering(VKContext &context, const VKExtensions &extensions)
void rendering_ensure(VKContext &context)
void rendering_ensure_render_pass(VKContext &context)
VKFrameBuffer(const char *name)
void clear_multi(const float(*clear_color)[4]) override
void vk_render_areas_append(Vector< VkRect2D > &r_render_areas) const
VkFormat stencil_attachment_format_get() const
void read(eGPUFrameBufferBits planes, eGPUDataFormat format, const int area[4], int channel_len, int slot, void *r_data) override
void subpass_transition_impl(const GPUAttachmentState depth_attachment_state, Span< GPUAttachmentState > color_attachment_states) override
void render_area_update(VkRect2D &render_area) const
void clear(eGPUFrameBufferBits buffers, const float clear_color[4], float clear_depth, uint clear_stencil) override
void bind(bool enabled_srgb) override
VkFormat depth_attachment_format_get() const
void rendering_end(VKContext &context)
bool check(char err_out[256]) override
void attachment_set_loadstore_op(GPUAttachmentType type, GPULoadStore) override
void blit_to(eGPUFrameBufferBits planes, int src_slot, FrameBuffer *dst, int dst_slot, int dst_offset_x, int dst_offset_y) override
int color_attachments_resource_size() const
void clear_attachment(GPUAttachmentType type, eGPUDataFormat data_format, const void *clear_value) override
void vk_viewports_append(Vector< VkViewport > &r_viewports) const
Span< VkFormat > color_attachment_formats_get() const
VkFormat vk_format() const
VkImageView vk_handle() const
void clear_depth_stencil(const eGPUFrameBufferBits buffer, float clear_depth, uint clear_stencil, std::optional< int > layer)
void copy_to(Texture *tex) override
eGPUTextureFormat device_format_get() const
VkImage vk_image_handle() const
const VKImageView & image_view_get(const VKImageViewInfo &info)
@ GPU_FB_DEPTH_STENCIL_ATTACHMENT
@ GPU_FB_MAX_ATTACHMENT
@ GPU_FB_COLOR_ATTACHMENT0
@ GPU_FB_DEPTH_ATTACHMENT
#define GPU_FB_MAX_COLOR_ATTACHMENT
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
format
#define G(x, y, z)
int context(const bContext *C, const char *member, bContextDataResult *result)
void object_label(GLenum type, GLuint object, const char *name)
Definition gl_debug.cc:329
constexpr GPULoadStore default_load_store()
static Context * unwrap(GPUContext *ctx)
static VkAttachmentStoreOp to_vk_attachment_store_op(eGPUStoreOp store_op)
static void set_load_store(VkRenderingAttachmentInfo &r_rendering_attachment, const GPULoadStore &ls)
static VkAttachmentLoadOp to_vk_attachment_load_op(eGPULoadOp load_op)
VkFormat to_vk_format(const eGPUTextureFormat format)
Definition vk_common.cc:131
VkClearColorValue to_vk_clear_color_value(const eGPUDataFormat format, const void *data)
Definition vk_common.cc:724
VkImageAspectFlags to_vk_image_aspect_flag_bits(const eGPUTextureFormat format)
Definition vk_common.cc:14
static void blit_aspect(VKContext &context, VKTexture &dst_texture, VKTexture &src_texture, int dst_offset_x, int dst_offset_y, VkImageAspectFlags image_aspect)
constexpr DataFormat to_data_format(TextureFormat format)
GPUTexture * tex
eGPULoadOp load_action
eGPUStoreOp store_action
static constexpr GPUSamplerState default_sampler()
i
Definition text_draw.cc:230
char * buffers[2]