[Bf-blender-cvs] [df1fe18ed75] master: Metal: Fix GPencil texture buffer attribute packing issue and cutting tool rendering.

Jason Fielder noreply at git.blender.org
Tue Dec 20 14:09:15 CET 2022


Commit: df1fe18ed75812265cf2af186f6b082d8d27d9fe
Author: Jason Fielder
Date:   Tue Dec 20 14:08:37 2022 +0100
Branches: master
https://developer.blender.org/rBdf1fe18ed75812265cf2af186f6b082d8d27d9fe

Metal: Fix GPencil texture buffer attribute packing issue and cutting tool rendering.

Line Loop topology support for cutting tool and add support for packing several vertex attributes across individual pixels within a texture buffer.

Authored by Apple: Michael Parkin-White

Ref T96261

Reviewed By: fclem

Maniphest Tasks: T96261

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

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

M	source/blender/gpu/metal/mtl_immediate.mm
M	source/blender/gpu/metal/mtl_primitive.hh
M	source/blender/gpu/metal/mtl_texture.mm

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

diff --git a/source/blender/gpu/metal/mtl_immediate.mm b/source/blender/gpu/metal/mtl_immediate.mm
index 7af5ca30578..f0809e6e9d3 100644
--- a/source/blender/gpu/metal/mtl_immediate.mm
+++ b/source/blender/gpu/metal/mtl_immediate.mm
@@ -39,8 +39,16 @@ uchar *MTLImmediate::begin()
   metal_primitive_mode_ = mtl_prim_type_to_topology_class(metal_primitive_type_);
   has_begun_ = true;
 
+  /* If prim type is line loop, add an extra vertex at the end for placing the closing line,
+   * as metal does not support this primitive type. We treat this as a Line strip with one
+   * extra value. */
+  int vertex_alloc_length = vertex_len;
+  if (prim_type == GPU_PRIM_LINE_LOOP) {
+    vertex_alloc_length++;
+  }
+
   /* Allocate a range of data and return host-accessible pointer. */
-  const size_t bytes_needed = vertex_buffer_size(&vertex_format, vertex_len);
+  const size_t bytes_needed = vertex_buffer_size(&vertex_format, vertex_alloc_length);
   current_allocation_ = context_->get_scratchbuffer_manager()
                             .scratch_buffer_allocate_range_aligned(bytes_needed, 256);
   [current_allocation_.metal_buffer retain];
@@ -266,71 +274,88 @@ void MTLImmediate::end()
        * For immediate mode, generating these is currently very cheap, as we use
        * fast scratch buffer allocations. Though we may benefit from caching of
        * frequently used buffer sizes. */
