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
This commit is contained in:
Jason Fielder 2023-01-08 16:16:21 +01:00 committed by Clément Foucault
parent ed8f3dc9c7
commit d3f626b535
Notes: blender-bot 2023-05-31 04:43:10 +02:00
Referenced by issue #103658, Metal: Partial texture update failing when using float images.
Referenced by issue #96261, Metal Viewport
1 changed files with 85 additions and 7 deletions

View File

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