Title: [292199] trunk/Source/WebGPU
Revision
292199
Author
[email protected]
Date
2022-03-31 21:48:09 -0700 (Thu, 31 Mar 2022)

Log Message

[WebGPU] Implement CommandEncoder::copyTextureToBuffer() according to the spec.
https://bugs.webkit.org/show_bug.cgi?id=238430

Reviewed by Dean Jackson.

This implements CommandEncoder::copyTextureToBuffer() according to the spec.
It re-uses many of the helper functions added in
https://bugs.webkit.org/show_bug.cgi?id=238428. There are links and quotes from
the spec where appropriate.

* WebGPU/CommandEncoder.mm:
(WebGPU::validateCopyTextureToBuffer):
(WebGPU::CommandEncoder::copyTextureToBuffer):
* WebGPU/Texture.h:
* WebGPU/Texture.mm:
(WebGPU::Texture::isValidImageCopySource):

Modified Paths

Diff

Modified: trunk/Source/WebGPU/ChangeLog (292198 => 292199)


--- trunk/Source/WebGPU/ChangeLog	2022-04-01 03:39:53 UTC (rev 292198)
+++ trunk/Source/WebGPU/ChangeLog	2022-04-01 04:48:09 UTC (rev 292199)
@@ -1,5 +1,24 @@
 2022-03-31  Myles C. Maxfield  <[email protected]>
 
+        [WebGPU] Implement CommandEncoder::copyTextureToBuffer() according to the spec.
+        https://bugs.webkit.org/show_bug.cgi?id=238430
+
+        Reviewed by Dean Jackson.
+
+        This implements CommandEncoder::copyTextureToBuffer() according to the spec.
+        It re-uses many of the helper functions added in
+        https://bugs.webkit.org/show_bug.cgi?id=238428. There are links and quotes from
+        the spec where appropriate.
+
+        * WebGPU/CommandEncoder.mm:
+        (WebGPU::validateCopyTextureToBuffer):
+        (WebGPU::CommandEncoder::copyTextureToBuffer):
+        * WebGPU/Texture.h:
+        * WebGPU/Texture.mm:
+        (WebGPU::Texture::isValidImageCopySource):
+
+2022-03-31  Myles C. Maxfield  <[email protected]>
+
         [WebGPU] Implement CommandEncoder::copyBufferToTexture() according to the spec
         https://bugs.webkit.org/show_bug.cgi?id=238428
 

Modified: trunk/Source/WebGPU/WebGPU/CommandEncoder.mm (292198 => 292199)


--- trunk/Source/WebGPU/WebGPU/CommandEncoder.mm	2022-04-01 03:39:53 UTC (rev 292198)
+++ trunk/Source/WebGPU/WebGPU/CommandEncoder.mm	2022-04-01 04:48:09 UTC (rev 292199)
@@ -354,11 +354,187 @@
     }
 }
 
