Blender  V3.3
mtl_framebuffer.mm
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "BKE_global.h"
8 
9 #include "mtl_context.hh"
10 #include "mtl_debug.hh"
11 #include "mtl_framebuffer.hh"
12 #include "mtl_texture.hh"
13 #import <Availability.h>
14 
15 namespace blender::gpu {
16 
17 /* -------------------------------------------------------------------- */
21 MTLFrameBuffer::MTLFrameBuffer(MTLContext *ctx, const char *name) : FrameBuffer(name)
22 {
23 
24  context_ = ctx;
25  is_dirty_ = true;
26  is_loadstore_dirty_ = true;
27  dirty_state_ctx_ = nullptr;
28  has_pending_clear_ = false;
29  colour_attachment_count_ = 0;
30  srgb_enabled_ = false;
31  is_srgb_ = false;
32 
33  for (int i = 0; i < GPU_FB_MAX_COLOR_ATTACHMENT; i++) {
34  mtl_color_attachments_[i].used = false;
35  }
36  mtl_depth_attachment_.used = false;
37  mtl_stencil_attachment_.used = false;
38 
39  for (int i = 0; i < MTL_FB_CONFIG_MAX; i++) {
40  framebuffer_descriptor_[i] = [[MTLRenderPassDescriptor alloc] init];
41  descriptor_dirty_[i] = true;
42  }
43 
44  for (int i = 0; i < GPU_FB_MAX_COLOR_ATTACHMENT; i++) {
45  colour_attachment_descriptors_[i] = [[MTLRenderPassColorAttachmentDescriptor alloc] init];
46  }
47 
48  /* Initial state. */
49  this->size_set(0, 0);
50  this->viewport_reset();
51  this->scissor_reset();
52 }
53 
55 {
56  /* If FrameBuffer is associated with a currently open RenderPass, end. */
57  if (context_->main_command_buffer.get_active_framebuffer() == this) {
59  }
60 
61  /* Restore default frame-buffer if this frame-buffer was bound. */
62  if (context_->active_fb == this && context_->back_left != this) {
63  /* If this assert triggers it means the frame-buffer is being freed while in use by another
64  * context which, by the way, is TOTALLY UNSAFE!!! (Copy from GL behavior). */
65  BLI_assert(context_ == static_cast<MTLContext *>(unwrap(GPU_context_active_get())));
67  }
68 
69  /* Free Render Pass Descriptors. */
70  for (int config = 0; config < MTL_FB_CONFIG_MAX; config++) {
71  if (framebuffer_descriptor_[config] != nil) {
72  [framebuffer_descriptor_[config] release];
73  framebuffer_descriptor_[config] = nil;
74  }
75  }
76 
77  /* Free colour attachment descriptors. */
78  for (int i = 0; i < GPU_FB_MAX_COLOR_ATTACHMENT; i++) {
79  if (colour_attachment_descriptors_[i] != nil) {
80  [colour_attachment_descriptors_[i] release];
81  colour_attachment_descriptors_[i] = nil;
82  }
83  }
84 
85  /* Remove attachments - release FB texture references. */
86  this->remove_all_attachments();
87 
88  if (context_ == nullptr) {
89  return;
90  }
91 }
92 
93 void MTLFrameBuffer::bind(bool enabled_srgb)
94 {
95 
96  /* Verify Context is valid. */
97  if (context_ != static_cast<MTLContext *>(unwrap(GPU_context_active_get()))) {
98  BLI_assert(false && "Trying to use the same frame-buffer in multiple context's.");
99  return;
100  }
101 
102  /* Ensure SRGB state is up-to-date and valid. */
103  bool srgb_state_changed = srgb_enabled_ != enabled_srgb;
104  if (context_->active_fb != this || srgb_state_changed) {
105  if (srgb_state_changed) {
106  this->mark_dirty();
107  }
108  srgb_enabled_ = enabled_srgb;
109  GPU_shader_set_framebuffer_srgb_target(srgb_enabled_ && is_srgb_);
110  }
111 
112  /* Ensure local MTLAttachment data is up to date. */
113  this->update_attachments(true);
114 
115  /* Reset clear state on bind -- Clears and load/store ops are set after binding. */
116  this->reset_clear_state();
117 
118  /* Bind to active context. */
119  MTLContext *mtl_context = reinterpret_cast<MTLContext *>(GPU_context_active_get());
120  if (mtl_context) {
121  mtl_context->framebuffer_bind(this);
122  dirty_state_ = true;
123  }
124  else {
125  MTL_LOG_WARNING("Attempting to bind FrameBuffer, but no context is active\n");
126  }
127 }
128 
129 bool MTLFrameBuffer::check(char err_out[256])
130 {
131  /* Ensure local MTLAttachment data is up to date. */
132  this->update_attachments(true);
133 
134  /* Ensure there is at least one attachment. */
135  bool valid = (this->get_attachment_count() > 0 ||
136  this->has_depth_attachment() | this->has_stencil_attachment());
137  if (!valid) {
138  const char *format = "Framebuffer %s does not have any attachments.\n";
139  if (err_out) {
140  BLI_snprintf(err_out, 256, format, name_);
141  }
142  else {
144  }
145  return false;
146  }
147 
148  /* Ensure all attachments have identical dimensions. */
149  /* Ensure all attachments are render-targets. */
150  bool first = true;
151  uint dim_x = 0;
152  uint dim_y = 0;
153  for (int col_att = 0; col_att < this->get_attachment_count(); col_att++) {
154  MTLAttachment att = this->get_color_attachment(col_att);
155  if (att.used) {
156  if (att.texture->gpu_image_usage_flags_ & GPU_TEXTURE_USAGE_ATTACHMENT) {
157  if (first) {
158  dim_x = att.texture->width_get();
159  dim_y = att.texture->height_get();
160  first = false;
161  }
162  else {
163  if (dim_x != att.texture->width_get() || dim_y != att.texture->height_get()) {
164  const char *format =
165  "Framebuffer %s: Color attachment dimensions do not match those of previous "
166  "attachment\n";
167  if (err_out) {
168  BLI_snprintf(err_out, 256, format, name_);
169  }
170  else {
171  fprintf(stderr, format, name_);
173  }
174  return false;
175  }
176  }
177  }
178  else {
179  const char *format =
180  "Framebuffer %s: Color attachment texture does not have usage flag "
181  "'GPU_TEXTURE_USAGE_ATTACHMENT'\n";
182  if (err_out) {
183  BLI_snprintf(err_out, 256, format, name_);
184  }
185  else {
186  fprintf(stderr, format, name_);
188  }
189  return false;
190  }
191  }
192  }
193  MTLAttachment depth_att = this->get_depth_attachment();
194  MTLAttachment stencil_att = this->get_stencil_attachment();
195  if (depth_att.used) {
196  if (first) {
197  dim_x = depth_att.texture->width_get();
198  dim_y = depth_att.texture->height_get();
199  first = false;
200  valid = (depth_att.texture->gpu_image_usage_flags_ & GPU_TEXTURE_USAGE_ATTACHMENT);
201 
202  if (!valid) {
203  const char *format =
204  "Framebuffer %n: Depth attachment does not have usage "
205  "'GPU_TEXTURE_USAGE_ATTACHMENT'\n";
206  if (err_out) {
207  BLI_snprintf(err_out, 256, format, name_);
208  }
209  else {
210  fprintf(stderr, format, name_);
212  }
213  return false;
214  }
215  }
216  else {
217  if (dim_x != depth_att.texture->width_get() || dim_y != depth_att.texture->height_get()) {
218  const char *format =
219  "Framebuffer %n: Depth attachment dimensions do not match that of previous "
220  "attachment\n";
221  if (err_out) {
222  BLI_snprintf(err_out, 256, format, name_);
223  }
224  else {
225  fprintf(stderr, format, name_);
227  }
228  return false;
229  }
230  }
231  }
232  if (stencil_att.used) {
233  if (first) {
234  dim_x = stencil_att.texture->width_get();
235  dim_y = stencil_att.texture->height_get();
236  first = false;
237  valid = (stencil_att.texture->gpu_image_usage_flags_ & GPU_TEXTURE_USAGE_ATTACHMENT);
238  if (!valid) {
239  const char *format =
240  "Framebuffer %s: Stencil attachment does not have usage "
241  "'GPU_TEXTURE_USAGE_ATTACHMENT'\n";
242  if (err_out) {
243  BLI_snprintf(err_out, 256, format, name_);
244  }
245  else {
246  fprintf(stderr, format, name_);
248  }
249  return false;
250  }
251  }
252  else {
253  if (dim_x != stencil_att.texture->width_get() ||
254  dim_y != stencil_att.texture->height_get()) {
255  const char *format =
256  "Framebuffer %s: Stencil attachment dimensions do not match that of previous "
257  "attachment";
258  if (err_out) {
259  BLI_snprintf(err_out, 256, format, name_);
260  }
261  else {
262  fprintf(stderr, format, name_);
264  }
265  return false;
266  }
267  }
268  }
269 
270  BLI_assert(valid);
271  return valid;
272 }
273 
274 void MTLFrameBuffer::force_clear()
275 {
276  /* Perform clear by ending current and starting a new render pass. */
277  MTLContext *mtl_context = static_cast<MTLContext *>(unwrap(GPU_context_active_get()));
278  MTLFrameBuffer *current_framebuffer = mtl_context->get_current_framebuffer();
279  if (current_framebuffer) {
280  BLI_assert(current_framebuffer == this);
281  /* End current render-pass. */
282  if (mtl_context->main_command_buffer.is_inside_render_pass()) {
284  }
285  mtl_context->ensure_begin_render_pass();
286  BLI_assert(has_pending_clear_ == false);
287  }
288 }
289 
291  const float clear_col[4],
292  float clear_depth,
293  uint clear_stencil)
294 {
295 
296  BLI_assert(unwrap(GPU_context_active_get()) == context_);
297  BLI_assert(context_->active_fb == this);
298 
299  /* Ensure attachments are up to date. */
300  this->update_attachments(true);
301 
302  /* If we had no previous clear pending, reset clear state. */
303  if (!has_pending_clear_) {
304  this->reset_clear_state();
305  }
306 
307  /* Ensure we only clear if attachments exist for given buffer bits. */
308  bool do_clear = false;
309  if (buffers & GPU_COLOR_BIT) {
310  for (int i = 0; i < colour_attachment_count_; i++) {
311  this->set_color_attachment_clear_color(i, clear_col);
312  do_clear = true;
313  }
314  }
315 
316  if (buffers & GPU_DEPTH_BIT) {
317  this->set_depth_attachment_clear_value(clear_depth);
318  do_clear = do_clear || this->has_depth_attachment();
319  }
320  if (buffers & GPU_STENCIL_BIT) {
321  this->set_stencil_attachment_clear_value(clear_stencil);
322  do_clear = do_clear || this->has_stencil_attachment();
323  }
324 
325  if (do_clear) {
326  has_pending_clear_ = true;
327 
328  /* Apply state before clear. */
329  this->apply_state();
330 
331  /* TODO(Metal): Optimize - Currently force-clear always used. Consider moving clear state to
332  * MTLTexture instead. */
333  /* Force clear if RP is not yet active -- not the most efficient, but there is no distinction
334  * between clears where no draws occur. Can optimize at the high-level by using explicit
335  * load-store flags. */
336  this->force_clear();
337  }
338 }
339 
340 void MTLFrameBuffer::clear_multi(const float (*clear_cols)[4])
341 {
342  /* If we had no previous clear pending, reset clear state. */
343  if (!has_pending_clear_) {
344  this->reset_clear_state();
345  }
346 
347  bool do_clear = false;
348  for (int i = 0; i < this->get_attachment_limit(); i++) {
349  if (this->has_attachment_at_slot(i)) {
350  this->set_color_attachment_clear_color(i, clear_cols[i]);
351  do_clear = true;
352  }
353  }
354 
355  if (do_clear) {
356  has_pending_clear_ = true;
357 
358  /* Apply state before clear. */
359  this->apply_state();
360 
361  /* TODO(Metal): Optimize - Currently force-clear always used. Consider moving clear state to
362  * MTLTexture instead. */
363  /* Force clear if RP is not yet active -- not the most efficient, but there is no distinction
364  * between clears where no draws occur. Can optimize at the high-level by using explicit
365  * load-store flags. */
366  this->force_clear();
367  }
368 }
369 
371  eGPUDataFormat data_format,
372  const void *clear_value)
373 {
374  BLI_assert(static_cast<MTLContext *>(unwrap(GPU_context_active_get())) == context_);
375  BLI_assert(context_->active_fb == this);
376 
377  /* If we had no previous clear pending, reset clear state. */
378  if (!has_pending_clear_) {
379  this->reset_clear_state();
380  }
381 
382  bool do_clear = false;
383 
385  if (this->has_depth_attachment() || this->has_stencil_attachment()) {
386  BLI_assert(data_format == GPU_DATA_UINT_24_8);
387  float depth = ((*(uint32_t *)clear_value) & 0x00FFFFFFu) / (float)0x00FFFFFFu;
388  int stencil = ((*(uint32_t *)clear_value) >> 24);
390  this->set_stencil_attachment_clear_value(stencil);
391  do_clear = true;
392  }
393  }
394  else if (type == GPU_FB_DEPTH_ATTACHMENT) {
395  if (this->has_depth_attachment()) {
396  if (data_format == GPU_DATA_FLOAT) {
397  this->set_depth_attachment_clear_value(*(float *)clear_value);
398  }
399  else {
400  float depth = *(uint32_t *)clear_value / (float)0xFFFFFFFFu;
402  }
403  do_clear = true;
404  }
405  }
406  else {
407  int slot = type - GPU_FB_COLOR_ATTACHMENT0;
408  if (this->has_attachment_at_slot(slot)) {
409  float col_clear_val[4] = {0.0};
410  switch (data_format) {
411  case GPU_DATA_FLOAT: {
412  const float *vals = (float *)clear_value;
413  col_clear_val[0] = vals[0];
414  col_clear_val[1] = vals[1];
415  col_clear_val[2] = vals[2];
416  col_clear_val[3] = vals[3];
417  } break;
418  case GPU_DATA_UINT: {
419  const uint *vals = (uint *)clear_value;
420  col_clear_val[0] = (float)(vals[0]);
421  col_clear_val[1] = (float)(vals[1]);
422  col_clear_val[2] = (float)(vals[2]);
423  col_clear_val[3] = (float)(vals[3]);
424  } break;
425  case GPU_DATA_INT: {
426  const int *vals = (int *)clear_value;
427  col_clear_val[0] = (float)(vals[0]);
428  col_clear_val[1] = (float)(vals[1]);
429  col_clear_val[2] = (float)(vals[2]);
430  col_clear_val[3] = (float)(vals[3]);
431  } break;
432  default:
433  BLI_assert_msg(0, "Unhandled data format");
434  break;
435  }
436  this->set_color_attachment_clear_color(slot, col_clear_val);
437  do_clear = true;
438  }
439  }
440 
441  if (do_clear) {
442  has_pending_clear_ = true;
443 
444  /* Apply state before clear. */
445  this->apply_state();
446 
447  /* TODO(Metal): Optimize - Currently force-clear always used. Consider moving clear state to
448  * MTLTexture instead. */
449  /* Force clear if RP is not yet active -- not the most efficient, but there is no distinction
450  * between clears where no draws occur. Can optimize at the high-level by using explicit
451  * load-store flags. */
452  this->force_clear();
453  }
454 }
455 
458  const int area[4],
459  int channel_len,
460  int slot,
461  void *r_data)
462 {
463 
464  BLI_assert((planes & GPU_STENCIL_BIT) == 0);
465  BLI_assert(area[2] > 0);
466  BLI_assert(area[3] > 0);
467 
468  switch (planes) {
469  case GPU_DEPTH_BIT: {
470  if (this->has_depth_attachment()) {
471  MTLAttachment depth = this->get_depth_attachment();
472  gpu::MTLTexture *tex = depth.texture;
473  if (tex) {
474  size_t sample_len = area[2] * area[3];
475  size_t sample_size = to_bytesize(tex->format_, format);
476  int debug_data_size = sample_len * sample_size;
477  tex->read_internal(0,
478  area[0],
479  area[1],
480  0,
481  area[2],
482  area[3],
483  1,
484  format,
485  channel_len,
486  debug_data_size,
487  r_data);
488  }
489  }
490  else {
492  "Attempting to read depth from a framebuffer which does not have a depth "
493  "attachment!\n");
494  }
495  }
496  return;
497 
498  case GPU_COLOR_BIT: {
499  if (this->has_attachment_at_slot(slot)) {
501  gpu::MTLTexture *tex = color.texture;
502  if (tex) {
503  size_t sample_len = area[2] * area[3];
504  size_t sample_size = to_bytesize(tex->format_, format);
505  int debug_data_size = sample_len * sample_size * channel_len;
506  tex->read_internal(0,
507  area[0],
508  area[1],
509  0,
510  area[2],
511  area[3],
512  1,
513  format,
514  channel_len,
515  debug_data_size,
516  r_data);
517  }
518  }
519  }
520  return;
521 
522  case GPU_STENCIL_BIT:
523  MTL_LOG_ERROR("GPUFramebuffer: Error: Trying to read stencil bit. Unsupported.\n");
524  return;
525  }
526 }
527 
529  int src_slot,
530  FrameBuffer *dst,
531  int dst_slot,
532  int dst_offset_x,
533  int dst_offset_y)
534 {
535  this->update_attachments(true);
536  static_cast<MTLFrameBuffer *>(dst)->update_attachments(true);
537 
538  BLI_assert(planes != 0);
539 
540  MTLFrameBuffer *metal_fb_write = static_cast<MTLFrameBuffer *>(dst);
541 
542  BLI_assert(this);
543  BLI_assert(metal_fb_write);
544 
545  /* Get width/height from attachment. */
546  MTLAttachment src_attachment;
547  const bool do_color = (planes & GPU_COLOR_BIT);
548  const bool do_depth = (planes & GPU_DEPTH_BIT);
549  const bool do_stencil = (planes & GPU_STENCIL_BIT);
550 
551  if (do_color) {
552  BLI_assert(!do_depth && !do_stencil);
553  src_attachment = this->get_color_attachment(src_slot);
554  }
555  else if (do_depth) {
556  BLI_assert(!do_color && !do_stencil);
557  src_attachment = this->get_depth_attachment();
558  }
559  else if (do_stencil) {
560  BLI_assert(!do_color && !do_depth);
561  src_attachment = this->get_stencil_attachment();
562  }
563 
564  BLI_assert(src_attachment.used);
565  this->blit(src_slot,
566  0,
567  0,
568  metal_fb_write,
569  dst_slot,
570  dst_offset_x,
571  dst_offset_y,
572  src_attachment.texture->width_get(),
573  src_attachment.texture->height_get(),
574  planes);
575 }
576 
579 /* -------------------------------------------------------------------- */
584 {
585  is_dirty_ = true;
586  is_loadstore_dirty_ = true;
587 }
588 
590 {
591  is_loadstore_dirty_ = true;
592 }
593 
595 {
596  has_pending_clear_ = false;
597 }
598 
600 {
601  has_pending_clear_ = true;
602 }
603 
604 void MTLFrameBuffer::update_attachments(bool update_viewport)
605 {
606  if (!dirty_attachments_) {
607  return;
608  }
609 
610  /* Cache viewport and scissor (If we have existing attachments). */
611  int t_viewport[4], t_scissor[4];
612  update_viewport = update_viewport &&
613  (this->get_attachment_count() > 0 && this->has_depth_attachment() &&
614  this->has_stencil_attachment());
615  if (update_viewport) {
616  this->viewport_get(t_viewport);
617  this->scissor_get(t_scissor);
618  }
619 
620  /* Clear current attachments state. */
621  this->remove_all_attachments();
622 
623  /* Reset framebuffer options. */
624  use_multilayered_rendering_ = false;
625 
626  /* Track first attachment for SRGB property extraction. */
627  GPUAttachmentType first_attachment = GPU_FB_MAX_ATTACHMENT;
628  MTLAttachment first_attachment_mtl;
629 
630  /* Scan through changes to attachments and populate local structures. */
631  bool depth_added = false;
632  for (GPUAttachmentType type = GPU_FB_MAX_ATTACHMENT - 1; type >= 0; --type) {
633  GPUAttachment &attach = attachments_[type];
634 
635  switch (type) {
638  /* If one of the DEPTH types has added a texture, we avoid running this again, as it would
639  * only remove the target. */
640  if (depth_added) {
641  break;
642  }
643  if (attach.tex) {
644  /* If we already had a depth attachment, preserve load/clear-state parameters,
645  * but remove existing and add new attachment. */
646  if (this->has_depth_attachment()) {
647  MTLAttachment depth_attachment_prev = this->get_depth_attachment();
648  this->remove_depth_attachment();
649  this->add_depth_attachment(
650  static_cast<gpu::MTLTexture *>(unwrap(attach.tex)), attach.mip, attach.layer);
651  this->set_depth_attachment_clear_value(depth_attachment_prev.clear_value.depth);
652  this->set_depth_loadstore_op(depth_attachment_prev.load_action,
653  depth_attachment_prev.store_action);
654  }
655  else {
656  this->add_depth_attachment(
657  static_cast<gpu::MTLTexture *>(unwrap(attach.tex)), attach.mip, attach.layer);
658  }
659 
660  /* Check stencil component -- if supplied texture format supports stencil. */
662  bool use_stencil = (type == GPU_FB_DEPTH_STENCIL_ATTACHMENT) &&
664  if (use_stencil) {
665  if (this->has_stencil_attachment()) {
666  MTLAttachment stencil_attachment_prev = this->get_stencil_attachment();
669  static_cast<gpu::MTLTexture *>(unwrap(attach.tex)), attach.mip, attach.layer);
671  stencil_attachment_prev.clear_value.stencil);
672  this->set_stencil_loadstore_op(stencil_attachment_prev.load_action,
673  stencil_attachment_prev.store_action);
674  }
675  else {
677  static_cast<gpu::MTLTexture *>(unwrap(attach.tex)), attach.mip, attach.layer);
678  }
679  }
680 
681  /* Flag depth as added -- mirrors the behavior in gl_framebuffer.cc to exit the for-loop
682  * after GPU_FB_DEPTH_STENCIL_ATTACHMENT has executed. */
683  depth_added = true;
684 
685  if (first_attachment == GPU_FB_MAX_ATTACHMENT) {
686  /* Only use depth texture to get information if there is no color attachment. */
687  first_attachment = type;
688  first_attachment_mtl = this->get_depth_attachment();
689  }
690  }
691  else {
692  this->remove_depth_attachment();
695  }
696  }
697  } break;
704  int color_slot_ind = type - GPU_FB_COLOR_ATTACHMENT0;
705  if (attach.tex) {
706  /* If we already had a colour attachment, preserve load/clear-state parameters,
707  * but remove existing and add new attachment. */
708  if (this->has_attachment_at_slot(color_slot_ind)) {
709  MTLAttachment color_attachment_prev = this->get_color_attachment(color_slot_ind);
710 
711  this->remove_color_attachment(color_slot_ind);
712  this->add_color_attachment(static_cast<gpu::MTLTexture *>(unwrap(attach.tex)),
713  color_slot_ind,
714  attach.mip,
715  attach.layer);
716  this->set_color_attachment_clear_color(color_slot_ind,
717  color_attachment_prev.clear_value.color);
718  this->set_color_loadstore_op(color_slot_ind,
719  color_attachment_prev.load_action,
720  color_attachment_prev.store_action);
721  }
722  else {
723  this->add_color_attachment(static_cast<gpu::MTLTexture *>(unwrap(attach.tex)),
724  color_slot_ind,
725  attach.mip,
726  attach.layer);
727  }
728  first_attachment = type;
729  first_attachment_mtl = this->get_color_attachment(color_slot_ind);
730  }
731  else {
732  this->remove_color_attachment(color_slot_ind);
733  }
734  } break;
735  default:
736  /* Non-attachment parameters. */
737  break;
738  }
739  }
740 
741  /* Check whether the first attachment is SRGB. */
742  if (first_attachment != GPU_FB_MAX_ATTACHMENT) {
743  is_srgb_ = (first_attachment_mtl.texture->format_get() == GPU_SRGB8_A8);
744  }
745 
746  /* Reset viewport and Scissor (If viewport is smaller or equal to the framebuffer size). */
747  if (update_viewport && t_viewport[2] <= width_ && t_viewport[3] <= height_) {
748 
749  this->viewport_set(t_viewport);
750  this->scissor_set(t_viewport);
751  }
752  else {
753  this->viewport_reset();
754  this->scissor_reset();
755  }
756 
757  /* We have now updated our internal structures. */
758  dirty_attachments_ = false;
759 }
760 
762 {
763  MTLContext *mtl_ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get()));
764  BLI_assert(mtl_ctx);
765  if (mtl_ctx->active_fb == this) {
766  if (dirty_state_ == false && dirty_state_ctx_ == mtl_ctx) {
767  return;
768  }
769 
770  /* Ensure viewport has been set. NOTE: This should no longer happen, but kept for safety to
771  * track bugs. */
772  if (viewport_[2] == 0 || viewport_[3] == 0) {
774  "Viewport had width and height of (0,0) -- Updating -- DEBUG Safety check\n");
775  viewport_reset();
776  }
777 
778  /* Update Context State. */
779  mtl_ctx->set_viewport(viewport_[0], viewport_[1], viewport_[2], viewport_[3]);
780  mtl_ctx->set_scissor(scissor_[0], scissor_[1], scissor_[2], scissor_[3]);
782 
783  dirty_state_ = false;
784  dirty_state_ctx_ = mtl_ctx;
785  }
786  else {
788  "Attempting to set FrameBuffer State (VIEWPORT, SCISSOR), But FrameBuffer is not bound to "
789  "current Context.\n");
790  }
791 }
792 
795 /* -------------------------------------------------------------------- */
800  uint slot,
801  int miplevel,
802  int layer)
803 {
804  BLI_assert(this);
805  BLI_assert(slot >= 0 && slot < this->get_attachment_limit());
806 
807  if (texture) {
808  if (miplevel < 0 || miplevel >= MTL_MAX_MIPMAP_COUNT) {
809  MTL_LOG_WARNING("Attachment specified with invalid mip level %u\n", miplevel);
810  miplevel = 0;
811  }
812 
813  /* Check if slot is in-use. */
814  /* Assume attachment load by default. */
815  colour_attachment_count_ += (!mtl_color_attachments_[slot].used) ? 1 : 0;
816  mtl_color_attachments_[slot].used = true;
817  mtl_color_attachments_[slot].texture = texture;
818  mtl_color_attachments_[slot].mip = miplevel;
819  mtl_color_attachments_[slot].load_action = GPU_LOADACTION_LOAD;
820  mtl_color_attachments_[slot].store_action = GPU_STOREACTION_STORE;
821  mtl_color_attachments_[slot].render_target_array_length = 0;
822 
823  /* Determine whether array slice or depth plane based on texture type. */
824  switch (texture->type_) {
825  case GPU_TEXTURE_1D:
826  case GPU_TEXTURE_2D:
827  BLI_assert(layer <= 0);
828  mtl_color_attachments_[slot].slice = 0;
829  mtl_color_attachments_[slot].depth_plane = 0;
830  break;
832  if (layer < 0) {
833  layer = 0;
834  MTL_LOG_WARNING("TODO: Support layered rendering for 1D array textures, if needed.\n");
835  }
836  BLI_assert(layer < texture->h_);
837  mtl_color_attachments_[slot].slice = layer;
838  mtl_color_attachments_[slot].depth_plane = 0;
839  break;
841  BLI_assert(layer < texture->d_);
842  mtl_color_attachments_[slot].slice = layer;
843  mtl_color_attachments_[slot].depth_plane = 0;
844  if (layer == -1) {
845  mtl_color_attachments_[slot].slice = 0;
846  mtl_color_attachments_[slot].render_target_array_length = texture->d_;
847  use_multilayered_rendering_ = true;
848  }
849  break;
850  case GPU_TEXTURE_3D:
851  BLI_assert(layer < texture->d_);
852  mtl_color_attachments_[slot].slice = 0;
853  mtl_color_attachments_[slot].depth_plane = layer;
854  if (layer == -1) {
855  mtl_color_attachments_[slot].depth_plane = 0;
856  mtl_color_attachments_[slot].render_target_array_length = texture->d_;
857  use_multilayered_rendering_ = true;
858  }
859  break;
860  case GPU_TEXTURE_CUBE:
861  BLI_assert(layer < 6);
862  mtl_color_attachments_[slot].slice = layer;
863  mtl_color_attachments_[slot].depth_plane = 0;
864  if (layer == -1) {
865  mtl_color_attachments_[slot].slice = 0;
866  mtl_color_attachments_[slot].depth_plane = 0;
867  mtl_color_attachments_[slot].render_target_array_length = 6;
868  use_multilayered_rendering_ = true;
869  }
870  break;
872  BLI_assert(layer < 6 * texture->d_);
873  /* TODO(Metal): Verify multilayered rendering for Cube arrays. */
874  mtl_color_attachments_[slot].slice = layer;
875  mtl_color_attachments_[slot].depth_plane = 0;
876  if (layer == -1) {
877  mtl_color_attachments_[slot].slice = 0;
878  mtl_color_attachments_[slot].depth_plane = 0;
879  mtl_color_attachments_[slot].render_target_array_length = texture->d_;
880  use_multilayered_rendering_ = true;
881  }
882  break;
883  case GPU_TEXTURE_BUFFER:
884  mtl_color_attachments_[slot].slice = 0;
885  mtl_color_attachments_[slot].depth_plane = 0;
886  break;
887  default:
888  MTL_LOG_ERROR("MTLFrameBuffer::add_color_attachment Unrecognised texture type %u\n",
889  texture->type_);
890  break;
891  }
892 
893  /* Update Framebuffer Resolution. */
894  int width_of_miplayer, height_of_miplayer;
895  if (miplevel <= 0) {
896  width_of_miplayer = texture->width_get();
897  height_of_miplayer = texture->height_get();
898  }
899  else {
900  width_of_miplayer = max_ii(texture->width_get() >> miplevel, 1);
901  height_of_miplayer = max_ii(texture->height_get() >> miplevel, 1);
902  }
903 
904  if (width_ == 0 || height_ == 0) {
905  this->size_set(width_of_miplayer, height_of_miplayer);
906  this->scissor_reset();
907  this->viewport_reset();
908  BLI_assert(width_ > 0);
909  BLI_assert(height_ > 0);
910  }
911  else {
912  BLI_assert(width_ == width_of_miplayer);
913  BLI_assert(height_ == height_of_miplayer);
914  }
915 
916  /* Flag as dirty. */
917  this->mark_dirty();
918  }
919  else {
921  "Passing in null texture to MTLFrameBuffer::addColourAttachment (This could be due to not "
922  "all texture types being supported).\n");
923  }
924  return true;
925 }
926 
927 bool MTLFrameBuffer::add_depth_attachment(gpu::MTLTexture *texture, int miplevel, int layer)
928 {
929  BLI_assert(this);
930 
931  if (texture) {
932  if (miplevel < 0 || miplevel >= MTL_MAX_MIPMAP_COUNT) {
933  MTL_LOG_WARNING("Attachment specified with invalid mip level %u\n", miplevel);
934  miplevel = 0;
935  }
936 
937  /* Assume attachment load by default. */
938  mtl_depth_attachment_.used = true;
939  mtl_depth_attachment_.texture = texture;
940  mtl_depth_attachment_.mip = miplevel;
941  mtl_depth_attachment_.load_action = GPU_LOADACTION_LOAD;
942  mtl_depth_attachment_.store_action = GPU_STOREACTION_STORE;
943  mtl_depth_attachment_.render_target_array_length = 0;
944 
945  /* Determine whether array slice or depth plane based on texture type. */
946  switch (texture->type_) {
947  case GPU_TEXTURE_1D:
948  case GPU_TEXTURE_2D:
949  BLI_assert(layer <= 0);
950  mtl_depth_attachment_.slice = 0;
951  mtl_depth_attachment_.depth_plane = 0;
952  break;
954  if (layer < 0) {
955  layer = 0;
956  MTL_LOG_WARNING("TODO: Support layered rendering for 1D array textures, if needed\n");
957  }
958  BLI_assert(layer < texture->h_);
959  mtl_depth_attachment_.slice = layer;
960  mtl_depth_attachment_.depth_plane = 0;
961  break;
963  BLI_assert(layer < texture->d_);
964  mtl_depth_attachment_.slice = layer;
965  mtl_depth_attachment_.depth_plane = 0;
966  if (layer == -1) {
967  mtl_depth_attachment_.slice = 0;
968  mtl_depth_attachment_.render_target_array_length = texture->d_;
969  use_multilayered_rendering_ = true;
970  }
971  break;
972  case GPU_TEXTURE_3D:
973  BLI_assert(layer < texture->d_);
974  mtl_depth_attachment_.slice = 0;
975  mtl_depth_attachment_.depth_plane = layer;
976  if (layer == -1) {
977  mtl_depth_attachment_.depth_plane = 0;
978  mtl_depth_attachment_.render_target_array_length = texture->d_;
979  use_multilayered_rendering_ = true;
980  }
981  break;
982  case GPU_TEXTURE_CUBE:
983  BLI_assert(layer < 6);
984  mtl_depth_attachment_.slice = layer;
985  mtl_depth_attachment_.depth_plane = 0;
986  if (layer == -1) {
987  mtl_depth_attachment_.slice = 0;
988  mtl_depth_attachment_.depth_plane = 0;
989  mtl_depth_attachment_.render_target_array_length = 1;
990  use_multilayered_rendering_ = true;
991  }
992  break;
994  /* TODO(Metal): Verify multilayered rendering for Cube arrays. */
995  BLI_assert(layer < 6 * texture->d_);
996  mtl_depth_attachment_.slice = layer;
997  mtl_depth_attachment_.depth_plane = 0;
998  if (layer == -1) {
999  mtl_depth_attachment_.slice = 0;
1000  mtl_depth_attachment_.depth_plane = 0;
1001  mtl_depth_attachment_.render_target_array_length = texture->d_;
1002  use_multilayered_rendering_ = true;
1003  }
1004  break;
1005  case GPU_TEXTURE_BUFFER:
1006  mtl_depth_attachment_.slice = 0;
1007  mtl_depth_attachment_.depth_plane = 0;
1008  break;
1009  default:
1010  BLI_assert(false && "Unrecognised texture type");
1011  break;
1012  }
1013 
1014  /* Update Framebuffer Resolution. */
1015  int width_of_miplayer, height_of_miplayer;
1016  if (miplevel <= 0) {
1017  width_of_miplayer = texture->width_get();
1018  height_of_miplayer = texture->height_get();
1019  }
1020  else {
1021  width_of_miplayer = max_ii(texture->width_get() >> miplevel, 1);
1022  height_of_miplayer = max_ii(texture->height_get() >> miplevel, 1);
1023  }
1024 
1025  /* Update Framebuffer Resolution. */
1026  if (width_ == 0 || height_ == 0) {
1027  this->size_set(width_of_miplayer, height_of_miplayer);
1028  this->scissor_reset();
1029  this->viewport_reset();
1030  BLI_assert(width_ > 0);
1031  BLI_assert(height_ > 0);
1032  }
1033  else {
1034  BLI_assert(width_ == texture->width_get());
1035  BLI_assert(height_ == texture->height_get());
1036  }
1037 
1038  /* Flag as dirty after attachments changed. */
1039  this->mark_dirty();
1040  }
1041  else {
1042  MTL_LOG_ERROR(
1043  "Passing in null texture to MTLFrameBuffer::addDepthAttachment (This could be due to not "
1044  "all texture types being supported).");
1045  }
1046  return true;
1047 }
1048 
1049 bool MTLFrameBuffer::add_stencil_attachment(gpu::MTLTexture *texture, int miplevel, int layer)
1050 {
1051  BLI_assert(this);
1052 
1053  if (texture) {
1054  if (miplevel < 0 || miplevel >= MTL_MAX_MIPMAP_COUNT) {
1055  MTL_LOG_WARNING("Attachment specified with invalid mip level %u\n", miplevel);
1056  miplevel = 0;
1057  }
1058 
1059  /* Assume attachment load by default. */
1060  mtl_stencil_attachment_.used = true;
1061  mtl_stencil_attachment_.texture = texture;
1062  mtl_stencil_attachment_.mip = miplevel;
1063  mtl_stencil_attachment_.load_action = GPU_LOADACTION_LOAD;
1064  mtl_stencil_attachment_.store_action = GPU_STOREACTION_STORE;
1065  mtl_stencil_attachment_.render_target_array_length = 0;
1066 
1067  /* Determine whether array slice or depth plane based on texture type. */
1068  switch (texture->type_) {
1069  case GPU_TEXTURE_1D:
1070  case GPU_TEXTURE_2D:
1071  BLI_assert(layer <= 0);
1072  mtl_stencil_attachment_.slice = 0;
1073  mtl_stencil_attachment_.depth_plane = 0;
1074  break;
1075  case GPU_TEXTURE_1D_ARRAY:
1076  if (layer < 0) {
1077  layer = 0;
1078  MTL_LOG_WARNING("TODO: Support layered rendering for 1D array textures, if needed\n");
1079  }
1080  BLI_assert(layer < texture->h_);
1081  mtl_stencil_attachment_.slice = layer;
1082  mtl_stencil_attachment_.depth_plane = 0;
1083  break;
1084  case GPU_TEXTURE_2D_ARRAY:
1085  BLI_assert(layer < texture->d_);
1086  mtl_stencil_attachment_.slice = layer;
1087  mtl_stencil_attachment_.depth_plane = 0;
1088  if (layer == -1) {
1089  mtl_stencil_attachment_.slice = 0;
1090  mtl_stencil_attachment_.render_target_array_length = texture->d_;
1091  use_multilayered_rendering_ = true;
1092  }
1093  break;
1094  case GPU_TEXTURE_3D:
1095  BLI_assert(layer < texture->d_);
1096  mtl_stencil_attachment_.slice = 0;
1097  mtl_stencil_attachment_.depth_plane = layer;
1098  if (layer == -1) {
1099  mtl_stencil_attachment_.depth_plane = 0;
1100  mtl_stencil_attachment_.render_target_array_length = texture->d_;
1101  use_multilayered_rendering_ = true;
1102  }
1103  break;
1104  case GPU_TEXTURE_CUBE:
1105  BLI_assert(layer < 6);
1106  mtl_stencil_attachment_.slice = layer;
1107  mtl_stencil_attachment_.depth_plane = 0;
1108  if (layer == -1) {
1109  mtl_stencil_attachment_.slice = 0;
1110  mtl_stencil_attachment_.depth_plane = 0;
1111  mtl_stencil_attachment_.render_target_array_length = 1;
1112  use_multilayered_rendering_ = true;
1113  }
1114  break;
1116  /* TODO(Metal): Verify multilayered rendering for Cube arrays. */
1117  BLI_assert(layer < 6 * texture->d_);
1118  mtl_stencil_attachment_.slice = layer;
1119  mtl_stencil_attachment_.depth_plane = 0;
1120  if (layer == -1) {
1121  mtl_stencil_attachment_.slice = 0;
1122  mtl_stencil_attachment_.depth_plane = 0;
1123  mtl_stencil_attachment_.render_target_array_length = texture->d_;
1124  use_multilayered_rendering_ = true;
1125  }
1126  break;
1127  case GPU_TEXTURE_BUFFER:
1128  mtl_stencil_attachment_.slice = 0;
1129  mtl_stencil_attachment_.depth_plane = 0;
1130  break;
1131  default:
1132  BLI_assert(false && "Unrecognised texture type");
1133  break;
1134  }
1135 
1136  /* Update Framebuffer Resolution. */
1137  int width_of_miplayer, height_of_miplayer;
1138  if (miplevel <= 0) {
1139  width_of_miplayer = texture->width_get();
1140  height_of_miplayer = texture->height_get();
1141  }
1142  else {
1143  width_of_miplayer = max_ii(texture->width_get() >> miplevel, 1);
1144  height_of_miplayer = max_ii(texture->height_get() >> miplevel, 1);
1145  }
1146 
1147  /* Update Framebuffer Resolution. */
1148  if (width_ == 0 || height_ == 0) {
1149  this->size_set(width_of_miplayer, height_of_miplayer);
1150  this->scissor_reset();
1151  this->viewport_reset();
1152  BLI_assert(width_ > 0);
1153  BLI_assert(height_ > 0);
1154  }
1155  else {
1156  BLI_assert(width_ == texture->width_get());
1157  BLI_assert(height_ == texture->height_get());
1158  }
1159 
1160  /* Flag as dirty after attachments changed. */
1161  this->mark_dirty();
1162  }
1163  else {
1164  MTL_LOG_ERROR(
1165  "Passing in null texture to MTLFrameBuffer::addStencilAttachment (This could be due to "
1166  "not all texture types being supported).");
1167  }
1168  return true;
1169 }
1170 
1172 {
1173  BLI_assert(this);
1174  BLI_assert(slot >= 0 && slot < this->get_attachment_limit());
1175 
1176  if (this->has_attachment_at_slot(slot)) {
1177  colour_attachment_count_ -= (mtl_color_attachments_[slot].used) ? 1 : 0;
1178  mtl_color_attachments_[slot].used = false;
1179  this->ensure_render_target_size();
1180  this->mark_dirty();
1181  return true;
1182  }
1183 
1184  return false;
1185 }
1186 
1188 {
1189  BLI_assert(this);
1190 
1191  mtl_depth_attachment_.used = false;
1192  mtl_depth_attachment_.texture = nullptr;
1193  this->ensure_render_target_size();
1194  this->mark_dirty();
1195 
1196  return true;
1197 }
1198 
1200 {
1201  BLI_assert(this);
1202 
1203  mtl_stencil_attachment_.used = false;
1204  mtl_stencil_attachment_.texture = nullptr;
1205  this->ensure_render_target_size();
1206  this->mark_dirty();
1207 
1208  return true;
1209 }
1210 
1212 {
1213  BLI_assert(this);
1214 
1215  for (int attachment = 0; attachment < GPU_FB_MAX_COLOR_ATTACHMENT; attachment++) {
1216  this->remove_color_attachment(attachment);
1217  }
1218  this->remove_depth_attachment();
1219  this->remove_stencil_attachment();
1220  colour_attachment_count_ = 0;
1221  this->mark_dirty();
1222 
1223  /* Verify height. */
1224  this->ensure_render_target_size();
1225 
1226  /* Flag attachments as no longer being dirty. */
1227  dirty_attachments_ = false;
1228 }
1229 
1231 {
1232  /* If we have no attachments, reset width and height to zero. */
1233  if (colour_attachment_count_ == 0 && !this->has_depth_attachment() &&
1234  !this->has_stencil_attachment()) {
1235 
1236  /* Reset Viewport and Scissor for NULL framebuffer. */
1237  this->size_set(0, 0);
1238  this->scissor_reset();
1239  this->viewport_reset();
1240  }
1241 }
1242 
1245 /* -------------------------------------------------------------------- */
1250  eGPULoadOp load_action,
1251  eGPUStoreOp store_action)
1252 {
1253  if (type >= GPU_FB_COLOR_ATTACHMENT0) {
1254  int slot = type - GPU_FB_COLOR_ATTACHMENT0;
1255  this->set_color_loadstore_op(slot, load_action, store_action);
1256  }
1257  else if (type == GPU_FB_DEPTH_STENCIL_ATTACHMENT) {
1258  this->set_depth_loadstore_op(load_action, store_action);
1259  this->set_stencil_loadstore_op(load_action, store_action);
1260  }
1261  else if (type == GPU_FB_DEPTH_ATTACHMENT) {
1262  this->set_depth_loadstore_op(load_action, store_action);
1263  }
1264 }
1265 
1266 bool MTLFrameBuffer::set_color_attachment_clear_color(uint slot, const float clear_color[4])
1267 {
1268  BLI_assert(this);
1269  BLI_assert(slot >= 0 && slot < this->get_attachment_limit());
1270 
1271  /* Only mark as dirty if values have changed. */
1272  bool changed = mtl_color_attachments_[slot].load_action != GPU_LOADACTION_CLEAR;
1273  changed = changed || (memcmp(mtl_color_attachments_[slot].clear_value.color,
1274  clear_color,
1275  sizeof(float) * 4) != 0);
1276  if (changed) {
1277  memcpy(mtl_color_attachments_[slot].clear_value.color, clear_color, sizeof(float) * 4);
1278  }
1279  mtl_color_attachments_[slot].load_action = GPU_LOADACTION_CLEAR;
1280 
1281  if (changed) {
1282  this->mark_loadstore_dirty();
1283  }
1284  return true;
1285 }
1286 
1288 {
1289  BLI_assert(this);
1290 
1291  if (mtl_depth_attachment_.clear_value.depth != depth_clear ||
1292  mtl_depth_attachment_.load_action != GPU_LOADACTION_CLEAR) {
1293  mtl_depth_attachment_.clear_value.depth = depth_clear;
1294  mtl_depth_attachment_.load_action = GPU_LOADACTION_CLEAR;
1295  this->mark_loadstore_dirty();
1296  }
1297  return true;
1298 }
1299 
1301 {
1302  BLI_assert(this);
1303 
1304  if (mtl_stencil_attachment_.clear_value.stencil != stencil_clear ||
1305  mtl_stencil_attachment_.load_action != GPU_LOADACTION_CLEAR) {
1306  mtl_stencil_attachment_.clear_value.stencil = stencil_clear;
1307  mtl_stencil_attachment_.load_action = GPU_LOADACTION_CLEAR;
1308  this->mark_loadstore_dirty();
1309  }
1310  return true;
1311 }
1312 
1314  eGPULoadOp load_action,
1315  eGPUStoreOp store_action)
1316 {
1317  BLI_assert(this);
1318  eGPULoadOp prev_load_action = mtl_color_attachments_[slot].load_action;
1319  eGPUStoreOp prev_store_action = mtl_color_attachments_[slot].store_action;
1320  mtl_color_attachments_[slot].load_action = load_action;
1321  mtl_color_attachments_[slot].store_action = store_action;
1322 
1323  bool changed = (mtl_color_attachments_[slot].load_action != prev_load_action ||
1324  mtl_color_attachments_[slot].store_action != prev_store_action);
1325  if (changed) {
1326  this->mark_loadstore_dirty();
1327  }
1328 
1329  return changed;
1330 }
1331 
1333 {
1334  BLI_assert(this);
1335  eGPULoadOp prev_load_action = mtl_depth_attachment_.load_action;
1336  eGPUStoreOp prev_store_action = mtl_depth_attachment_.store_action;
1337  mtl_depth_attachment_.load_action = load_action;
1338  mtl_depth_attachment_.store_action = store_action;
1339 
1340  bool changed = (mtl_depth_attachment_.load_action != prev_load_action ||
1341  mtl_depth_attachment_.store_action != prev_store_action);
1342  if (changed) {
1343  this->mark_loadstore_dirty();
1344  }
1345 
1346  return changed;
1347 }
1348 
1350 {
1351  BLI_assert(this);
1352  eGPULoadOp prev_load_action = mtl_stencil_attachment_.load_action;
1353  eGPUStoreOp prev_store_action = mtl_stencil_attachment_.store_action;
1354  mtl_stencil_attachment_.load_action = load_action;
1355  mtl_stencil_attachment_.store_action = store_action;
1356 
1357  bool changed = (mtl_stencil_attachment_.load_action != prev_load_action ||
1358  mtl_stencil_attachment_.store_action != prev_store_action);
1359  if (changed) {
1360  this->mark_loadstore_dirty();
1361  }
1362 
1363  return changed;
1364 }
1365 
1367 {
1368  for (int slot = 0; slot < colour_attachment_count_; slot++) {
1370  }
1373  return true;
1374 }
1375 
1378 /* -------------------------------------------------------------------- */
1383 {
1384  BLI_assert(this);
1385 
1386  if (slot >= 0 && slot < this->get_attachment_limit()) {
1387  return mtl_color_attachments_[slot].used;
1388  }
1389  return false;
1390 }
1391 
1393 {
1394  BLI_assert(this);
1395 
1396  for (int attachment = 0; attachment < this->get_attachment_limit(); attachment++) {
1397  if (mtl_color_attachments_[attachment].used &&
1398  mtl_color_attachments_[attachment].texture == texture) {
1399  return true;
1400  }
1401  }
1402  return false;
1403 }
1404 
1406 {
1407  BLI_assert(this);
1408  return mtl_depth_attachment_.used;
1409 }
1410 
1412 {
1413  BLI_assert(this);
1414  return mtl_stencil_attachment_.used;
1415 }
1416 
1418 {
1419  BLI_assert(this);
1420  BLI_assert(texture);
1421 
1422  for (int attachment = 0; attachment < this->get_attachment_limit(); attachment++) {
1423  if (mtl_color_attachments_[attachment].used &&
1424  (mtl_color_attachments_[attachment].texture == texture)) {
1425  return attachment;
1426  }
1427  }
1428  return -1;
1429 }
1430 
1432 {
1433  BLI_assert(this);
1434  return colour_attachment_count_;
1435 }
1436 
1438 {
1439  BLI_assert(this);
1440  if (slot >= 0 && slot < GPU_FB_MAX_COLOR_ATTACHMENT) {
1441  return mtl_color_attachments_[slot];
1442  }
1443  MTLAttachment null_attachment;
1444  null_attachment.used = false;
1445  return null_attachment;
1446 }
1447 
1449 {
1450  BLI_assert(this);
1451  return mtl_depth_attachment_;
1452 }
1453 
1455 {
1456  BLI_assert(this);
1457  return mtl_stencil_attachment_;
1458 }
1459 
1462 /* -------------------------------------------------------------------- */
1466 {
1467  BLI_assert(this);
1468 
1469  /* First update attachments if dirty. */
1470  this->update_attachments(true);
1471 
1472  /* Verify attachment count. */
1473  int used_attachments = 0;
1474  for (int attachment = 0; attachment < GPU_FB_MAX_COLOR_ATTACHMENT; attachment++) {
1475  if (mtl_color_attachments_[attachment].used) {
1476  used_attachments++;
1477  }
1478  }
1479  used_attachments += (mtl_depth_attachment_.used) ? 1 : 0;
1480  used_attachments += (mtl_stencil_attachment_.used) ? 1 : 0;
1481  return (used_attachments > 0);
1482 }
1483 
1485 {
1486  return (action == GPU_LOADACTION_LOAD) ?
1487  MTLLoadActionLoad :
1488  ((action == GPU_LOADACTION_CLEAR) ? MTLLoadActionClear : MTLLoadActionDontCare);
1489 }
1490 
1492 {
1493  return (action == GPU_STOREACTION_STORE) ? MTLStoreActionStore : MTLStoreActionDontCare;
1494 }
1495 
1496 MTLRenderPassDescriptor *MTLFrameBuffer::bake_render_pass_descriptor(bool load_contents)
1497 {
1498  BLI_assert(this);
1499  if (load_contents) {
1500  /* Only force-load contents if there is no clear pending. */
1501  BLI_assert(!has_pending_clear_);
1502  }
1503 
1504  /* Ensure we are inside a frame boundary. */
1505  MTLContext *metal_ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get()));
1506  BLI_assert(metal_ctx && metal_ctx->get_inside_frame());
1507  UNUSED_VARS_NDEBUG(metal_ctx);
1508 
1509  /* If Framebuffer has been modified, regenerate descriptor. */
1510  if (is_dirty_) {
1511  /* Clear all configs. */
1512  for (int config = 0; config < 3; config++) {
1513  descriptor_dirty_[config] = true;
1514  }
1515  }
1516  else if (is_loadstore_dirty_) {
1517  /* Load config always has load ops, so we only need to re-generate custom and clear state. */
1518  descriptor_dirty_[MTL_FB_CONFIG_CLEAR] = true;
1519  descriptor_dirty_[MTL_FB_CONFIG_CUSTOM] = true;
1520  }
1521 
1522  /* If we need to populate descriptor" */
1523  /* Select config based on FrameBuffer state:
1524  * [0] {MTL_FB_CONFIG_CLEAR} = Clear config -- we have a pending clear so should perform our
1525  * configured clear.
1526  * [1] {MTL_FB_CONFIG_LOAD} = Load config -- We need to re-load ALL attachments,
1527  * used for re-binding/pass-breaks.
1528  * [2] {MTL_FB_CONFIG_CUSTOM} = Custom config -- Use this when a custom binding config is
1529  * specified.
1530  */
1531  uint descriptor_config = (load_contents) ? MTL_FB_CONFIG_LOAD :
1532  ((this->get_pending_clear()) ? MTL_FB_CONFIG_CLEAR :
1533  MTL_FB_CONFIG_CUSTOM);
1534  if (descriptor_dirty_[descriptor_config] || framebuffer_descriptor_[descriptor_config] == nil) {
1535 
1536  /* Create descriptor if it does not exist. */
1537  if (framebuffer_descriptor_[descriptor_config] == nil) {
1538  framebuffer_descriptor_[descriptor_config] = [[MTLRenderPassDescriptor alloc] init];
1539  }
1540 
1541 #if defined(MAC_OS_X_VERSION_11_0) && __MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_11_0
1542  if (@available(macOS 11.00, *)) {
1543  /* Optimization: Use smaller tile size on Apple Silicon if exceeding a certain bpp limit. */
1544  bool is_tile_based_gpu = [metal_ctx->device hasUnifiedMemory];
1545  if (is_tile_based_gpu) {
1546  uint framebuffer_bpp = this->get_bits_per_pixel();
1547  bool use_small_tiles = (framebuffer_bpp > 64);
1548 
1549  if (use_small_tiles) {
1550  framebuffer_descriptor_[descriptor_config].tileWidth = 16;
1551  framebuffer_descriptor_[descriptor_config].tileHeight = 16;
1552  }
1553  }
1554  }
1555 #endif
1556 
1557  /* Configure multilayered rendering. */
1558  if (use_multilayered_rendering_) {
1559  /* Ensure all targets have the same length. */
1560  int len = 0;
1561  bool valid = true;
1562 
1563  for (int attachment_ind = 0; attachment_ind < GPU_FB_MAX_COLOR_ATTACHMENT;
1564  attachment_ind++) {
1565  if (mtl_color_attachments_[attachment_ind].used) {
1566  if (len == 0) {
1567  len = mtl_color_attachments_[attachment_ind].render_target_array_length;
1568  }
1569  else {
1570  valid = valid &&
1571  (len == mtl_color_attachments_[attachment_ind].render_target_array_length);
1572  }
1573  }
1574  }
1575 
1576  if (mtl_depth_attachment_.used) {
1577  if (len == 0) {
1578  len = mtl_depth_attachment_.render_target_array_length;
1579  }
1580  else {
1581  valid = valid && (len == mtl_depth_attachment_.render_target_array_length);
1582  }
1583  }
1584 
1585  if (mtl_stencil_attachment_.used) {
1586  if (len == 0) {
1587  len = mtl_stencil_attachment_.render_target_array_length;
1588  }
1589  else {
1590  valid = valid && (len == mtl_stencil_attachment_.render_target_array_length);
1591  }
1592  }
1593 
1594  BLI_assert(len > 0);
1595  BLI_assert(valid);
1596  framebuffer_descriptor_[descriptor_config].renderTargetArrayLength = len;
1597  }
1598  else {
1599  framebuffer_descriptor_[descriptor_config].renderTargetArrayLength = 0;
1600  }
1601 
1602  /* Color attachments. */
1603  int colour_attachments = 0;
1604  for (int attachment_ind = 0; attachment_ind < GPU_FB_MAX_COLOR_ATTACHMENT; attachment_ind++) {
1605 
1606  if (mtl_color_attachments_[attachment_ind].used) {
1607 
1608  /* Create attachment descriptor. */
1609  MTLRenderPassColorAttachmentDescriptor *attachment =
1610  colour_attachment_descriptors_[attachment_ind];
1611  BLI_assert(attachment != nil);
1612 
1613  id<MTLTexture> texture =
1614  mtl_color_attachments_[attachment_ind].texture->get_metal_handle_base();
1615  if (texture == nil) {
1616  MTL_LOG_ERROR("Attempting to assign invalid texture as attachment\n");
1617  }
1618 
1619  /* IF SRGB is enabled, but we are rendering with SRGB disabled, sample texture view. */
1620  /* TODO(Metal): Consider caching SRGB texture view. */
1621  id<MTLTexture> source_color_texture = texture;
1622  if (this->get_is_srgb() && !this->get_srgb_enabled()) {
1623  source_color_texture = [texture newTextureViewWithPixelFormat:MTLPixelFormatRGBA8Unorm];
1624  }
1625 
1626  /* Resolve appropriate load action -- IF force load, perform load.
1627  * If clear but framebuffer has no pending clear, also load. */
1628  eGPULoadOp load_action = mtl_color_attachments_[attachment_ind].load_action;
1629  if (descriptor_config == MTL_FB_CONFIG_LOAD) {
1630  /* MTL_FB_CONFIG_LOAD must always load. */
1631  load_action = GPU_LOADACTION_LOAD;
1632  }
1633  else if (descriptor_config == MTL_FB_CONFIG_CUSTOM &&
1634  load_action == GPU_LOADACTION_CLEAR) {
1635  /* Custom config should be LOAD or DONT_CARE only. */
1636  load_action = GPU_LOADACTION_LOAD;
1637  }
1638  attachment.texture = source_color_texture;
1639  attachment.loadAction = mtl_load_action_from_gpu(load_action);
1640  attachment.clearColor =
1641  (load_action == GPU_LOADACTION_CLEAR) ?
1642  MTLClearColorMake(mtl_color_attachments_[attachment_ind].clear_value.color[0],
1643  mtl_color_attachments_[attachment_ind].clear_value.color[1],
1644  mtl_color_attachments_[attachment_ind].clear_value.color[2],
1645  mtl_color_attachments_[attachment_ind].clear_value.color[3]) :
1646  MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
1647  attachment.storeAction = mtl_store_action_from_gpu(
1648  mtl_color_attachments_[attachment_ind].store_action);
1649  attachment.level = mtl_color_attachments_[attachment_ind].mip;
1650  attachment.slice = mtl_color_attachments_[attachment_ind].slice;
1651  attachment.depthPlane = mtl_color_attachments_[attachment_ind].depth_plane;
1652  colour_attachments++;
1653 
1654  /* Copy attachment info back in. */
1655  [framebuffer_descriptor_[descriptor_config].colorAttachments setObject:attachment
1656  atIndexedSubscript:attachment_ind];
1657  }
1658  else {
1659  /* Disable colour attachment. */
1660  [framebuffer_descriptor_[descriptor_config].colorAttachments setObject:nil
1661  atIndexedSubscript:attachment_ind];
1662  }
1663  }
1664  BLI_assert(colour_attachments == colour_attachment_count_);
1665 
1666  /* Depth attachment. */
1667  if (mtl_depth_attachment_.used) {
1668  framebuffer_descriptor_[descriptor_config].depthAttachment.texture =
1669  (id<MTLTexture>)mtl_depth_attachment_.texture->get_metal_handle_base();
1670 
1671  /* Resolve appropriate load action -- IF force load, perform load.
1672  * If clear but framebuffer has no pending clear, also load. */
1673  eGPULoadOp load_action = mtl_depth_attachment_.load_action;
1674  if (descriptor_config == MTL_FB_CONFIG_LOAD) {
1675  /* MTL_FB_CONFIG_LOAD must always load. */
1676  load_action = GPU_LOADACTION_LOAD;
1677  }
1678  else if (descriptor_config == MTL_FB_CONFIG_CUSTOM && load_action == GPU_LOADACTION_CLEAR) {
1679  /* Custom config should be LOAD or DONT_CARE only. */
1680  load_action = GPU_LOADACTION_LOAD;
1681  }
1682  framebuffer_descriptor_[descriptor_config].depthAttachment.loadAction =
1683  mtl_load_action_from_gpu(load_action);
1684  framebuffer_descriptor_[descriptor_config].depthAttachment.clearDepth =
1685  (load_action == GPU_LOADACTION_CLEAR) ? mtl_depth_attachment_.clear_value.depth : 0;
1686  framebuffer_descriptor_[descriptor_config].depthAttachment.storeAction =
1687  mtl_store_action_from_gpu(mtl_depth_attachment_.store_action);
1688  framebuffer_descriptor_[descriptor_config].depthAttachment.level = mtl_depth_attachment_.mip;
1689  framebuffer_descriptor_[descriptor_config].depthAttachment.slice =
1690  mtl_depth_attachment_.slice;
1691  framebuffer_descriptor_[descriptor_config].depthAttachment.depthPlane =
1692  mtl_depth_attachment_.depth_plane;
1693  }
1694  else {
1695  framebuffer_descriptor_[descriptor_config].depthAttachment.texture = nil;
1696  }
1697 
1698  /* Stencil attachment. */
1699  if (mtl_stencil_attachment_.used) {
1700  framebuffer_descriptor_[descriptor_config].stencilAttachment.texture =
1701  (id<MTLTexture>)mtl_stencil_attachment_.texture->get_metal_handle_base();
1702 
1703  /* Resolve appropriate load action -- IF force load, perform load.
1704  * If clear but framebuffer has no pending clear, also load. */
1705  eGPULoadOp load_action = mtl_stencil_attachment_.load_action;
1706  if (descriptor_config == MTL_FB_CONFIG_LOAD) {
1707  /* MTL_FB_CONFIG_LOAD must always load. */
1708  load_action = GPU_LOADACTION_LOAD;
1709  }
1710  else if (descriptor_config == MTL_FB_CONFIG_CUSTOM && load_action == GPU_LOADACTION_CLEAR) {
1711  /* Custom config should be LOAD or DONT_CARE only. */
1712  load_action = GPU_LOADACTION_LOAD;
1713  }
1714  framebuffer_descriptor_[descriptor_config].stencilAttachment.loadAction =
1715  mtl_load_action_from_gpu(load_action);
1716  framebuffer_descriptor_[descriptor_config].stencilAttachment.clearStencil =
1717  (load_action == GPU_LOADACTION_CLEAR) ? mtl_stencil_attachment_.clear_value.stencil : 0;
1718  framebuffer_descriptor_[descriptor_config].stencilAttachment.storeAction =
1719  mtl_store_action_from_gpu(mtl_stencil_attachment_.store_action);
1720  framebuffer_descriptor_[descriptor_config].stencilAttachment.level =
1721  mtl_stencil_attachment_.mip;
1722  framebuffer_descriptor_[descriptor_config].stencilAttachment.slice =
1723  mtl_stencil_attachment_.slice;
1724  framebuffer_descriptor_[descriptor_config].stencilAttachment.depthPlane =
1725  mtl_stencil_attachment_.depth_plane;
1726  }
1727  else {
1728  framebuffer_descriptor_[descriptor_config].stencilAttachment.texture = nil;
1729  }
1730  descriptor_dirty_[descriptor_config] = false;
1731  }
1732  is_dirty_ = false;
1733  is_loadstore_dirty_ = false;
1734  return framebuffer_descriptor_[descriptor_config];
1735 }
1736 
1739 /* -------------------------------------------------------------------- */
1744  uint src_x_offset,
1745  uint src_y_offset,
1746  MTLFrameBuffer *metal_fb_write,
1747  uint write_slot,
1748  uint dst_x_offset,
1749  uint dst_y_offset,
1750  uint width,
1751  uint height,
1752  eGPUFrameBufferBits blit_buffers)
1753 {
1754  BLI_assert(this);
1755  BLI_assert(metal_fb_write);
1756  if (!(this && metal_fb_write)) {
1757  return;
1758  }
1759  MTLContext *mtl_context = reinterpret_cast<MTLContext *>(GPU_context_active_get());
1760 
1761  const bool do_color = (blit_buffers & GPU_COLOR_BIT);
1762  const bool do_depth = (blit_buffers & GPU_DEPTH_BIT);
1763  const bool do_stencil = (blit_buffers & GPU_STENCIL_BIT);
1764 
1765  /* Early exit if there is no blit to do. */
1766  if (!(do_color || do_depth || do_stencil)) {
1768  " MTLFrameBuffer: requested blit but no color, depth or stencil flag was set\n");
1769  return;
1770  }
1771 
1772  id<MTLBlitCommandEncoder> blit_encoder = nil;
1773 
1774  /* If the color format is not the same, we cannot use the BlitCommandEncoder, and instead use
1775  * a Graphics-based blit. */
1776  if (do_color && (this->get_color_attachment(read_slot).texture->format_get() !=
1777  metal_fb_write->get_color_attachment(read_slot).texture->format_get())) {
1778 
1779  MTLAttachment src_attachment = this->get_color_attachment(read_slot);
1780  MTLAttachment dst_attachment = metal_fb_write->get_color_attachment(write_slot);
1781  assert(src_attachment.slice == 0 &&
1782  "currently only supporting slice 0 for graphics framebuffer blit");
1783 
1784  src_attachment.texture->blit(dst_attachment.texture,
1785  src_x_offset,
1786  src_y_offset,
1787  dst_x_offset,
1788  dst_y_offset,
1789  src_attachment.mip,
1790  dst_attachment.mip,
1791  dst_attachment.slice,
1792  width,
1793  height);
1794  }
1795  else {
1796 
1797  /* Setup blit encoder. */
1798  blit_encoder = mtl_context->main_command_buffer.ensure_begin_blit_encoder();
1799 
1800  if (do_color) {
1801  MTLAttachment src_attachment = this->get_color_attachment(read_slot);
1802  MTLAttachment dst_attachment = metal_fb_write->get_color_attachment(write_slot);
1803 
1804  if (src_attachment.used && dst_attachment.used) {
1805 
1806  /* TODO(Metal): Support depth(z) offset in blit if needed. */
1807  src_attachment.texture->blit(blit_encoder,
1808  src_x_offset,
1809  src_y_offset,
1810  0,
1811  src_attachment.slice,
1812  src_attachment.mip,
1813  dst_attachment.texture,
1814  dst_x_offset,
1815  dst_y_offset,
1816  0,
1817  dst_attachment.slice,
1818  dst_attachment.mip,
1819  width,
1820  height,
1821  1);
1822  }
1823  else {
1824  MTL_LOG_ERROR("Failed performing colour blit\n");
1825  }
1826  }
1827  }
1828  if ((do_depth || do_stencil) && blit_encoder == nil) {
1829  blit_encoder = mtl_context->main_command_buffer.ensure_begin_blit_encoder();
1830  }
1831 
1832  if (do_depth) {
1833  MTLAttachment src_attachment = this->get_depth_attachment();
1834  MTLAttachment dst_attachment = metal_fb_write->get_depth_attachment();
1835 
1836  if (src_attachment.used && dst_attachment.used) {
1837 
1838  /* TODO(Metal): Support depth(z) offset in blit if needed. */
1839  src_attachment.texture->blit(blit_encoder,
1840  src_x_offset,
1841  src_y_offset,
1842  0,
1843  src_attachment.slice,
1844  src_attachment.mip,
1845  dst_attachment.texture,
1846  dst_x_offset,
1847  dst_y_offset,
1848  0,
1849  dst_attachment.slice,
1850  dst_attachment.mip,
1851  width,
1852  height,
1853  1);
1854  }
1855  else {
1856  MTL_LOG_ERROR("Failed performing depth blit\n");
1857  }
1858  }
1859 
1860  /* Stencil attachment blit. */
1861  if (do_stencil) {
1862  MTLAttachment src_attachment = this->get_stencil_attachment();
1863  MTLAttachment dst_attachment = metal_fb_write->get_stencil_attachment();
1864 
1865  if (src_attachment.used && dst_attachment.used) {
1866 
1867  /* TODO(Metal): Support depth(z) offset in blit if needed. */
1868  src_attachment.texture->blit(blit_encoder,
1869  src_x_offset,
1870  src_y_offset,
1871  0,
1872  src_attachment.slice,
1873  src_attachment.mip,
1874  dst_attachment.texture,
1875  dst_x_offset,
1876  dst_y_offset,
1877  0,
1878  dst_attachment.slice,
1879  dst_attachment.mip,
1880  width,
1881  height,
1882  1);
1883  }
1884  else {
1885  MTL_LOG_ERROR("Failed performing Stencil blit\n");
1886  }
1887  }
1888 }
1889 
1891 {
1892  return width_;
1893 }
1895 {
1896  return height_;
1897 }
1898 
1899 } // blender::gpu
typedef float(TangentPoint)[2]
#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 maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED_VARS_NDEBUG(...)
eGPULoadOp
@ GPU_LOADACTION_LOAD
@ GPU_LOADACTION_CLEAR
eGPUStoreOp
@ GPU_STOREACTION_STORE
GPUContext * GPU_context_active_get(void)
Definition: gpu_context.cc:142
void GPU_framebuffer_restore(void)
eGPUFrameBufferBits
@ GPU_DEPTH_BIT
@ GPU_STENCIL_BIT
@ GPU_COLOR_BIT
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear)
Definition: gpu_shader.cc:753
eGPUDataFormat
Definition: GPU_texture.h:170
@ GPU_DATA_UINT_24_8
Definition: GPU_texture.h:175
@ GPU_DATA_INT
Definition: GPU_texture.h:172
@ GPU_DATA_UINT
Definition: GPU_texture.h:173
@ GPU_DATA_FLOAT
Definition: GPU_texture.h:171
@ GPU_TEXTURE_USAGE_ATTACHMENT
Definition: GPU_texture.h:184
eGPUTextureFormat
Definition: GPU_texture.h:83
@ GPU_DEPTH32F_STENCIL8
Definition: GPU_texture.h:119
@ GPU_SRGB8_A8
Definition: GPU_texture.h:121
@ GPU_DEPTH24_STENCIL8
Definition: GPU_texture.h:120
eGPUTextureFormat GPU_texture_format(const GPUTexture *tex)
Definition: gpu_texture.cc:639
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a color
void size_set(int width, int height)
void viewport_set(const int viewport[4])
void scissor_set(const int scissor[4])
void scissor_get(int r_scissor[4]) const
void viewport_get(int r_viewport[4]) const
GPUAttachment attachments_[GPU_FB_MAX_ATTACHMENT]
id< MTLBlitCommandEncoder > ensure_begin_blit_encoder()
MTLFrameBuffer * get_current_framebuffer()
Definition: mtl_context.mm:219
void set_scissor_enabled(bool scissor_enabled)
Definition: mtl_context.mm:359
void framebuffer_bind(MTLFrameBuffer *framebuffer)
Definition: mtl_context.mm:150
id< MTLRenderCommandEncoder > ensure_begin_render_pass()
Definition: mtl_context.mm:164
id< MTLDevice > device
Definition: mtl_context.hh:604
void set_viewport(int origin_x, int origin_y, int width, int height)
Definition: mtl_context.mm:318
void set_scissor(int scissor_x, int scissor_y, int scissor_width, int scissor_height)
Definition: mtl_context.mm:339
MTLCommandBufferManager main_command_buffer
Definition: mtl_context.hh:611
bool set_depth_loadstore_op(eGPULoadOp load_action, eGPUStoreOp store_action)
MTLAttachment get_color_attachment(uint slot)
bool remove_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
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)
MTLAttachment get_stencil_attachment()
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, eGPULoadOp load_action, eGPUStoreOp store_action) override
bool set_stencil_attachment_clear_value(uint stencil_clear)
bool add_stencil_attachment(gpu::MTLTexture *texture, int miplevel, int layer)
bool has_attachment_at_slot(uint slot)
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
eGPUTextureFormat format_get() const
int len
Definition: draw_manager.c:108
@ GPU_FB_DEPTH_STENCIL_ATTACHMENT
@ GPU_FB_COLOR_ATTACHMENT5
@ GPU_FB_COLOR_ATTACHMENT2
@ GPU_FB_COLOR_ATTACHMENT3
@ GPU_FB_MAX_ATTACHMENT
@ GPU_FB_COLOR_ATTACHMENT4
@ GPU_FB_COLOR_ATTACHMENT1
@ GPU_FB_COLOR_ATTACHMENT0
@ GPU_FB_DEPTH_ATTACHMENT
#define GPU_FB_MAX_COLOR_ATTACHMENT
format
Definition: logImageCore.h:38
#define MTL_LOG_WARNING(info,...)
Definition: mtl_debug.hh:36
#define MTL_LOG_ERROR(info,...)
Definition: mtl_debug.hh:24
#define MTL_FB_CONFIG_MAX
static void area(int d1, int d2, int e1, int e2, float weights[2])
MTLLoadAction mtl_load_action_from_gpu(eGPULoadOp action)
static Context * unwrap(GPUContext *ctx)
static const int MTL_MAX_MIPMAP_COUNT
Definition: mtl_texture.hh:124
static size_t to_bytesize(GPUIndexBufType type)
MTLStoreAction mtl_store_action_from_gpu(eGPUStoreOp action)
unsigned int uint32_t
Definition: stdint.h:80
struct GPUTexture * tex
union blender::gpu::MTLAttachment::@685 clear_value