+      bool rendered = false;
       if (mtl_needs_topology_emulation(this->prim_type)) {
 
-        /* Debug safety check for SSBO FETCH MODE. */
-        if (active_mtl_shader->get_uses_ssbo_vertex_fetch()) {
-          BLI_assert(false && "Topology emulation not supported with SSBO Vertex Fetch mode");
-        }
-
         /* Emulate Tri-fan. */
-        if (this->prim_type == GPU_PRIM_TRI_FAN) {
-          /* Prepare Triangle-Fan emulation index buffer on CPU based on number of input
-           * vertices. */
-          uint32_t base_vert_count = this->vertex_idx;
-          uint32_t num_triangles = max_ii(base_vert_count - 2, 0);
-          uint32_t fan_index_count = num_triangles * 3;
-          BLI_assert(num_triangles > 0);
-
-          uint32_t alloc_size = sizeof(uint32_t) * fan_index_count;
-          uint32_t *index_buffer = nullptr;
-
-          MTLTemporaryBuffer allocation =
-              context_->get_scratchbuffer_manager().scratch_buffer_allocate_range_aligned(
-                  alloc_size, 128);
-          index_buffer = (uint32_t *)allocation.data;
-
-          int a = 0;
-          for (int i = 0; i < num_triangles; i++) {
-            index_buffer[a++] = 0;
-            index_buffer[a++] = i + 1;
-            index_buffer[a++] = i + 2;
-          }
+        switch (this->prim_type) {
+          case GPU_PRIM_TRI_FAN: {
+            /* Debug safety check for SSBO FETCH MODE. */
+            if (active_mtl_shader->get_uses_ssbo_vertex_fetch()) {
+              BLI_assert(
+                  false &&
+                  "Topology emulation for TriangleFan not supported with SSBO Vertex Fetch mode");
+            }
 
-          @autoreleasepool {
+            /* Prepare Triangle-Fan emulation index buffer on CPU based on number of input
+             * vertices. */
+            uint32_t base_vert_count = this->vertex_idx;
+            uint32_t num_triangles = max_ii(base_vert_count - 2, 0);
+            uint32_t fan_index_count = num_triangles * 3;
+            BLI_assert(num_triangles > 0);
+
+            uint32_t alloc_size = sizeof(uint32_t) * fan_index_count;
+            uint32_t *index_buffer = nullptr;
+
+            MTLTemporaryBuffer allocation =
+                context_->get_scratchbuffer_manager().scratch_buffer_allocate_range_aligned(
+                    alloc_size, 128);
+            index_buffer = (uint32_t *)allocation.data;
+
+            int a = 0;
+            for (int i = 0; i < num_triangles; i++) {
+              index_buffer[a++] = 0;
+              index_buffer[a++] = i + 1;
+              index_buffer[a++] = i + 2;
+            }
 
-            id<MTLBuffer> index_buffer_mtl = nil;
-            uint32_t index_buffer_offset = 0;
+            @autoreleasepool {
 
-            /* Region of scratch buffer used for topology emulation element data.
-             * NOTE(Metal): We do not need to manually flush as the entire scratch
-             * buffer for current command buffer is flushed upon submission. */
-            index_buffer_mtl = allocation.metal_buffer;
-            index_buffer_offset = allocation.buffer_offset;
+              id<MTLBuffer> index_buffer_mtl = nil;
+              uint32_t index_buffer_offset = 0;
 
-            /* Set depth stencil state (requires knowledge of primitive type). */
-            context_->ensure_depth_stencil_state(MTLPrimitiveTypeTriangle);
+              /* Region of scratch buffer used for topology emulation element data.
+               * NOTE(Metal): We do not need to manually flush as the entire scratch
+               * buffer for current command buffer is flushed upon submission. */
+              index_buffer_mtl = allocation.metal_buffer;
+              index_buffer_offset = allocation.buffer_offset;
 
-            /* Bind Vertex Buffer. */
-            rps.bind_vertex_buffer(
-                current_allocation_.metal_buffer, current_allocation_.buffer_offset, 0);
+              /* Set depth stencil state (requires knowledge of primitive type). */
+              context_->ensure_depth_stencil_state(MTLPrimitiveTypeTriangle);
 
-            /* Draw. */
-            [rec drawIndexedPrimitives:MTLPrimitiveTypeTriangle
-                            indexCount:fan_index_count
-                             indexType:MTLIndexTypeUInt32
-                           indexBuffer:index_buffer_mtl
-                     indexBufferOffset:index_buffer_offset];
-          }
-        }
-        else {
-          /* TODO(Metal): Topology emulation for line loop.
-           * NOTE(Metal): This is currently not used anywhere and modified at the high
-           * level for efficiency in such cases. */
-          BLI_assert_msg(false, "LineLoop requires emulation support in immediate mode.");
+              /* Bind Vertex Buffer. */
+              rps.bind_vertex_buffer(
+                  current_allocation_.metal_buffer, current_allocation_.buffer_offset, 0);
+
+              /* Draw. */
+              [rec drawIndexedPrimitives:MTLPrimitiveTypeTriangle
+                              indexCount:fan_index_count
+                               indexType:MTLIndexTypeUInt32
+                             indexBuffer:index_buffer_mtl
+                       indexBufferOffset:index_buffer_offset];
+              context_->main_command_buffer.register_draw_counters(fan_index_count);
+            }
+            rendered = true;
+          } break;
+          case GPU_PRIM_LINE_LOOP: {
+            /* Patch final vertex of line loop to close. Rendered using LineStrip.
+             * Note: vertex_len represents original length, however, allocated Metal
+             * buffer contains space for one extra vertex when LineLoop is used. */
+            uchar *buffer_data = reinterpret_cast<uchar *>(current_allocation_.data);
+            memcpy(buffer_data + (vertex_len)*vertex_format.stride,
+                   buffer_data,
+                   vertex_format.stride);
+            this->vertex_idx++;
+          } break;
+          default: {
+            BLI_assert_unreachable();
+          } break;
         }
       }
-      else {
+
+      /* If not yet rendered, run through main render path. LineLoop primitive topology emulation
+       * will simply amend original data passed into default rendering path. */
+      if (!rendered) {
         MTLPrimitiveType primitive_type = metal_primitive_type_;
         int vertex_count = this->vertex_idx;
 
diff --git a/source/blender/gpu/metal/mtl_primitive.hh b/source/blender/gpu/metal/mtl_primitive.hh
index b32854a04bf..0b66a51d630 100644
--- a/source/blender/gpu/metal/mtl_primitive.hh
+++ b/source/blender/gpu/metal/mtl_primitive.hh
@@ -39,10 +39,10 @@ static inline MTLPrimitiveType gpu_prim_type_to_metal(GPUPrimType prim_type)
       return MTLPrimitiveTypePoint;
     case GPU_PRIM_LINES:
     case GPU_PRIM_LINES_ADJ:
-    case GPU_PRIM_LINE_LOOP:
       return MTLPrimitiveTypeLine;
     case GPU_PRIM_LINE_STRIP:
     case GPU_PRIM_LINE_STRIP_ADJ:
+    case GPU_PRIM_LINE_LOOP:
       return MTLPrimitiveTypeLineStrip;
     case GPU_PRIM_TRIS:
     case GPU_PRIM_TRI_FAN:
diff --git a/source/blender/gpu/metal/mtl_texture.mm b/source/blender/gpu/metal/mtl_texture.mm
index 411d1187610..d2d466bffe1 100644
--- a/source/blender/gpu/metal/mtl_texture.mm
+++ b/source/blender/gpu/metal/mtl_texture.mm
@@ -1621,6 +1621,7 @@ bool gpu::MTLTexture::init_internal(GPUVertBuf *vbo)
   }
 
   /* Verify Texture and vertex buffer alignment. */
+  const GPUVertFormat *format = GPU_vertbuf_get_format(vbo);
   int bytes_per_pixel = get_mtl_format_bytesize(mtl_format);
   int bytes_per_row = bytes_per_pixel * w_;
 
@@ -1628,12 +1629,40 @@ bool gpu::MTLTexture::init_internal(GPUVertBuf *vbo)
   uint32_t align_requirement = static_cast<uint32_t>(
       [mtl_ctx->device minimumLinearTextureAlignmentForPixelFormat:mtl_format]);
 
-  /* Verify per-vertex size aligns with texture size. */
-  const GPUVertFormat *format = GPU_vertbuf_get_format(vbo);
-  BLI_assert(bytes_per_pixel == format->stride &&
-             "Pixel format stride MUST match the texture format stride -- These being different "
-             "is likely caused by Metal's VBO padding to a minimum of 4-bytes per-vertex");
-  UNUSED_VARS_NDEBUG(format);
+  /* If stride is larger than bytes per pixel, but format has multiple attributes,
+   * split attributes across several pixels. */
+  if (format->stride > bytes_per_pixel && format->attr_len > 1) {
+
+    /* We need to increase the number of pixels available to store additional attributes.
+     * First ensure that the total stride of the vertex format fits uniformly into
+     * multiple pixels. If these sizes are different, then attributes are of differing
+     * sizes and this operation is unsupported. */
+    if (bytes_per_pixel * format->attr_len != format->stride) {
+      B

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list