+static bool validateCopyTextureToBuffer(const WGPUImageCopyTexture& source, const WGPUImageCopyBuffer& destination, const WGPUExtent3D& copySize)
+{
+    // "Let srcTextureDesc be source.texture.[[descriptor]]."
+    const auto& srcTextureDesc = fromAPI(source.texture).descriptor();
+
+    // "validating GPUImageCopyTexture(source, copySize) returns true."
+    if (!Texture::validateImageCopyTexture(source, copySize))
+        return false;
+
+    // "srcTextureDesc.usage contains COPY_SRC."
+    if (!(srcTextureDesc.usage & WGPUBufferUsage_CopySrc))
+        return false;
+
+    // "srcTextureDesc.sampleCount is 1."
+    if (srcTextureDesc.sampleCount != 1)
+        return false;
+
+    // "Let aspectSpecificFormat = dstTextureDesc.format."
+    WGPUTextureFormat aspectSpecificFormat = srcTextureDesc.format;
+
+    // "If srcTextureDesc.format is a depth-stencil format:"
+    if (Texture::isDepthOrStencilFormat(srcTextureDesc.format)) {
+        // "source.aspect must refer to a single aspect of srcTextureDesc.format"
+        if (!Texture::refersToSingleAspect(srcTextureDesc.format, source.aspect))
+            return false;
+
+        // "and that aspect must be a valid image copy source according to § 25.1.2 Depth-stencil formats."
+        if (!Texture::isValidImageCopySource(srcTextureDesc.format, source.aspect))
+            return false;
+
+        // "Set aspectSpecificFormat to the aspect-specific format according to § 25.1.2 Depth-stencil formats."
+        aspectSpecificFormat = Texture::aspectSpecificFormat(srcTextureDesc.format, source.aspect);
+    }
+
+    // "validating GPUImageCopyBuffer(destination) returns true."
+    if (!validateImageCopyBuffer(destination))
+        return false;
+
+    // "destination.buffer.[[usage]] contains COPY_DST."
+    if (!(fromAPI(destination.buffer).usage() & WGPUBufferUsage_CopyDst))
+        return false;
+
+    // "validating texture copy range(source, copySize) returns true."
+    if (!Texture::validateTextureCopyRange(source, copySize))
+        return false;
+
+    // "If srcTextureDesc.format is not a depth-or-stencil format:"
+    if (!Texture::isDepthOrStencilFormat(srcTextureDesc.format)) {
+        // "destination.offset is a multiple of the texel block size of srcTextureDesc.format."
+        auto texelBlockSize = Texture::texelBlockSize(srcTextureDesc.format);
+        if (destination.layout.offset % texelBlockSize)
+            return false;
+    }
+
+    // "If srcTextureDesc.format is a depth-or-stencil format:"
+    if (Texture::isDepthOrStencilFormat(srcTextureDesc.format)) {
+        // "destination.offset is a multiple of 4."
+        if (destination.layout.offset % 4)
+            return false;
+    }
+
+    // "validating linear texture data(destination, destination.buffer.[[size]], aspectSpecificFormat, copySize) succeeds."
+    if (!Texture::validateLinearTextureData(destination.layout, fromAPI(destination.buffer).size(), aspectSpecificFormat, copySize))
+        return false;
+
+    return true;
+}
+
 void CommandEncoder::copyTextureToBuffer(const WGPUImageCopyTexture& source, const WGPUImageCopyBuffer& destination, const WGPUExtent3D& copySize)
 {
-    UNUSED_PARAM(source);
-    UNUSED_PARAM(destination);
-    UNUSED_PARAM(copySize);
+    if (source.nextInChain || destination.nextInChain || destination.layout.nextInChain)
+        return;
+
+    // https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-copytexturetobuffer
+
+    // "Prepare the encoder state of this. If it returns false, stop."
+    if (!prepareTheEncoderState())
+        return;
+
+    // "If any of the following conditions are unsatisfied"
+    if (!validateCopyTextureToBuffer(source, destination, copySize)) {
+        // "generate a validation error and stop."
+        m_device->generateAValidationError("Validation failure.");
+        return;
+    }
+
+    ensureBlitCommandEncoder();
+
+    NSUInteger destinationBytesPerRow = destination.layout.bytesPerRow;
+
+    // FIXME: Use checked arithmetic
+    NSUInteger destinationBytesPerImage = destination.layout.rowsPerImage * destination.layout.bytesPerRow;
+
+    MTLBlitOption options = MTLBlitOptionNone;
+    switch (source.aspect) {
+    case WGPUTextureAspect_All:
+        options = MTLBlitOptionNone;
+        break;
+    case WGPUTextureAspect_StencilOnly:
+        options = MTLBlitOptionStencilFromDepthStencil;
+        break;
+    case WGPUTextureAspect_DepthOnly:
+        options = MTLBlitOptionDepthFromDepthStencil;
+        break;
+    case WGPUTextureAspect_Force32:
+        return;
+    }
+
+    auto logicalSize = fromAPI(source.texture).logicalMiplevelSpecificTextureExtent(source.mipLevel);
+    auto widthForMetal = std::min(copySize.width, logicalSize.width);
+    auto heightForMetal = std::min(copySize.height, logicalSize.height);
+    auto depthForMetal = std::min(copySize.depthOrArrayLayers, logicalSize.depthOrArrayLayers);
+
+    auto& sourceDescriptor = fromAPI(source.texture).descriptor();
+    switch (sourceDescriptor.dimension) {
+    case WGPUTextureDimension_1D: {
+        // https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400756-copyfromtexture?language=objc
+        // "When you copy to a 1D texture, height and depth must be 1."
+        auto sourceSize = MTLSizeMake(widthForMetal, 1, 1);
+        auto sourceOrigin = MTLOriginMake(source.origin.x, 1, 1);
+        for (uint32_t layer = 0; layer < copySize.depthOrArrayLayers; ++layer) {
+            // FIXME: Use checked arithmetic.
+            auto destinationOffset = static_cast<NSUInteger>(destination.layout.offset + layer * destinationBytesPerImage);
+            NSUInteger sourceSlice = source.origin.z + layer;
+            [m_blitCommandEncoder
+                copyFromTexture:fromAPI(source.texture).texture()
+                sourceSlice:sourceSlice
+                sourceLevel:source.mipLevel
+                sourceOrigin:sourceOrigin
+                sourceSize:sourceSize
+                toBuffer:fromAPI(destination.buffer).buffer()
+                destinationOffset:destinationOffset
+                destinationBytesPerRow:destinationBytesPerRow
+                destinationBytesPerImage:destinationBytesPerImage
+                options:options];
+        }
+        break;
+    }
+    case WGPUTextureDimension_2D: {
+        // https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400756-copyfromtexture?language=objc
+        // "When you copy to a 2D texture, depth must be 1."
+        auto sourceSize = MTLSizeMake(widthForMetal, heightForMetal, 1);
+        auto sourceOrigin = MTLOriginMake(source.origin.x, source.origin.y, 1);
+        for (uint32_t layer = 0; layer < copySize.depthOrArrayLayers; ++layer) {
+            // FIXME: Use checked arithmetic.
+            auto destinationOffset = static_cast<NSUInteger>(destination.layout.offset + layer * destinationBytesPerImage);
+            NSUInteger sourceSlice = source.origin.z + layer;
+            [m_blitCommandEncoder
+                copyFromTexture:fromAPI(source.texture).texture()
+                sourceSlice:sourceSlice
+                sourceLevel:source.mipLevel
+                sourceOrigin:sourceOrigin
+                sourceSize:sourceSize
+                toBuffer:fromAPI(destination.buffer).buffer()
+                destinationOffset:destinationOffset
+                destinationBytesPerRow:destinationBytesPerRow
+                destinationBytesPerImage:destinationBytesPerImage
+                options:options];
+        }
+        break;
+    }
+    case WGPUTextureDimension_3D: {
+        auto sourceSize = MTLSizeMake(widthForMetal, heightForMetal, depthForMetal);
+        auto sourceOrigin = MTLOriginMake(source.origin.x, source.origin.y, source.origin.z);
+        auto destinationOffset = static_cast<NSUInteger>(destination.layout.offset);
+            [m_blitCommandEncoder
+                copyFromTexture:fromAPI(source.texture).texture()
+                sourceSlice:0
+                sourceLevel:source.mipLevel
+                sourceOrigin:sourceOrigin
+                sourceSize:sourceSize
+                toBuffer:fromAPI(destination.buffer).buffer()
+                destinationOffset:destinationOffset
+                destinationBytesPerRow:destinationBytesPerRow
+                destinationBytesPerImage:destinationBytesPerImage
+                options:options];
+        break;
+    }
+    case WGPUTextureDimension_Force32:
+        return;
+    }
 }
 
 void CommandEncoder::copyTextureToTexture(const WGPUImageCopyTexture& source, const WGPUImageCopyTexture& destination, const WGPUExtent3D& copySize)

