[Bf-blender-cvs] [4527dd1ce47] master: Metal: MTLMemoryManager implementation includes functions which manage allocation of MTLBuffer resources.

Jason Fielder noreply at git.blender.org
Fri Jul 1 10:37:04 CEST 2022


Commit: 4527dd1ce4784292cd3b8dd3764b9cd843020f9a
Author: Jason Fielder
Date:   Fri Jul 1 10:30:16 2022 +0200
Branches: master
https://developer.blender.org/rB4527dd1ce4784292cd3b8dd3764b9cd843020f9a

Metal: MTLMemoryManager implementation includes functions which manage allocation of MTLBuffer resources.

The memory manager includes both a GPUContext-local manager which allocates per-context resources such as Circular Scratch Buffers for temporary data such as uniform updates and resource staging, and a GPUContext-global memory manager which features a pooled memory allocator for efficient re-use of resources, to reduce CPU-overhead of frequent memory allocations.

These Memory Managers act as a simple interface for use by other Metal backend modules and to coordinate the lifetime of buffers, to ensure that GPU-resident resources are correctly tracked and freed when no longer in use.

Note: This also contains dependent DIFF changes from D15027, though these will be removed once D15027 lands.

Authored by Apple: Michael Parkin-White

Ref T96261

Reviewed By: fclem

Maniphest Tasks: T96261

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

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

M	source/blender/blenlib/BLI_math_base.h
M	source/blender/blenlib/intern/math_base_inline.c
M	source/blender/draw/engines/eevee/eevee_render.c
M	source/blender/draw/engines/workbench/workbench_render.c
M	source/blender/gpu/CMakeLists.txt
M	source/blender/gpu/intern/gpu_immediate_util.c
M	source/blender/gpu/metal/mtl_backend.mm
M	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_framebuffer.mm
A	source/blender/gpu/metal/mtl_memory.hh
A	source/blender/gpu/metal/mtl_memory.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

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

diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index f072a17f384..c0c4594ddc0 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -221,6 +221,19 @@ MINLINE unsigned int power_of_2_min_u(unsigned int x);
  * with integers, to avoid gradual darkening when rounding down.
  */
 MINLINE int divide_round_i(int a, int b);
+
+/**
+ * Integer division that returns the ceiling, instead of flooring like normal C division.
+ */
+MINLINE uint divide_ceil_u(uint a, uint b);
+MINLINE uint64_t divide_ceil_ul(uint64_t a, uint64_t b);
+
+/**
+ * Returns \a a if it is a multiple of \a b or the next multiple or \a b after \b a .
+ */
+MINLINE uint ceil_to_multiple_u(uint a, uint b);
+MINLINE uint64_t ceil_to_multiple_ul(uint64_t a, uint64_t b);
+
 /**
  * modulo that handles negative numbers, works the same as Python's.
  */
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index cb7659a7059..fb71e84c23e 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -370,6 +370,11 @@ MINLINE uint divide_ceil_u(uint a, uint b)
   return (a + b - 1) / b;
 }
 
+MINLINE uint64_t divide_ceil_ul(uint64_t a, uint64_t b)
+{
+  return (a + b - 1) / b;
+}
+
 /**
  * Returns \a a if it is a multiple of \a b or the next multiple or \a b after \b a .
  */
@@ -378,6 +383,11 @@ MINLINE uint ceil_to_multiple_u(uint a, uint b)
   return divide_ceil_u(a, b) * b;
 }
 
+MINLINE uint64_t ceil_to_multiple_ul(uint64_t a, uint64_t b)
+{
+  return divide_ceil_ul(a, b) * b;
+}
+
 MINLINE int mod_i(int i, int n)
 {
   return (i % n + n) % n;
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index bef19c589c2..82944f237ea 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -24,6 +24,7 @@
 #include "DEG_depsgraph_query.h"
 
 #include "GPU_capabilities.h"
+#include "GPU_context.h"
 #include "GPU_framebuffer.h"
 #include "GPU_state.h"
 
@@ -646,6 +647,10 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
     /* XXX Seems to fix TDR issue with NVidia drivers on linux. */
     GPU_finish();
 
+    /* Perform render step between samples to allow
+     * flushing of freed GPUBackend resources. */
+    GPU_render_step();
+
     RE_engine_update_progress(engine, (float)(render_samples++) / (float)tot_sample);
   }
 }
diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c
index e5dcf6c5624..931f6a2dc92 100644
--- a/source/blender/draw/engines/workbench/workbench_render.c
+++ b/source/blender/draw/engines/workbench/workbench_render.c
@@ -17,6 +17,7 @@
 
 #include "ED_view3d.h"
 
+#include "GPU_context.h"
 #include "GPU_shader.h"
 
 #include "DEG_depsgraph.h"
@@ -188,6 +189,10 @@ void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer
 
   workbench_draw_finish(data);
 
+  /* Perform render step between samples to allow
+   * flushing of freed GPUBackend resources. */
+  GPU_render_step();
+
   /* Write render output. */
   const char *viewname = RE_GetActiveRenderView(engine->re);
   RenderPass *rp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 62d5537772a..9b5ce6e147e 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -194,6 +194,7 @@ set(METAL_SRC
   metal/mtl_command_buffer.mm
   metal/mtl_debug.mm
   metal/mtl_framebuffer.mm
+  metal/mtl_memory.mm
   metal/mtl_state.mm
   metal/mtl_texture.mm
   metal/mtl_texture_util.mm
@@ -204,6 +205,7 @@ set(METAL_SRC
   metal/mtl_context.hh
   metal/mtl_debug.hh
   metal/mtl_framebuffer.hh
+  metal/mtl_memory.hh
   metal/mtl_state.hh
   metal/mtl_texture.hh
 )
diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c
index a275fd8fc6c..5233ff2dbf6 100644
--- a/source/blender/gpu/intern/gpu_immediate_util.c
+++ b/source/blender/gpu/intern/gpu_immediate_util.c
@@ -142,7 +142,7 @@ static void imm_draw_circle(GPUPrimType prim_type,
                             int nsegments)
 {
   if (prim_type == GPU_PRIM_LINE_LOOP) {
-    /* Note(Metal/AMD): For small primitives, line list more efficient than line strip.. */
+    /* NOTE(Metal/AMD): For small primitives, line list more efficient than line strip.. */
     immBegin(GPU_PRIM_LINES, nsegments * 2);
 
     immVertex2f(shdr_pos, x + (radius_x * cosf(0.0f)), y + (radius_y * sinf(0.0f)));
@@ -333,7 +333,7 @@ static void imm_draw_circle_3D(
     GPUPrimType prim_type, uint pos, float x, float y, float radius, int nsegments)
 {
   if (prim_type == GPU_PRIM_LINE_LOOP) {
-    /* Note(Metal/AMD): For small primitives, line list more efficient than line strip. */
+    /* NOTE(Metal/AMD): For small primitives, line list more efficient than line strip. */
     immBegin(GPU_PRIM_LINES, nsegments * 2);
 
     const float angle = (float)(2 * M_PI) / (float)nsegments;
@@ -386,7 +386,7 @@ void imm_draw_circle_fill_3d(uint pos, float x, float y, float radius, int nsegm
 
 void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
 {
-  /* Note(Metal/AMD): For small primitives, line list more efficient than line-strip. */
+  /* NOTE(Metal/AMD): For small primitives, line list more efficient than line-strip. */
   immBegin(GPU_PRIM_LINES, 8);
   immVertex2f(pos, x1, y1);
   immVertex2f(pos, x1, y2);
@@ -405,7 +405,7 @@ void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
 void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2)
 {
   /* use this version when GPUVertFormat has a vec3 position */
-  /* Note(Metal/AMD): For small primitives, line list more efficient than line-strip. */
+  /* NOTE(Metal/AMD): For small primitives, line list more efficient than line-strip. */
   immBegin(GPU_PRIM_LINES, 8);
   immVertex3f(pos, x1, y1, 0.0f);
   immVertex3f(pos, x1, y2, 0.0f);
diff --git a/source/blender/gpu/metal/mtl_backend.mm b/source/blender/gpu/metal/mtl_backend.mm
index 81f8f279759..117b8352a0a 100644
--- a/source/blender/gpu/metal/mtl_backend.mm
+++ b/source/blender/gpu/metal/mtl_backend.mm
@@ -127,7 +127,21 @@ void MTLBackend::render_end()
 
 void MTLBackend::render_step()
 {
-  /* Placeholder */
+  /* NOTE(Metal): Primarily called from main thread, but below datastructures
+   * and operations are thread-safe, and GPUContext rendering coordination
+   * is also thread-safe. */
+
+  /* Flush any MTLSafeFreeLists which have previously been released by any MTLContext. */
+  MTLContext::get_global_memory_manager().update_memory_pools();
+
+  /* End existing MTLSafeFreeList and begin new list --
+   * Buffers wont `free` until all associated in-flight command buffers have completed.
+   * Decrement final reference count for ensuring the previous list is certainly
+   * released. */
+  MTLSafeFreeList *cmd_free_buffer_list =
+      MTLContext::get_global_memory_manager().get_current_safe_list();
+  MTLContext::get_global_memory_manager().begin_new_safe_list();
+  cmd_free_buffer_list->decrement_reference();
 }
 
 bool MTLBackend::is_inside_render_boundary()
diff --git a/source/blender/gpu/metal/mtl_command_buffer.mm b/source/blender/gpu/metal/mtl_command_buffer.mm
index 4f6077e8159..f9edd87a73c 100644
--- a/source/blender/gpu/metal/mtl_command_buffer.mm
+++ b/source/blender/gpu/metal/mtl_command_buffer.mm
@@ -19,7 +19,7 @@ namespace blender::gpu {
  * dependencies not being honored for work submitted between
  * different GPUContext's. */
 id<MTLEvent> MTLCommandBufferManager::sync_event = nil;
-unsigned long long MTLCommandBufferManager::event_signal_val = 0;
+uint64_t MTLCommandBufferManager::event_signal_val = 0;
 
 /* Counter for active command buffers. */
 int MTLCommandBufferManager::num_active_cmd_bufs = 0;
@@ -28,10 +28,9 @@ int MTLCommandBufferManager::num_active_cmd_bufs = 0;
 /** \name MTLCommandBuffer initialization and render coordination.
  * \{ */
 
-void MTLCommandBufferManager::prepare(MTLContext *ctx, bool supports_render)
+void MTLCommandBufferManager::prepare(bool supports_render)
 {
-  context_ = ctx;
-  render_pass_state_.prepare(this, ctx);
+  render_pass_state_.reset_state();
 }
 
 void MTLCommandBufferManager::register_encoder_counters()
@@ -54,10 +53,10 @@ id<MTLCommandBuffer> MTLCommandBufferManager::ensure_begin()
       MTLCommandBufferDescriptor *desc = [[MTLCommandBufferDescriptor alloc] init];
       desc.errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus;
       desc.retainedReferences = YES;
-      active_command_buffer_ = [context_->queue commandBufferWithDescriptor:desc];
+      active_command_buffer_ = [context_.queue commandBufferWithDescriptor:desc];
     }
     else {
-      active_command_buffer_ = [context_->queue commandBuffer];
+      active_command_buffer_ = [context_.queue commandBuffer];
     }
     [active_command_buffer_ retain];
     MTLCommandBufferManager::num_active_cmd_bufs++;
@@ -67,6 +66,10 @@ id<MTLCommandBuffer> MTLCommandBufferManager::ensure_begin()
       [active_command_buffer_ encodeWaitForEvent:this->sync_event value:this->event_signal_val];
     }
 
+    /* Ensure we begin new Scratch Buffer if we are on a new frame. */
+    MTLScratchBufferManager &mem = context_.memory_manager;
+    mem.ensure_increment_scratch_buffer();
+
     /* Reset Command buffer heuristics. */
     this->reset_counters();
   }
@@ -86,12 +89,15 @@ bool MTLCommandBufferManager::submit(bool wait)
   this->end_active_command_encoder();
   BLI_assert(active_command_encoder_type_ == MTL_NO_COMMAND_ENCODER);
 
+  /* Flush active ScratchBuffer associated with parent MTLContext. */
+  context_.memory_manager.flush_active_scratch_buffer();
+
   /*** Submit Command Buffer. ***/
   /* Strict ordering ensures command buffers are guaranteed to execute after a previous
    * one has completed. Resolves flickering when command buffers are submitted from
    * different MTLContex

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list