Skip to content

Commit

Permalink
[WebGPU] Queue::writeTexture is not implemented correctly for compres…
Browse files Browse the repository at this point in the history
…sed texture formats

https://bugs.webkit.org/show_bug.cgi?id=263546
rdar://117368535

Reviewed by Dan Glastonbury.

webgpu:api,operation,command_buffer,* passes locally after
fixing this bug but the test times out run via WKTR so no
expectations are added.

* Source/WebGPU/WebGPU/Queue.mm:
(WebGPU::Queue::writeTexture):

Canonical link: https://commits.webkit.org/270623@main
  • Loading branch information
mwyrzykowski committed Nov 13, 2023
1 parent 41848d9 commit 53c6f57
Showing 1 changed file with 33 additions and 16 deletions.
49 changes: 33 additions & 16 deletions Source/WebGPU/WebGPU/Queue.mm
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,9 @@ static bool validateWriteTexture(const WGPUImageCopyTexture& destination, const

auto logicalSize = texture.logicalMiplevelSpecificTextureExtent(destination.mipLevel);
auto widthForMetal = std::min(size.width, logicalSize.width);
if (!widthForMetal)
return;

auto heightForMetal = std::min(size.height, logicalSize.height);
auto depthForMetal = std::min(size.depthOrArrayLayers, logicalSize.depthOrArrayLayers);

Expand All @@ -382,14 +385,13 @@ static bool validateWriteTexture(const WGPUImageCopyTexture& destination, const
return;
}

constexpr auto levelInfoRowBlockBytes = 0;
id<MTLTexture> mtlTexture = texture.texture();
auto textureDimension = texture.dimension();
NSUInteger maxRowBytes = textureDimension == WGPUTextureDimension_3D ? (2048 * blockSize) : bytesPerRow;
if (bytesPerRow % blockSize || (bytesPerRow > maxRowBytes)) {
auto blockHeight = Texture::texelBlockHeight(textureFormat);
bool isCompressed = Texture::isCompressedFormat(textureFormat);

bool isCompressed = Texture::isCompressedFormat(textureFormat);
auto blockHeight = Texture::texelBlockHeight(textureFormat);
auto blockWidth = Texture::texelBlockWidth(textureFormat);
if (!isCompressed && (bytesPerRow % blockSize || (bytesPerRow > maxRowBytes))) {
WGPUExtent3D newSize {
.width = size.width,
.height = isCompressed ? blockSize : blockHeight,
Expand All @@ -404,9 +406,6 @@ static bool validateWriteTexture(const WGPUImageCopyTexture& destination, const
.rowsPerImage = newSize.height
};

if (isCompressed)
bytesPerRow = levelInfoRowBlockBytes;

for (uint32_t z = 0, endZ = std::max<uint32_t>(1, depthForMetal); z < endZ; ++z) {
WGPUImageCopyTexture newDestination = destination;
newDestination.origin.z = destination.origin.z + z;
Expand All @@ -424,15 +423,33 @@ static bool validateWriteTexture(const WGPUImageCopyTexture& destination, const
return;
}

if (heightForMetal == 1) {
bytesPerRow = 0;
bytesPerImage = 0;
} else {
bytesPerRow = levelInfoRowBlockBytes;
bytesPerImage = 0;
if (auto add = widthForMetal % blockSize)
widthForMetal = std::min<NSUInteger>(widthForMetal + (blockSize - add), logicalSize.width);
ASSERT(heightForMetal == 1);
bytesPerRow = 0;
bytesPerImage = 0;
}

Vector<uint8_t> newData;
const auto levelInfoRowBlockBytes = blockSize * (widthForMetal / blockWidth);
const auto newBytesPerRow = blockSize * (widthForMetal / blockWidth);
if (isCompressed && levelInfoRowBlockBytes != bytesPerRow && (widthForMetal == logicalSize.width && heightForMetal == logicalSize.height)) {
auto maxY = std::max<size_t>(blockHeight, heightForMetal) / blockHeight;
auto newBytesPerImage = levelInfoRowBlockBytes * std::max<size_t>(blockHeight, logicalSize.height) / blockHeight;
auto maxZ = std::max<size_t>(1, size.depthOrArrayLayers);
newData.resize(newBytesPerImage * maxZ);
memset(&newData[0], 0, newData.size());
for (size_t z = 0; z < maxZ; ++z) {
for (size_t y = 0; y < maxY; ++y) {
auto sourceBytes = static_cast<const uint8_t*>(data) + y * bytesPerRow + z * bytesPerImage;
RELEASE_ASSERT(y * bytesPerRow + z * bytesPerImage + newBytesPerRow <= dataByteSize);
auto destBytes = &newData[0] + y * newBytesPerRow + z * newBytesPerImage;
memcpy(destBytes, sourceBytes, newBytesPerRow);
}
}

bytesPerRow = levelInfoRowBlockBytes;
dataByteSize = newData.size();
bytesPerImage = newBytesPerImage;
data = &newData[0];
}

// FIXME(PERFORMANCE): Instead of checking whether or not the whole queue is idle,
Expand Down

0 comments on commit 53c6f57

Please sign in to comment.