v3dv: relax buffer padding in TFU buffer<->image copy

Adjust eligibility check on imageExtent vs slice dimensions
rather than on the buffer addressing dimensions. The TFU codepath
here always writes/reads the full slice from its origin, so the
required invariant is 'imageExtent == slice'; bufferRowLength and
bufferImageHeight may be larger than imageExtent (the spec permits
this for non-zero values), in which case the TFU reads/writes at the
buffer's row/layer stride but only touches slice->width pixels per
row and slice->height rows per layer, leaving the trailing padding
untouched.

The previous combined check (width == slice->width && height ==
slice->height applied to the buffer dimensions) would reject any
caller that set bufferRowLength or bufferImageHeight larger than the
image (this is common for buffers shared across mip levels or
for alignment requirements like Dawn aligning bufferRowLength to 2
for 1-pixel-wide textures), forcing those copies through the slower
TLB / blit / compute paths.

For compressed formats, keep the strict equality check since
block-level stride semantics are more complex.

Assisted-by: Claude Opus 4.7
Reviewed-by: Iago Toral Quiroga <itoral@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41725>
This commit is contained in:
Jose Maria Casanova Crespo 2026-05-22 10:39:22 +02:00 committed by Marge Bot
parent 99bce54daa
commit 2a62490fa7

View file

@ -1981,16 +1981,30 @@ copy_buffer_image_tfu(struct v3dv_cmd_buffer *cmd_buffer,
const uint32_t mip_level = region->imageSubresource.mipLevel;
const struct v3d_resource_slice *slice = &image->planes[plane].slices[mip_level];
if (width != slice->width || height != slice->height)
return false;
/* Handle region semantics for compressed images */
const uint32_t block_w =
vk_format_get_blockwidth(image->planes[plane].vk_format);
const uint32_t block_h =
vk_format_get_blockheight(image->planes[plane].vk_format);
/* The TFU writes/reads the full slice from its origin, so the copy
* region must span it. The buffer side may have trailing row/height
* padding (bufferRowLength, bufferImageHeight) that the TFU never
* touches. For compressed formats, require tight packing since
* block-level stride semantics are more complex.
*/
if (region->imageExtent.width != slice->width ||
region->imageExtent.height != slice->height) {
return false;
}
const bool is_compressed = block_w > 1 || block_h > 1;
if (is_compressed && (width != slice->width || height != slice->height))
return false;
width = DIV_ROUND_UP(width, block_w);
height = DIV_ROUND_UP(height, block_h);
const uint32_t tfu_height = is_compressed ? height : slice->height;
/* Format must be supported for texturing via the TFU. Since we are just
* copying raw data and not converting between pixel formats, we can ignore
@ -2032,6 +2046,8 @@ copy_buffer_image_tfu(struct v3dv_cmd_buffer *cmd_buffer,
buffer->mem_offset + region->bufferOffset +
height * buffer_stride * i;
const uint32_t tfu_width = is_compressed ? width : slice->width;
if (to_buffer) {
v3d_X((&cmd_buffer->device->devinfo), meta_emit_tfu_job)(
cmd_buffer,
@ -2039,7 +2055,7 @@ copy_buffer_image_tfu(struct v3dv_cmd_buffer *cmd_buffer,
V3D_TILING_RASTER, width, 1,
image_bo->handle, image_offset,
slice->tiling, tfu_slice_stride_arg(slice), cpp,
width, height, format_plane);
tfu_width, tfu_height, format_plane);
} else {
v3d_X((&cmd_buffer->device->devinfo), meta_emit_tfu_job)(
cmd_buffer,
@ -2047,7 +2063,7 @@ copy_buffer_image_tfu(struct v3dv_cmd_buffer *cmd_buffer,
slice->tiling, tfu_slice_stride_arg(slice), cpp,
buffer_bo->handle, buffer_offset,
V3D_TILING_RASTER, width, 1,
width, height, format_plane);
tfu_width, tfu_height, format_plane);
}
}