From f472f93db8f921b46021b8b5bc1be31fa8e34fd9 Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Fri, 2 Jan 2026 00:29:25 -0500 Subject: [PATCH] gpu: D3D12 uploads should also factor in block size for height, not just width. It turns out the reason this function was having so many overread issues was because our row copies were wrong - for compressed images we also need to reduce the row count based on the block size, similar to what we already do for pitch calculation - these copies are byte copies, not pixel copies! --- src/gpu/d3d12/SDL_gpu_d3d12.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c index 4c97daaa3a..a445b06ccd 100644 --- a/src/gpu/d3d12/SDL_gpu_d3d12.c +++ b/src/gpu/d3d12/SDL_gpu_d3d12.c @@ -5922,7 +5922,10 @@ static void D3D12_UploadToTexture( D3D12_TEXTURE_COPY_LOCATION sourceLocation; D3D12_TEXTURE_COPY_LOCATION destinationLocation; Uint32 pixelsPerRow = source->pixels_per_row; + Uint32 blockWidth; + Uint32 blockSize; Uint32 rowPitch; + Uint32 blockHeight; Uint32 alignedRowPitch; Uint32 rowsPerSlice = source->rows_per_layer; Uint32 bytesPerSlice; @@ -5956,15 +5959,18 @@ static void D3D12_UploadToTexture( pixelsPerRow = destination->w; } - rowPitch = BytesPerRow(pixelsPerRow, textureContainer->header.info.format); - if (rowsPerSlice == 0) { rowsPerSlice = destination->h; } + blockWidth = Texture_GetBlockWidth(textureContainer->header.info.format); + blockSize = SDL_GPUTextureFormatTexelBlockSize(textureContainer->header.info.format); + rowPitch = (pixelsPerRow + (blockWidth - 1)) / blockWidth * blockSize; + blockHeight = (rowsPerSlice + (blockWidth - 1)) / blockWidth; + bytesPerSlice = rowsPerSlice * rowPitch; - alignedRowPitch = BytesPerRow(destination->w, textureContainer->header.info.format); + alignedRowPitch = (destination->w + (blockWidth - 1)) / blockWidth * blockSize; alignedRowPitch = D3D12_INTERNAL_Align(alignedRowPitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); needsRealignment = rowsPerSlice != destination->h || rowPitch != alignedRowPitch; needsPlacementCopy = source->offset % D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT != 0; @@ -5983,7 +5989,7 @@ static void D3D12_UploadToTexture( temporaryBuffer = D3D12_INTERNAL_CreateBuffer( d3d12CommandBuffer->renderer, 0, - alignedRowPitch * destination->h * destination->d, + alignedRowPitch * blockHeight * destination->d, D3D12_BUFFER_TYPE_UPLOAD, NULL); @@ -5994,21 +6000,13 @@ static void D3D12_UploadToTexture( sourceLocation.pResource = temporaryBuffer->handle; for (Uint32 sliceIndex = 0; sliceIndex < destination->d; sliceIndex += 1) { - // copy row count minus one to avoid overread - for (Uint32 rowIndex = 0; rowIndex < destination->h - 1; rowIndex += 1) { - + for (Uint32 rowIndex = 0; rowIndex < blockHeight; rowIndex += 1) { SDL_memcpy( temporaryBuffer->mapPointer + (sliceIndex * alignedBytesPerSlice) + (rowIndex * alignedRowPitch), transferBufferContainer->activeBuffer->mapPointer + source->offset + (sliceIndex * bytesPerSlice) + (rowIndex * rowPitch), - alignedRowPitch); + rowPitch); } - Uint32 offset = source->offset + (sliceIndex * bytesPerSlice) + ((destination->h - 1) * rowPitch); - - SDL_memcpy( - temporaryBuffer->mapPointer + (sliceIndex * alignedBytesPerSlice) + ((destination->h - 1) * alignedRowPitch), - transferBufferContainer->activeBuffer->mapPointer + offset, - SDL_min(alignedRowPitch, transferBufferContainer->size - offset)); sourceLocation.PlacedFootprint.Footprint.Width = destination->w; sourceLocation.PlacedFootprint.Footprint.Height = destination->h; @@ -6037,7 +6035,7 @@ static void D3D12_UploadToTexture( temporaryBuffer = D3D12_INTERNAL_CreateBuffer( d3d12CommandBuffer->renderer, 0, - alignedRowPitch * destination->h * destination->d, + alignedRowPitch * blockHeight * destination->d, D3D12_BUFFER_TYPE_UPLOAD, NULL); @@ -6048,7 +6046,7 @@ static void D3D12_UploadToTexture( SDL_memcpy( temporaryBuffer->mapPointer, transferBufferContainer->activeBuffer->mapPointer + source->offset, - alignedRowPitch * destination->h * destination->d); + alignedRowPitch * blockHeight * destination->d); sourceLocation.pResource = temporaryBuffer->handle; sourceLocation.PlacedFootprint.Offset = 0;