Skip to content

Commit 7ea2d4a

Browse files
committed
Handle GL_UNPACK_ROW_LENGTH == 0 in uploadSubTextureAsync
In GL, UNPACK_ROW_LENGTH defaults to 0, which means "rows are tightly packed", i.e. the row stride equals the width of the transferred region. VulkanImage took the 0 literally and used it as an actual stride. With unpackRowLength == 0 the upload size collapsed to 0, so StagingBuffer.copyBuffer staged nothing and left the staging offset unchanged. The srcOffset handed to copyBufferToImageCmd therefore still pointed at whatever previous upload occupied the shared staging buffer, and bufferRowLength was passed as 0, which in Vulkan means "tightly packed to imageExtent.width". The GPU then copied width * height * formatSize bytes of stale staging memory into the target image, filling the texture with unrelated data from earlier uploads. VulkanMod's own callers never hit this because VkCommandEncoder issues _pixelStore(3314, width) before each upload, so a nonzero row length is always supplied. Mods that leave UNPACK_ROW_LENGTH at the GL default are silently corrupted instead. Normalize the row length to width when it is 0, and use the normalized value for the source skip advance and as bufferRowLength. Passing rowLength explicitly is valid since rowLength == width satisfies the bufferRowLength == 0 || >= imageExtent.width rule. Also correct the upload size. (rowLength * height - unpackSkipPixels) mixed a row stride term with a pixel skip term, and because srcPtr has already been advanced past the skip, it over-read the source by up to unpackSkipRows * rowLength * formatSize bytes. The region actually read spans rowLength * (height - 1) + width pixels.
1 parent 7f69043 commit 7ea2d4a

1 file changed

Lines changed: 6 additions & 3 deletions

File tree

src/main/java/net/vulkanmod/vulkan/texture/VulkanImage.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,10 @@ public void uploadSubTextureAsync(int mipLevel, int arrayLayer,
229229
int unpackSkipRows, int unpackSkipPixels, int unpackRowLength,
230230
long srcPtr)
231231
{
232-
long uploadSize = (long) (unpackRowLength * height - unpackSkipPixels) * this.formatSize;
232+
// In GL a row length of 0 means rows are tightly packed, i.e. the row stride is the region width
233+
final int rowLength = unpackRowLength != 0 ? unpackRowLength : width;
234+
235+
long uploadSize = (long) (rowLength * (height - 1) + width) * this.formatSize;
233236

234237
StagingBuffer stagingBuffer = Vulkan.getStagingBuffer();
235238

@@ -240,7 +243,7 @@ public void uploadSubTextureAsync(int mipLevel, int arrayLayer,
240243
stagingBuffer.scheduleFree();
241244
}
242245

243-
srcPtr += ((long) unpackRowLength * unpackSkipRows + unpackSkipPixels) * this.formatSize;
246+
srcPtr += ((long) rowLength * unpackSkipRows + unpackSkipPixels) * this.formatSize;
244247

245248
stagingBuffer.align(this.formatSize);
246249
stagingBuffer.copyBuffer((int) uploadSize, srcPtr);
@@ -255,7 +258,7 @@ public void uploadSubTextureAsync(int mipLevel, int arrayLayer,
255258

256259
ImageUtil.copyBufferToImageCmd(stack, commandBuffer, bufferId, this.id,
257260
arrayLayer, mipLevel, width, height, xOffset, yOffset,
258-
srcOffset, unpackRowLength, height);
261+
srcOffset, rowLength, height);
259262

260263
ImageUtil.imageTransferMemoryBarrier(stack, commandBuffer, this, mipLevel);
261264
}

0 commit comments

Comments
 (0)