Repository: google/filament
File: filament/backend/src/webgpu/WebGPUDriver.cpp (C++)

Code before:
    // Clamp read region to texture bounds
    if (x >= srcWidth || y >= srcHeight) {
        scheduleDestroy(std::move(pixelBufferDescriptor));
        return;
    }
    auto actualWidth = std::min(width, srcWidth - x);
    auto actualHeight = std::min(height, srcHeight - y);
    if (actualWidth == 0 || actualHeight == 0) {
        scheduleDestroy(std::move(pixelBufferDescriptor));
        return;
    }
    const size_t dstBytesPerPixel = PixelBufferDescriptor::computePixelSize(
            pixelBufferDescriptor.format, pixelBufferDescriptor.type);
    const size_t srcBytesPerPixel =
            WebGPUTexture::getWGPUTextureFormatPixelSize(srcTexture.GetFormat());

    FILAMENT_CHECK_PRECONDITION(dstBytesPerPixel == srcBytesPerPixel && dstBytesPerPixel > 0)
            << "Source texture pixel size (" << srcBytesPerPixel
            << ") does not match destination pixel buffer pixel size (" << dstBytesPerPixel
            << "), or the format is not supported for readPixels.";

    // Create a staging buffer to copy the texture to. WebGPU requires 256 byte alignment
    const size_t bytesPerPixel = dstBytesPerPixel;
    const size_t unpaddedBytesPerRow = actualWidth * bytesPerPixel;
    const size_t alignment = 256;
    const size_t paddedBytesPerRow = (unpaddedBytesPerRow + alignment - 1) & ~(alignment - 1);

    size_t bufferSize = paddedBytesPerRow * height;
    wgpu::BufferDescriptor bufferDesc;
    bufferDesc.size = bufferSize;
    bufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::MapRead;
    wgpu::Buffer stagingBuffer = mDevice.CreateBuffer(&bufferDesc);
    assert_invariant(stagingBuffer);

    wgpu::CommandEncoder encoder = mDevice.CreateCommandEncoder();
    assert_invariant(encoder);

    // WebGPU flips the y axis like Metal does
    const uint32_t flippedY = srcHeight - y - height;
    wgpu::TexelCopyTextureInfo source{ .texture = srcTexture,
        .mipLevel = 0,
        .origin = { x, flippedY, 0 } };
    wgpu::TexelCopyBufferInfo destination {
        .layout = {
            .offset = 0,
            .bytesPerRow = static_cast<uint32_t>(paddedBytesPerRow),
            .rowsPerImage = actualHeight,
        },
        .buffer = stagingBuffer
    };
    wgpu::Extent3D copySize{ .width = actualWidth,

Review comment (suggestion):
Prob the same result but isnt this the same as using 
`PixelBufferDescriptor::computeDataSize()` https://github.com/google/filament/blob/main/filament/backend/src/metal/MetalHandles.mm#L761

Edit: 
Actually nvm

Code after:
    // Clamp read region to texture bounds
    if (x >= srcWidth || y >= srcHeight) {
        scheduleDestroy(std::move(pixelBufferDescriptor));
        return;
    }
    auto actualWidth = std::min(width, srcWidth - x);
    auto actualHeight = std::min(height, srcHeight - y);
    if (actualWidth == 0 || actualHeight == 0) {
        scheduleDestroy(std::move(pixelBufferDescriptor));
        return;
    }
    const size_t dstBytesPerPixel = PixelBufferDescriptor::computePixelSize(
            pixelBufferDescriptor.format, pixelBufferDescriptor.type);
    const size_t srcBytesPerPixel =
            WebGPUTexture::getWGPUTextureFormatPixelSize(srcTexture.GetFormat());

    FILAMENT_CHECK_PRECONDITION(dstBytesPerPixel == srcBytesPerPixel && dstBytesPerPixel > 0)
            << "Source texture pixel size (" << srcBytesPerPixel
            << ") does not match destination pixel buffer pixel size (" << dstBytesPerPixel
            << "), or the format is not supported for readPixels.";

    // Create a staging buffer to copy the texture to. WebGPU requires 256 byte alignment
    const size_t bytesPerPixel = dstBytesPerPixel;
    const size_t unpaddedBytesPerRow = actualWidth * bytesPerPixel;
    const size_t alignment = 256;
    const size_t paddedBytesPerRow = (unpaddedBytesPerRow + alignment - 1) & ~(alignment - 1);

    size_t bufferSize = paddedBytesPerRow * height;
    wgpu::BufferDescriptor bufferDesc;
    bufferDesc.size = bufferSize;
    bufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::MapRead;
    wgpu::Buffer stagingBuffer = mDevice.CreateBuffer(&bufferDesc);
    assert_invariant(stagingBuffer);

    wgpu::CommandEncoder encoder = mDevice.CreateCommandEncoder();
    assert_invariant(encoder);

    // WebGPU flips the y axis like Metal does
    const uint32_t flippedY = srcHeight - y - height;
    wgpu::TexelCopyTextureInfo source{
        .texture = srcTexture,
        .mipLevel = 0,
        .origin = { .x = x, .y = flippedY, .z = 0 },
    };
    wgpu::TexelCopyBufferInfo destination {
        .layout = {
            .offset = 0,
            .bytesPerRow = static_cast<uint32_t>(paddedBytesPerRow),
            .rowsPerImage = actualHeight,
        },
        .buffer = stagingBuffer