[Bf-blender-cvs] [9130a60d3d8] master: MTLCommandBufferState for coordinating GPU workload submission and render pass coordination.

Jason Fielder noreply at git.blender.org
Mon Jun 27 11:46:13 CEST 2022


Commit: 9130a60d3d833718c932d3f971b746ba253734bc
Author: Jason Fielder
Date:   Mon Jun 27 11:41:04 2022 +0200
Branches: master
https://developer.blender.org/rB9130a60d3d833718c932d3f971b746ba253734bc

MTLCommandBufferState for coordinating GPU workload submission and render pass coordination.

MTLFrameBuffer has been implemented to support creation of RenderCommandEncoders, along with supporting functionality in the Metal Context.

Optimisation stubs for GPU_framebuffer_bind_ext has been added, which enables specific assignment of attachment load-store ops at the bind level, rather than on a framebuffer object as a whole.

Begin and end frame markers are used to encapsulate frame boundaries for explicit workload submission. This is required for explicit APIs where implicit flushing of work does not occur.

Ref T96261

Reviewed By: fclem

Maniphest Tasks: T96261

Differential Revision: https://developer.blender.org/D15027

===================================================================

M	source/blender/gpu/CMakeLists.txt
M	source/blender/gpu/GPU_common_types.h
M	source/blender/gpu/GPU_context.h
M	source/blender/gpu/GPU_framebuffer.h
M	source/blender/gpu/intern/gpu_context.cc
M	source/blender/gpu/intern/gpu_context_private.hh
M	source/blender/gpu/intern/gpu_framebuffer.cc
M	source/blender/gpu/intern/gpu_framebuffer_private.hh
M	source/blender/gpu/metal/mtl_backend.hh
M	source/blender/gpu/metal/mtl_backend.mm
M	source/blender/gpu/metal/mtl_capabilities.hh
A	source/blender/gpu/metal/mtl_command_buffer.mm
M	source/blender/gpu/metal/mtl_common.hh
M	source/blender/gpu/metal/mtl_context.hh
M	source/blender/gpu/metal/mtl_context.mm
M	source/blender/gpu/metal/mtl_debug.mm
A	source/blender/gpu/metal/mtl_framebuffer.hh
A	source/blender/gpu/metal/mtl_framebuffer.mm
M	source/blender/gpu/metal/mtl_state.hh
M	source/blender/gpu/metal/mtl_state.mm
M	source/blender/gpu/metal/mtl_texture.hh
M	source/blender/gpu/metal/mtl_texture.mm
M	source/blender/gpu/metal/mtl_texture_util.mm
M	source/blender/gpu/opengl/gl_context.cc
M	source/blender/gpu/opengl/gl_context.hh
M	source/blender/gpu/opengl/gl_framebuffer.hh
M	source/blender/windowmanager/intern/wm_draw.c
M	source/blender/windowmanager/intern/wm_init_exit.c

===================================================================

diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index cadc2c4445b..d8ed74390f4 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -188,7 +188,9 @@ set(OPENGL_SRC
 set(METAL_SRC
   metal/mtl_backend.mm
   metal/mtl_context.mm
+  metal/mtl_command_buffer.mm
   metal/mtl_debug.mm
+  metal/mtl_framebuffer.mm
   metal/mtl_state.mm
   metal/mtl_texture.mm
   metal/mtl_texture_util.mm
@@ -198,6 +200,7 @@ set(METAL_SRC
   metal/mtl_common.hh
   metal/mtl_context.hh
   metal/mtl_debug.hh
+  metal/mtl_framebuffer.hh
   metal/mtl_state.hh
   metal/mtl_texture.hh
 )
diff --git a/source/blender/gpu/GPU_common_types.h b/source/blender/gpu/GPU_common_types.h
index 8c91d60812f..5913caf72e3 100644
--- a/source/blender/gpu/GPU_common_types.h
+++ b/source/blender/gpu/GPU_common_types.h
@@ -8,6 +8,14 @@
 extern "C" {
 #endif
 
+typedef enum eGPULoadOp {
+  GPU_LOADACTION_CLEAR = 0,
+  GPU_LOADACTION_LOAD,
+  GPU_LOADACTION_DONT_CARE
+} eGPULoadOp;
+
+typedef enum eGPUStoreOp { GPU_STOREACTION_STORE = 0, GPU_STOREACTION_DONT_CARE } eGPUStoreOp;
+
 typedef enum eGPUFrontFace {
   GPU_CLOCKWISE,
   GPU_COUNTERCLOCKWISE,
diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h
index f3b7f8c29bf..1fcd94c48fc 100644
--- a/source/blender/gpu/GPU_context.h
+++ b/source/blender/gpu/GPU_context.h
@@ -38,6 +38,13 @@ void GPU_context_discard(GPUContext *);
 void GPU_context_active_set(GPUContext *);
 GPUContext *GPU_context_active_get(void);
 
+/* Begin and end frame are used to mark the singular boundary representing the lifetime of a whole
+ * frame. This also acts as a divisor for ensuring workload submission and flushing, especially for
+ * background rendering when there is no call to present.
+ * This is required by explicit-API's where there is no implicit workload flushing. */
+void GPU_context_begin_frame(GPUContext *ctx);
+void GPU_context_end_frame(GPUContext *ctx);
+
 /* Legacy GPU (Intel HD4000 series) do not support sharing GPU objects between GPU
  * contexts. EEVEE/Workbench can create different contexts for image/preview rendering, baking or
  * compiling. When a legacy GPU is detected (`GPU_use_main_context_workaround()`) any worker
diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h
index 4436f7a5a7b..6eb51c200f1 100644
--- a/source/blender/gpu/GPU_framebuffer.h
+++ b/source/blender/gpu/GPU_framebuffer.h
@@ -14,6 +14,7 @@
 
 #pragma once
 
+#include "GPU_common_types.h"
 #include "GPU_texture.h"
 
 typedef enum eGPUFrameBufferBits {
@@ -52,6 +53,44 @@ void GPU_framebuffer_bind(GPUFrameBuffer *fb);
 void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *fb);
 void GPU_framebuffer_restore(void);
 
+/* Advanced binding control. */
+typedef struct GPULoadStore {
+  eGPULoadOp load_action;
+  eGPUStoreOp store_action;
+} GPULoadStore;
+#define NULL_LOAD_STORE \
+  { \
+    GPU_LOADACTION_DONT_CARE, GPU_STOREACTION_DONT_CARE \
+  }
+
+/* Load store config array (load_store_actions) matches attachment structure of
+ * GPU_framebuffer_config_array. This allows us to explicitly specify whether attachment data needs
+ * to be loaded and stored on a per-attachment basis. This enables a number of bandwidth
+ * optimisations:
+ *  - No need to load contents if subsequent work is over-writing every pixel.
+ *  - No need to store attachments whose contents are not used beyond this pass e.g. depth buffer.
+ *  - State can be customised at bind-time rather than applying to the framebuffer object as a
+ * whole.
+ *
+ * Example:
+ * \code{.c}
+ * GPU_framebuffer_bind_loadstore(&fb, {
+ *         {GPU_LOADACTION_LOAD, GPU_STOREACTION_DONT_CARE} // must be depth buffer
+ *         {GPU_LOADACTION_LOAD, GPU_STOREACTION_STORE}, // Colour attachment 0
+ *         {GPU_LOADACTION_DONT_CARE, GPU_STOREACTION_STORE}, // Colour attachment 1
+ *         {GPU_LOADACTION_DONT_CARE, GPU_STOREACTION_STORE} // Colour attachment 2
+ * })
+ * \encode
+ */
+void GPU_framebuffer_bind_loadstore(GPUFrameBuffer *fb,
+                                    const GPULoadStore *load_store_actions,
+                                    uint actions_len);
+#define GPU_framebuffer_bind_ex(_fb, ...) \
+  { \
+    GPULoadStore actions[] = __VA_ARGS__; \
+    GPU_framebuffer_bind_loadstore(_fb, actions, (sizeof(actions) / sizeof(GPULoadStore))); \
+  }
+
 bool GPU_framebuffer_bound(GPUFrameBuffer *fb);
 bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]);
 
diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc
index 9fb5826506a..4a0a9ecc7f6 100644
--- a/source/blender/gpu/intern/gpu_context.cc
+++ b/source/blender/gpu/intern/gpu_context.cc
@@ -123,6 +123,22 @@ GPUContext *GPU_context_active_get()
   return wrap(Context::get());
 }
 
+void GPU_context_begin_frame(GPUContext *ctx)
+{
+  blender::gpu::Context *_ctx = unwrap(ctx);
+  if (_ctx) {
+    _ctx->begin_frame();
+  }
+}
+
+void GPU_context_end_frame(GPUContext *ctx)
+{
+  blender::gpu::Context *_ctx = unwrap(ctx);
+  if (_ctx) {
+    _ctx->end_frame();
+  }
+}
+
 /* -------------------------------------------------------------------- */
 /** \name Main context global mutex
  *
diff --git a/source/blender/gpu/intern/gpu_context_private.hh b/source/blender/gpu/intern/gpu_context_private.hh
index af9791fde88..9cdf0075632 100644
--- a/source/blender/gpu/intern/gpu_context_private.hh
+++ b/source/blender/gpu/intern/gpu_context_private.hh
@@ -63,6 +63,8 @@ class Context {
 
   virtual void activate() = 0;
   virtual void deactivate() = 0;
+  virtual void begin_frame() = 0;
+  virtual void end_frame() = 0;
 
   /* Will push all pending commands to the GPU. */
   virtual void flush() = 0;
diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc
index 08d761106e5..f12d8fd7e55 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.cc
+++ b/source/blender/gpu/intern/gpu_framebuffer.cc
@@ -124,6 +124,43 @@ void FrameBuffer::attachment_remove(GPUAttachmentType type)
   dirty_attachments_ = true;
 }
 