Modified: trunk/Source/WebGPU/WebGPU/Texture.h (292198 => 292199)


--- trunk/Source/WebGPU/WebGPU/Texture.h	2022-04-01 03:39:53 UTC (rev 292198)
+++ trunk/Source/WebGPU/WebGPU/Texture.h	2022-04-01 04:48:09 UTC (rev 292199)
@@ -64,6 +64,7 @@
     static bool validateImageCopyTexture(const WGPUImageCopyTexture&, const WGPUExtent3D&);
     static bool validateTextureCopyRange(const WGPUImageCopyTexture&, const WGPUExtent3D&);
     static bool refersToSingleAspect(WGPUTextureFormat, WGPUTextureAspect);
+    static bool isValidImageCopySource(WGPUTextureFormat, WGPUTextureAspect);
     static bool isValidImageCopyDestination(WGPUTextureFormat, WGPUTextureAspect);
     static bool validateLinearTextureData(const WGPUTextureDataLayout&, uint64_t, WGPUTextureFormat, WGPUExtent3D);
 

Modified: trunk/Source/WebGPU/WebGPU/Texture.mm (292198 => 292199)


--- trunk/Source/WebGPU/WebGPU/Texture.mm	2022-04-01 03:39:53 UTC (rev 292198)
+++ trunk/Source/WebGPU/WebGPU/Texture.mm	2022-04-01 04:48:09 UTC (rev 292199)
@@ -2424,6 +2424,119 @@
     return true;
 }
 
