Blender V5.0
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
8
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/* -------------------------------------------------------------------- */
24
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) {
62 context_->main_command_buffer.end_active_command_encoder();
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()) {
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 if (!MTLBackend::capabilities.supports_native_tile_inputs) {
480 /* Break render-pass if tile memory is unsupported to ensure current frame-buffer results are
481 * stored. */
482 context_->main_command_buffer.end_active_command_encoder(true);
483
484 /* Bind frame-buffer attachments as textures.
485 * NOTE: Follows behavior of gl_framebuffer. However, shaders utilizing subpass_in will
486 * need to avoid bind-point collisions for image/texture resources. */
487 for (int i : color_attachment_states.index_range()) {
489 gpu::Texture *attach_tex = this->attachments_[type].tex;
490 if (color_attachment_states[i] == GPU_ATTACHMENT_READ) {
491 GPU_texture_image_bind(attach_tex, i);
492 }
493 }
494 }
495}
496
499 const int area[4],
500 int channel_len,
501 int slot,
502 void *r_data)
503{
504
505 BLI_assert((planes & GPU_STENCIL_BIT) == 0);
506 BLI_assert(area[2] > 0);
507 BLI_assert(area[3] > 0);
508
509 /* Early exit if requested read region area is zero. */
510 if (area[2] <= 0 || area[3] <= 0) {
511 return;
512 }
513
514 switch (planes) {
515 case GPU_DEPTH_BIT: {
516 if (this->has_depth_attachment()) {
517 MTLAttachment depth = this->get_depth_attachment();
518 gpu::MTLTexture *tex = depth.texture;
519 if (tex) {
520 size_t sample_len = area[2] * area[3];
521 size_t sample_size = to_bytesize(tex->format_, format);
522 size_t debug_data_size = sample_len * sample_size;
523 tex->read_internal(0,
524 area[0],
525 area[1],
526 0,
527 area[2],
528 area[3],
529 1,
530 format,
531 channel_len,
532 debug_data_size,
533 r_data);
534 }
535 }
536 else {
538 "Attempting to read depth from a framebuffer which does not have a depth "
539 "attachment!");
540 }
541 }
542 return;
543
544 case GPU_COLOR_BIT: {
545 if (this->has_attachment_at_slot(slot)) {
547 gpu::MTLTexture *tex = color.texture;
548 if (tex) {
549 size_t sample_len = area[2] * area[3];
550 size_t sample_size = to_bytesize(tex->format_, format);
551 size_t debug_data_size = sample_len * sample_size * channel_len;
552 tex->read_internal(0,
553 area[0],
554 area[1],
555 0,
556 area[2],
557 area[3],
558 1,
559 format,
560 channel_len,
561 debug_data_size,
562 r_data);
563 }
564 }
565 }
566 return;
567
568 case GPU_STENCIL_BIT:
569 MTL_LOG_ERROR("Framebuffer: Trying to read stencil bit. Unsupported.");
570 return;
571 }
572}
573
575 int src_slot,
576 FrameBuffer *dst,
577 int dst_slot,
578 int dst_offset_x,
579 int dst_offset_y)
580{
582 static_cast<MTLFrameBuffer *>(dst)->ensure_attachments_and_viewport();
583
584 BLI_assert(planes != 0);
585
586 MTLFrameBuffer *metal_fb_write = static_cast<MTLFrameBuffer *>(dst);
587
588 BLI_assert(this);
589 BLI_assert(metal_fb_write);
590
591 /* Get width/height from attachment. */
592 MTLAttachment src_attachment;
593 const bool do_color = (planes & GPU_COLOR_BIT);
594 const bool do_depth = (planes & GPU_DEPTH_BIT);
595 const bool do_stencil = (planes & GPU_STENCIL_BIT);
596
597 if (do_color) {
598 BLI_assert(!do_depth && !do_stencil);
599 src_attachment = this->get_color_attachment(src_slot);
600 }
601 else if (do_depth) {
602 BLI_assert(!do_color && !do_stencil);
603 src_attachment = this->get_depth_attachment();
604 }
605 else if (do_stencil) {
606 BLI_assert(!do_color && !do_depth);
607 src_attachment = this->get_stencil_attachment();
608 }
609
610 BLI_assert(src_attachment.used);
611 this->blit(src_slot,
612 0,
613 0,
614 metal_fb_write,
615 dst_slot,
616 dst_offset_x,
617 dst_offset_y,
618 src_attachment.texture->width_get(),
619 src_attachment.texture->height_get(),
620 planes);
621}
622
624
625/* -------------------------------------------------------------------- */
628
630{
631 is_dirty_ = true;
632 is_loadstore_dirty_ = true;
633}
634
636{
637 is_loadstore_dirty_ = true;
638}
639
641{
642 has_pending_clear_ = false;
643}
644
646{
647 has_pending_clear_ = true;
648}
649
650void MTLFrameBuffer::update_attachments(bool /*update_viewport*/)
651{
652 if (!dirty_attachments_) {
653 return;
654 }
655 /* Clear current attachments state. */
657
658 /* Reset framebuffer options. */
659 use_multilayered_rendering_ = false;
660
661 /* Track first attachment for SRGB property extraction. */
662 GPUAttachmentType first_attachment = GPU_FB_MAX_ATTACHMENT;
663 MTLAttachment first_attachment_mtl;
664
665 /* Scan through changes to attachments and populate local structures. */
666 bool depth_added = false;
667 for (GPUAttachmentType type = GPU_FB_MAX_ATTACHMENT - 1; type >= 0; --type) {
668 GPUAttachment &attach = attachments_[type];
669
670 switch (type) {
673 /* If one of the DEPTH types has added a texture, we avoid running this again, as it would
674 * only remove the target. */
675 if (depth_added) {
676 break;
677 }
678 if (attach.tex) {
679 /* If we already had a depth attachment, preserve load/clear-state parameters,
680 * but remove existing and add new attachment. */
681 if (this->has_depth_attachment()) {
682 MTLAttachment depth_attachment_prev = this->get_depth_attachment();
685 static_cast<gpu::MTLTexture *>(attach.tex), attach.mip, attach.layer);
686 this->set_depth_attachment_clear_value(depth_attachment_prev.clear_value.depth);
687 this->set_depth_loadstore_op(depth_attachment_prev.load_action,
688 depth_attachment_prev.store_action);
689 }
690 else {
692 static_cast<gpu::MTLTexture *>(attach.tex), attach.mip, attach.layer);
693 }
694
695 /* Check stencil component -- if supplied texture format supports stencil. */
697 bool use_stencil = (type == GPU_FB_DEPTH_STENCIL_ATTACHMENT) &&
698 (format == TextureFormat::SFLOAT_32_DEPTH_UINT_8);
699 if (use_stencil) {
700 if (this->has_stencil_attachment()) {
701 MTLAttachment stencil_attachment_prev = this->get_stencil_attachment();
704 static_cast<gpu::MTLTexture *>(attach.tex), attach.mip, attach.layer);
706 stencil_attachment_prev.clear_value.stencil);
707 this->set_stencil_loadstore_op(stencil_attachment_prev.load_action,
708 stencil_attachment_prev.store_action);
709 }
710 else {
712 static_cast<gpu::MTLTexture *>(attach.tex), attach.mip, attach.layer);
713 }
714 }
715
716 /* Flag depth as added -- mirrors the behavior in gl_framebuffer.cc to exit the for-loop
717 * after GPU_FB_DEPTH_STENCIL_ATTACHMENT has executed. */
718 depth_added = true;
719
720 if (first_attachment == GPU_FB_MAX_ATTACHMENT) {
721 /* Only use depth texture to get information if there is no color attachment. */
722 first_attachment = type;
723 first_attachment_mtl = this->get_depth_attachment();
724 }
725 }
726 else {
730 }
731 }
732 } break;
741 int color_slot_ind = type - GPU_FB_COLOR_ATTACHMENT0;
742 if (attach.tex) {
743 /* If we already had a color attachment, preserve load/clear-state parameters,
744 * but remove existing and add new attachment. */
745 if (this->has_attachment_at_slot(color_slot_ind)) {
746 MTLAttachment color_attachment_prev = this->get_color_attachment(color_slot_ind);
747
748 this->remove_color_attachment(color_slot_ind);
749 this->add_color_attachment(static_cast<gpu::MTLTexture *>(attach.tex),
750 color_slot_ind,
751 attach.mip,
752 attach.layer);
753 this->set_color_attachment_clear_color(color_slot_ind,
754 color_attachment_prev.clear_value.color);
755 this->set_color_loadstore_op(color_slot_ind,
756 color_attachment_prev.load_action,
757 color_attachment_prev.store_action);
758 }
759 else {
760 this->add_color_attachment(static_cast<gpu::MTLTexture *>(attach.tex),
761 color_slot_ind,
762 attach.mip,
763 attach.layer);
764 }
765 first_attachment = type;
766 first_attachment_mtl = this->get_color_attachment(color_slot_ind);
767 }
768 else {
769 this->remove_color_attachment(color_slot_ind);
770 }
771 } break;
772 default:
773 /* Non-attachment parameters. */
774 break;
775 }
776 }
777
778 /* Extract attachment size and determine if framebuffer is SRGB. */
779 if (first_attachment != GPU_FB_MAX_ATTACHMENT) {
780 /* Ensure size is correctly assigned. */
781 GPUAttachment &attach = attachments_[first_attachment];
782 int size[3];
783 GPU_texture_get_mipmap_size(attach.tex, attach.mip, size);
784 this->size_set(size[0], size[1]);
785 srgb_ = (GPU_texture_format(attach.tex) == TextureFormat::SRGBA_8_8_8_8);
786 }
787
788 /* We have now updated our internal structures. */
789 dirty_attachments_ = false;
790}
791
793{
794 MTLContext *mtl_ctx = MTLContext::get();
795 BLI_assert(mtl_ctx);
796 if (mtl_ctx->active_fb == this) {
797 if (dirty_state_ == false && dirty_state_ctx_ == mtl_ctx) {
798 return;
799 }
800
801 /* Ensure viewport has been set. NOTE: This should no longer happen, but kept for safety to
802 * track bugs. If viewport size is zero, use framebuffer size. */
803 int viewport_w = viewport_[0][2];
804 int viewport_h = viewport_[0][3];
805 if (viewport_w == 0 || viewport_h == 0) {
806 MTL_LOG_WARNING("Viewport had width and height of (0,0) -- Updating -- DEBUG Safety check");
807 viewport_w = default_width_;
808 viewport_h = default_height_;
809 }
810
811 /* Update Context State. */
812 if (multi_viewport_) {
814 }
815 else {
816 mtl_ctx->set_viewport(viewport_[0][0], viewport_[0][1], viewport_w, viewport_h);
817 }
818 mtl_ctx->set_scissor(scissor_[0], scissor_[1], scissor_[2], scissor_[3]);
820
821 dirty_state_ = false;
822 dirty_state_ctx_ = mtl_ctx;
823 }
824 else {
826 "Attempting to set FrameBuffer State (VIEWPORT, SCISSOR), But FrameBuffer is not bound to "
827 "current Context.");
828 }
829}
830
832
833/* -------------------------------------------------------------------- */
836
838 uint slot,
839 int miplevel,
840 int layer)
841{
842 BLI_assert(this);
843 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
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
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());
1207
1208 if (this->has_attachment_at_slot(slot)) {
1209 colour_attachment_count_ -= (mtl_color_attachments_[slot].used) ? 1 : 0;
1210 mtl_color_attachments_[slot].used = false;
1212 this->mark_dirty();
1213 return true;
1214 }
1215
1216 return false;
1217}
1218
1220{
1221 BLI_assert(this);
1222
1223 mtl_depth_attachment_.used = false;
1224 mtl_depth_attachment_.texture = nullptr;
1226 this->mark_dirty();
1227
1228 return true;
1229}
1230
1232{
1233 BLI_assert(this);
1234
1235 mtl_stencil_attachment_.used = false;
1236 mtl_stencil_attachment_.texture = nullptr;
1238 this->mark_dirty();
1239
1240 return true;
1241}
1242
1244{
1245 BLI_assert(this);
1246
1247 for (int attachment = 0; attachment < GPU_FB_MAX_COLOR_ATTACHMENT; attachment++) {
1248 this->remove_color_attachment(attachment);
1249 }
1252 colour_attachment_count_ = 0;
1253 this->mark_dirty();
1254
1255 /* Verify height. */
1257
1258 /* Flag attachments as no longer being dirty. */
1259 dirty_attachments_ = false;
1260}
1261
1263{
1264 /* If we have no attachments, reset width and height to zero. */
1265 if (colour_attachment_count_ == 0 && !this->has_depth_attachment() &&
1266 !this->has_stencil_attachment())
1267 {
1268 /* Reset default size for empty framebuffer. */
1269 this->default_size_set(0, 0);
1270 }
1271}
1272
1274
1275/* -------------------------------------------------------------------- */
1278
1280{
1281 if (type >= GPU_FB_COLOR_ATTACHMENT0) {
1282 int slot = type - GPU_FB_COLOR_ATTACHMENT0;
1285 }
1287 }
1288 else if (type == GPU_FB_DEPTH_STENCIL_ATTACHMENT) {
1291 }
1294 }
1295 else if (type == GPU_FB_DEPTH_ATTACHMENT) {
1298 }
1300 }
1301}
1302
1303bool MTLFrameBuffer::set_color_attachment_clear_color(uint slot, const float clear_color[4])
1304{
1305 BLI_assert(this);
1306 BLI_assert(slot >= 0 && slot < this->get_attachment_limit());
1307
1308 /* Only mark as dirty if values have changed. */
1309 bool changed = mtl_color_attachments_[slot].load_action != GPU_LOADACTION_CLEAR;
1310 float *attachment_clear_color = mtl_color_attachments_[slot].clear_value.color;
1311 changed = changed || (attachment_clear_color[0] != clear_color[0] ||
1312 attachment_clear_color[1] != clear_color[1] ||
1313 attachment_clear_color[2] != clear_color[2] ||
1314 attachment_clear_color[3] != clear_color[3]);
1315 if (changed) {
1316 attachment_clear_color[0] = clear_color[0];
1317 attachment_clear_color[1] = clear_color[1];
1318 attachment_clear_color[2] = clear_color[2];
1319 attachment_clear_color[3] = clear_color[3];
1320 }
1321 mtl_color_attachments_[slot].load_action = GPU_LOADACTION_CLEAR;
1322
1323 if (changed) {
1324 this->mark_loadstore_dirty();
1325 }
1326 return true;
1327}
1328
1330{
1331 BLI_assert(this);
1332
1333 if (mtl_depth_attachment_.clear_value.depth != depth_clear ||
1334 mtl_depth_attachment_.load_action != GPU_LOADACTION_CLEAR)
1335 {
1336 mtl_depth_attachment_.clear_value.depth = depth_clear;
1337 mtl_depth_attachment_.load_action = GPU_LOADACTION_CLEAR;
1338 this->mark_loadstore_dirty();
1339 }
1340 return true;
1341}
1342
1344{
1345 BLI_assert(this);
1346
1347 if (mtl_stencil_attachment_.clear_value.stencil != stencil_clear ||
1348 mtl_stencil_attachment_.load_action != GPU_LOADACTION_CLEAR)
1349 {
1350 mtl_stencil_attachment_.clear_value.stencil = stencil_clear;
1351 mtl_stencil_attachment_.load_action = GPU_LOADACTION_CLEAR;
1352 this->mark_loadstore_dirty();
1353 }
1354 return true;
1355}
1356
1358 GPULoadOp load_action,
1359 GPUStoreOp store_action)
1360{
1361 BLI_assert(this);
1362 GPULoadOp prev_load_action = mtl_color_attachments_[slot].load_action;
1363 GPUStoreOp prev_store_action = mtl_color_attachments_[slot].store_action;
1364 mtl_color_attachments_[slot].load_action = load_action;
1365 mtl_color_attachments_[slot].store_action = store_action;
1366
1367 bool changed = (mtl_color_attachments_[slot].load_action != prev_load_action ||
1368 mtl_color_attachments_[slot].store_action != prev_store_action);
1369 if (changed) {
1370 this->mark_loadstore_dirty();
1371 }
1372
1373 return changed;
1374}
1375
1377{
1378 BLI_assert(this);
1379 GPULoadOp prev_load_action = mtl_depth_attachment_.load_action;
1380 GPUStoreOp prev_store_action = mtl_depth_attachment_.store_action;
1381 mtl_depth_attachment_.load_action = load_action;
1382 mtl_depth_attachment_.store_action = store_action;
1383
1384 bool changed = (mtl_depth_attachment_.load_action != prev_load_action ||
1385 mtl_depth_attachment_.store_action != prev_store_action);
1386 if (changed) {
1387 this->mark_loadstore_dirty();
1388 }
1389
1390 return changed;
1391}
1392
1394{
1395 BLI_assert(this);
1396 GPULoadOp prev_load_action = mtl_stencil_attachment_.load_action;
1397 GPUStoreOp prev_store_action = mtl_stencil_attachment_.store_action;
1398 mtl_stencil_attachment_.load_action = load_action;
1399 mtl_stencil_attachment_.store_action = store_action;
1400
1401 bool changed = (mtl_stencil_attachment_.load_action != prev_load_action ||
1402 mtl_stencil_attachment_.store_action != prev_store_action);
1403 if (changed) {
1404 this->mark_loadstore_dirty();
1405 }
1406
1407 return changed;
1408}
1409
1411{
1412 for (int slot = 0; slot < colour_attachment_count_; slot++) {
1414 }
1417 return true;
1418}
1419
1421
1422/* -------------------------------------------------------------------- */
1425
1427{
1428 BLI_assert(this);
1429
1430 if (slot >= 0 && slot < this->get_attachment_limit()) {
1431 return mtl_color_attachments_[slot].used;
1432 }
1433 return false;
1434}
1435
1437{
1438 BLI_assert(this);
1439
1440 for (int attachment = 0; attachment < this->get_attachment_limit(); attachment++) {
1441 if (mtl_color_attachments_[attachment].used &&
1442 mtl_color_attachments_[attachment].texture == texture)
1443 {
1444 return true;
1445 }
1446 }
1447 return false;
1448}
1449
1451{
1452 BLI_assert(this);
1453 return mtl_depth_attachment_.used;
1454}
1455
1457{
1458 BLI_assert(this);
1459 return mtl_stencil_attachment_.used;
1460}
1461
1463{
1464 BLI_assert(this);
1466
1467 for (int attachment = 0; attachment < this->get_attachment_limit(); attachment++) {
1468 if (mtl_color_attachments_[attachment].used &&
1469 (mtl_color_attachments_[attachment].texture == texture))
1470 {
1471 return attachment;
1472 }
1473 }
1474 return -1;
1475}
1476
1478{
1479 BLI_assert(this);
1480 return colour_attachment_count_;
1481}
1482
1484{
1485 BLI_assert(this);
1486 if (slot >= 0 && slot < GPU_FB_MAX_COLOR_ATTACHMENT) {
1487 return mtl_color_attachments_[slot];
1488 }
1489 MTLAttachment null_attachment;
1490 null_attachment.used = false;
1491 return null_attachment;
1492}
1493
1495{
1496 BLI_assert(this);
1497 return mtl_depth_attachment_;
1498}
1499
1501{
1502 BLI_assert(this);
1503 return mtl_stencil_attachment_;
1504}
1505
1507
1508/* -------------------------------------------------------------------- */
1512{
1513 BLI_assert(this);
1514
1515 /* First update attachments if dirty. */
1516 if (dirty_attachments_) {
1517 this->update_attachments(true);
1518 }
1519
1520 /* NOTE: Attachment-less render targets now supported so we do not need to validate attachment
1521 * counts. Keeping this function in place if other parameters need to be validate. */
1522 return true;
1523}
1524
1526{
1527 return (action == GPU_LOADACTION_LOAD) ?
1528 MTLLoadActionLoad :
1529 ((action == GPU_LOADACTION_CLEAR) ? MTLLoadActionClear : MTLLoadActionDontCare);
1530}
1531
1533{
1534 return (action == GPU_STOREACTION_STORE) ? MTLStoreActionStore : MTLStoreActionDontCare;
1535}
1536
1537MTLRenderPassDescriptor *MTLFrameBuffer::bake_render_pass_descriptor(bool load_contents)
1538{
1539 BLI_assert(this);
1540 if (load_contents) {
1541 /* Only force-load contents if there is no clear pending. */
1542 BLI_assert(!has_pending_clear_);
1543 }
1544
1545 /* Ensure we are inside a frame boundary. */
1546 MTLContext *metal_ctx = MTLContext::get();
1547 BLI_assert(metal_ctx && metal_ctx->get_inside_frame());
1548 UNUSED_VARS_NDEBUG(metal_ctx);
1549
1550 /* If Frame-buffer has been modified, regenerate descriptor. */
1551 if (is_dirty_) {
1552 /* Clear all configurations. */
1553 for (int config = 0; config < 3; config++) {
1554 descriptor_dirty_[config] = true;
1555 }
1556 }
1557 else if (is_loadstore_dirty_) {
1558 /* Load config always has load ops, so we only need to re-generate custom and clear state. */
1559 descriptor_dirty_[MTL_FB_CONFIG_CLEAR] = true;
1560 descriptor_dirty_[MTL_FB_CONFIG_CUSTOM] = true;
1561 }
1562
1563 /* If we need to populate descriptor" */
1564 /* Select config based on FrameBuffer state:
1565 * [0] {MTL_FB_CONFIG_CLEAR} = Clear config -- we have a pending clear so should perform our
1566 * configured clear.
1567 * [1] {MTL_FB_CONFIG_LOAD} = Load config -- We need to re-load ALL attachments,
1568 * used for re-binding/pass-breaks.
1569 * [2] {MTL_FB_CONFIG_CUSTOM} = Custom config -- Use this when a custom binding config is
1570 * specified.
1571 */
1572 uint descriptor_config = (load_contents) ? MTL_FB_CONFIG_LOAD :
1573 ((this->get_pending_clear()) ? MTL_FB_CONFIG_CLEAR :
1574 MTL_FB_CONFIG_CUSTOM);
1575
1576 /* NOTE: If `GPU_framebuffer_bind_loadstore` is used, the `use_explicit_load_store_` flag will be
1577 * set in which case, we should always use the custom configuration. Calls with this flag will
1578 * only happen for the first render pass after binding. */
1580 descriptor_config = MTL_FB_CONFIG_CUSTOM;
1581 descriptor_dirty_[descriptor_config] = true;
1582 }
1583
1584 if (descriptor_dirty_[descriptor_config] || framebuffer_descriptor_[descriptor_config] == nil) {
1585
1586 /* Create descriptor if it does not exist. */
1587 if (framebuffer_descriptor_[descriptor_config] == nil) {
1588 framebuffer_descriptor_[descriptor_config] = [[MTLRenderPassDescriptor alloc] init];
1589 }
1590
1591 /* Configure multilayered rendering. */
1592 if (use_multilayered_rendering_) {
1593 /* Ensure all targets have the same length. */
1594 int len = 0;
1595 bool valid = true;
1596
1597 for (int attachment_ind = 0; attachment_ind < GPU_FB_MAX_COLOR_ATTACHMENT; attachment_ind++)
1598 {
1599 if (mtl_color_attachments_[attachment_ind].used) {
1600 if (len == 0) {
1601 len = mtl_color_attachments_[attachment_ind].render_target_array_length;
1602 }
1603 else {
1604 valid = valid &&
1605 (len == mtl_color_attachments_[attachment_ind].render_target_array_length);
1606 }
1607 }
1608 }
1609
1610 if (mtl_depth_attachment_.used) {
1611 if (len == 0) {
1612 len = mtl_depth_attachment_.render_target_array_length;
1613 }
1614 else {
1615 valid = valid && (len == mtl_depth_attachment_.render_target_array_length);
1616 }
1617 }
1618
1619 if (mtl_stencil_attachment_.used) {
1620 if (len == 0) {
1621 len = mtl_stencil_attachment_.render_target_array_length;
1622 }
1623 else {
1624 valid = valid && (len == mtl_stencil_attachment_.render_target_array_length);
1625 }
1626 }
1627
1628 BLI_assert(len > 0);
1629 BLI_assert(valid);
1630 framebuffer_descriptor_[descriptor_config].renderTargetArrayLength = len;
1631 }
1632 else {
1633 framebuffer_descriptor_[descriptor_config].renderTargetArrayLength = 0;
1634 }
1635
1636 /* Color attachments. */
1637 int colour_attachments = 0;
1638 for (int attachment_ind = 0; attachment_ind < GPU_FB_MAX_COLOR_ATTACHMENT; attachment_ind++) {
1639 MTLAttachment &attachment_config = mtl_color_attachments_[attachment_ind];
1640
1641 if (attachment_config.used) {
1642 id<MTLTexture> texture = attachment_config.texture->get_metal_handle_base();
1643 if (texture == nil) {
1644 MTL_LOG_ERROR("Attempting to assign invalid texture as attachment");
1645 }
1646
1647 bool texture_is_memoryless = (attachment_config.texture->usage_get() &
1649
1650 /* IF SRGB is enabled, but we are rendering with SRGB disabled, sample texture view. */
1651 id<MTLTexture> source_color_texture = texture;
1652 if (this->get_is_srgb() && attachment_config.texture->is_format_srgb() &&
1653 !this->get_srgb_enabled())
1654 {
1655 source_color_texture = attachment_config.texture->get_non_srgb_handle();
1656 BLI_assert(source_color_texture != nil);
1657 }
1658
1659 /* Resolve appropriate load action -- IF force load, perform load.
1660 * If clear but framebuffer has no pending clear, also load. */
1661 GPULoadOp load_action = attachment_config.load_action;
1662 if (descriptor_config == MTL_FB_CONFIG_LOAD) {
1663 /* MTL_FB_CONFIG_LOAD must always load. */
1664 load_action = GPU_LOADACTION_LOAD;
1665 }
1666 else if (descriptor_config == MTL_FB_CONFIG_CUSTOM && load_action == GPU_LOADACTION_CLEAR)
1667 {
1668 /* If Custom load config is used, fallback to loading if explicit bind state flag is
1669 * unset. This is to ensure attachments are loaded by default in the case a framebuffer
1670 * is unbound and rebound, or, if a render pass breaks mid-pass for compute or blit
1671 * operations. */
1672 if (!use_explicit_load_store_ && !texture_is_memoryless) {
1673 load_action = GPU_LOADACTION_LOAD;
1674 }
1675 }
1676
1677 /* Ensure memoryless attachment cannot load or store results. */
1678 GPUStoreOp store_action = attachment_config.store_action;
1679 if (texture_is_memoryless && load_action == GPU_LOADACTION_LOAD) {
1680 load_action = GPU_LOADACTION_DONT_CARE;
1681 }
1682 if (texture_is_memoryless && store_action == GPU_STOREACTION_STORE) {
1683 store_action = GPU_STOREACTION_DONT_CARE;
1684 }
1685
1686 /* Create attachment descriptor. */
1687 MTLRenderPassColorAttachmentDescriptor *attachment =
1688 colour_attachment_descriptors_[attachment_ind];
1689 BLI_assert(attachment != nil);
1690
1691 attachment.texture = source_color_texture;
1692 attachment.loadAction = mtl_load_action_from_gpu(load_action);
1693 attachment.clearColor = (load_action == GPU_LOADACTION_CLEAR) ?
1694 MTLClearColorMake(
1695 UNPACK4(attachment_config.clear_value.color)) :
1696 MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
1697 attachment.storeAction = mtl_store_action_from_gpu(store_action);
1698 attachment.level = attachment_config.mip;
1699 attachment.slice = attachment_config.slice;
1700 attachment.depthPlane = attachment_config.depth_plane;
1701 colour_attachments++;
1702
1703 /* Copy attachment info back in. */
1704 [framebuffer_descriptor_[descriptor_config].colorAttachments setObject:attachment
1705 atIndexedSubscript:attachment_ind];
1706 }
1707 else {
1708 /* Disable color attachment. */
1709 [framebuffer_descriptor_[descriptor_config].colorAttachments setObject:nil
1710 atIndexedSubscript:attachment_ind];
1711 }
1712 }
1713 BLI_assert(colour_attachments == colour_attachment_count_);
1714 UNUSED_VARS_NDEBUG(colour_attachments);
1715
1716 /* Depth attachment. */
1717 if (mtl_depth_attachment_.used) {
1718 framebuffer_descriptor_[descriptor_config].depthAttachment.texture =
1719 (id<MTLTexture>)mtl_depth_attachment_.texture->get_metal_handle_base();
1720
1721 bool texture_is_memoryless = (mtl_depth_attachment_.texture->usage_get() &
1723
1724 /* Resolve appropriate load action -- IF force load, perform load.
1725 * If clear but framebuffer has no pending clear, also load. */
1726 GPULoadOp load_action = mtl_depth_attachment_.load_action;
1727 if (descriptor_config == MTL_FB_CONFIG_LOAD) {
1728 /* MTL_FB_CONFIG_LOAD must always load. */
1729 load_action = GPU_LOADACTION_LOAD;
1730 }
1731 else if (descriptor_config == MTL_FB_CONFIG_CUSTOM && load_action == GPU_LOADACTION_CLEAR) {
1732 /* If Custom load config is used, fallback to loading if explicit bind state flag is unset.
1733 * This is to ensure attachments are loaded by default in the case a framebuffer is unbound
1734 * and rebound, or, if a render pass breaks mid-pass for compute or blit operations. */
1735 if (!use_explicit_load_store_ && !texture_is_memoryless) {
1736 load_action = GPU_LOADACTION_LOAD;
1737 }
1738 }
1739
1740 /* Ensure memoryless attachment cannot load or store results. */
1741 GPUStoreOp store_action = mtl_depth_attachment_.store_action;
1742 if (texture_is_memoryless && load_action == GPU_LOADACTION_LOAD) {
1743 load_action = GPU_LOADACTION_DONT_CARE;
1744 }
1745 if (texture_is_memoryless && store_action == GPU_STOREACTION_STORE) {
1746 store_action = GPU_STOREACTION_DONT_CARE;
1747 }
1748
1749 framebuffer_descriptor_[descriptor_config].depthAttachment.loadAction =
1750 mtl_load_action_from_gpu(load_action);
1751 framebuffer_descriptor_[descriptor_config].depthAttachment.clearDepth =
1752 (load_action == GPU_LOADACTION_CLEAR) ? mtl_depth_attachment_.clear_value.depth : 0;
1753 framebuffer_descriptor_[descriptor_config].depthAttachment.storeAction =
1754 mtl_store_action_from_gpu(store_action);
1755 framebuffer_descriptor_[descriptor_config].depthAttachment.level = mtl_depth_attachment_.mip;
1756 framebuffer_descriptor_[descriptor_config].depthAttachment.slice =
1757 mtl_depth_attachment_.slice;
1758 framebuffer_descriptor_[descriptor_config].depthAttachment.depthPlane =
1759 mtl_depth_attachment_.depth_plane;
1760 }
1761 else {
1762 framebuffer_descriptor_[descriptor_config].depthAttachment.texture = nil;
1763 }
1764
1765 /* Stencil attachment. */
1766 if (mtl_stencil_attachment_.used) {
1767 framebuffer_descriptor_[descriptor_config].stencilAttachment.texture =
1768 (id<MTLTexture>)mtl_stencil_attachment_.texture->get_metal_handle_base();
1769
1770 bool texture_is_memoryless = (mtl_stencil_attachment_.texture->usage_get() &
1772
1773 /* Resolve appropriate load action -- IF force load, perform load.
1774 * If clear but framebuffer has no pending clear, also load. */
1775 GPULoadOp load_action = mtl_stencil_attachment_.load_action;
1776 if (descriptor_config == MTL_FB_CONFIG_LOAD) {
1777 /* MTL_FB_CONFIG_LOAD must always load. */
1778 load_action = GPU_LOADACTION_LOAD;
1779 }
1780 else if (descriptor_config == MTL_FB_CONFIG_CUSTOM && load_action == GPU_LOADACTION_CLEAR) {
1781 /* If Custom load config is used, fallback to loading if explicit bind state flag is unset.
1782 * This is to ensure attachments are loaded by default in the case a framebuffer is unbound
1783 * and rebound, or, if a render pass breaks mid-pass for compute or blit operations. */
1784 if (!use_explicit_load_store_ && !texture_is_memoryless) {
1785 load_action = GPU_LOADACTION_LOAD;
1786 }
1787 }
1788
1789 /* Ensure memoryless attachment cannot load or store results. */
1790 GPUStoreOp store_action = mtl_stencil_attachment_.store_action;
1791 if (texture_is_memoryless && load_action == GPU_LOADACTION_LOAD) {
1792 load_action = GPU_LOADACTION_DONT_CARE;
1793 }
1794 if (texture_is_memoryless && store_action == GPU_STOREACTION_STORE) {
1795 store_action = GPU_STOREACTION_DONT_CARE;
1796 }
1797
1798 framebuffer_descriptor_[descriptor_config].stencilAttachment.loadAction =
1799 mtl_load_action_from_gpu(load_action);
1800 framebuffer_descriptor_[descriptor_config].stencilAttachment.clearStencil =
1801 (load_action == GPU_LOADACTION_CLEAR) ? mtl_stencil_attachment_.clear_value.stencil : 0;
1802 framebuffer_descriptor_[descriptor_config].stencilAttachment.storeAction =
1803 mtl_store_action_from_gpu(store_action);
1804 framebuffer_descriptor_[descriptor_config].stencilAttachment.level =
1805 mtl_stencil_attachment_.mip;
1806 framebuffer_descriptor_[descriptor_config].stencilAttachment.slice =
1807 mtl_stencil_attachment_.slice;
1808 framebuffer_descriptor_[descriptor_config].stencilAttachment.depthPlane =
1809 mtl_stencil_attachment_.depth_plane;
1810 }
1811 else {
1812 framebuffer_descriptor_[descriptor_config].stencilAttachment.texture = nil;
1813 }
1814
1815 /* Attachmentless render support. */
1816 int total_num_attachments = colour_attachment_count_ + (mtl_depth_attachment_.used ? 1 : 0) +
1817 (mtl_stencil_attachment_.used ? 1 : 0);
1818 if (total_num_attachments == 0) {
1819 BLI_assert(width_ > 0 && height_ > 0);
1820 framebuffer_descriptor_[descriptor_config].renderTargetWidth = width_;
1821 framebuffer_descriptor_[descriptor_config].renderTargetHeight = height_;
1822 framebuffer_descriptor_[descriptor_config].defaultRasterSampleCount = 1;
1823 }
1824
1825 descriptor_dirty_[descriptor_config] = false;
1826 }
1827 /* Clear dirty state flags. */
1828 is_dirty_ = false;
1829 is_loadstore_dirty_ = false;
1830
1831 /* Clear explicit bind flag. */
1833
1834 return framebuffer_descriptor_[descriptor_config];
1835}
1836
1838
1839/* -------------------------------------------------------------------- */
1842
1844 uint src_x_offset,
1845 uint src_y_offset,
1846 MTLFrameBuffer *metal_fb_write,
1847 uint write_slot,
1848 uint dst_x_offset,
1849 uint dst_y_offset,
1850 uint width,
1851 uint height,
1852 GPUFrameBufferBits blit_buffers)
1853{
1854 BLI_assert(metal_fb_write);
1855 if (!metal_fb_write) {
1856 return;
1857 }
1858 MTLContext *mtl_context = MTLContext::get();
1859
1860 const bool do_color = (blit_buffers & GPU_COLOR_BIT);
1861 const bool do_depth = (blit_buffers & GPU_DEPTH_BIT);
1862 const bool do_stencil = (blit_buffers & GPU_STENCIL_BIT);
1863
1864 /* Early exit if there is no blit to do. */
1865 if (!(do_color || do_depth || do_stencil)) {
1866 MTL_LOG_WARNING("FrameBuffer: requested blit but no color, depth or stencil flag was set");
1867 return;
1868 }
1869
1870 id<MTLBlitCommandEncoder> blit_encoder = nil;
1871
1872 /* If the color format is not the same, we cannot use the BlitCommandEncoder, and instead use
1873 * a Graphics-based blit. */
1874 if (do_color && (this->get_color_attachment(read_slot).texture->format_get() !=
1875 metal_fb_write->get_color_attachment(read_slot).texture->format_get()))
1876 {
1877
1878 MTLAttachment src_attachment = this->get_color_attachment(read_slot);
1879 MTLAttachment dst_attachment = metal_fb_write->get_color_attachment(write_slot);
1880 assert(src_attachment.slice == 0 &&
1881 "currently only supporting slice 0 for graphics framebuffer blit");
1882
1883 src_attachment.texture->blit(dst_attachment.texture,
1884 src_x_offset,
1885 src_y_offset,
1886 dst_x_offset,
1887 dst_y_offset,
1888 src_attachment.mip,
1889 dst_attachment.mip,
1890 dst_attachment.slice,
1891 width,
1892 height);
1893 }
1894 else {
1895
1896 /* Setup blit encoder. */
1897 blit_encoder = mtl_context->main_command_buffer.ensure_begin_blit_encoder();
1898
1899 if (do_color) {
1900 MTLAttachment src_attachment = this->get_color_attachment(read_slot);
1901 MTLAttachment dst_attachment = metal_fb_write->get_color_attachment(write_slot);
1902
1903 if (src_attachment.used && dst_attachment.used) {
1904
1905 /* TODO(Metal): Support depth(z) offset in blit if needed. */
1906 src_attachment.texture->blit(blit_encoder,
1907 src_x_offset,
1908 src_y_offset,
1909 0,
1910 src_attachment.slice,
1911 src_attachment.mip,
1912 dst_attachment.texture,
1913 dst_x_offset,
1914 dst_y_offset,
1915 0,
1916 dst_attachment.slice,
1917 dst_attachment.mip,
1918 width,
1919 height,
1920 1);
1921 }
1922 else {
1923 MTL_LOG_ERROR("Failed performing colour blit");
1924 }
1925 }
1926 }
1927 if ((do_depth || do_stencil) && blit_encoder == nil) {
1928 blit_encoder = mtl_context->main_command_buffer.ensure_begin_blit_encoder();
1929 }
1930
1931 if (do_depth) {
1932 MTLAttachment src_attachment = this->get_depth_attachment();
1933 MTLAttachment dst_attachment = metal_fb_write->get_depth_attachment();
1934
1935 if (src_attachment.used && dst_attachment.used) {
1936
1937 /* TODO(Metal): Support depth(z) offset in blit if needed. */
1938 src_attachment.texture->blit(blit_encoder,
1939 src_x_offset,
1940 src_y_offset,
1941 0,
1942 src_attachment.slice,
1943 src_attachment.mip,
1944 dst_attachment.texture,
1945 dst_x_offset,
1946 dst_y_offset,
1947 0,
1948 dst_attachment.slice,
1949 dst_attachment.mip,
1950 width,
1951 height,
1952 1);
1953 }
1954 else {
1955 MTL_LOG_ERROR("Failed performing depth blit");
1956 }
1957 }
1958
1959 /* Stencil attachment blit. */
1960 if (do_stencil) {
1961 MTLAttachment src_attachment = this->get_stencil_attachment();
1962 MTLAttachment dst_attachment = metal_fb_write->get_stencil_attachment();
1963
1964 if (src_attachment.used && dst_attachment.used) {
1965
1966 /* TODO(Metal): Support depth(z) offset in blit if needed. */
1967 src_attachment.texture->blit(blit_encoder,
1968 src_x_offset,
1969 src_y_offset,
1970 0,
1971 src_attachment.slice,
1972 src_attachment.mip,
1973 dst_attachment.texture,
1974 dst_x_offset,
1975 dst_y_offset,
1976 0,
1977 dst_attachment.slice,
1978 dst_attachment.mip,
1979 width,
1980 height,
1981 1);
1982 }
1983 else {
1984 MTL_LOG_ERROR("Failed performing Stencil blit");
1985 }
1986 }
1987}
1988
1990{
1991 return width_;
1992}
1994{
1995 return height_;
1996}
1997
1999{
2000 return default_width_;
2001}
2003{
2004 return default_height_;
2005}
2006
2007} // namespace blender::gpu
#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)
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
@ GPU_STOREACTION_STORE
@ GPU_STOREACTION_DONT_CARE
GPUAttachmentState
@ GPU_ATTACHMENT_READ
GPUFrameBufferBits
@ GPU_DEPTH_BIT
@ GPU_STENCIL_BIT
@ GPU_COLOR_BIT
void GPU_framebuffer_restore()
static constexpr int GPU_MAX_VIEWPORTS
void GPU_texture_get_mipmap_size(blender::gpu::Texture *texture, int mip_level, int *r_size)
blender::gpu::TextureFormat GPU_texture_format(const blender::gpu::Texture *texture)
eGPUDataFormat
@ GPU_DATA_INT
@ GPU_DATA_UINT
@ GPU_DATA_UINT_24_8_DEPRECATED
@ GPU_DATA_FLOAT
@ GPU_TEXTURE_USAGE_MEMORYLESS
@ GPU_TEXTURE_USAGE_ATTACHMENT
void GPU_texture_image_bind(blender::gpu::Texture *texture, int unit)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
void size_set(int width, int height)
void set_color_attachment_bit(GPUAttachmentType type, bool value)
FrameBuffer(const char *name)
GPUAttachment attachments_[GPU_FB_MAX_ATTACHMENT]
int viewport_[GPU_MAX_VIEWPORTS][4]
static MTLCapabilities capabilities
bool end_active_command_encoder(bool retain_framebuffers=false)
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
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, GPUFrameBufferBits blit_buffers)
bool set_stencil_loadstore_op(GPULoadOp load_action, GPUStoreOp store_action)
bool set_depth_loadstore_op(GPULoadOp load_action, GPUStoreOp store_action)
int get_color_attachment_slot_from_texture(gpu::MTLTexture *texture)
void default_size_set(int w, int h)
bool check(char err_out[256]) override
void read(GPUFrameBufferBits planes, eGPUDataFormat format, const int area[4], int channel_len, int slot, void *r_data) 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)
bool set_color_loadstore_op(uint slot, GPULoadOp load_action, GPUStoreOp store_action)
void clear_multi(const float(*clear_cols)[4]) override
void blit_to(GPUFrameBufferBits planes, int src_slot, FrameBuffer *dst, int dst_slot, int dst_offset_x, int dst_offset_y) override
bool add_depth_attachment(gpu::MTLTexture *texture, int miplevel, int layer)
void attachment_set_loadstore_op(GPUAttachmentType type, GPULoadStore ls) override
void clear(GPUFrameBufferBits buffers, const float clear_col[4], float clear_depth, uint clear_stencil) 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 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)
eGPUTextureUsage usage_get() const
TextureFormat format_get() const
nullptr 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
#define assert(assertion)
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
format
#define MTL_LOG_WARNING(info,...)
Definition mtl_debug.hh:42
#define MTL_LOG_ERROR(info,...)
Definition mtl_debug.hh:34
MTLLoadAction mtl_load_action_from_gpu(GPULoadOp action)
MTLStoreAction mtl_store_action_from_gpu(GPUStoreOp action)
int to_bytesize(const DataFormat format)
static const int MTL_MAX_MIPMAP_COUNT
static void init(bNodeTree *, bNode *node)
const char * name
blender::gpu::Texture * tex
GPUStoreOp store_action
GPULoadOp load_action
union blender::gpu::MTLAttachment::@142227134026063347366002067303226104245171177125 clear_value
i
Definition text_draw.cc:230
uint len
char * buffers[2]