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];
     }

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
List details, subscription details or unsubscribe:
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to