Blender V4.3
mtl_framebuffer.mm
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_string.h"
10
11#include "BKE_global.hh"
12
13#include "mtl_context.hh"
14#include "mtl_debug.hh"
15#include "mtl_framebuffer.hh"
16#include "mtl_texture.hh"
17#import <Availability.h>
18
19namespace blender::gpu {
20
21/* -------------------------------------------------------------------- */
26{
27
28 context_ = ctx;
29 is_dirty_ = true;
30 is_loadstore_dirty_ = true;
31 dirty_state_ctx_ = nullptr;
32 has_pending_clear_ = false;
33 colour_attachment_count_ = 0;
34 enabled_srgb_ = false;
35 srgb_ = false;
36
37 for (int i = 0; i < GPU_FB_MAX_COLOR_ATTACHMENT; i++) {
38 mtl_color_attachments_[i].used = false;
39 }
40 mtl_depth_attachment_.used = false;
41 mtl_stencil_attachment_.used = false;
42
43 for (int i = 0; i < MTL_FB_CONFIG_MAX; i++) {
44 framebuffer_descriptor_[i] = [[MTLRenderPassDescriptor alloc] init];
45 descriptor_dirty_[i] = true;
46 }
47
48 for (int i = 0; i < GPU_FB_MAX_COLOR_ATTACHMENT; i++) {
49 colour_attachment_descriptors_[i] = [[MTLRenderPassColorAttachmentDescriptor alloc] init];
50 }
51
52 /* Initial state. */
53 this->size_set(0, 0);
54 this->viewport_reset();
55 this->scissor_reset();
56}
57
59{
60 /* If FrameBuffer is associated with a currently open RenderPass, end. */
61 if (context_->main_command_buffer.get_active_framebuffer() == this) {
63 }
64
65 /* Restore default frame-buffer if this frame-buffer was bound. */
66 if (context_->active_fb == this && context_->back_left != this) {
67 /* If this assert triggers it means the frame-buffer is being freed while in use by another
68 * context which, by the way, is TOTALLY UNSAFE!!! (Copy from GL behavior). */
69 BLI_assert(context_ == MTLContext::get());
71 }
72
73 /* Free Render Pass Descriptors. */
74 for (int config = 0; config < MTL_FB_CONFIG_MAX; config++) {
75 if (framebuffer_descriptor_[config] != nil) {
76 [framebuffer_descriptor_[config] release];
77 framebuffer_descriptor_[config] = nil;
78 }
79 }
80
81 /* Free color attachment descriptors. */
82 for (int i = 0; i < GPU_FB_MAX_COLOR_ATTACHMENT; i++) {
83 if (colour_attachment_descriptors_[i] != nil) {
84 [colour_attachment_descriptors_[i] release];
85 colour_attachment_descriptors_[i] = nil;
86 }
87 }
88
89 /* Remove attachments - release FB texture references. */
91
92 if (context_ == nullptr) {
93 return;
94 }
95}
96
98{
99 /* Ensure local MTLAttachment data is up to date.
100 * NOTE: We only refresh viewport/scissor region when attachments are updated during bind.
101 * This is to ensure state is consistent with the OpenGL backend. */
102 if (dirty_attachments_) {
103 this->update_attachments(true);
104 this->viewport_reset();
105 this->scissor_reset();
106 }
107}
108
109void MTLFrameBuffer::bind(bool enabled_srgb)
110{
111
112 /* Verify Context is valid. */
113 if (context_ != MTLContext::get()) {
114 BLI_assert_msg(false, "Trying to use the same frame-buffer in multiple context's.");
115 return;
116 }
117
118 /* Ensure local MTLAttachment data is up to date.
119 * NOTE: We only refresh viewport/scissor region when attachments are updated during bind.
120 * This is to ensure state is consistent with the OpenGL backend. */
122
123 /* Ensure SRGB state is up-to-date and valid. */
124 bool srgb_state_changed = enabled_srgb_ != enabled_srgb;
125 if (context_->active_fb != this || srgb_state_changed) {
126 if (srgb_state_changed) {
127 this->mark_dirty();
128 }
129 enabled_srgb_ = enabled_srgb;
130 Shader::set_framebuffer_srgb_target(enabled_srgb && srgb_);
131 }
132
133 /* Reset clear state on bind -- Clears and load/store ops are set after binding. */
134 this->reset_clear_state();
135
136 /* Bind to active context. */
137 MTLContext *mtl_context = MTLContext::get();
138 if (mtl_context) {
139 mtl_context->framebuffer_bind(this);
140 dirty_state_ = true;
141 }
142 else {
143 MTL_LOG_WARNING("Attempting to bind FrameBuffer, but no context is active");
144 }
145}
146
147bool MTLFrameBuffer::check(char err_out[256])
148{
149 /* Ensure local MTLAttachment data is up to date.
150 * NOTE: We only refresh viewport/scissor region when attachments are updated during bind.
151 * This is to ensure state is consistent with the OpenGL backend. */
153
154 /* Ensure there is at least one attachment. */
155 bool valid = (this->get_attachment_count() > 0 || this->has_depth_attachment() ||
156 this->has_stencil_attachment());
157 if (!valid) {
158 const char *format = "Framebuffer %s does not have any attachments.\n";
159 if (err_out) {
160 BLI_snprintf(err_out, 256, format, name_);
161 }
162 else {
164 }
165 return false;
166 }
167
168 /* Ensure all attachments have identical dimensions. */
169 /* Ensure all attachments are render-targets. */
170 bool first = true;
171 uint dim_x = 0;
172 uint dim_y = 0;
173 for (int col_att = 0; col_att < this->get_attachment_count(); col_att++) {
174 MTLAttachment att = this->get_color_attachment(col_att);
175 if (att.used) {
176 if (att.texture->internal_gpu_image_usage_flags_ & GPU_TEXTURE_USAGE_ATTACHMENT) {
177 if (first) {
178 dim_x = att.texture->width_get();
179 dim_y = att.texture->height_get();
180 first = false;
181 }
182 else {
183 if (dim_x != att.texture->width_get() || dim_y != att.texture->height_get()) {
184 const char *format =
185 "Framebuffer %s: Color attachment dimensions do not match those of previous "
186 "attachment\n";
187 if (err_out) {
188 BLI_snprintf(err_out, 256, format, name_);
189 }
190 else {
191 fprintf(stderr, format, name_);
193 }
194 return false;
195 }
196 }
197 }
198 else {
199 const char *format =
200 "Framebuffer %s: Color attachment texture does not have usage flag "
201 "'GPU_TEXTURE_USAGE_ATTACHMENT'\n";
202 if (err_out) {
203 BLI_snprintf(err_out, 256, format, name_);
204 }
205 else {
206 fprintf(stderr, format, name_);
208 }
209 return false;
210 }
211 }
212 }
213 MTLAttachment depth_att = this->get_depth_attachment();
214 MTLAttachment stencil_att = this->get_stencil_attachment();
215 if (depth_att.used) {
216 if (first) {
217 dim_x = depth_att.texture->width_get();
218 dim_y = depth_att.texture->height_get();
219 first = false;
220 valid = (depth_att.texture->internal_gpu_image_usage_flags_ & GPU_TEXTURE_USAGE_ATTACHMENT);
221
222 if (!valid) {
223 const char *format =
224 "Framebuffer %n: Depth attachment does not have usage "
225 "'GPU_TEXTURE_USAGE_ATTACHMENT'\n";
226 if (err_out) {
227 BLI_snprintf(err_out, 256, format, name_);
228 }
229 else {
230 fprintf(stderr, format, name_);
232 }
233 return false;
234 }
235 }
236 else {
237 if (dim_x != depth_att.texture->width_get() || dim_y != depth_att.texture->height_get()) {
238 const char *format =
239 "Framebuffer %n: Depth attachment dimensions do not match that of previous "
240 "attachment\n";
241 if (err_out) {
242 BLI_snprintf(err_out, 256, format, name_);
243 }
244 else {
245 fprintf(stderr, format, name_);
247 }
248 return false;
249 }
250 }
251 }
252 if (stencil_att.used) {
253 if (first) {
254 dim_x = stencil_att.texture->width_get();
255 dim_y = stencil_att.texture->height_get();
256 first = false;
257 valid = (stencil_att.texture->internal_gpu_image_usage_flags_ &
259 if (!valid) {
260 const char *format =
261 "Framebuffer %s: Stencil attachment does not have usage "
262 "'GPU_TEXTURE_USAGE_ATTACHMENT'\n";
263 if (err_out) {
264 BLI_snprintf(err_out, 256, format, name_);
265 }
266 else {
267 fprintf(stderr, format, name_);
269 }
270 return false;
271 }
272 }
273 else {
274 if (dim_x != stencil_att.texture->width_get() || dim_y != stencil_att.texture->height_get())
275 {
276 const char *format =
277 "Framebuffer %s: Stencil attachment dimensions do not match that of previous "
278 "attachment";
279 if (err_out) {
280 BLI_snprintf(err_out, 256, format, name_);
281 }
282 else {
283 fprintf(stderr, format, name_);
285 }
286 return false;
287 }
288 }
289 }
290
291 BLI_assert(valid);
292 return valid;
293}
294
295void MTLFrameBuffer::force_clear()
296{
297 /* Perform clear by ending current and starting a new render pass. */
298 MTLContext *mtl_context = MTLContext::get();
299 MTLFrameBuffer *current_framebuffer = mtl_context->get_current_framebuffer();
300 if (current_framebuffer) {
301 BLI_assert(current_framebuffer == this);
302 /* End current render-pass. */
303 if (mtl_context->main_command_buffer.is_inside_render_pass()) {
305 }
306 mtl_context->ensure_begin_render_pass();
307 BLI_assert(has_pending_clear_ == false);
308 }
309}
310
312 const float clear_col[4],
313 float clear_depth,
314 uint clear_stencil)
315{
316
317 BLI_assert(MTLContext::get() == context_);
318 BLI_assert(context_->active_fb == this);
319
320 /* Ensure attachments are up to date. */
321 this->update_attachments(true);
322
323 /* If we had no previous clear pending, reset clear state. */
324 if (!has_pending_clear_) {
325 this->reset_clear_state();
326 }
327
328 /* Ensure we only clear if attachments exist for given buffer bits. */
329 bool do_clear = false;
330 if (buffers & GPU_COLOR_BIT) {
331 for (int i = 0; i < colour_attachment_count_; i++) {
332 this->set_color_attachment_clear_color(i, clear_col);
333 do_clear = true;
334 }
335 }
336
337 if (buffers & GPU_DEPTH_BIT) {
338 this->set_depth_attachment_clear_value(clear_depth);
339 do_clear = do_clear || this->has_depth_attachment();
340 }
341 if (buffers & GPU_STENCIL_BIT) {
342 this->set_stencil_attachment_clear_value(clear_stencil);
343 do_clear = do_clear || this->has_stencil_attachment();
344 }
345
346 if (do_clear) {
347 has_pending_clear_ = true;
348
349 /* Apply state before clear. */
350 this->apply_state();
351
352 /* TODO(Metal): Optimize - Currently force-clear always used. Consider moving clear state to
353 * MTLTexture instead. */
354 /* Force clear if RP is not yet active -- not the most efficient, but there is no distinction
355 * between clears where no draws occur. Can optimize at the high-level by using explicit
356 * load-store flags. */
357 this->force_clear();
358 }
359}
360
361void MTLFrameBuffer::clear_multi(const float (*clear_cols)[4])
362{
363 /* If we had no previous clear pending, reset clear state. */
364 if (!has_pending_clear_) {
365 this->reset_clear_state();
366 }
367
368 bool do_clear = false;
369 for (int i = 0; i < this->get_attachment_limit(); i++) {
370 if (this->has_attachment_at_slot(i)) {
371 this->set_color_attachment_clear_color(i, clear_cols[i]);
372 do_clear = true;
373 }
374 }
375
376 if (do_clear) {
377 has_pending_clear_ = true;
378
379 /* Apply state before clear. */
380 this->apply_state();
381
382 /* TODO(Metal): Optimize - Currently force-clear always used. Consider moving clear state to
383 * MTLTexture instead. */
384 /* Force clear if RP is not yet active -- not the most efficient, but there is no distinction
385 * between clears where no draws occur. Can optimize at the high-level by using explicit
386 * load-store flags. */
387 this->force_clear();
388 }
389}
390
392 eGPUDataFormat data_format,
393 const void *clear_value)
394{
395 BLI_assert(MTLContext::get() == context_);
396 BLI_assert(context_->active_fb == this);
397
398 /* If we had no previous clear pending, reset clear state. */
399 if (!has_pending_clear_) {
400 this->reset_clear_state();
401 }
402
403 bool do_clear = false;
404
406 if (this->has_depth_attachment() || this->has_stencil_attachment()) {
407 BLI_assert(data_format == GPU_DATA_UINT_24_8);
408 float depth = ((*(uint32_t *)clear_value) & 0x00FFFFFFu) / (float)0x00FFFFFFu;
409 int stencil = ((*(uint32_t *)clear_value) >> 24);
412 do_clear = true;
413 }
414 }
415 else if (type == GPU_FB_DEPTH_ATTACHMENT) {
416 if (this->has_depth_attachment()) {
417 if (data_format == GPU_DATA_FLOAT) {
418 this->set_depth_attachment_clear_value(*(float *)clear_value);
419 }
420 else {
421 float depth = *(uint32_t *)clear_value / (float)0xFFFFFFFFu;
423 }
424 do_clear = true;
425 }
426 }
427 else {
428 int slot = type - GPU_FB_COLOR_ATTACHMENT0;
429 if (this->has_attachment_at_slot(slot)) {
430 float col_clear_val[4] = {0.0};
431 switch (data_format) {
432 case GPU_DATA_FLOAT: {
433 const float *vals = (float *)clear_value;
434 col_clear_val[0] = vals[0];
435 col_clear_val[1] = vals[1];
436 col_clear_val[2] = vals[2];
437 col_clear_val[3] = vals[3];
438 } break;
439 case GPU_DATA_UINT: {
440 const uint *vals = (uint *)clear_value;
441 col_clear_val[0] = (float)(vals[0]);
442 col_clear_val[1] = (float)(vals[1]);
443 col_clear_val[2] = (float)(vals[2]);
444 col_clear_val[3] = (float)(vals[3]);
445 } break;
446 case GPU_DATA_INT: {
447 const int *vals = (int *)clear_value;
448 col_clear_val[0] = (float)(vals[0]);
449 col_clear_val[1] = (float)(vals[1]);
450 col_clear_val[2] = (float)(vals[2]);
451 col_clear_val[3] = (float)(vals[3]);
452 } break;
453 default:
454 BLI_assert_msg(0, "Unhandled data format");
455 break;
456 }
457 this->set_color_attachment_clear_color(slot, col_clear_val);
458 do_clear = true;
459 }
460 }
461
462 if (do_clear) {
463 has_pending_clear_ = true;
464
465 /* Apply state before clear. */
466 this->apply_state();
467
468 /* TODO(Metal): Optimize - Currently force-clear always used. Consider moving clear state to
469 * MTLTexture instead. */
470 /* Force clear if RP is not yet active -- not the most efficient, but there is no distinction
471 * between clears where no draws occur. Can optimize at the high-level by using explicit
472 * load-store flags. */
473 this->force_clear();
474 }
475}
477 Span<GPUAttachmentState> color_attachment_states)
478{
479 const bool is_tile_based_arch = (GPU_platform_architecture() == GPU_ARCHITECTURE_TBDR);
480 if (!is_tile_based_arch) {
481 /* Break render-pass if tile memory is unsupported to ensure current frame-buffer results are
482 * stored. */
484
485 /* Bind frame-buffer attachments as textures.
486 * NOTE: Follows behavior of gl_framebuffer. However, shaders utilizing subpass_in will
487 * need to avoid bind-point collisions for image/texture resources. */
488 for (int i : color_attachment_states.index_range()) {
490 GPUTexture *attach_tex = this->attachments_[type].tex;
491 if (color_attachment_states[i] == GPU_ATTACHMENT_READ) {
492 GPU_texture_image_bind(attach_tex, i);
493 }
494 }
495 }
496}
497
500 const int area[4],
501 int channel_len,
502 int slot,
503 void *r_data)
504{
505
506 BLI_assert((planes & GPU_STENCIL_BIT) == 0);
507 BLI_assert(area[2] > 0);
508 BLI_assert(area[3] > 0);
509
510 /* Early exit if requested read region area is zero. */
511 if (area[2] <= 0 || area[3] <= 0) {
512 return;
513 }
514
515 switch (planes) {
516 case GPU_DEPTH_BIT: {
517 if (this->has_depth_attachment()) {
518 MTLAttachment depth = this->get_depth_attachment();
519 gpu::MTLTexture *tex = depth.texture;
520 if (tex) {
521 size_t sample_len = area[2] * area[3];
522 size_t sample_size = to_bytesize(tex->format_, format);
523 size_t debug_data_size = sample_len * sample_size;
524 tex->read_internal(0,
525 area[0],
526 area[1],
527 0,
528 area[2],
529 area[3],
530 1,
531 format,
532 channel_len,
533 debug_data_size,
534 r_data);
535 }
536 }
537 else {
539 "Attempting to read depth from a framebuffer which does not have a depth "
540 "attachment!");
541 }
542 }
543 return;
544
545 case GPU_COLOR_BIT: {
546 if (this->has_attachment_at_slot(slot)) {
547 MTLAttachment color = this->get_color_attachment(slot);
548 gpu::MTLTexture *tex = color.texture;
549 if (tex) {
550 size_t sample_len = area[2] * area[3];
551 size_t sample_size = to_bytesize(tex->format_, format);
552 size_t debug_data_size = sample_len * sample_size * channel_len;
553 tex->read_internal(0,
554 area[0],
555 area[1],
556 0,
557 area[2],
558 area[3],
559 1,
560 format,
561 channel_len,
562 debug_data_size,
563 r_data);
564 }
565 }
566 }
567 return;
568
569 case GPU_STENCIL_BIT:
570 MTL_LOG_ERROR("Framebuffer: Trying to read stencil bit. Unsupported.");
571 return;
572 }
573}
574
576 int src_slot,
577 FrameBuffer *dst,
578 int dst_slot,
579 int dst_offset_x,
580 int dst_offset_y)
581{
583 static_cast<MTLFrameBuffer *>(dst)->ensure_attachments_and_viewport();
584
585 BLI_assert(planes != 0);
586
587 MTLFrameBuffer *metal_fb_write = static_cast<MTLFrameBuffer *>(dst);
588
589 BLI_assert(this);
590 BLI_assert(metal_fb_write);
591
592 /* Get width/height from attachment. */
593 MTLAttachment src_attachment;
594 const bool do_color = (planes & GPU_COLOR_BIT);
595 const bool do_depth = (planes & GPU_DEPTH_BIT);
596 const bool do_stencil = (planes & GPU_STENCIL_BIT);
597
598 if (do_color) {
599 BLI_assert(!do_depth && !do_stencil);
600 src_attachment = this->get_color_attachment(src_slot);
601 }
602 else if (do_depth) {
603 BLI_assert(!do_color && !do_stencil);
604 src_attachment = this->get_depth_attachment();
605 }
606 else if (do_stencil) {
607 BLI_assert(!do_color && !do_depth);
608 src_attachment = this->get_stencil_attachment();
609 }
610
611 BLI_assert(src_attachment.used);
612 this->blit(src_slot,
613 0,
614 0,
615 metal_fb_write,
616 dst_slot,
617 dst_offset_x,
618 dst_offset_y,
619 src_attachment.texture->width_get(),
620 src_attachment.texture->height_get(),
621 planes);
622}
623
626/* -------------------------------------------------------------------- */
631{
632 is_dirty_ = true;
633 is_loadstore_dirty_ = true;
634}
635
637{
638 is_loadstore_dirty_ = true;
639}
640
642{
643 has_pending_clear_ = false;
644}
645
647{
648 has_pending_clear_ = true;
649}
650
651void MTLFrameBuffer::update_attachments(bool /*update_viewport*/)
652{
653 if (!dirty_attachments_) {
654 return;
655 }
656 /* Clear current attachments state. */
658
659 /* Reset framebuffer options. */
660 use_multilayered_rendering_ = false;
661
662 /* Track first attachment for SRGB property extraction. */
663 GPUAttachmentType first_attachment = GPU_FB_MAX_ATTACHMENT;
664 MTLAttachment first_attachment_mtl;
665
666 /* Scan through changes to attachments and populate local structures. */
667 bool depth_added = false;
668 for (GPUAttachmentType type = GPU_FB_MAX_ATTACHMENT - 1; type >= 0; --type) {
669 GPUAttachment &attach = attachments_[type];
670
671 switch (type) {
674 /* If one of the DEPTH types has added a texture, we avoid running this again, as it would
675 * only remove the target. */
676 if (depth_added) {
677 break;
678 }
679 if (attach.tex) {
680 /* If we already had a depth attachment, preserve load/clear-state parameters,
681 * but remove existing and add new attachment. */
682 if (this->has_depth_attachment()) {
683 MTLAttachment depth_attachment_prev = this->get_depth_attachment();
686 static_cast<gpu::MTLTexture *>(unwrap(attach.tex)), attach.mip, attach.layer);
687 this->set_depth_attachment_clear_value(depth_attachment_prev.clear_value.depth);
688 this->set_depth_loadstore_op(depth_attachment_prev.load_action,
689 depth_attachment_prev.store_action);
690 }
691 else {
693 static_cast<gpu::MTLTexture *>(unwrap(attach.tex)), attach.mip, attach.layer);
694 }
695
696 /* Check stencil component -- if supplied texture format supports stencil. */
698 bool use_stencil = (type == GPU_FB_DEPTH_STENCIL_ATTACHMENT) &&
700 if (use_stencil) {
701 if (this->has_stencil_attachment()) {
702 MTLAttachment stencil_attachment_prev = this->get_stencil_attachment();
705 static_cast<gpu::MTLTexture *>(unwrap(attach.tex)), attach.mip, attach.layer);
707 stencil_attachment_prev.clear_value.stencil);
708 this->set_stencil_loadstore_op(stencil_attachment_prev.load_action,
709 stencil_attachment_prev.store_action);
710 }
711 else {
713 static_cast<gpu::MTLTexture *>(unwrap(attach.tex)), attach.mip, attach.layer);
714 }
715 }
716
717 /* Flag depth as added -- mirrors the behavior in gl_framebuffer.cc to exit the for-loop
718 * after GPU_FB_DEPTH_STENCIL_ATTACHMENT has executed. */
719 depth_added = true;
720
721 if (first_attachment == GPU_FB_MAX_ATTACHMENT) {
722 /* Only use depth texture to get information if there is no color attachment. */
723 first_attachment = type;
724 first_attachment_mtl = this->get_depth_attachment();
725 }
726 }
727 else {
731 }
732 }
733 } break;
742 int color_slot_ind = type - GPU_FB_COLOR_ATTACHMENT0;
743 if (attach.tex) {
744 /* If we already had a color attachment, preserve load/clear-state parameters,
745 * but remove existing and add new attachment. */
746 if (this->has_attachment_at_slot(color_slot_ind)) {
747 MTLAttachment color_attachment_prev = this->get_color_attachment(color_slot_ind);
748
749 this->remove_color_attachment(color_slot_ind);
750 this->add_color_attachment(static_cast<gpu::MTLTexture *>(unwrap(attach.tex)),
751 color_slot_ind,
752 attach.mip,
753 attach.layer);
754 this->set_color_attachment_clear_color(color_slot_ind,
755 color_attachment_prev.clear_value.color);
756 this->set_color_loadstore_op(color_slot_ind,
757 color_attachment_prev.load_action,
758 color_attachment_prev.store_action);
759 }
760 else {
761 this->add_color_attachment(static_cast<gpu::MTLTexture *>(unwrap(attach.tex)),
762 color_slot_ind,
763 attach.mip,
764 attach.layer);
765 }
766 first_attachment = type;
767 first_attachment_mtl = this->get_color_attachment(color_slot_ind);
768 }
769 else {
770 this->remove_color_attachment(color_slot_ind);
771 }
772 } break;
773 default:
774 /* Non-attachment parameters. */
775 break;
776 }
777 }
778
779 /* Extract attachment size and determine if framebuffer is SRGB. */
780 if (first_attachment != GPU_FB_MAX_ATTACHMENT) {
781 /* Ensure size is correctly assigned. */
782 GPUAttachment &attach = attachments_[first_attachment];
783 int size[3];
784 GPU_texture_get_mipmap_size(attach.tex, attach.mip, size);
785 this->size_set(size[0], size[1]);
786 srgb_ = (GPU_texture_format(attach.tex) == GPU_SRGB8_A8);
787 }
788
789 /* We have now updated our internal structures. */
790 dirty_attachments_ = false;
791}
792
794{
795 MTLContext *mtl_ctx = MTLContext::get();
796 BLI_assert(mtl_ctx);
797 if (mtl_ctx->active_fb == this) {
798 if (dirty_state_ == false && dirty_state_ctx_ == mtl_ctx) {
799 return;
800 }
801
802 /* Ensure viewport has been set. NOTE: This should no longer happen, but kept for safety to
803 * track bugs. If viewport size is zero, use framebuffer size. */
804 int viewport_w = viewport_[0][2];
805 int viewport_h = viewport_[0][3];
806 if (viewport_w == 0 || viewport_h == 0) {
807 MTL_LOG_WARNING("Viewport had width and height of (0,0) -- Updating -- DEBUG Safety check");
808 viewport_w = default_width_;
809 viewport_h = default_height_;
810 }
811
812 /* Update Context State. */
813 if (multi_viewport_) {
815 }
816 else {
817 mtl_ctx->set_viewport(viewport_[0][0], viewport_[0][1], viewport_w, viewport_h);
818 }
819 mtl_ctx->set_scissor(scissor_[0], scissor_[1], scissor_[2], scissor_[3]);
821
822 dirty_state_ = false;
823 dirty_state_ctx_ = mtl_ctx;
824 }
825 else {
827 "Attempting to set FrameBuffer State (VIEWPORT, SCISSOR), But FrameBuffer is not bound to "
828 "current Context.");
829 }
830}
831
834/* -------------------------------------------------------------------- */
839 uint slot,
840 int miplevel,
841 int layer)
842{
843 BLI_assert(this);
844 BLI_assert(slot >= 0 && slot < this->get_attachment_limit());
845
846 if (texture) {
847 if (miplevel < 0 || miplevel >= MTL_MAX_MIPMAP_COUNT) {
848 MTL_LOG_WARNING("Attachment specified with invalid mip level %u", miplevel);
849 miplevel = 0;
850 }
851
852 /* Check if slot is in-use. */
853 /* Assume attachment load by default. */
854 colour_attachment_count_ += (!mtl_color_attachments_[slot].used) ? 1 : 0;
855 mtl_color_attachments_[slot].used = true;
856 mtl_color_attachments_[slot].texture = texture;
857 mtl_color_attachments_[slot].mip = miplevel;
858 mtl_color_attachments_[slot].load_action = GPU_LOADACTION_LOAD;
859 mtl_color_attachments_[slot].store_action = GPU_STOREACTION_STORE;
860 mtl_color_attachments_[slot].render_target_array_length = 0;
861
862 /* Determine whether array slice or depth plane based on texture type. */
863 switch (texture->type_) {
864 case GPU_TEXTURE_1D:
865 case GPU_TEXTURE_2D:
866 BLI_assert(layer <= 0);
867 mtl_color_attachments_[slot].slice = 0;
868 mtl_color_attachments_[slot].depth_plane = 0;
869 break;
871 if (layer < 0) {
872 layer = 0;
873 MTL_LOG_WARNING("TODO: Support layered rendering for 1D array textures, if needed.");
874 }
875 BLI_assert(layer < texture->h_);
876 mtl_color_attachments_[slot].slice = layer;
877 mtl_color_attachments_[slot].depth_plane = 0;
878 break;
880 BLI_assert(layer < texture->d_);
881 mtl_color_attachments_[slot].slice = layer;
882 mtl_color_attachments_[slot].depth_plane = 0;
883 if (layer == -1) {
884 mtl_color_attachments_[slot].slice = 0;
885 mtl_color_attachments_[slot].render_target_array_length = texture->d_;
886 use_multilayered_rendering_ = true;
887 }
888 break;
889 case GPU_TEXTURE_3D:
890 BLI_assert(layer < texture->d_);
891 mtl_color_attachments_[slot].slice = 0;
892 mtl_color_attachments_[slot].depth_plane = layer;
893 if (layer == -1) {
894 mtl_color_attachments_[slot].depth_plane = 0;
895 mtl_color_attachments_[slot].render_target_array_length = texture->d_;
896 use_multilayered_rendering_ = true;
897 }
898 break;
899 case GPU_TEXTURE_CUBE:
900 BLI_assert(layer < 6);
901 mtl_color_attachments_[slot].slice = layer;
902 mtl_color_attachments_[slot].depth_plane = 0;
903 if (layer == -1) {
904 mtl_color_attachments_[slot].slice = 0;
905 mtl_color_attachments_[slot].depth_plane = 0;
906 mtl_color_attachments_[slot].render_target_array_length = 6;
907 use_multilayered_rendering_ = true;
908 }
909 break;
911 BLI_assert(layer < 6 * texture->d_);
912 /* TODO(Metal): Verify multilayered rendering for Cube arrays. */
913 mtl_color_attachments_[slot].slice = layer;
914 mtl_color_attachments_[slot].depth_plane = 0;
915 if (layer == -1) {
916 mtl_color_attachments_[slot].slice = 0;
917 mtl_color_attachments_[slot].depth_plane = 0;
918 mtl_color_attachments_[slot].render_target_array_length = texture->d_;
919 use_multilayered_rendering_ = true;
920 }
921 break;
923 mtl_color_attachments_[slot].slice = 0;
924 mtl_color_attachments_[slot].depth_plane = 0;
925 break;
926 default:
927 MTL_LOG_ERROR("MTLFrameBuffer::add_color_attachment Unrecognized texture type %u",
928 texture->type_);
929 break;
930 }
931
932 /* Update default attachment size and ensure future attachments match the same size. */
933 int width_of_miplayer, height_of_miplayer;
934 if (miplevel <= 0) {
935 width_of_miplayer = texture->width_get();
936 height_of_miplayer = texture->height_get();
937 }
938 else {
939 width_of_miplayer = max_ii(texture->width_get() >> miplevel, 1);
940 height_of_miplayer = max_ii(texture->height_get() >> miplevel, 1);
941 }
942
943 if (default_width_ == 0 || default_height_ == 0) {
944 this->default_size_set(width_of_miplayer, height_of_miplayer);
945 BLI_assert(default_width_ > 0);
946 BLI_assert(default_height_ > 0);
947 }
948 else {
949 BLI_assert(default_width_ == width_of_miplayer);
950 BLI_assert(default_height_ == height_of_miplayer);
951 }
952
953 /* Flag as dirty. */
954 this->mark_dirty();
955 }
956 else {
958 "Passing in null texture to MTLFrameBuffer::add_color_attachment (This could be due to "
959 "not all texture types being supported).");
960 }
961 return true;
962}
963
964bool MTLFrameBuffer::add_depth_attachment(gpu::MTLTexture *texture, int miplevel, int layer)
965{
966 BLI_assert(this);
967
968 if (texture) {
969 if (miplevel < 0 || miplevel >= MTL_MAX_MIPMAP_COUNT) {
970 MTL_LOG_WARNING("Attachment specified with invalid mip level %u", miplevel);
971 miplevel = 0;
972 }
973
974 /* Assume attachment load by default. */
975 mtl_depth_attachment_.used = true;
976 mtl_depth_attachment_.texture = texture;
977 mtl_depth_attachment_.mip = miplevel;
978 mtl_depth_attachment_.load_action = GPU_LOADACTION_LOAD;
979 mtl_depth_attachment_.store_action = GPU_STOREACTION_STORE;
980 mtl_depth_attachment_.render_target_array_length = 0;
981
982 /* Determine whether array slice or depth plane based on texture type. */
983 switch (texture->type_) {
984 case GPU_TEXTURE_1D:
985 case GPU_TEXTURE_2D:
986 BLI_assert(layer <= 0);
987 mtl_depth_attachment_.slice = 0;
988 mtl_depth_attachment_.depth_plane = 0;
989 break;
991 if (layer < 0) {
992 layer = 0;
993 MTL_LOG_WARNING("TODO: Support layered rendering for 1D array textures, if needed");
994 }
995 BLI_assert(layer < texture->h_);
996 mtl_depth_attachment_.slice = layer;
997 mtl_depth_attachment_.depth_plane = 0;
998 break;
1000 BLI_assert(layer < texture->d_);
1001 mtl_depth_attachment_.slice = layer;
1002 mtl_depth_attachment_.depth_plane = 0;
1003 if (layer == -1) {
1004 mtl_depth_attachment_.slice = 0;
1005 mtl_depth_attachment_.render_target_array_length = texture->d_;
1006 use_multilayered_rendering_ = true;
1007 }
1008 break;
1009 case GPU_TEXTURE_3D:
1010 BLI_assert(layer < texture->d_);
1011 mtl_depth_attachment_.slice = 0;
1012 mtl_depth_attachment_.depth_plane = layer;
1013 if (layer == -1) {
1014 mtl_depth_attachment_.depth_plane = 0;
1015 mtl_depth_attachment_.render_target_array_length = texture->d_;
1016 use_multilayered_rendering_ = true;
1017 }
1018 break;
1019 case GPU_TEXTURE_CUBE:
1020 BLI_assert(layer < 6);
1021 mtl_depth_attachment_.slice = layer;
1022 mtl_depth_attachment_.depth_plane = 0;
1023 if (layer == -1) {
1024 mtl_depth_attachment_.slice = 0;
1025 mtl_depth_attachment_.depth_plane = 0;
1026 mtl_depth_attachment_.render_target_array_length = 6;
1027 use_multilayered_rendering_ = true;
1028 }
1029 break;
1031 /* TODO(Metal): Verify multilayered rendering for Cube arrays. */
1032 BLI_assert(layer < 6 * texture->d_);
1033 mtl_depth_attachment_.slice = layer;
1034 mtl_depth_attachment_.depth_plane = 0;
1035 if (layer == -1) {
1036 mtl_depth_attachment_.slice = 0;
1037 mtl_depth_attachment_.depth_plane = 0;
1038 mtl_depth_attachment_.render_target_array_length = texture->d_;
1039 use_multilayered_rendering_ = true;
1040 }
1041 break;
1042 case GPU_TEXTURE_BUFFER:
1043 mtl_depth_attachment_.slice = 0;
1044 mtl_depth_attachment_.depth_plane = 0;
1045 break;
1046 default:
1047 BLI_assert_msg(false, "Unrecognized texture type");
1048 break;
1049 }
1050
1051 /* Update default attachment size and ensure future attachments match the same size. */
1052 int width_of_miplayer, height_of_miplayer;
1053 if (miplevel <= 0) {
1054 width_of_miplayer = texture->width_get();
1055 height_of_miplayer = texture->height_get();
1056 }
1057 else {
1058 width_of_miplayer = max_ii(texture->width_get() >> miplevel, 1);
1059 height_of_miplayer = max_ii(texture->height_get() >> miplevel, 1);
1060 }
1061
1062 if (default_width_ == 0 || default_height_ == 0) {
1063 this->default_size_set(width_of_miplayer, height_of_miplayer);
1064 BLI_assert(default_width_ > 0);
1065 BLI_assert(default_height_ > 0);
1066 }
1067 else {
1068 BLI_assert(default_width_ == width_of_miplayer);
1069 BLI_assert(default_height_ == height_of_miplayer);
1070 }
1071
1072 /* Flag as dirty after attachments changed. */
1073 this->mark_dirty();
1074 }
1075 else {
1077 "Passing in null texture to MTLFrameBuffer::addDepthAttachment (This could be due to not "
1078 "all texture types being supported).");
1079 }
1080 return true;
1081}
1082
1083bool MTLFrameBuffer::add_stencil_attachment(gpu::MTLTexture *texture, int miplevel, int layer)
1084{
1085 BLI_assert(this);
1086
1087 if (texture) {
1088 if (miplevel < 0 || miplevel >= MTL_MAX_MIPMAP_COUNT) {
1089 MTL_LOG_WARNING("Attachment specified with invalid mip level %u", miplevel);
1090 miplevel = 0;
1091 }
1092
1093 /* Assume attachment load by default. */
1094 mtl_stencil_attachment_.used = true;
1095 mtl_stencil_attachment_.texture = texture;
1096 mtl_stencil_attachment_.mip = miplevel;
1097 mtl_stencil_attachment_.load_action = GPU_LOADACTION_LOAD;
1098 mtl_stencil_attachment_.store_action = GPU_STOREACTION_STORE;
1099 mtl_stencil_attachment_.render_target_array_length = 0;
1100
1101 /* Determine whether array slice or depth plane based on texture type. */
1102 switch (texture->type_) {
1103 case GPU_TEXTURE_1D:
1104 case GPU_TEXTURE_2D:
1105 BLI_assert(layer <= 0);
1106 mtl_stencil_attachment_.slice = 0;
1107 mtl_stencil_attachment_.depth_plane = 0;
1108 break;
1110 if (layer < 0) {
1111 layer = 0;
1112 MTL_LOG_WARNING("TODO: Support layered rendering for 1D array textures, if needed");
1113 }
1114 BLI_assert(layer < texture->h_);
1115 mtl_stencil_attachment_.slice = layer;
1116 mtl_stencil_attachment_.depth_plane = 0;
1117 break;
1119 BLI_assert(layer < texture->d_);
1120 mtl_stencil_attachment_.slice = layer;
1121 mtl_stencil_attachment_.depth_plane = 0;
1122 if (layer == -1) {
1123 mtl_stencil_attachment_.slice = 0;
1124 mtl_stencil_attachment_.render_target_array_length = texture->d_;
1125 use_multilayered_rendering_ = true;
1126 }
1127 break;
1128 case GPU_TEXTURE_3D:
1129 BLI_assert(layer < texture->d_);
1130 mtl_stencil_attachment_.slice = 0;
1131 mtl_stencil_attachment_.depth_plane = layer;
1132 if (layer == -1) {
1133 mtl_stencil_attachment_.depth_plane = 0;
1134 mtl_stencil_attachment_.render_target_array_length = texture->d_;
1135 use_multilayered_rendering_ = true;
1136 }
1137 break;
1138 case GPU_TEXTURE_CUBE:
1139 BLI_assert(layer < 6);
1140 mtl_stencil_attachment_.slice = layer;
1141 mtl_stencil_attachment_.depth_plane = 0;
1142 if (layer == -1) {
1143 mtl_stencil_attachment_.slice = 0;
1144 mtl_stencil_attachment_.depth_plane = 0;
1145 mtl_stencil_attachment_.render_target_array_length = 6;
1146 use_multilayered_rendering_ = true;
1147 }
1148 break;
1150 /* TODO(Metal): Verify multilayered rendering for Cube arrays. */
1151 BLI_assert(layer < 6 * texture->d_);
1152 mtl_stencil_attachment_.slice = layer;
1153 mtl_stencil_attachment_.depth_plane = 0;
1154 if (layer == -1) {
1155 mtl_stencil_attachment_.slice = 0;
1156 mtl_stencil_attachment_.depth_plane = 0;
1157 mtl_stencil_attachment_.render_target_array_length = texture->d_;
1158 use_multilayered_rendering_ = true;
1159 }
1160 break;
1161 case GPU_TEXTURE_BUFFER:
1162 mtl_stencil_attachment_.slice = 0;
1163 mtl_stencil_attachment_.depth_plane = 0;
1164 break;
1165 default:
1166 BLI_assert_msg(false, "Unrecognized texture type");
1167 break;
1168 }
1169
1170 /* Update default attachment size and ensure future attachments match the same size. */
1171 int width_of_miplayer, height_of_miplayer;
1172 if (miplevel <= 0) {
1173 width_of_miplayer = texture->width_get();
1174 height_of_miplayer = texture->height_get();
1175 }
1176 else {
1177 width_of_miplayer = max_ii(texture->width_get() >> miplevel, 1);
1178 height_of_miplayer = max_ii(texture->height_get() >> miplevel, 1);
1179 }
1180
1181 if (default_width_ == 0 || default_height_ == 0) {
1182 this->default_size_set(width_of_miplayer, height_of_miplayer);
1183 BLI_assert(default_width_ > 0);
1184 BLI_assert(default_height_ > 0);
1185 }
1186 else {
1187 BLI_assert(default_width_ == width_of_miplayer);
1188 BLI_assert(default_height_ == height_of_miplayer);
1189 }
1190
1191 /* Flag as dirty after attachments changed. */
1192 this->mark_dirty();
1193 }
1194 else {
1196 "Passing in null texture to MTLFrameBuffer::addStencilAttachment (This could be due to "
1197 "not all texture types being supported).");
1198 }
1199 return true;
1200}
1201
1203{
1204 BLI_assert(this);
1205 BLI_assert(slot >= 0 && slot < this->get_attachment_limit());
1206
1207 if (this->has_attachment_at_slot(slot)) {
1208 colour_attachment_count_ -= (mtl_color_attachments_[slot].used) ? 1 : 0;
1209 mtl_color_attachments_[slot].used = false;
1211 this->mark_dirty();
1212 return true;
1213 }
1214
1215 return false;
1216}
1217
1219{
1220 BLI_assert(this);
1221
1222 mtl_depth_attachment_.used = false;
1223 mtl_depth_attachment_.texture = nullptr;
1225 this->mark_dirty();
1226
1227 return true;
1228}
1229
1231{
1232 BLI_assert(this);
1233
1234 mtl_stencil_attachment_.used = false;
1235 mtl_stencil_attachment_.texture = nullptr;
1237 this->mark_dirty();
1238
1239 return true;
1240}
1241
1243{
1244 BLI_assert(this);
1245
1246 for (int attachment = 0; attachment < GPU_FB_MAX_COLOR_ATTACHMENT; attachment++) {
1247 this->remove_color_attachment(attachment);
1248 }
1251 colour_attachment_count_ = 0;
1252 this->mark_dirty();
1253
1254 /* Verify height. */
1256
1257 /* Flag attachments as no longer being dirty. */
1258 dirty_attachments_ = false;
1259}
1260
1262{
1263 /* If we have no attachments, reset width and height to zero. */
1264 if (colour_attachment_count_ == 0 && !this->has_depth_attachment() &&
1265 !this->has_stencil_attachment())
1266 {
1267 /* Reset default size for empty framebuffer. */
1268 this->default_size_set(0, 0);
1269 }
1270}
1271
1274/* -------------------------------------------------------------------- */
1279{
1280 if (type >= GPU_FB_COLOR_ATTACHMENT0) {
1281 int slot = type - GPU_FB_COLOR_ATTACHMENT0;
1284 }
1286 }
1287 else if (type == GPU_FB_DEPTH_STENCIL_ATTACHMENT) {
1290 }
1293 }
1294 else if (type == GPU_FB_DEPTH_ATTACHMENT) {
1297 }
1299 }
1300}
1301
1302bool MTLFrameBuffer::set_color_attachment_clear_color(uint slot, const float clear_color[4])
1303{
1304 BLI_assert(this);
1305 BLI_assert(slot >= 0 && slot < this->get_attachment_limit());
1306
1307 /* Only mark as dirty if values have changed. */
1308 bool changed = mtl_color_attachments_[slot].load_action != GPU_LOADACTION_CLEAR;
1309 changed = changed || (memcmp(mtl_color_attachments_[slot].clear_value.color,
1310 clear_color,
1311 sizeof(float) * 4) != 0);
1312 if (changed) {
1313 memcpy(mtl_color_attachments_[slot].clear_value.color, clear_color, sizeof(float) * 4);
1314 }
1315 mtl_color_attachments_[slot].load_action = GPU_LOADACTION_CLEAR;
1316
1317 if (changed) {
1318 this->mark_loadstore_dirty();
1319 }
1320 return true;
1321}
1322
1324{
1325 BLI_assert(this);
1326
1327 if (mtl_depth_attachment_.clear_value.depth != depth_clear ||
1328 mtl_depth_attachment_.load_action != GPU_LOADACTION_CLEAR)
1329 {
1330 mtl_depth_attachment_.clear_value.depth = depth_clear;
1331 mtl_depth_attachment_.load_action = GPU_LOADACTION_CLEAR;
1332 this->mark_loadstore_dirty();
1333 }
1334 return true;
1335}
1336
1338{
1339 BLI_assert(this);
1340
1341 if (mtl_stencil_attachment_.clear_value.stencil != stencil_clear ||
1342 mtl_stencil_attachment_.load_action != GPU_LOADACTION_CLEAR)
1343 {
1344 mtl_stencil_attachment_.clear_value.stencil = stencil_clear;
1345 mtl_stencil_attachment_.load_action = GPU_LOADACTION_CLEAR;
1346 this->mark_loadstore_dirty();
1347 }
1348 return true;
1349}
1350
1352 eGPULoadOp load_action,
1353 eGPUStoreOp store_action)
1354{
1355 BLI_assert(this);
1356 eGPULoadOp prev_load_action = mtl_color_attachments_[slot].load_action;
1357 eGPUStoreOp prev_store_action = mtl_color_attachments_[slot].store_action;
1358 mtl_color_attachments_[slot].load_action = load_action;
1359 mtl_color_attachments_[slot].store_action = store_action;
1360
1361 bool changed = (mtl_color_attachments_[slot].load_action != prev_load_action ||
1362 mtl_color_attachments_[slot].store_action != prev_store_action);
1363 if (changed) {
1364 this->mark_loadstore_dirty();
1365 }
1366
1367 return changed;
1368}
1369
1371{
1372 BLI_assert(this);
1373 eGPULoadOp prev_load_action = mtl_depth_attachment_.load_action;
1374 eGPUStoreOp prev_store_action = mtl_depth_attachment_.store_action;
1375 mtl_depth_attachment_.load_action = load_action;
1376 mtl_depth_attachment_.store_action = store_action;
1377
1378 bool changed = (mtl_depth_attachment_.load_action != prev_load_action ||
1379 mtl_depth_attachment_.store_action != prev_store_action);
1380 if (changed) {
1381 this->mark_loadstore_dirty();
1382 }
1383
1384 return changed;
1385}
1386
1388{
1389 BLI_assert(this);
1390 eGPULoadOp prev_load_action = mtl_stencil_attachment_.load_action;
1391 eGPUStoreOp prev_store_action = mtl_stencil_attachment_.store_action;
1392 mtl_stencil_attachment_.load_action = load_action;
1393 mtl_stencil_attachment_.store_action = store_action;
1394
1395 bool changed = (mtl_stencil_attachment_.load_action != prev_load_action ||
1396 mtl_stencil_attachment_.store_action != prev_store_action);
1397 if (changed) {
1398 this->mark_loadstore_dirty();
1399 }
1400
1401 return changed;
1402}
1403
1405{
1406 for (int slot = 0; slot < colour_attachment_count_; slot++) {
1408 }
1411 return true;
1412}
1413
1416/* -------------------------------------------------------------------- */
1421{
1422 BLI_assert(this);
1423
1424 if (slot >= 0 && slot < this->get_attachment_limit()) {
1425 return mtl_color_attachments_[slot].used;
1426 }
1427 return false;
1428}
1429
1431{
1432 BLI_assert(this);
1433
1434 for (int attachment = 0; attachment < this->get_attachment_limit(); attachment++) {
1435 if (mtl_color_attachments_[attachment].used &&
1436 mtl_color_attachments_[attachment].texture == texture)
1437 {
1438 return true;
1439 }
1440 }
1441 return false;
1442}
1443
1445{
1446 BLI_assert(this);
1447 return mtl_depth_attachment_.used;
1448}
1449
1451{
1452 BLI_assert(this);
1453 return mtl_stencil_attachment_.used;
1454}
1455
1457{
1458 BLI_assert(this);
1459 BLI_assert(texture);
1460
1461 for (int attachment = 0; attachment < this->get_attachment_limit(); attachment++) {
1462 if (mtl_color_attachments_[attachment].used &&
1463 (mtl_color_attachments_[attachment].texture == texture))
1464 {
1465 return attachment;
1466 }
1467 }
1468 return -1;
1469}
1470
1472{
1473 BLI_assert(this);
1474 return colour_attachment_count_;
1475}
1476
1478{
1479 BLI_assert(this);
1480 if (slot >= 0 && slot < GPU_FB_MAX_COLOR_ATTACHMENT) {
1481 return mtl_color_attachments_[slot];
1482 }
1483 MTLAttachment null_attachment;
1484 null_attachment.used = false;
1485 return null_attachment;
1486}
1487
1489{
1490 BLI_assert(this);
1491 return mtl_depth_attachment_;
1492}
1493
1495{
1496 BLI_assert(this);
1497 return mtl_stencil_attachment_;
1498}
1499
1502/* -------------------------------------------------------------------- */
1506{
1507 BLI_assert(this);
1508
1509 /* First update attachments if dirty. */
1510 if (dirty_attachments_) {
1511 this->update_attachments(true);
1512 }
1513
1514 /* NOTE: Attachment-less render targets now supported so we do not need to validate attachment
1515 * counts. Keeping this function in place if other parameters need to be validate. */
1516 return true;
1517}
1518
1520{
1521 return (action == GPU_LOADACTION_LOAD) ?
1522 MTLLoadActionLoad :
1523 ((action == GPU_LOADACTION_CLEAR) ? MTLLoadActionClear : MTLLoadActionDontCare);
1524}
1525
1527{
1528 return (action == GPU_STOREACTION_STORE) ? MTLStoreActionStore : MTLStoreActionDontCare;
1529}
1530
1531MTLRenderPassDescriptor *MTLFrameBuffer::bake_render_pass_descriptor(bool load_contents)
1532{
1533 BLI_assert(this);
1534 if (load_contents) {
1535 /* Only force-load contents if there is no clear pending. */
1536 BLI_assert(!has_pending_clear_);
1537 }
1538
1539 /* Ensure we are inside a frame boundary. */
1540 MTLContext *metal_ctx = MTLContext::get();
1541 BLI_assert(metal_ctx && metal_ctx->get_inside_frame());
1542 UNUSED_VARS_NDEBUG(metal_ctx);
1543
1544 /* If Frame-buffer has been modified, regenerate descriptor. */
1545 if (is_dirty_) {
1546 /* Clear all configs. */
1547 for (int config = 0; config < 3; config++) {
1548 descriptor_dirty_[config] = true;
1549 }
1550 }
1551 else if (is_loadstore_dirty_) {
1552 /* Load config always has load ops, so we only need to re-generate custom and clear state. */
1553 descriptor_dirty_[MTL_FB_CONFIG_CLEAR] = true;
1554 descriptor_dirty_[MTL_FB_CONFIG_CUSTOM] = true;
1555 }
1556
1557 /* If we need to populate descriptor" */
1558 /* Select config based on FrameBuffer state:
1559 * [0] {MTL_FB_CONFIG_CLEAR} = Clear config -- we have a pending clear so should perform our
1560 * configured clear.
1561 * [1] {MTL_FB_CONFIG_LOAD} = Load config -- We need to re-load ALL attachments,
1562 * used for re-binding/pass-breaks.
1563 * [2] {MTL_FB_CONFIG_CUSTOM} = Custom config -- Use this when a custom binding config is
1564 * specified.
1565 */
1566 uint descriptor_config = (load_contents) ? MTL_FB_CONFIG_LOAD :
1567 ((this->get_pending_clear()) ? MTL_FB_CONFIG_CLEAR :
1568 MTL_FB_CONFIG_CUSTOM);
1569
1570 /* NOTE: If `GPU_framebuffer_bind_loadstore` is used, the `use_explicit_load_store_` flag will be
1571 * set in which case, we should always use the custom configuration. Calls with this flag will
1572 * only happen for the first render pass after binding. */
1574 descriptor_config = MTL_FB_CONFIG_CUSTOM;
1575 descriptor_dirty_[descriptor_config] = true;
1576 }
1577
1578 if (descriptor_dirty_[descriptor_config] || framebuffer_descriptor_[descriptor_config] == nil) {
1579
1580 /* Create descriptor if it does not exist. */
1581 if (framebuffer_descriptor_[descriptor_config] == nil) {
1582 framebuffer_descriptor_[descriptor_config] = [[MTLRenderPassDescriptor alloc] init];
1583 }
1584
1585 /* Configure multilayered rendering. */
1586 if (use_multilayered_rendering_) {
1587 /* Ensure all targets have the same length. */
1588 int len = 0;
1589 bool valid = true;
1590
1591 for (int attachment_ind = 0; attachment_ind < GPU_FB_MAX_COLOR_ATTACHMENT; attachment_ind++)
1592 {
1593 if (mtl_color_attachments_[attachment_ind].used) {
1594 if (len == 0) {
1595 len = mtl_color_attachments_[attachment_ind].render_target_array_length;
1596 }
1597 else {
1598 valid = valid &&
1599 (len == mtl_color_attachments_[attachment_ind].render_target_array_length);
1600 }
1601 }
1602 }
1603
1604 if (mtl_depth_attachment_.used) {
1605 if (len == 0) {
1606 len = mtl_depth_attachment_.render_target_array_length;
1607 }
1608 else {
1609 valid = valid && (len == mtl_depth_attachment_.render_target_array_length);
1610 }
1611 }
1612
1613 if (mtl_stencil_attachment_.used) {
1614 if (len == 0) {
1615 len = mtl_stencil_attachment_.render_target_array_length;
1616 }
1617 else {
1618 valid = valid && (len == mtl_stencil_attachment_.render_target_array_length);
1619 }
1620 }
1621
1622 BLI_assert(len > 0);
1623 BLI_assert(valid);
1624 framebuffer_descriptor_[descriptor_config].renderTargetArrayLength = len;
1625 }
1626 else {
1627 framebuffer_descriptor_[descriptor_config].renderTargetArrayLength = 0;
1628 }
1629
1630 /* Color attachments. */
1631 int colour_attachments = 0;
1632 for (int attachment_ind = 0; attachment_ind < GPU_FB_MAX_COLOR_ATTACHMENT; attachment_ind++) {
1633 MTLAttachment &attachment_config = mtl_color_attachments_[attachment_ind];
1634
1635 if (attachment_config.used) {
1636 id<MTLTexture> texture = attachment_config.texture->get_metal_handle_base();
1637 if (texture == nil) {
1638 MTL_LOG_ERROR("Attempting to assign invalid texture as attachment");
1639 }
1640
1641 bool texture_is_memoryless = (attachment_config.texture->usage_get() &
1643
1644 /* IF SRGB is enabled, but we are rendering with SRGB disabled, sample texture view. */
1645 id<MTLTexture> source_color_texture = texture;
1646 if (this->get_is_srgb() && attachment_config.texture->is_format_srgb() &&
1647 !this->get_srgb_enabled())
1648 {
1649 source_color_texture = attachment_config.texture->get_non_srgb_handle();
1650 BLI_assert(source_color_texture != nil);
1651 }
1652
1653 /* Resolve appropriate load action -- IF force load, perform load.
1654 * If clear but framebuffer has no pending clear, also load. */
1655 eGPULoadOp load_action = attachment_config.load_action;
1656 if (descriptor_config == MTL_FB_CONFIG_LOAD) {
1657 /* MTL_FB_CONFIG_LOAD must always load. */
1658 load_action = GPU_LOADACTION_LOAD;
1659 }
1660 else if (descriptor_config == MTL_FB_CONFIG_CUSTOM && load_action == GPU_LOADACTION_CLEAR)
1661 {
1662 /* If Custom load config is used, fallback to loading if explicit bind state flag is
1663 * unset. This is to ensure attachments are loaded by default in the case a framebuffer
1664 * is unbound and rebound, or, if a render pass breaks mid-pass for compute or blit
1665 * operations. */
1666 if (!use_explicit_load_store_ && !texture_is_memoryless) {
1667 load_action = GPU_LOADACTION_LOAD;
1668 }
1669 }
1670
1671 /* Ensure memoryless attachment cannot load or store results. */
1672 eGPUStoreOp store_action = attachment_config.store_action;
1673 if (texture_is_memoryless && load_action == GPU_LOADACTION_LOAD) {
1674 load_action = GPU_LOADACTION_DONT_CARE;
1675 }
1676 if (texture_is_memoryless && store_action == GPU_STOREACTION_STORE) {
1677 store_action = GPU_STOREACTION_DONT_CARE;
1678 }
1679
1680 /* Create attachment descriptor. */
1681 MTLRenderPassColorAttachmentDescriptor *attachment =
1682 colour_attachment_descriptors_[attachment_ind];
1683 BLI_assert(attachment != nil);
1684
1685 attachment.texture = source_color_texture;
1686 attachment.loadAction = mtl_load_action_from_gpu(load_action);
1687 attachment.clearColor = (load_action == GPU_LOADACTION_CLEAR) ?
1688 MTLClearColorMake(
1689 UNPACK4(attachment_config.clear_value.color)) :
1690 MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
1691 attachment.storeAction = mtl_store_action_from_gpu(store_action);
1692 attachment.level = attachment_config.mip;
1693 attachment.slice = attachment_config.slice;
1694 attachment.depthPlane = attachment_config.depth_plane;
1695 colour_attachments++;
1696
1697 /* Copy attachment info back in. */
1698 [framebuffer_descriptor_[descriptor_config].colorAttachments setObject:attachment
1699 atIndexedSubscript:attachment_ind];
1700 }
1701 else {
1702 /* Disable color attachment. */
1703 [framebuffer_descriptor_[descriptor_config].colorAttachments setObject:nil
1704 atIndexedSubscript:attachment_ind];
1705 }
1706 }
1707 BLI_assert(colour_attachments == colour_attachment_count_);
1708 UNUSED_VARS_NDEBUG(colour_attachments);
1709
1710 /* Depth attachment. */
1711 if (mtl_depth_attachment_.used) {
1712 framebuffer_descriptor_[descriptor_config].depthAttachment.texture =
1713 (id<MTLTexture>)mtl_depth_attachment_.texture->get_metal_handle_base();
1714
1715 bool texture_is_memoryless = (mtl_depth_attachment_.texture->usage_get() &
1717
1718 /* Resolve appropriate load action -- IF force load, perform load.
1719 * If clear but framebuffer has no pending clear, also load. */
1720 eGPULoadOp load_action = mtl_depth_attachment_.load_action;
1721 if (descriptor_config == MTL_FB_CONFIG_LOAD) {
1722 /* MTL_FB_CONFIG_LOAD must always load. */
1723 load_action = GPU_LOADACTION_LOAD;
1724 }
1725 else if (descriptor_config == MTL_FB_CONFIG_CUSTOM && load_action == GPU_LOADACTION_CLEAR) {
1726 /* If Custom load config is used, fallback to loading if explicit bind state flag is unset.
1727 * This is to ensure attachments are loaded by default in the case a framebuffer is unbound
1728 * and rebound, or, if a render pass breaks mid-pass for compute or blit operations. */
1729 if (!use_explicit_load_store_ && !texture_is_memoryless) {
1730 load_action = GPU_LOADACTION_LOAD;
1731 }
1732 }
1733
1734 /* Ensure memoryless attachment cannot load or store results. */
1735 eGPUStoreOp store_action = mtl_depth_attachment_.store_action;
1736 if (texture_is_memoryless && load_action == GPU_LOADACTION_LOAD) {
1737 load_action = GPU_LOADACTION_DONT_CARE;
1738 }
1739 if (texture_is_memoryless && store_action == GPU_STOREACTION_STORE) {
1740 store_action = GPU_STOREACTION_DONT_CARE;
1741 }
1742
1743 framebuffer_descriptor_[descriptor_config].depthAttachment.loadAction =
1744 mtl_load_action_from_gpu(load_action);
1745 framebuffer_descriptor_[descriptor_config].depthAttachment.clearDepth =
1746 (load_action == GPU_LOADACTION_CLEAR) ? mtl_depth_attachment_.clear_value.depth : 0;
1747 framebuffer_descriptor_[descriptor_config].depthAttachment.storeAction =
1748 mtl_store_action_from_gpu(store_action);
1749 framebuffer_descriptor_[descriptor_config].depthAttachment.level = mtl_depth_attachment_.mip;
1750 framebuffer_descriptor_[descriptor_config].depthAttachment.slice =
1751 mtl_depth_attachment_.slice;
1752 framebuffer_descriptor_[descriptor_config].depthAttachment.depthPlane =
1753 mtl_depth_attachment_.depth_plane;
1754 }
1755 else {
1756 framebuffer_descriptor_[descriptor_config].depthAttachment.texture = nil;
1757 }
1758
1759 /* Stencil attachment. */
1760 if (mtl_stencil_attachment_.used) {
1761 framebuffer_descriptor_[descriptor_config].stencilAttachment.texture =
1762 (id<MTLTexture>)mtl_stencil_attachment_.texture->get_metal_handle_base();
1763
1764 bool texture_is_memoryless = (mtl_stencil_attachment_.texture->usage_get() &
1766
1767 /* Resolve appropriate load action -- IF force load, perform load.
1768 * If clear but framebuffer has no pending clear, also load. */
1769 eGPULoadOp load_action = mtl_stencil_attachment_.load_action;
1770 if (descriptor_config == MTL_FB_CONFIG_LOAD) {
1771 /* MTL_FB_CONFIG_LOAD must always load. */
1772 load_action = GPU_LOADACTION_LOAD;
1773 }
1774 else if (descriptor_config == MTL_FB_CONFIG_CUSTOM && load_action == GPU_LOADACTION_CLEAR) {
1775 /* If Custom load config is used, fallback to loading if explicit bind state flag is unset.
1776 * This is to ensure attachments are loaded by default in the case a framebuffer is unbound
1777 * and rebound, or, if a render pass breaks mid-pass for compute or blit operations. */
1778 if (!use_explicit_load_store_ && !texture_is_memoryless) {
1779 load_action = GPU_LOADACTION_LOAD;
1780 }
1781 }
1782
1783 /* Ensure memoryless attachment cannot load or store results. */
1784 eGPUStoreOp store_action = mtl_stencil_attachment_.store_action;
1785 if (texture_is_memoryless && load_action == GPU_LOADACTION_LOAD) {
1786 load_action = GPU_LOADACTION_DONT_CARE;
1787 }
1788 if (texture_is_memoryless && store_action == GPU_STOREACTION_STORE) {
1789 store_action = GPU_STOREACTION_DONT_CARE;
1790 }
1791
1792 framebuffer_descriptor_[descriptor_config].stencilAttachment.loadAction =
1793 mtl_load_action_from_gpu(load_action);
1794 framebuffer_descriptor_[descriptor_config].stencilAttachment.clearStencil =
1795 (load_action == GPU_LOADACTION_CLEAR) ? mtl_stencil_attachment_.clear_value.stencil : 0;
1796 framebuffer_descriptor_[descriptor_config].stencilAttachment.storeAction =
1797 mtl_store_action_from_gpu(store_action);
1798 framebuffer_descriptor_[descriptor_config].stencilAttachment.level =
1799 mtl_stencil_attachment_.mip;
1800 framebuffer_descriptor_[descriptor_config].stencilAttachment.slice =
1801 mtl_stencil_attachment_.slice;
1802 framebuffer_descriptor_[descriptor_config].stencilAttachment.depthPlane =
1803 mtl_stencil_attachment_.depth_plane;
1804 }
1805 else {
1806 framebuffer_descriptor_[descriptor_config].stencilAttachment.texture = nil;
1807 }
1808
1809 /* Attachmentless render support. */
1810 int total_num_attachments = colour_attachment_count_ + (mtl_depth_attachment_.used ? 1 : 0) +
1811 (mtl_stencil_attachment_.used ? 1 : 0);
1812 if (total_num_attachments == 0) {
1813 BLI_assert(width_ > 0 && height_ > 0);
1814 framebuffer_descriptor_[descriptor_config].renderTargetWidth = width_;
1815 framebuffer_descriptor_[descriptor_config].renderTargetHeight = height_;
1816 framebuffer_descriptor_[descriptor_config].defaultRasterSampleCount = 1;
1817 }
1818
1819 descriptor_dirty_[descriptor_config] = false;
1820 }
1821 /* Clear dirty state flags. */
1822 is_dirty_ = false;
1823 is_loadstore_dirty_ = false;
1824
1825 /* Clear explicit bind flag. */
1827
1828 return framebuffer_descriptor_[descriptor_config];
1829}
1830
1833/* -------------------------------------------------------------------- */
1838 uint src_x_offset,
1839 uint src_y_offset,
1840 MTLFrameBuffer *metal_fb_write,
1841 uint write_slot,
1842 uint dst_x_offset,
1843 uint dst_y_offset,
1844 uint width,
1845 uint height,
1846 eGPUFrameBufferBits blit_buffers)
1847{
1848 BLI_assert(metal_fb_write);
1849 if (!metal_fb_write) {
1850 return;
1851 }
1852 MTLContext *mtl_context = MTLContext::get();
1853
1854 const bool do_color = (blit_buffers & GPU_COLOR_BIT);
1855 const bool do_depth = (blit_buffers & GPU_DEPTH_BIT);
1856 const bool do_stencil = (blit_buffers & GPU_STENCIL_BIT);
1857
1858 /* Early exit if there is no blit to do. */
1859 if (!(do_color || do_depth || do_stencil)) {
1860 MTL_LOG_WARNING("FrameBuffer: requested blit but no color, depth or stencil flag was set");
1861 return;
1862 }
1863
1864 id<MTLBlitCommandEncoder> blit_encoder = nil;
1865
1866 /* If the color format is not the same, we cannot use the BlitCommandEncoder, and instead use
1867 * a Graphics-based blit. */
1868 if (do_color && (this->get_color_attachment(read_slot).texture->format_get() !=
1869 metal_fb_write->get_color_attachment(read_slot).texture->format_get()))
1870 {
1871
1872 MTLAttachment src_attachment = this->get_color_attachment(read_slot);
1873 MTLAttachment dst_attachment = metal_fb_write->get_color_attachment(write_slot);
1874 assert(src_attachment.slice == 0 &&
1875 "currently only supporting slice 0 for graphics framebuffer blit");
1876
1877 src_attachment.texture->blit(dst_attachment.texture,
1878 src_x_offset,
1879 src_y_offset,
1880 dst_x_offset,
1881 dst_y_offset,
1882 src_attachment.mip,
1883 dst_attachment.mip,
1884 dst_attachment.slice,
1885 width,
1886 height);
1887 }
1888 else {
1889
1890 /* Setup blit encoder. */
1891 blit_encoder = mtl_context->main_command_buffer.ensure_begin_blit_encoder();
1892
1893 if (do_color) {
1894 MTLAttachment src_attachment = this->get_color_attachment(read_slot);
1895 MTLAttachment dst_attachment = metal_fb_write->get_color_attachment(write_slot);
1896
1897 if (src_attachment.used && dst_attachment.used) {
1898
1899 /* TODO(Metal): Support depth(z) offset in blit if needed. */
1900 src_attachment.texture->blit(blit_encoder,
1901 src_x_offset,
1902 src_y_offset,
1903 0,
1904 src_attachment.slice,
1905 src_attachment.mip,
1906 dst_attachment.texture,
1907 dst_x_offset,
1908 dst_y_offset,
1909 0,
1910 dst_attachment.slice,
1911 dst_attachment.mip,
1912 width,
1913 height,
1914 1);
1915 }
1916 else {
1917 MTL_LOG_ERROR("Failed performing colour blit");
1918 }
1919 }
1920 }
1921 if ((do_depth || do_stencil) && blit_encoder == nil) {
1922 blit_encoder = mtl_context->main_command_buffer.ensure_begin_blit_encoder();
1923 }
1924
1925 if (do_depth) {
1926 MTLAttachment src_attachment = this->get_depth_attachment();
1927 MTLAttachment dst_attachment = metal_fb_write->get_depth_attachment();
1928
1929 if (src_attachment.used && dst_attachment.used) {
1930
1931 /* TODO(Metal): Support depth(z) offset in blit if needed. */
1932 src_attachment.texture->blit(blit_encoder,
1933 src_x_offset,
1934 src_y_offset,
1935 0,
1936 src_attachment.slice,
1937 src_attachment.mip,
1938 dst_attachment.texture,
1939 dst_x_offset,
1940 dst_y_offset,
1941 0,
1942 dst_attachment.slice,
1943 dst_attachment.mip,
1944 width,
1945 height,
1946 1);
1947 }
1948 else {
1949 MTL_LOG_ERROR("Failed performing depth blit");
1950 }
1951 }
1952
1953 /* Stencil attachment blit. */
1954 if (do_stencil) {
1955 MTLAttachment src_attachment = this->get_stencil_attachment();
1956 MTLAttachment dst_attachment = metal_fb_write->get_stencil_attachment();
1957
1958 if (src_attachment.used && dst_attachment.used) {
1959
1960 /* TODO(Metal): Support depth(z) offset in blit if needed. */
1961 src_attachment.texture->blit(blit_encoder,
1962 src_x_offset,
1963 src_y_offset,
1964 0,
1965 src_attachment.slice,
1966 src_attachment.mip,
1967 dst_attachment.texture,
1968 dst_x_offset,
1969 dst_y_offset,
1970 0,
1971 dst_attachment.slice,
1972 dst_attachment.mip,
1973 width,
1974 height,
1975 1);
1976 }
1977 else {
1978 MTL_LOG_ERROR("Failed performing Stencil blit");
1979 }
1980 }
1981}
1982
1984{
1985 return width_;
1986}
1988{
1989 return height_;
1990}
1991
1993{
1994 return default_width_;
1995}
1997{
1998 return default_height_;
1999}
2000
2001} // namespace blender::gpu
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
MINLINE int max_ii(int a, int b)
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
#define UNPACK4(a)
#define UNUSED_VARS_NDEBUG(...)
@ GPU_LOADACTION_LOAD
@ GPU_LOADACTION_DONT_CARE
@ GPU_LOADACTION_CLEAR
eGPUStoreOp
@ GPU_STOREACTION_STORE
@ GPU_STOREACTION_DONT_CARE
GPUAttachmentState
@ GPU_ATTACHMENT_READ
void GPU_framebuffer_restore()
eGPUFrameBufferBits
@ GPU_DEPTH_BIT
@ GPU_STENCIL_BIT
@ GPU_COLOR_BIT
#define GPU_MAX_VIEWPORTS
@ GPU_ARCHITECTURE_TBDR
GPUArchitectureType GPU_platform_architecture()
eGPUDataFormat
@ GPU_DATA_UINT_24_8
@ GPU_DATA_INT
@ GPU_DATA_UINT
@ GPU_DATA_FLOAT
@ GPU_TEXTURE_USAGE_MEMORYLESS
@ GPU_TEXTURE_USAGE_ATTACHMENT
void GPU_texture_image_bind(GPUTexture *texture, int unit)
eGPUTextureFormat
@ GPU_DEPTH32F_STENCIL8
@ GPU_SRGB8_A8
@ GPU_DEPTH24_STENCIL8
void GPU_texture_get_mipmap_size(GPUTexture *texture, int mip_level, int *r_size)
eGPUTextureFormat GPU_texture_format(const GPUTexture *texture)
void init()
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
void size_set(int width, int height)
GPUAttachment attachments_[GPU_FB_MAX_ATTACHMENT]
int viewport_[GPU_MAX_VIEWPORTS][4]
id< MTLBlitCommandEncoder > ensure_begin_blit_encoder()
MTLFrameBuffer * get_current_framebuffer()
void set_scissor_enabled(bool scissor_enabled)
void framebuffer_bind(MTLFrameBuffer *framebuffer)
id< MTLRenderCommandEncoder > ensure_begin_render_pass()
static MTLContext * get()
void set_viewport(int origin_x, int origin_y, int width, int height)
void set_viewports(int count, const int(&viewports)[GPU_MAX_VIEWPORTS][4])
void set_scissor(int scissor_x, int scissor_y, int scissor_width, int scissor_height)
MTLCommandBufferManager main_command_buffer
bool set_depth_loadstore_op(eGPULoadOp load_action, eGPUStoreOp store_action)
MTLAttachment get_color_attachment(uint slot)
void blit(uint read_slot, uint src_x_offset, uint src_y_offset, MTLFrameBuffer *metal_fb_write, uint write_slot, uint dst_x_offset, uint dst_y_offset, uint width, uint height, eGPUFrameBufferBits blit_buffers)
void read(eGPUFrameBufferBits planes, eGPUDataFormat format, const int area[4], int channel_len, int slot, void *r_data) override
int get_color_attachment_slot_from_texture(gpu::MTLTexture *texture)
void blit_to(eGPUFrameBufferBits planes, int src_slot, FrameBuffer *dst, int dst_slot, int dst_offset_x, int dst_offset_y) override
void default_size_set(int w, int h)
bool check(char err_out[256]) override
bool add_color_attachment(gpu::MTLTexture *texture, uint slot, int miplevel, int layer)
bool set_color_attachment_clear_color(uint slot, const float clear_color[4])
MTLFrameBuffer(MTLContext *ctx, const char *name)
bool set_depth_attachment_clear_value(float depth_clear)
void update_attachments(bool update_viewport)
MTLRenderPassDescriptor * bake_render_pass_descriptor(bool load_contents)
bool has_color_attachment_with_texture(gpu::MTLTexture *texture)
void clear_multi(const float(*clear_cols)[4]) override
bool set_stencil_loadstore_op(eGPULoadOp load_action, eGPUStoreOp store_action)
bool set_color_loadstore_op(uint slot, eGPULoadOp load_action, eGPUStoreOp store_action)
bool add_depth_attachment(gpu::MTLTexture *texture, int miplevel, int layer)
void attachment_set_loadstore_op(GPUAttachmentType type, GPULoadStore ls) override
bool set_stencil_attachment_clear_value(uint stencil_clear)
bool add_stencil_attachment(gpu::MTLTexture *texture, int miplevel, int layer)
void clear_attachment(GPUAttachmentType type, eGPUDataFormat data_format, const void *clear_value) override
void clear(eGPUFrameBufferBits buffers, const float clear_col[4], float clear_depth, uint clear_stencil) override
void bind(bool enabled_srgb) override
void subpass_transition_impl(const GPUAttachmentState, Span< GPUAttachmentState > color_attachment_states) override
static void set_framebuffer_srgb_target(int use_srgb_to_linear)
eGPUTextureFormat format_get() const
eGPUTextureUsage usage_get() const
local_group_size(16, 16) .push_constant(Type texture
int len
draw_view in_light_buf[] float
@ GPU_FB_DEPTH_STENCIL_ATTACHMENT
@ GPU_FB_COLOR_ATTACHMENT5
@ GPU_FB_COLOR_ATTACHMENT2
@ GPU_FB_COLOR_ATTACHMENT3
@ GPU_FB_MAX_ATTACHMENT
@ GPU_FB_COLOR_ATTACHMENT6
@ GPU_FB_COLOR_ATTACHMENT7
@ GPU_FB_COLOR_ATTACHMENT4
@ GPU_FB_COLOR_ATTACHMENT1
@ GPU_FB_COLOR_ATTACHMENT0
@ GPU_FB_DEPTH_ATTACHMENT
#define GPU_FB_MAX_COLOR_ATTACHMENT
format
#define MTL_LOG_WARNING(info,...)
Definition mtl_debug.hh:44
#define MTL_LOG_ERROR(info,...)
Definition mtl_debug.hh:36
#define MTL_FB_CONFIG_MAX
static Context * unwrap(GPUContext *ctx)
MTLLoadAction mtl_load_action_from_gpu(eGPULoadOp action)
size_t to_bytesize(GPUIndexBufType type)
static const int MTL_MAX_MIPMAP_COUNT
MTLStoreAction mtl_store_action_from_gpu(eGPUStoreOp action)
unsigned int uint32_t
Definition stdint.h:80
GPUTexture * tex
eGPULoadOp load_action
eGPUStoreOp store_action
union blender::gpu::MTLAttachment::@650 clear_value
char * buffers[2]