[Bf-blender-cvs] [d3f626b5353] master: Fix T103658: Resolve Metal partial texture update overwriting whole image when staging textures are used.

Jason Fielder noreply at git.blender.org
Sun Jan 8 16:25:46 CET 2023


Commit: d3f626b535313af616b0574958b2d064fc88c5d3
Author: Jason Fielder
Date:   Sun Jan 8 16:16:21 2023 +0100
Branches: master
https://developer.blender.org/rBd3f626b535313af616b0574958b2d064fc88c5d3

Fix T103658: Resolve Metal partial texture update overwriting whole image when staging textures are used.

Staging texture update copied over the entire texture, rather than just the region of the texture which had been updated. Also added early-exit for cases where the net texture update extent was zero, as this was causing validation failures.

Authored by Apple: Michael Parkin-White

Ref T103658
Ref T96261

Reviewed By: fclem

Maniphest Tasks: T103658, T96261

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

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

M	source/blender/gpu/metal/mtl_texture.mm

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

diff --git a/source/blender/gpu/metal/mtl_texture.mm b/source/blender/gpu/metal/mtl_texture.mm
index daf3fb8c36e..043033e6b0e 100644
--- a/source/blender/gpu/metal/mtl_texture.mm
+++ b/source/blender/gpu/metal/mtl_texture.mm
@@ -457,16 +457,14 @@ void gpu::MTLTexture::update_sub(
   if (is_depth_format) {
     switch (type_) {
 
-      case GPU_TEXTURE_2D: {
+      case GPU_TEXTURE_2D:
         update_sub_depth_2d(mip, offset, extent, type, data);
         return;
-      }
       default:
         MTL_LOG_ERROR(
             "[Error] gpu::MTLTexture::update_sub not yet supported for other depth "
             "configurations\n");
         return;
-        return;
     }
   }
 
@@ -488,17 +486,29 @@ void gpu::MTLTexture::update_sub(
         totalsize = input_bytes_per_pixel * max_ii(expected_update_w, 1);
         break;
       case 2:
-        totalsize = input_bytes_per_pixel * max_ii(expected_update_w, 1) * max_ii(extent[1], 1);
+        totalsize = input_bytes_per_pixel * max_ii(expected_update_w, 1) * extent[1];
         break;
       case 3:
-        totalsize = input_bytes_per_pixel * max_ii(expected_update_w, 1) * max_ii(extent[1], 1) *
-                    max_ii(extent[2], 1);
+        totalsize = input_bytes_per_pixel * max_ii(expected_update_w, 1) * extent[1] * extent[2];
         break;
       default:
         BLI_assert(false);
         break;
     }
 
+    /* Early exit if update size is zero. update_sub sometimes has a zero-sized
+     * extent when called from texture painting.  */
+    if (totalsize <= 0 || extent[0] <= 0) {
+      MTL_LOG_WARNING(
+          "MTLTexture::update_sub called with extent size of zero for one or more dimensions. "
+          "(%d, %d, %d) - DimCount: %u\n",
+          extent[0],
+          extent[1],
+          extent[2],
+          this->dimensions_count());
+      return;
+    }
+
     /* When unpack row length is used, provided data does not necessarily contain padding for last
      * row, so we only include up to the end of updated data. */
     if (ctx->pipeline_state.unpack_row_length > 0) {
@@ -942,7 +952,75 @@ void gpu::MTLTexture::update_sub(
       /* When using staging texture, copy results into existing texture. */
       BLI_assert(staging_texture != nil);
       blit_encoder = ctx->main_command_buffer.ensure_begin_blit_encoder();
-      [blit_encoder copyFromTexture:staging_texture toTexture:texture_];
+
+      /* Copy modified staging texture region back to original texture.
+       * Differing blit dimensions based on type. */
+      switch (type_) {
+        case GPU_TEXTURE_1D:
+        case GPU_TEXTURE_1D_ARRAY: {
+          int base_slice = (type_ == GPU_TEXTURE_1D_ARRAY) ? offset[1] : 0;
+          int final_slice = base_slice + ((type_ == GPU_TEXTURE_1D_ARRAY) ? extent[1] : 1);
+          for (int array_index = base_slice; array_index < final_slice; array_index++) {
+            [blit_encoder copyFromTexture:staging_texture
+                              sourceSlice:array_index
+                              sourceLevel:mip
+                             sourceOrigin:MTLOriginMake(offset[0], 0, 0)
+                               sourceSize:MTLSizeMake(extent[0], 1, 1)
+                                toTexture:texture_
+                         destinationSlice:array_index
+                         destinationLevel:mip
+                        destinationOrigin:MTLOriginMake(offset[0], 0, 0)];
+          }
+        } break;
+        case GPU_TEXTURE_2D:
+        case GPU_TEXTURE_2D_ARRAY: {
+          int base_slice = (type_ == GPU_TEXTURE_2D_ARRAY) ? offset[2] : 0;
+          int final_slice = base_slice + ((type_ == GPU_TEXTURE_2D_ARRAY) ? extent[2] : 1);
+          for (int array_index = base_slice; array_index < final_slice; array_index++) {
+            [blit_encoder copyFromTexture:staging_texture
+                              sourceSlice:array_index
+                              sourceLevel:mip
+                             sourceOrigin:MTLOriginMake(offset[0], offset[1], 0)
+                               sourceSize:MTLSizeMake(extent[0], extent[1], 1)
+                                toTexture:texture_
+                         destinationSlice:array_index
+                         destinationLevel:mip
+                        destinationOrigin:MTLOriginMake(offset[0], offset[1], 0)];
+          }
+        } break;
+        case GPU_TEXTURE_3D: {
+          [blit_encoder copyFromTexture:staging_texture
+                            sourceSlice:0
+                            sourceLevel:mip
+                           sourceOrigin:MTLOriginMake(offset[0], offset[1], offset[2])
+                             sourceSize:MTLSizeMake(extent[0], extent[1], extent[2])
+                              toTexture:texture_
+                       destinationSlice:0
+                       destinationLevel:mip
+                      destinationOrigin:MTLOriginMake(offset[0], offset[1], offset[2])];
+        } break;
+        case GPU_TEXTURE_CUBE:
+        case GPU_TEXTURE_CUBE_ARRAY: {
+          /* Iterate over all cube faces in range (offset[2], offset[2] + extent[2]). */
+          for (int i = 0; i < extent[2]; i++) {
+            int face_index = offset[2] + i;
+            [blit_encoder copyFromTexture:staging_texture
+                              sourceSlice:face_index
+                              sourceLevel:mip
+                             sourceOrigin:MTLOriginMake(offset[0], offset[1], 0)
+                               sourceSize:MTLSizeMake(extent[0], extent[1], 1)
+                                toTexture:texture_
+                         destinationSlice:face_index
+                         destinationLevel:mip
+                        destinationOrigin:MTLOriginMake(offset[0], offset[1], 0)];
+          }
+        } break;
+        case GPU_TEXTURE_ARRAY:
+        case GPU_TEXTURE_BUFFER:
+          BLI_assert_unreachable();
+          break;
+      }
+
       [staging_texture release];
     }



More information about the Bf-blender-cvs mailing list