+bool Texture::isValidImageCopySource(WGPUTextureFormat format, WGPUTextureAspect aspect)
+{
+    // https://gpuweb.github.io/gpuweb/#depth-formats
+
+    switch (format) {
+    case WGPUTextureFormat_Undefined:
+    case WGPUTextureFormat_R8Unorm:
+    case WGPUTextureFormat_R8Snorm:
+    case WGPUTextureFormat_R8Uint:
+    case WGPUTextureFormat_R8Sint:
+    case WGPUTextureFormat_R16Uint:
+    case WGPUTextureFormat_R16Sint:
+    case WGPUTextureFormat_R16Float:
+    case WGPUTextureFormat_RG8Unorm:
+    case WGPUTextureFormat_RG8Snorm:
+    case WGPUTextureFormat_RG8Uint:
+    case WGPUTextureFormat_RG8Sint:
+    case WGPUTextureFormat_R32Float:
+    case WGPUTextureFormat_R32Uint:
+    case WGPUTextureFormat_R32Sint:
+    case WGPUTextureFormat_RG16Uint:
+    case WGPUTextureFormat_RG16Sint:
+    case WGPUTextureFormat_RG16Float:
+    case WGPUTextureFormat_RGBA8Unorm:
+    case WGPUTextureFormat_RGBA8UnormSrgb:
+    case WGPUTextureFormat_RGBA8Snorm:
+    case WGPUTextureFormat_RGBA8Uint:
+    case WGPUTextureFormat_RGBA8Sint:
+    case WGPUTextureFormat_BGRA8Unorm:
+    case WGPUTextureFormat_BGRA8UnormSrgb:
+    case WGPUTextureFormat_RGB10A2Unorm:
+    case WGPUTextureFormat_RG11B10Ufloat:
+    case WGPUTextureFormat_RGB9E5Ufloat:
+    case WGPUTextureFormat_RG32Float:
+    case WGPUTextureFormat_RG32Uint:
+    case WGPUTextureFormat_RG32Sint:
+    case WGPUTextureFormat_RGBA16Uint:
+    case WGPUTextureFormat_RGBA16Sint:
+    case WGPUTextureFormat_RGBA16Float:
+    case WGPUTextureFormat_RGBA32Float:
+    case WGPUTextureFormat_RGBA32Uint:
+    case WGPUTextureFormat_RGBA32Sint:
+        ASSERT_NOT_REACHED();
+        return false;
+    case WGPUTextureFormat_Stencil8:
+    case WGPUTextureFormat_Depth16Unorm:
+        return true;
+    case WGPUTextureFormat_Depth24Plus:
+        return false;
+    case WGPUTextureFormat_Depth24PlusStencil8:
+    case WGPUTextureFormat_Depth24UnormStencil8:
+        return aspect == WGPUTextureAspect_StencilOnly;
+    case WGPUTextureFormat_Depth32Float:
+    case WGPUTextureFormat_Depth32FloatStencil8:
+        return true;
+    case WGPUTextureFormat_BC1RGBAUnorm:
+    case WGPUTextureFormat_BC1RGBAUnormSrgb:
+    case WGPUTextureFormat_BC2RGBAUnorm:
+    case WGPUTextureFormat_BC2RGBAUnormSrgb:
+    case WGPUTextureFormat_BC3RGBAUnorm:
+    case WGPUTextureFormat_BC3RGBAUnormSrgb:
+    case WGPUTextureFormat_BC4RUnorm:
+    case WGPUTextureFormat_BC4RSnorm:
+    case WGPUTextureFormat_BC5RGUnorm:
+    case WGPUTextureFormat_BC5RGSnorm:
+    case WGPUTextureFormat_BC6HRGBUfloat:
+    case WGPUTextureFormat_BC6HRGBFloat:
+    case WGPUTextureFormat_BC7RGBAUnorm:
+    case WGPUTextureFormat_BC7RGBAUnormSrgb:
+    case WGPUTextureFormat_ETC2RGB8Unorm:
+    case WGPUTextureFormat_ETC2RGB8UnormSrgb:
+    case WGPUTextureFormat_ETC2RGB8A1Unorm:
+    case WGPUTextureFormat_ETC2RGB8A1UnormSrgb:
+    case WGPUTextureFormat_ETC2RGBA8Unorm:
+    case WGPUTextureFormat_ETC2RGBA8UnormSrgb:
+    case WGPUTextureFormat_EACR11Unorm:
+    case WGPUTextureFormat_EACR11Snorm:
+    case WGPUTextureFormat_EACRG11Unorm:
+    case WGPUTextureFormat_EACRG11Snorm:
+    case WGPUTextureFormat_ASTC4x4Unorm:
+    case WGPUTextureFormat_ASTC4x4UnormSrgb:
+    case WGPUTextureFormat_ASTC5x4Unorm:
+    case WGPUTextureFormat_ASTC5x4UnormSrgb:
+    case WGPUTextureFormat_ASTC5x5Unorm:
+    case WGPUTextureFormat_ASTC5x5UnormSrgb:
+    case WGPUTextureFormat_ASTC6x5Unorm:
+    case WGPUTextureFormat_ASTC6x5UnormSrgb:
+    case WGPUTextureFormat_ASTC6x6Unorm:
+    case WGPUTextureFormat_ASTC6x6UnormSrgb:
+    case WGPUTextureFormat_ASTC8x5Unorm:
+    case WGPUTextureFormat_ASTC8x5UnormSrgb:
+    case WGPUTextureFormat_ASTC8x6Unorm:
+    case WGPUTextureFormat_ASTC8x6UnormSrgb:
+    case WGPUTextureFormat_ASTC8x8Unorm:
+    case WGPUTextureFormat_ASTC8x8UnormSrgb:
+    case WGPUTextureFormat_ASTC10x5Unorm:
+    case WGPUTextureFormat_ASTC10x5UnormSrgb:
+    case WGPUTextureFormat_ASTC10x6Unorm:
+    case WGPUTextureFormat_ASTC10x6UnormSrgb:
+    case WGPUTextureFormat_ASTC10x8Unorm:
+    case WGPUTextureFormat_ASTC10x8UnormSrgb:
+    case WGPUTextureFormat_ASTC10x10Unorm:
+    case WGPUTextureFormat_ASTC10x10UnormSrgb:
+    case WGPUTextureFormat_ASTC12x10Unorm:
+    case WGPUTextureFormat_ASTC12x10UnormSrgb:
+    case WGPUTextureFormat_ASTC12x12Unorm:
+    case WGPUTextureFormat_ASTC12x12UnormSrgb:
+    case WGPUTextureFormat_Force32:
+        ASSERT_NOT_REACHED();
+        return false;
+    }
+}
+
 bool Texture::isValidImageCopyDestination(WGPUTextureFormat format, WGPUTextureAspect aspect)
 {
     // https://gpuweb.github.io/gpuweb/#depth-formats
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to