+void FrameBuffer::load_store_config_array(const GPULoadStore *load_store_actions, uint actions_len)
+{
+  /* Follows attachment structure of GPU_framebuffer_config_array/GPU_framebuffer_ensure_config */
+  const GPULoadStore &depth_action = load_store_actions[0];
+  Span<GPULoadStore> color_attachments(load_store_actions + 1, actions_len - 1);
+
+  if (this->attachments_[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex) {
+    this->attachment_set_loadstore_op(
+        GPU_FB_DEPTH_STENCIL_ATTACHMENT, depth_action.load_action, depth_action.store_action);
+  }
+  if (this->attachments_[GPU_FB_DEPTH_ATTACHMENT].tex) {
+    this->attachment_set_loadstore_op(
+        GPU_FB_DEPTH_ATTACHMENT, depth_action.load_action, depth_action.store_action);
+  }
+
+  GPUAttachmentType type = GPU_FB_COLOR_ATTACHMENT0;
+  for (const GPULoadStore &actions : color_attachments) {
+    if (this->attachments_[type].tex) {
+      this->attachment_set_loadstore_op(type, actions.load_action, actions.store_action);
+    }
+    ++type;
+  }
+}
+
+unsigned int FrameBuffer::get_bits_per_pixel(void)
+{
+  unsigned int total_bits = 0;
+  for (GPUAttachment &attachment : attachments_) {
+    Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
+    if (tex != nullptr) {
+      int bits = to_bytesize(tex->format_get()) * to_component_len(tex->format_get());
+      total_bits += bits;
+    }
+  }
+  return total_bits;
+}
+
 void FrameBuffer::recursive_downsample(int max_lvl,
                                        void (*callback)(void *userData, int level),
                                        void *userData)
@@ -149,10 +186,21 @@ void FrameBuffer::recursive_downsample(int max_lvl,
         attachment.mip = mip_lvl;
       }
     }
+
     /* Update the internal attachments and viewport size. */
     dirty_attachments_ = true;
     this->bind(true);
 
+    /* Optimise load-store state. */
+    GPUAttachmentType type = GPU_FB_DEPTH_ATTACHMENT;
+    for (GPUAttachment &attachment : attachments_) {
+      Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
+      if (tex != nullptr) {
+        this->attachment_set_loadstore_op(type, GPU_LOADACTION_DONT_CARE, GPU_STOREACTION_STORE);
+      }
+      ++type;
+    }
+
     callback(userData, mip_lvl);
   }
 
@@ -198,6 +246,18 @@ void GPU_framebuffer_bind(GPUFrameBuffer *gpu_fb)
   unwrap(gpu_fb)->bind(enable_srgb);
 }
 
+void GPU_framebuffer_bind_loadstore(GPUFrameBuffer *gpu_fb,
+                                    const GPULoadStore *load_store_actions,
+                                    uint actions_len)
+{
+  /* Bind */
+  GPU_framebuffer_bind(gpu_fb);
+
+  /* Update load store */
+  FrameBuffer *fb = unwrap(gpu_fb);
+  fb->load_store_config_array(load_store_actions, actions_len);
+}
+
 void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *gpu_fb)
 {
   const bool enable_srgb = false;
diff --git a/source/blender/gpu/intern/gpu_framebuffer_private.hh b/source/blender/gpu/intern/gpu_framebuffer_private.hh
index d218662d17f..8cecc6b8b15 100644
--- a/source/blender/gpu/intern/gpu_framebuffer_private.hh
+++ b/source/blender/gpu/intern/gpu_framebuffer_private.hh
@@ -114,6 +114,10 @@ class FrameBuffer {
                                 eGPUDataFormat data_format,
                                 const void *clear_value) = 0;
 
+  virtual void attachment_set_loadstore_op(GPUAttachmentType type,
+                                           eGPULoadOp load_action,
+                                           eGPUStoreOp store_action) = 0;
+
   virtual void read(eGPUFrameBufferBits planes,
                     eGPUDataFormat format,
                     const int area[4],
@@ -128,12 +132,15 @@ class FrameBuffer {
                        int dst_offset_x,
                        int dst_offset_y) = 0;
 
+  void load_store_config_array(const GPULoadStore *load_store_actions, uint actions_len);
+
   void attachment_set(GPUAttachmentType type, const GPUAttachment &new_attachment);
   void attachment_remove(GPUAttachmentType type);
 
   void recursive_downsample(int max_lvl,
                             void (*callback)(void *userData

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list