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

Code before:
    }
    auto texture = handleCast<WGPUTexture>(th);

    // TODO: Writing to a depth texture is illegal and errors. I'm not sure why Filament is trying
    // to do so, but early returning is working?
    if(texture->getAspect() == wgpu::TextureAspect::DepthOnly){
        scheduleDestroy(std::move(p));
        return;
    }
    size_t blockWidth = texture->getBlockWidth();
    size_t blockHeight = texture->getBlockHeight();
    // WebGPU specification requires that for compressed textures, the x and y offsets
    // must be a multiple of the compressed texture format's block width and height.
    // See: https://www.w3.org/TR/webgpu/#abstract-opdef-validating-gputexelcopytextureinfo
    if (blockWidth > 1 || blockHeight > 1) {
        FILAMENT_CHECK_PRECONDITION(xoffset % blockWidth == 0)
                << "xoffset must be aligned to blockwidth, but offset is " << blockWidth
                << "and offset is " << xoffset;
        FILAMENT_CHECK_PRECONDITION(yoffset % blockHeight == 0)
                << "yoffset must be aligned to blockHeight, but offset is " << blockHeight
                << "and offset is " << yoffset;
    }

    auto copyInfo = wgpu::TexelCopyTextureInfo{ .texture = texture->getTexture(),
        .mipLevel = level,
        .origin = { xoffset, yoffset, zoffset },
        .aspect = texture->getAspect() };
    uint32_t bytesPerRow = static_cast<uint32_t>(
            PixelBufferDescriptor::computePixelSize(data->format, data->type) * width);
    auto extent = wgpu::Extent3D{ .width = width, .height = height, .depthOrArrayLayers = depth };

    const uint8_t* dataBuff = static_cast<const uint8_t*>(data->buffer);
    size_t dataSize = data->size;
    std::unique_ptr<uint8_t[]> paddedBuffer;

    if (bytesPerRow % 256 != 0) {
        uint32_t padding = 256 - (bytesPerRow % 256);
        uint32_t paddedBytesPerRow = bytesPerRow + padding;

        size_t paddedBufferSize = static_cast<size_t>(paddedBytesPerRow) * height * depth;
        paddedBuffer = std::make_unique<uint8_t[]>(paddedBufferSize);
        uint8_t* dest = paddedBuffer.get();

        for (uint32_t z = 0; z < depth; ++z) {
            for (uint32_t y = 0; y < height; ++y) {
                std::memcpy(dest, dataBuff, bytesPerRow);
                dest += paddedBytesPerRow;
                dataBuff += bytesPerRow;
            }
        }
        dataBuff = paddedBuffer.get();

Review comment (suggestion):
nit: preference thing, but I prefer being explicit and not depend on order, e.g. `{.x = xOffset, .y=yoffset, .z=zoffset }`

Code after:
    }
    auto texture = handleCast<WGPUTexture>(th);

    // TODO: Writing to a depth texture is illegal and errors. I'm not sure why Filament is trying
    // to do so, but early returning is working?
    if(texture->getAspect() == wgpu::TextureAspect::DepthOnly){
        scheduleDestroy(std::move(p));
        return;
    }
    size_t blockWidth = texture->getBlockWidth();
    size_t blockHeight = texture->getBlockHeight();
    // WebGPU specification requires that for compressed textures, the x and y offsets
    // must be a multiple of the compressed texture format's block width and height.
    // See: https://www.w3.org/TR/webgpu/#abstract-opdef-validating-gputexelcopytextureinfo
    if (blockWidth > 1 || blockHeight > 1) {
        FILAMENT_CHECK_PRECONDITION(xoffset % blockWidth == 0)
                << "xoffset must be aligned to blockwidth, but offset is " << blockWidth
                << "and offset is " << xoffset;
        FILAMENT_CHECK_PRECONDITION(yoffset % blockHeight == 0)
                << "yoffset must be aligned to blockHeight, but offset is " << blockHeight
                << "and offset is " << yoffset;
    }

    auto copyInfo = wgpu::TexelCopyTextureInfo{ .texture = texture->getTexture(),
        .mipLevel = level,
        .origin = { .x = xoffset, .y = yoffset, .z = zoffset },
        .aspect = texture->getAspect() };
    uint32_t bytesPerRow = static_cast<uint32_t>(
            PixelBufferDescriptor::computePixelSize(data->format, data->type) * width);
    auto extent = wgpu::Extent3D{ .width = width, .height = height, .depthOrArrayLayers = depth };

    const uint8_t* dataBuff = static_cast<const uint8_t*>(data->buffer);
    size_t dataSize = data->size;
    std::unique_ptr<uint8_t[]> paddedBuffer;

    if (bytesPerRow % 256 != 0) {
        uint32_t padding = 256 - (bytesPerRow % 256);
        uint32_t paddedBytesPerRow = bytesPerRow + padding;

        size_t paddedBufferSize = static_cast<size_t>(paddedBytesPerRow) * height * depth;
        paddedBuffer = std::make_unique<uint8_t[]>(paddedBufferSize);
        uint8_t* dest = paddedBuffer.get();

        for (uint32_t z = 0; z < depth; ++z) {
            for (uint32_t y = 0; y < height; ++y) {
                std::memcpy(dest, dataBuff, bytesPerRow);
                dest += paddedBytesPerRow;
                dataBuff += bytesPerRow;
            }
        }
        dataBuff = paddedBuffer.get();