[Web GPU] Blitting function prototypes
authorjustin_fan@apple.com <justin_fan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 Mar 2019 00:55:15 +0000 (00:55 +0000)
committerjustin_fan@apple.com <justin_fan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 Mar 2019 00:55:15 +0000 (00:55 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195224
<rdar://problem/48538902>

Reviewed by Dean Jackson.

Source/WebCore:

Implement barebones GPUCommandBuffer::copy* prototypes while rounding out GPUTexture implementation details.

Test: webgpu/blit-commands.html

* Modules/webgpu/GPUOrigin3D.h: Added.
* Modules/webgpu/GPUOrigin3D.idl: Added.
* Modules/webgpu/WebGPUCommandBuffer.cpp: Add copy view struct implementations.
(WebCore::WebGPUBufferCopyView::asGPUBufferCopyView const): Added.
(WebCore::WebGPUTextureCopyView::asGPUTextureCopyView const): Added.
(WebCore::WebGPUCommandBuffer::copyBufferToBuffer): Added.
(WebCore::WebGPUCommandBuffer::copyBufferToTexture): Added.
(WebCore::WebGPUCommandBuffer::copyTextureToBuffer): Added.
(WebCore::WebGPUCommandBuffer::copyTextureToTexture): Added.
* Modules/webgpu/WebGPUCommandBuffer.h: Add new functions and supporting structs.
* Modules/webgpu/WebGPUCommandBuffer.idl: Ditto.
* Modules/webgpu/WebGPURenderPassDescriptor.cpp: Refactor constructors to copy the entire base class.
(WebCore::GPURenderPassColorAttachmentDescriptor::GPURenderPassColorAttachmentDescriptor):
(WebCore::GPURenderPassDepthStencilAttachmentDescriptor::GPURenderPassDepthStencilAttachmentDescriptor):
(WebCore::WebGPURenderPassDescriptor::asGPURenderPassDescriptor const):
(WebCore::attachment): Deleted.
* Modules/webgpu/WebGPUTexture.h:
(WebCore::WebGPUTexture::texture const): Added.
* platform/graphics/gpu/GPUBuffer.h:
(WebCore::GPUBuffer::byteLength const): Added.
(WebCore::GPUBuffer::isTransferSource const): Added.
(WebCore::GPUBuffer::isTransferDestination const): Renamed from isTransferDst. Refactored for OptionSet API.
(WebCore::GPUBuffer::isVertex const): Ditto.
(WebCore::GPUBuffer::isUniform const): Ditto.
(WebCore::GPUBuffer::isStorage const): Ditto.
(WebCore::GPUBuffer::isMappable const): Ditto.
(WebCore::GPUBuffer::isMapWrite const): Ditto.
(WebCore::GPUBuffer::isMapRead const): Ditto.
* platform/graphics/gpu/GPUBufferUsage.h: Refactored for better bit flag style.
* platform/graphics/gpu/GPUCommandBuffer.h:
(WebCore::GPUCommandBuffer::blitEncoder const): Added.
* platform/graphics/gpu/GPURenderPassDescriptor.h:
* platform/graphics/gpu/GPUTexture.h: Cache usage flags for reference.
(WebCore::GPUTexture::isTransferSrc const): Added.
(WebCore::GPUTexture::isTransferDst const): Added.
(WebCore::GPUTexture::isOutputAttachment const): Added.
* platform/graphics/gpu/GPUTextureUsage.h: Refactor to match GPUBufferUsage.h.
* platform/graphics/gpu/cocoa/GPUBufferMetal.mm:
(WebCore::GPUBuffer::validateBufferUsage): Renamed from validateBufferCreate, refactored for OptionSet.
(WebCore::GPUBuffer::tryCreate):
(WebCore::GPUBuffer::GPUBuffer):
(WebCore::GPUBuffer::isReadOnly const):
(WebCore::GPUBuffer::setSubData): Add alignment check according to Metal docs.
* platform/graphics/gpu/cocoa/GPUCommandBufferMetal.mm:
(WebCore::GPUCommandBuffer::create): No need to use this alias here.
(WebCore::GPUCommandBuffer::GPUCommandBuffer): Ditto.
(WebCore::GPUCommandBuffer::copyBufferToBuffer): Added.
(WebCore::GPUCommandBuffer::copyBufferToTexture): Added.
(WebCore::GPUCommandBuffer::copyTextureToBuffer): Added.
(WebCore::GPUCommandBuffer::copyTextureToTexture): Added.
* platform/graphics/gpu/cocoa/GPUQueueMetal.mm:
(WebCore::GPUQueue::submit): End encoding on the MTLCommandBuffer's blitCommandEncoder if it was used.
* platform/graphics/gpu/cocoa/GPUSwapChainMetal.mm:
(WebCore::GPUSwapChain::getNextTexture): Now provide usage flags to texture creation.
* platform/graphics/gpu/cocoa/GPUTextureMetal.mm:
(WebCore::mtlTextureUsageForGPUTextureUsageFlags): Refactor validation.
(WebCore::tryCreateMtlTextureDescriptor): Ditto.
(WebCore::GPUTexture::tryCreate): Now provide usage flags to texture creation.
(WebCore::GPUTexture::create): Ditto.
(WebCore::GPUTexture::GPUTexture): Ditto.
(WebCore::GPUTexture::createDefaultTextureView): Ditto.

LayoutTests:

Add basic test to copy data with all new blitting functions and verify the result.

* webgpu/blit-commands-expected.html: Added.
* webgpu/blit-commands.html: Added.
* webgpu/buffer-command-buffer-races.html: Fixed typo.
* webgpu/resources/green-400.png: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@242404 268f45cc-cd09-0410-ab3c-d52691b4dbfc

30 files changed:
LayoutTests/ChangeLog
LayoutTests/webgpu/blit-commands-expected.html [new file with mode: 0644]
LayoutTests/webgpu/blit-commands.html [new file with mode: 0644]
LayoutTests/webgpu/buffer-command-buffer-races.html
LayoutTests/webgpu/resources/green-400.png [new file with mode: 0644]
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/DerivedSources-input.xcfilelist
Source/WebCore/DerivedSources-output.xcfilelist
Source/WebCore/DerivedSources.make
Source/WebCore/Modules/webgpu/GPUOrigin3D.h [new file with mode: 0644]
Source/WebCore/Modules/webgpu/GPUOrigin3D.idl [new file with mode: 0644]
Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.cpp
Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.h
Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.idl
Source/WebCore/Modules/webgpu/WebGPURenderPassDescriptor.cpp
Source/WebCore/Modules/webgpu/WebGPUTexture.h
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/graphics/gpu/GPUBuffer.h
Source/WebCore/platform/graphics/gpu/GPUBufferUsage.h
Source/WebCore/platform/graphics/gpu/GPUCommandBuffer.h
Source/WebCore/platform/graphics/gpu/GPURenderPassDescriptor.h
Source/WebCore/platform/graphics/gpu/GPUTexture.h
Source/WebCore/platform/graphics/gpu/GPUTextureUsage.h
Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm
Source/WebCore/platform/graphics/gpu/cocoa/GPUCommandBufferMetal.mm
Source/WebCore/platform/graphics/gpu/cocoa/GPUQueueMetal.mm
Source/WebCore/platform/graphics/gpu/cocoa/GPUSwapChainMetal.mm
Source/WebCore/platform/graphics/gpu/cocoa/GPUTextureMetal.mm

index d36954e..4a81846 100644 (file)
@@ -1,3 +1,18 @@
+2019-03-04  Justin Fan  <justin_fan@apple.com>
+
+        [Web GPU] Blitting function prototypes
+        https://bugs.webkit.org/show_bug.cgi?id=195224
+        <rdar://problem/48538902>
+
+        Reviewed by Dean Jackson.
+
+        Add basic test to copy data with all new blitting functions and verify the result.
+
+        * webgpu/blit-commands-expected.html: Added.
+        * webgpu/blit-commands.html: Added.
+        * webgpu/buffer-command-buffer-races.html: Fixed typo.
+        * webgpu/resources/green-400.png: Added.
+
 2019-03-04  Zalan Bujtas  <zalan@apple.com>
 
         [ContentChangeObserver] Introduce fixed duration content observation
diff --git a/LayoutTests/webgpu/blit-commands-expected.html b/LayoutTests/webgpu/blit-commands-expected.html
new file mode 100644 (file)
index 0000000..886f13e
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Reference File</title>
+<p>Pass if square canvas below is completely green.</p>
+<canvas width="400" height="400"></canvas>
+<script>
+const canvas = document.querySelector("canvas");
+const context = canvas.getContext('2d');
+
+context.fillStyle = 'rgb(0, 255, 0)';
+context.fillRect(0, 0, canvas.width, canvas.height);
+</script>
\ No newline at end of file
diff --git a/LayoutTests/webgpu/blit-commands.html b/LayoutTests/webgpu/blit-commands.html
new file mode 100644 (file)
index 0000000..2a94889
--- /dev/null
@@ -0,0 +1,112 @@
+<!DOCTYPE html><!-- webkit-test-runner [ experimental:WebGPUEnabled=true ] -->
+<meta charset="utf-8">
+<title>Basic Blitting</title>
+<meta name="assert" content="Blit operations copy a green canvas.">
+<link rel="match" href="blit-commands-expected.html">
+<p>Pass if square canvas below is completely green.</p>
+<canvas width="400" height="400"></canvas>
+<body>
+<script src="js/webgpu-functions.js"></script>
+<script>
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+async function loadImage() {
+    const image = new Image();
+    image.src = "resources/green-400.png";
+    image.onload = () => { test(image); }
+}
+
+async function test(image) {
+    const device = await getBasicDevice();
+
+    const canvas2d = document.createElement('canvas');
+    canvas2d.width = image.width;
+    canvas2d.height = image.height;
+    const context2d = canvas2d.getContext('2d');
+    context2d.drawImage(image, 0, 0);
+
+    const imageData = context2d.getImageData(0, 0, image.width, image.height);
+
+    const bufferDescriptor = {
+        size: imageData.data.byteLength,
+        usage: GPUBufferUsage.TRANSFER_SRC | GPUBufferUsage.TRANSFER_DST
+    };
+    const bufferA = device.createBuffer(bufferDescriptor);
+    bufferA.setSubData(0, imageData.data.buffer);
+
+    const bufferB = device.createBuffer(bufferDescriptor);
+    const bufferViewB = {
+        buffer: bufferB,
+        offset: 0,
+        rowPitch: 0,
+        imageHeight: 0
+    };
+
+    const textureSize = {
+        width: image.width,
+        height: image.height,
+        depth: 1
+    };
+    const textureDescriptor = {
+        size: textureSize,
+        arrayLayerCount: 1,
+        mipLevelCount: 1,
+        sampleCount: 1,
+        dimension: "2d",
+        format: "r8g8b8a8-unorm",
+        usage: GPUTextureUsage.TRANSFER_SRC | GPUTextureUsage.TRANSFER_DST
+    };
+    const textureA = device.createTexture(textureDescriptor);
+    const textureViewA = {
+        texture: textureA,
+        mipLevel: 0,
+        arrayLayer: 0,
+        origin: { x: 0, y: 0, z: 0 }
+    };
+
+    const textureB = device.createTexture(textureDescriptor);
+    const textureViewB = {
+        texture: textureB,
+        mipLevel: 0,
+        arrayLayer: 0,
+        origin: { x: 0, y: 0, z: 0 }
+    };
+
+    const readBufferDescriptor = {
+        size: imageData.data.byteLength,
+        usage: GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ
+    };
+    const readBuffer = device.createBuffer(readBufferDescriptor);
+    const readBufferView = {
+        buffer: readBuffer,
+        offset: 0,
+        rowPitch: 0,
+        imageHeight: 0
+    };
+
+    const commandBuffer = device.createCommandBuffer();
+    commandBuffer.copyBufferToBuffer(bufferA, 0, bufferB, 0, imageData.data.byteLength);
+    commandBuffer.copyBufferToTexture(bufferViewB, textureViewA, textureSize);
+    commandBuffer.copyTextureToTexture(textureViewA, textureViewB, textureSize);
+    commandBuffer.copyTextureToBuffer(textureViewB, readBufferView, textureSize);
+    device.getQueue().submit([commandBuffer]);
+
+    const resultContext = document.querySelector('canvas').getContext('2d');
+
+    await readBuffer.mapReadAsync().then(ab => {
+        const array = new Uint8ClampedArray(ab);
+        const resultImageData = new ImageData(array, image.width, image.height);
+
+        resultContext.putImageData(resultImageData, 0, 0);
+
+        readBuffer.unmap();
+    });
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+loadImage();
+</script>
+</body>
\ No newline at end of file
index 3b3378a..35a32a8 100644 (file)
@@ -2,7 +2,7 @@
 <meta charset="utf-8">
 <title>WebGPU Hello Triangles</title>
 <meta name="assert" content="WebGPU correctly renders a green canvas.">
-<link rel="match" href="vertex-buffer-triangle-strip-expected.html">
+<link rel="match" href="buffer-command-buffer-races-expected.html">
 <p>Pass if square canvas below is completely green.</p>
 <canvas width="400" height="400"></canvas>
 <script src="js/webgpu-functions.js"></script>
diff --git a/LayoutTests/webgpu/resources/green-400.png b/LayoutTests/webgpu/resources/green-400.png
new file mode 100644 (file)
index 0000000..6c7f88e
Binary files /dev/null and b/LayoutTests/webgpu/resources/green-400.png differ
index cd63192..60124fc 100644 (file)
@@ -469,6 +469,7 @@ set(WebCore_NON_SVG_IDL_FILES
     Modules/webgpu/GPUDepthStencilStateDescriptor.idl
     Modules/webgpu/GPUExtent3D.idl
     Modules/webgpu/GPULoadOp.idl
+    Modules/webgpu/GPUOrigin3D.idl
     Modules/webgpu/GPURequestAdapterOptions.idl
     Modules/webgpu/GPUStoreOp.idl
     Modules/webgpu/GPUTextureDescriptor.idl
index 5899a53..c1a41bc 100644 (file)
@@ -1,3 +1,77 @@
+2019-03-04  Justin Fan  <justin_fan@apple.com>
+
+        [Web GPU] Blitting function prototypes
+        https://bugs.webkit.org/show_bug.cgi?id=195224
+        <rdar://problem/48538902>
+
+        Reviewed by Dean Jackson.
+
+        Implement barebones GPUCommandBuffer::copy* prototypes while rounding out GPUTexture implementation details.
+
+        Test: webgpu/blit-commands.html
+
+        * Modules/webgpu/GPUOrigin3D.h: Added.
+        * Modules/webgpu/GPUOrigin3D.idl: Added.
+        * Modules/webgpu/WebGPUCommandBuffer.cpp: Add copy view struct implementations.
+        (WebCore::WebGPUBufferCopyView::asGPUBufferCopyView const): Added.
+        (WebCore::WebGPUTextureCopyView::asGPUTextureCopyView const): Added.
+        (WebCore::WebGPUCommandBuffer::copyBufferToBuffer): Added.
+        (WebCore::WebGPUCommandBuffer::copyBufferToTexture): Added.
+        (WebCore::WebGPUCommandBuffer::copyTextureToBuffer): Added.
+        (WebCore::WebGPUCommandBuffer::copyTextureToTexture): Added.
+        * Modules/webgpu/WebGPUCommandBuffer.h: Add new functions and supporting structs.
+        * Modules/webgpu/WebGPUCommandBuffer.idl: Ditto.
+        * Modules/webgpu/WebGPURenderPassDescriptor.cpp: Refactor constructors to copy the entire base class.
+        (WebCore::GPURenderPassColorAttachmentDescriptor::GPURenderPassColorAttachmentDescriptor):
+        (WebCore::GPURenderPassDepthStencilAttachmentDescriptor::GPURenderPassDepthStencilAttachmentDescriptor):
+        (WebCore::WebGPURenderPassDescriptor::asGPURenderPassDescriptor const):
+        (WebCore::attachment): Deleted.
+        * Modules/webgpu/WebGPUTexture.h:
+        (WebCore::WebGPUTexture::texture const): Added.
+        * platform/graphics/gpu/GPUBuffer.h:
+        (WebCore::GPUBuffer::byteLength const): Added.
+        (WebCore::GPUBuffer::isTransferSource const): Added.
+        (WebCore::GPUBuffer::isTransferDestination const): Renamed from isTransferDst. Refactored for OptionSet API.
+        (WebCore::GPUBuffer::isVertex const): Ditto.
+        (WebCore::GPUBuffer::isUniform const): Ditto.
+        (WebCore::GPUBuffer::isStorage const): Ditto.
+        (WebCore::GPUBuffer::isMappable const): Ditto.
+        (WebCore::GPUBuffer::isMapWrite const): Ditto.
+        (WebCore::GPUBuffer::isMapRead const): Ditto.
+        * platform/graphics/gpu/GPUBufferUsage.h: Refactored for better bit flag style.
+        * platform/graphics/gpu/GPUCommandBuffer.h:
+        (WebCore::GPUCommandBuffer::blitEncoder const): Added.
+        * platform/graphics/gpu/GPURenderPassDescriptor.h: 
+        * platform/graphics/gpu/GPUTexture.h: Cache usage flags for reference.
+        (WebCore::GPUTexture::isTransferSrc const): Added.
+        (WebCore::GPUTexture::isTransferDst const): Added.
+        (WebCore::GPUTexture::isOutputAttachment const): Added.
+        * platform/graphics/gpu/GPUTextureUsage.h: Refactor to match GPUBufferUsage.h.
+        * platform/graphics/gpu/cocoa/GPUBufferMetal.mm:
+        (WebCore::GPUBuffer::validateBufferUsage): Renamed from validateBufferCreate, refactored for OptionSet.
+        (WebCore::GPUBuffer::tryCreate):
+        (WebCore::GPUBuffer::GPUBuffer):
+        (WebCore::GPUBuffer::isReadOnly const):
+        (WebCore::GPUBuffer::setSubData): Add alignment check according to Metal docs.
+        * platform/graphics/gpu/cocoa/GPUCommandBufferMetal.mm: 
+        (WebCore::GPUCommandBuffer::create): No need to use this alias here.
+        (WebCore::GPUCommandBuffer::GPUCommandBuffer): Ditto.
+        (WebCore::GPUCommandBuffer::copyBufferToBuffer): Added.
+        (WebCore::GPUCommandBuffer::copyBufferToTexture): Added.
+        (WebCore::GPUCommandBuffer::copyTextureToBuffer): Added. 
+        (WebCore::GPUCommandBuffer::copyTextureToTexture): Added. 
+        * platform/graphics/gpu/cocoa/GPUQueueMetal.mm:
+        (WebCore::GPUQueue::submit): End encoding on the MTLCommandBuffer's blitCommandEncoder if it was used.
+        * platform/graphics/gpu/cocoa/GPUSwapChainMetal.mm:
+        (WebCore::GPUSwapChain::getNextTexture): Now provide usage flags to texture creation.
+        * platform/graphics/gpu/cocoa/GPUTextureMetal.mm:
+        (WebCore::mtlTextureUsageForGPUTextureUsageFlags): Refactor validation.
+        (WebCore::tryCreateMtlTextureDescriptor): Ditto.
+        (WebCore::GPUTexture::tryCreate): Now provide usage flags to texture creation.
+        (WebCore::GPUTexture::create): Ditto.
+        (WebCore::GPUTexture::GPUTexture): Ditto.
+        (WebCore::GPUTexture::createDefaultTextureView): Ditto.
+
 2019-03-04  Zalan Bujtas  <zalan@apple.com>
 
         [ContentChangeObserver] Introduce fixed duration content observation
index 7e6bf5b..255ab44 100644 (file)
@@ -321,13 +321,14 @@ $(PROJECT_DIR)/Modules/webdatabase/SQLTransactionCallback.idl
 $(PROJECT_DIR)/Modules/webdatabase/SQLTransactionErrorCallback.idl
 $(PROJECT_DIR)/Modules/webdriver/NavigatorWebDriver.idl
 $(PROJECT_DIR)/Modules/webgpu/DOMWindowWebGPU.idl
-$(PROJECT_DIR)/Modules/webgpu/GPUColor.idl
 $(PROJECT_DIR)/Modules/webgpu/GPUBufferDescriptor.idl
 $(PROJECT_DIR)/Modules/webgpu/GPUBufferUsage.idl
+$(PROJECT_DIR)/Modules/webgpu/GPUColor.idl
 $(PROJECT_DIR)/Modules/webgpu/GPUCompareFunction.idl
 $(PROJECT_DIR)/Modules/webgpu/GPUDepthStencilStateDescriptor.idl
 $(PROJECT_DIR)/Modules/webgpu/GPUExtent3D.idl
 $(PROJECT_DIR)/Modules/webgpu/GPULoadOp.idl
+$(PROJECT_DIR)/Modules/webgpu/GPUOrigin3D.idl
 $(PROJECT_DIR)/Modules/webgpu/GPURequestAdapterOptions.idl
 $(PROJECT_DIR)/Modules/webgpu/GPUStoreOp.idl
 $(PROJECT_DIR)/Modules/webgpu/GPUTextureDescriptor.idl
index ceddbae..b5f022d 100644 (file)
@@ -577,12 +577,12 @@ $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSFontFaceSet.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSFontFaceSet.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGCObservation.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGCObservation.h
-$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUColor.cpp
-$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUColor.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUBufferDescriptor.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUBufferDescriptor.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUBufferUsage.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUBufferUsage.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUColor.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUColor.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUCompareFunction.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUCompareFunction.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUDepthStencilStateDescriptor.cpp
@@ -591,6 +591,8 @@ $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUExtent3D.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUExtent3D.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPULoadOp.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPULoadOp.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUOrigin3D.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUOrigin3D.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPURequestAdapterOptions.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPURequestAdapterOptions.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSGPUStoreOp.cpp
index 9e1818d..0668792 100644 (file)
@@ -379,6 +379,7 @@ JS_BINDING_IDLS = \
     $(WebCore)/Modules/webgpu/GPUDepthStencilStateDescriptor.idl \
     $(WebCore)/Modules/webgpu/GPUExtent3D.idl \
     $(WebCore)/Modules/webgpu/GPULoadOp.idl \
+    $(WebCore)/Modules/webgpu/GPUOrigin3D.idl \
     $(WebCore)/Modules/webgpu/GPURequestAdapterOptions.idl \
     $(WebCore)/Modules/webgpu/GPUStoreOp.idl \
     $(WebCore)/Modules/webgpu/GPUTextureDescriptor.idl \
diff --git a/Source/WebCore/Modules/webgpu/GPUOrigin3D.h b/Source/WebCore/Modules/webgpu/GPUOrigin3D.h
new file mode 100644 (file)
index 0000000..f59540e
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBGPU)
+
+namespace WebCore {
+
+struct GPUOrigin3D {
+    unsigned x;
+    unsigned y;
+    unsigned z;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBGPU)
diff --git a/Source/WebCore/Modules/webgpu/GPUOrigin3D.idl b/Source/WebCore/Modules/webgpu/GPUOrigin3D.idl
new file mode 100644 (file)
index 0000000..813a231
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
+
+typedef unsigned long u32;
+
+[
+    Conditional=WEBGPU,
+    EnabledAtRuntime=WebGPU
+] dictionary GPUOrigin3D {
+    u32 x;
+    u32 y;
+    u32 z;
+};
index 28a5ab7..f2f29e6 100644 (file)
 
 #include "GPURenderPassDescriptor.h"
 #include "GPURenderPassEncoder.h"
+#include "WebGPUBuffer.h"
 #include "WebGPURenderPassDescriptor.h"
 #include "WebGPURenderPassEncoder.h"
+#include "WebGPUTexture.h"
 
 namespace WebCore {
 
+Optional<GPUBufferCopyView> WebGPUBufferCopyView::asGPUBufferCopyView() const
+{
+    if (!buffer || !buffer->buffer()) {
+        LOG(WebGPU, "GPUCommandEncoder: Invalid buffer for copy!");
+        return WTF::nullopt;
+    }
+
+    // FIXME: Add Web GPU validation.
+
+    return GPUBufferCopyView { buffer->buffer().releaseNonNull(), *this };
+}
+
+Optional<GPUTextureCopyView> WebGPUTextureCopyView::asGPUTextureCopyView() const
+{
+    if (!texture || !texture->texture()) {
+        LOG(WebGPU, "GPUCommandEncoder: Invalid texture for copy!");
+        return WTF::nullopt;
+    }
+
+    // FIXME: Add Web GPU validation.
+
+    return GPUTextureCopyView { texture->texture().releaseNonNull(), *this };
+}
+
 Ref<WebGPUCommandBuffer> WebGPUCommandBuffer::create(Ref<GPUCommandBuffer>&& buffer)
 {
     return adoptRef(*new WebGPUCommandBuffer(WTFMove(buffer)));
@@ -56,6 +82,57 @@ RefPtr<WebGPURenderPassEncoder> WebGPUCommandBuffer::beginRenderPass(WebGPURende
     return nullptr;
 }
 
+void WebGPUCommandBuffer::copyBufferToBuffer(const WebGPUBuffer& src, unsigned long srcOffset, const WebGPUBuffer& dst, unsigned long dstOffset, unsigned long size)
+{
+    if (!src.buffer() || !dst.buffer()) {
+        LOG(WebGPU, "GPUCommandBuffer::copyBufferToBuffer(): Invalid GPUBuffer!");
+        return;
+    }
+
+    // FIXME: Add Web GPU validation.
+
+    m_commandBuffer->copyBufferToBuffer(src.buffer().releaseNonNull(), srcOffset, dst.buffer().releaseNonNull(), dstOffset, size);
+}
+
+void WebGPUCommandBuffer::copyBufferToTexture(const WebGPUBufferCopyView& srcBuffer, const WebGPUTextureCopyView& dstTexture, const GPUExtent3D& size)
+{
+    auto gpuBufferView = srcBuffer.asGPUBufferCopyView();
+    auto gpuTextureView = dstTexture.asGPUTextureCopyView();
+
+    if (!gpuBufferView || !gpuTextureView)
+        return;
+
+    // FIXME: Add Web GPU validation.
+
+    m_commandBuffer->copyBufferToTexture(*gpuBufferView, *gpuTextureView, size);
+}
+
+void WebGPUCommandBuffer::copyTextureToBuffer(const WebGPUTextureCopyView& srcTexture, const WebGPUBufferCopyView& dstBuffer, const GPUExtent3D& size)
+{
+    auto gpuTextureView = srcTexture.asGPUTextureCopyView();
+    auto gpuBufferView = dstBuffer.asGPUBufferCopyView();
+
+    if (!gpuTextureView || !gpuBufferView)
+        return;
+
+    // FIXME: Add Web GPU validation.
+
+    m_commandBuffer->copyTextureToBuffer(*gpuTextureView, *gpuBufferView, size);
+}
+
+void WebGPUCommandBuffer::copyTextureToTexture(const WebGPUTextureCopyView& src, const WebGPUTextureCopyView& dst, const GPUExtent3D& size)
+{
+    auto gpuSrcView = src.asGPUTextureCopyView();
+    auto gpuDstView = dst.asGPUTextureCopyView();
+
+    if (!gpuSrcView || !gpuDstView)
+        return;
+
+    // FIXME: Add Web GPU validation.
+
+    m_commandBuffer->copyTextureToTexture(*gpuSrcView, *gpuDstView, size);
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(WEBGPU)
index 98ee40c..a09b7f1 100644 (file)
 
 #include "GPUCommandBuffer.h"
 
+#include <wtf/Optional.h>
 #include <wtf/Ref.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
 
 namespace WebCore {
 
+class WebGPUBuffer;
 class WebGPURenderPassEncoder;
+class WebGPUTexture;
 
+struct GPUExtent3D;
 struct WebGPURenderPassDescriptor;
 
+struct WebGPUBufferCopyView : GPUBufferCopyViewBase {
+    Optional<GPUBufferCopyView> asGPUBufferCopyView() const;
+
+    RefPtr<WebGPUBuffer> buffer;
+};
+
+struct WebGPUTextureCopyView : GPUTextureCopyViewBase {
+    Optional<GPUTextureCopyView> asGPUTextureCopyView() const;
+
+    RefPtr<WebGPUTexture> texture;
+};
+
 class WebGPUCommandBuffer : public RefCounted<WebGPUCommandBuffer> {
 public:
     static Ref<WebGPUCommandBuffer> create(Ref<GPUCommandBuffer>&&);
@@ -46,6 +62,10 @@ public:
     const GPUCommandBuffer& commandBuffer() const { return m_commandBuffer.get(); }
 
     RefPtr<WebGPURenderPassEncoder> beginRenderPass(WebGPURenderPassDescriptor&&);
+    void copyBufferToBuffer(const WebGPUBuffer&, unsigned long srcOffset, const WebGPUBuffer&, unsigned long dstOffset, unsigned long size);
+    void copyBufferToTexture(const WebGPUBufferCopyView&, const WebGPUTextureCopyView&, const GPUExtent3D&);
+    void copyTextureToBuffer(const WebGPUTextureCopyView&, const WebGPUBufferCopyView&, const GPUExtent3D&);
+    void copyTextureToTexture(const WebGPUTextureCopyView&, const WebGPUTextureCopyView&, const GPUExtent3D&);
 
 private:
     WebGPUCommandBuffer(Ref<GPUCommandBuffer>&&);
index b9f42cf..1bd6f54 100644 (file)
  */
 // https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
 
+typedef unsigned long u32;
+typedef unsigned long long u64;
+
+[
+    Conditional=WEBGPU,
+    EnabledAtRuntime=WebGPU,
+    ImplementedAs=WebGPUBufferCopyView
+] dictionary GPUBufferCopyView {
+    WebGPUBuffer buffer;
+    u64 offset;
+    u64 rowPitch;
+    u32 imageHeight;
+};
+
+[
+    Conditional=WEBGPU,
+    EnabledAtRuntime=WebGPU,
+    ImplementedAs=WebGPUTextureCopyView
+] dictionary GPUTextureCopyView {
+    WebGPUTexture texture;
+    u32 mipLevel;
+    u32 arrayLayer;
+    GPUOrigin3D origin;
+};
+
 [
     Conditional=WEBGPU,
     EnabledAtRuntime=WebGPU,
 ] interface WebGPUCommandBuffer {
     WebGPURenderPassEncoder beginRenderPass(WebGPURenderPassDescriptor descriptor);
 
-/* Not Yet Implemented
-    WebGPUComputePassEncoder beginComputePass();
-
-    // Commands allowed outside of "passes"
-        void copyBufferToBuffer(
+    void copyBufferToBuffer(
         WebGPUBuffer src,
         u64 srcOffset,
         WebGPUBuffer dst,
         u64 size);
 
     void copyBufferToTexture(
-        WebGPUBufferCopyView source,
-        WebGPUTextureCopyView destination,
-        WebGPUExtent3D copySize);
+        GPUBufferCopyView source,
+        GPUTextureCopyView destination,
+        GPUExtent3D copySize);
 
     void copyTextureToBuffer(
-        WebGPUTextureCopyView source,
-        WebGPUBufferCopyView destination,
-        WebGPUExtent3D copySize);
+        GPUTextureCopyView source,
+        GPUBufferCopyView destination,
+        GPUExtent3D copySize);
 
     void copyTextureToTexture(
-        WebGPUTextureCopyView source,
-        WebGPUTextureCopyView destination,
-        WebGPUExtent3D copySize);
+        GPUTextureCopyView source,
+        GPUTextureCopyView destination,
+        GPUExtent3D copySize);
 
-    // TODO figure which other commands are needed
-    void blit();
-*/
+    // Not Yet Implemented
+    // WebGPUComputePassEncoder beginComputePass();
 };
index 2d28abc..bad14ca 100644 (file)
 
 namespace WebCore {
 
-GPURenderPassColorAttachmentDescriptor::GPURenderPassColorAttachmentDescriptor(Ref<GPUTexture>&& texture, GPULoadOp load, GPUStoreOp store, GPUColor color)
-    : GPURenderPassColorAttachmentDescriptorBase { load, store, color }
+GPURenderPassColorAttachmentDescriptor::GPURenderPassColorAttachmentDescriptor(Ref<GPUTexture>&& texture, const GPURenderPassColorAttachmentDescriptorBase& base)
+    : GPURenderPassColorAttachmentDescriptorBase(base)
     , attachment(WTFMove(texture))
 {
 }
 
-GPURenderPassDepthStencilAttachmentDescriptor::GPURenderPassDepthStencilAttachmentDescriptor(Ref<GPUTexture>&& texture, GPULoadOp load, GPUStoreOp store, float depth)
-    : GPURenderPassDepthStencilAttachmentDescriptorBase { load, store, depth }
+GPURenderPassDepthStencilAttachmentDescriptor::GPURenderPassDepthStencilAttachmentDescriptor(Ref<GPUTexture>&& texture, const GPURenderPassDepthStencilAttachmentDescriptorBase& base)
+    : GPURenderPassDepthStencilAttachmentDescriptorBase(base)
     , attachment(WTFMove(texture))
 {
 }
@@ -56,21 +56,21 @@ Optional<GPURenderPassDescriptor> WebGPURenderPassDescriptor::asGPURenderPassDes
     Vector<GPURenderPassColorAttachmentDescriptor> gpuColorAttachments;
 
     for (const auto& colorAttachment : colorAttachments) {
-        if (!colorAttachment.attachment) {
+        if (!colorAttachment.attachment || !colorAttachment.attachment->texture()->isOutputAttachment()) {
             LOG(WebGPU, "GPURenderPassDescriptor: Invalid attachment in GPURenderPassColorAttachmentDescriptor!");
             return WTF::nullopt;
         }
-        gpuColorAttachments.append(GPURenderPassColorAttachmentDescriptor(colorAttachment.attachment->texture(), colorAttachment.loadOp, colorAttachment.storeOp, colorAttachment.clearColor));
+        gpuColorAttachments.append(GPURenderPassColorAttachmentDescriptor { colorAttachment.attachment->texture(), colorAttachment });
     }
 
     Optional<GPURenderPassDepthStencilAttachmentDescriptor> gpuDepthAttachment;
 
     if (depthStencilAttachment) {
-        if (!depthStencilAttachment->attachment) {
+        if (!depthStencilAttachment->attachment || !depthStencilAttachment->attachment->texture()->isOutputAttachment()) {
             LOG(WebGPU, "GPURenderPassDescriptor: Invalid attachment in GPURenderPassDepthStencilAttachmentDescriptor!");
             return WTF::nullopt;
         }
-        gpuDepthAttachment = GPURenderPassDepthStencilAttachmentDescriptor(depthStencilAttachment->attachment->texture(), depthStencilAttachment->depthLoadOp, depthStencilAttachment->depthStoreOp, depthStencilAttachment->clearDepth);
+        gpuDepthAttachment = GPURenderPassDepthStencilAttachmentDescriptor { depthStencilAttachment->attachment->texture(), *depthStencilAttachment };
     }
 
     return GPURenderPassDescriptor { WTFMove(gpuColorAttachments), WTFMove(gpuDepthAttachment) };
index c590bdf..62fed98 100644 (file)
@@ -40,6 +40,8 @@ class WebGPUTexture : public RefCounted<WebGPUTexture> {
 public:
     static Ref<WebGPUTexture> create(RefPtr<GPUTexture>&&);
 
+    RefPtr<GPUTexture> texture() const { return m_texture; }
+
     RefPtr<WebGPUTextureView> createDefaultTextureView();
 
 private:
index 965d042..b575e68 100644 (file)
@@ -2775,6 +2775,7 @@ JSGPUCompareFunction.cpp
 JSGPUDepthStencilStateDescriptor.cpp
 JSGPUExtent3D.cpp
 JSGPULoadOp.cpp
+JSGPUOrigin3D.cpp
 JSGPURequestAdapterOptions.cpp
 JSGPUStoreOp.cpp
 JSGPUTextureDescriptor.cpp
index ac04cd4..8f0909b 100644 (file)
                D0CAAE9C216824A7001C91C7 /* WebMetalComputeCommandEncoder.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebMetalComputeCommandEncoder.cpp; sourceTree = "<group>"; };
                D0CAAE9D216824A7001C91C7 /* WebMetalBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebMetalBuffer.h; sourceTree = "<group>"; };
                D0CAAE9E216824A8001C91C7 /* WebMetalCommandBuffer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebMetalCommandBuffer.cpp; sourceTree = "<group>"; };
+               D0CCA94922299F97006979B6 /* GPUOrigin3D.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPUOrigin3D.h; sourceTree = "<group>"; };
+               D0CCA94A22299F97006979B6 /* GPUOrigin3D.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = GPUOrigin3D.idl; sourceTree = "<group>"; };
                D0D8648721B64CAA003C983C /* GPUBufferDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPUBufferDescriptor.h; sourceTree = "<group>"; };
                D0D8648C21B70676003C983C /* WebGPUBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebGPUBuffer.h; sourceTree = "<group>"; };
                D0D8648D21B70676003C983C /* WebGPUBuffer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebGPUBuffer.cpp; sourceTree = "<group>"; };
                                D03C84A221FFD7230002227F /* GPUDepthStencilStateDescriptor.idl */,
                                D026F480220A2B7000AC5F49 /* GPUExtent3D.idl */,
                                D08AA02D220D0B9C0058C502 /* GPULoadOp.idl */,
+                               D0CCA94922299F97006979B6 /* GPUOrigin3D.h */,
+                               D0CCA94A22299F97006979B6 /* GPUOrigin3D.idl */,
                                D02C26922181416D00D818E4 /* GPURequestAdapterOptions.idl */,
                                D08AA031220D0CE60058C502 /* GPUStoreOp.idl */,
                                D026F48B220A5B0B00AC5F49 /* GPUTextureDescriptor.idl */,
index d929fd1..b0ca27e 100644 (file)
@@ -30,6 +30,7 @@
 #include "DeferrableTask.h"
 #include "GPUBufferUsage.h"
 #include <wtf/Function.h>
+#include <wtf/OptionSet.h>
 #include <wtf/Ref.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RetainPtr.h>
@@ -70,12 +71,14 @@ public:
     static RefPtr<GPUBuffer> tryCreate(Ref<GPUDevice>&&, GPUBufferDescriptor&&);
 
     PlatformBuffer *platformBuffer() const { return m_platformBuffer.get(); }
-    bool isTransferDst() const { return m_usage & GPUBufferUsage::TransferDst; }
-    bool isVertex() const { return m_usage & GPUBufferUsage::Vertex; }
-    bool isUniform() const { return m_usage & GPUBufferUsage::Uniform; }
-    bool isStorage() const { return m_usage & GPUBufferUsage::Storage; }
+    unsigned long byteLength() const { return m_byteLength; }
+    bool isTransferSource() const { return m_usage.contains(GPUBufferUsage::Flags::TransferSource); }
+    bool isTransferDestination() const { return m_usage.contains(GPUBufferUsage::Flags::TransferDestination); }
+    bool isVertex() const { return m_usage.contains(GPUBufferUsage::Flags::Vertex); }
+    bool isUniform() const { return m_usage.contains(GPUBufferUsage::Flags::Uniform); }
+    bool isStorage() const { return m_usage.contains(GPUBufferUsage::Flags::Storage); }
     bool isReadOnly() const;
-    bool isMappable() const { return m_usage & (GPUBufferUsage::MapWrite | GPUBufferUsage::MapRead); }
+    bool isMappable() const { return m_usage.containsAny({ GPUBufferUsage::Flags::MapWrite, GPUBufferUsage::Flags::MapRead }); }
     State state() const;
 
 #if USE(METAL)
@@ -104,16 +107,16 @@ private:
         PendingMappingCallback(MappingCallback&&);
     };
 
-    static bool validateBufferCreate(const GPUDevice&, const GPUBufferDescriptor&);
+    static bool validateBufferUsage(const GPUDevice&, OptionSet<GPUBufferUsage::Flags>);
 
-    GPUBuffer(PlatformBufferSmartPtr&&, const GPUBufferDescriptor&, Ref<GPUDevice>&&);
+    GPUBuffer(PlatformBufferSmartPtr&&, const GPUBufferDescriptor&, OptionSet<GPUBufferUsage::Flags>, Ref<GPUDevice>&&);
 
     JSC::ArrayBuffer* stagingBufferForRead();
     JSC::ArrayBuffer* stagingBufferForWrite();
     void runMappingCallback();
 
-    bool isMapWrite() const { return m_usage & GPUBufferUsage::MapWrite; }
-    bool isMapRead() const { return m_usage & GPUBufferUsage::MapRead; }
+    bool isMapWrite() const { return m_usage.contains(GPUBufferUsage::Flags::MapWrite); }
+    bool isMapRead() const { return m_usage.contains(GPUBufferUsage::Flags::MapRead); }
     bool isMapWriteable() const { return isMapWrite() && state() == State::Unmapped; }
     bool isMapReadable() const { return isMapRead() && state() == State::Unmapped; }
 
@@ -129,7 +132,7 @@ private:
     DeferrableTask<Timer> m_mappingCallbackTask;
 
     unsigned long m_byteLength;
-    GPUBufferUsage::Flags m_usage;
+    OptionSet<GPUBufferUsage::Flags> m_usage;
     unsigned m_numScheduledCommandBuffers = 0;
 };
 
index d2c4a67..983db48 100644 (file)
 
 namespace WebCore {
 
-using GPUBufferUsageFlags = unsigned long;
+using GPUBufferUsageFlags = unsigned;
 
 class GPUBufferUsage : public RefCounted<GPUBufferUsage> {
 public:
-    enum Flags : GPUBufferUsageFlags {
+    enum class Flags : GPUBufferUsageFlags {
         None = 0,
-        MapRead = 1,
-        MapWrite = 2,
-        TransferSrc = 4,
-        TransferDst = 8,
-        Index = 16,
-        Vertex = 32,
-        Uniform = 64,
-        Storage = 128
+        MapRead = 1 << 0,
+        MapWrite = 1 << 1,
+        TransferSource = 1 << 2,
+        TransferDestination = 1 << 3,
+        Index = 1 << 4,
+        Vertex = 1 << 5,
+        Uniform = 1 << 6,
+        Storage = 1 << 7,
     };
 };
 
index 99bcef0..a5825c1 100644 (file)
 
 #if ENABLE(WEBGPU)
 
+#include "GPUOrigin3D.h"
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
 #include <wtf/RetainPtr.h>
 #include <wtf/Vector.h>
 
+OBJC_PROTOCOL(MTLBlitCommandEncoder);
 OBJC_PROTOCOL(MTLCommandBuffer);
 
 namespace WebCore {
 
 class GPUBuffer;
 class GPUDevice;
+class GPUTexture;
+
+struct GPUExtent3D;
 
 using PlatformCommandBuffer = MTLCommandBuffer;
 using PlatformCommandBufferSmartPtr = RetainPtr<MTLCommandBuffer>;
 
+struct GPUBufferCopyViewBase {
+    unsigned long offset;
+    unsigned long rowPitch;
+    unsigned imageHeight;
+};
+
+struct GPUBufferCopyView final : GPUBufferCopyViewBase {
+    GPUBufferCopyView(Ref<GPUBuffer>&& bufferCopy, const GPUBufferCopyViewBase& base)
+        : GPUBufferCopyViewBase(base)
+        , buffer(WTFMove(bufferCopy))
+    {
+    }
+
+    Ref<GPUBuffer> buffer;
+};
+
+struct GPUTextureCopyViewBase {
+    unsigned mipLevel;
+    unsigned arrayLayer;
+    GPUOrigin3D origin;
+};
+
+struct GPUTextureCopyView final : GPUTextureCopyViewBase {
+    GPUTextureCopyView(Ref<GPUTexture>&& textureCopy, const GPUTextureCopyViewBase& base)
+        : GPUTextureCopyViewBase(base)
+        , texture(WTFMove(textureCopy))
+    {
+    }
+
+    Ref<GPUTexture> texture;
+};
+
 class GPUCommandBuffer : public RefCounted<GPUCommandBuffer> {
 public:
     static RefPtr<GPUCommandBuffer> create(GPUDevice&);
 
     PlatformCommandBuffer* platformCommandBuffer() const { return m_platformCommandBuffer.get(); }
     const Vector<Ref<GPUBuffer>>& usedBuffers() const { return m_usedBuffers; }
+#if USE(METAL)
+    MTLBlitCommandEncoder *blitEncoder() const;
+#endif
+
+    void copyBufferToBuffer(Ref<GPUBuffer>&&, unsigned long srcOffset, Ref<GPUBuffer>&&, unsigned long dstOffset, unsigned long size);
+    void copyBufferToTexture(const GPUBufferCopyView&, const GPUTextureCopyView&, const GPUExtent3D&);
+    void copyTextureToBuffer(const GPUTextureCopyView&, const GPUBufferCopyView&, const GPUExtent3D&);
+    void copyTextureToTexture(const GPUTextureCopyView&, const GPUTextureCopyView&, const GPUExtent3D&);
 
     void useBuffer(Ref<GPUBuffer>&& buffer) { m_usedBuffers.append(WTFMove(buffer)); }
 
@@ -56,6 +101,9 @@ private:
 
     PlatformCommandBufferSmartPtr m_platformCommandBuffer;
     Vector<Ref<GPUBuffer>> m_usedBuffers;
+#if USE(METAL)
+    mutable RetainPtr<MTLBlitCommandEncoder> m_blitEncoder;
+#endif
 };
 
 } // namespace WebCore
index f4ac69a..d64cf5f 100644 (file)
@@ -43,7 +43,7 @@ struct GPURenderPassColorAttachmentDescriptorBase {
 };
 
 struct GPURenderPassColorAttachmentDescriptor final : GPURenderPassColorAttachmentDescriptorBase {
-    GPURenderPassColorAttachmentDescriptor(Ref<GPUTexture>&&, GPULoadOp, GPUStoreOp, GPUColor);
+    GPURenderPassColorAttachmentDescriptor(Ref<GPUTexture>&&, const GPURenderPassColorAttachmentDescriptorBase&);
 
     Ref<GPUTexture> attachment;
 };
@@ -57,7 +57,7 @@ struct GPURenderPassDepthStencilAttachmentDescriptorBase {
 };
 
 struct GPURenderPassDepthStencilAttachmentDescriptor final : GPURenderPassDepthStencilAttachmentDescriptorBase {
-    GPURenderPassDepthStencilAttachmentDescriptor(Ref<GPUTexture>&&, GPULoadOp, GPUStoreOp, float);
+    GPURenderPassDepthStencilAttachmentDescriptor(Ref<GPUTexture>&&, const GPURenderPassDepthStencilAttachmentDescriptorBase&);
 
     Ref<GPUTexture> attachment;
 };
index 55d1e3c..9a3693a 100644 (file)
@@ -27,6 +27,8 @@
 
 #if ENABLE(WEBGPU)
 
+#include "GPUTextureUsage.h"
+#include <wtf/OptionSet.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
 #include <wtf/RetainPtr.h>
@@ -44,17 +46,22 @@ using PlatformTextureSmartPtr = RetainPtr<MTLTexture>;
 
 class GPUTexture : public RefCounted<GPUTexture> {
 public:
-    static RefPtr<GPUTexture> tryCreate(const GPUDevice&, GPUTextureDescriptor&&);
-    static Ref<GPUTexture> create(PlatformTextureSmartPtr&&);
+    static RefPtr<GPUTexture> tryCreate(const GPUDevice&, const GPUTextureDescriptor&);
+    static Ref<GPUTexture> create(PlatformTextureSmartPtr&&, OptionSet<GPUTextureUsage::Flags>);
 
     PlatformTexture *platformTexture() const { return m_platformTexture.get(); }
+    bool isTransferSource() const { return m_usage.contains(GPUTextureUsage::Flags::TransferSource); }
+    bool isTransferDestination() const { return m_usage.contains(GPUTextureUsage::Flags::TransferDestination); }
+    bool isOutputAttachment() const { return m_usage.contains(GPUTextureUsage::Flags::OutputAttachment); }
 
     RefPtr<GPUTexture> createDefaultTextureView();
 
 private:
-    explicit GPUTexture(PlatformTextureSmartPtr&&);
+    explicit GPUTexture(PlatformTextureSmartPtr&&, OptionSet<GPUTextureUsage::Flags>);
 
     PlatformTextureSmartPtr m_platformTexture;
+
+    OptionSet<GPUTextureUsage::Flags> m_usage;
 };
 
 } // namespace WebCore
index 17a0300..6289f92 100644 (file)
 
 namespace WebCore {
     
-using GPUTextureUsageFlags = unsigned long;
+using GPUTextureUsageFlags = unsigned;
     
 class GPUTextureUsage : public RefCounted<GPUTextureUsage> {
 public:
-    static const GPUTextureUsageFlags None = 0;
-    static const GPUTextureUsageFlags TransferSrc = 1;
-    static const GPUTextureUsageFlags TransferDst = 2;
-    static const GPUTextureUsageFlags Sampled = 4;
-    static const GPUTextureUsageFlags Storage = 8;
-    static const GPUTextureUsageFlags OutputAttachment = 16;
+    enum class Flags : GPUTextureUsageFlags {
+        None = 0,
+        TransferSource = 1 << 0,
+        TransferDestination = 1 << 1,
+        Sampled = 1 << 2,
+        Storage = 1 << 3,
+        OutputAttachment = 1 << 4,
+    };
 };
 
 } // namespace WebCore
index 0d8c208..869ae90 100644 (file)
 
 namespace WebCore {
 
-static const auto readOnlyMask = GPUBufferUsage::Index | GPUBufferUsage::Vertex | GPUBufferUsage::Uniform | GPUBufferUsage::TransferSrc;
+static const auto readOnlyFlags = OptionSet<GPUBufferUsage::Flags> { GPUBufferUsage::Flags::Index, GPUBufferUsage::Flags::Vertex, GPUBufferUsage::Flags::Uniform, GPUBufferUsage::Flags::TransferSource };
 
 
-bool GPUBuffer::validateBufferCreate(const GPUDevice& device, const GPUBufferDescriptor& descriptor)
+bool GPUBuffer::validateBufferUsage(const GPUDevice& device, OptionSet<GPUBufferUsage::Flags> usage)
 {
     if (!device.platformDevice()) {
         LOG(WebGPU, "GPUBuffer::create(): Invalid GPUDevice!");
         return false;
     }
 
-    if ((descriptor.usage & GPUBufferUsage::MapWrite) && (descriptor.usage & GPUBufferUsage::MapRead)) {
+    if (usage.containsAll({ GPUBufferUsage::Flags::MapWrite, GPUBufferUsage::Flags::MapRead })) {
         LOG(WebGPU, "GPUBuffer::create(): Buffer cannot have both MAP_READ and MAP_WRITE usage!");
         return false;
     }
 
-    if ((descriptor.usage & readOnlyMask) && (descriptor.usage & GPUBufferUsage::Storage)) {
+    if (usage.containsAny(readOnlyFlags) && (usage & GPUBufferUsage::Flags::Storage)) {
         LOG(WebGPU, "GPUBuffer::create(): Buffer cannot have both STORAGE and a read-only usage!");
         return false;
     }
@@ -64,7 +64,8 @@ bool GPUBuffer::validateBufferCreate(const GPUDevice& device, const GPUBufferDes
 
 RefPtr<GPUBuffer> GPUBuffer::tryCreate(Ref<GPUDevice>&& device, GPUBufferDescriptor&& descriptor)
 {
-    if (!validateBufferCreate(device.get(), descriptor))
+    auto usage = OptionSet<GPUBufferUsage::Flags>::fromRaw(descriptor.usage);
+    if (!validateBufferUsage(device.get(), usage))
         return nullptr;
 
     // FIXME: Metal best practices: Read-only one-time-use data less than 4 KB should not allocate a MTLBuffer and be used in [MTLCommandEncoder set*Bytes] calls instead.
@@ -72,7 +73,7 @@ RefPtr<GPUBuffer> GPUBuffer::tryCreate(Ref<GPUDevice>&& device, GPUBufferDescrip
     MTLResourceOptions resourceOptions = MTLResourceCPUCacheModeDefaultCache;
 
     // Mappable buffers use shared storage allocation.
-    resourceOptions |= (descriptor.usage & (GPUBufferUsage::MapWrite | GPUBufferUsage::MapRead)) ? MTLResourceStorageModeShared : MTLResourceStorageModePrivate;
+    resourceOptions |= usage.containsAny({ GPUBufferUsage::Flags::MapWrite, GPUBufferUsage::Flags::MapRead }) ? MTLResourceStorageModeShared : MTLResourceStorageModePrivate;
 
     RetainPtr<MTLBuffer> mtlBuffer;
 
@@ -87,14 +88,14 @@ RefPtr<GPUBuffer> GPUBuffer::tryCreate(Ref<GPUDevice>&& device, GPUBufferDescrip
         return nullptr;
     }
 
-    return adoptRef(*new GPUBuffer(WTFMove(mtlBuffer), descriptor, WTFMove(device)));
+    return adoptRef(*new GPUBuffer(WTFMove(mtlBuffer), descriptor, usage, WTFMove(device)));
 }
 
-GPUBuffer::GPUBuffer(RetainPtr<MTLBuffer>&& buffer, const GPUBufferDescriptor& descriptor, Ref<GPUDevice>&& device)
+GPUBuffer::GPUBuffer(RetainPtr<MTLBuffer>&& buffer, const GPUBufferDescriptor& descriptor, OptionSet<GPUBufferUsage::Flags> usage, Ref<GPUDevice>&& device)
     : m_platformBuffer(WTFMove(buffer))
     , m_device(WTFMove(device))
     , m_byteLength(descriptor.size)
-    , m_usage(static_cast<GPUBufferUsage::Flags>(descriptor.usage))
+    , m_usage(usage)
 {
 }
 
@@ -105,7 +106,7 @@ GPUBuffer::~GPUBuffer()
 
 bool GPUBuffer::isReadOnly() const
 {
-    return m_usage & readOnlyMask;
+    return m_usage.containsAny(readOnlyFlags);
 }
 
 GPUBuffer::State GPUBuffer::state() const
@@ -120,18 +121,24 @@ GPUBuffer::State GPUBuffer::state() const
 
 void GPUBuffer::setSubData(unsigned long offset, const JSC::ArrayBuffer& data)
 {
-    if (!isTransferDst() || state() != State::Unmapped) {
+    if (!isTransferDestination() || state() != State::Unmapped) {
         LOG(WebGPU, "GPUBuffer::setSubData(): Invalid operation!");
         return;
     }
+
+#if PLATFORM(MAC)
+    if (offset % 4 || data.byteLength() % 4) {
+        LOG(WebGPU, "GPUBuffer::setSubData(): Data must be aligned to a multiple of 4 bytes!");
+        return;
+    }
+#endif
+
     auto subDataLength = checkedSum<unsigned long>(data.byteLength(), offset);
     if (subDataLength.hasOverflowed() || subDataLength.unsafeGet() > m_byteLength) {
         LOG(WebGPU, "GPUBuffer::setSubData(): Invalid offset or data size!");
         return;
     }
 
-    // FIXME: Add alignment checks once specified.
-
     if (m_subDataBuffers.isEmpty()) {
         BEGIN_BLOCK_OBJC_EXCEPTIONS;
         m_subDataBuffers.append(adoptNS([m_platformBuffer.get().device newBufferWithLength:m_byteLength options:MTLResourceCPUCacheModeDefaultCache]));
index 93edc11..b0a976d 100644 (file)
 
 #if ENABLE(WEBGPU)
 
+#import "GPUBuffer.h"
 #import "GPUDevice.h"
+#import "GPUExtent3D.h"
 #import "GPUQueue.h"
+#import "GPUTexture.h"
 #import "Logging.h"
 
 #import <Metal/Metal.h>
 #import <wtf/BlockObjCExceptions.h>
+#import <wtf/CheckedArithmetic.h>
 
 namespace WebCore {
 
@@ -50,7 +54,7 @@ RefPtr<GPUCommandBuffer> GPUCommandBuffer::create(GPUDevice& device)
 
     auto mtlQueue = gpuCommandQueue->platformQueue();
 
-    PlatformCommandBufferSmartPtr buffer;
+    RetainPtr<MTLCommandBuffer> buffer;
 
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
@@ -66,11 +70,142 @@ RefPtr<GPUCommandBuffer> GPUCommandBuffer::create(GPUDevice& device)
     return adoptRef(new GPUCommandBuffer(WTFMove(buffer)));
 }
 
-GPUCommandBuffer::GPUCommandBuffer(PlatformCommandBufferSmartPtr&& buffer)
+GPUCommandBuffer::GPUCommandBuffer(RetainPtr<MTLCommandBuffer>&& buffer)
     : m_platformCommandBuffer(WTFMove(buffer))
 {
 }
 
+MTLBlitCommandEncoder *GPUCommandBuffer::blitEncoder() const
+{
+    return m_blitEncoder ? m_blitEncoder.get() : (m_blitEncoder = [m_platformCommandBuffer blitCommandEncoder]).get();
+}
+
+void GPUCommandBuffer::copyBufferToBuffer(Ref<GPUBuffer>&& src, unsigned long srcOffset, Ref<GPUBuffer>&& dst, unsigned long dstOffset, unsigned long size)
+{
+    if (!src->isTransferSource() || !dst->isTransferDestination()) {
+        LOG(WebGPU, "GPUCommandBuffer::copyBufferToBuffer(): Invalid operation!");
+        return;
+    }
+
+#if PLATFORM(MAC)
+    if (size % 4 || srcOffset % 4 || dstOffset % 4) {
+        LOG(WebGPU, "GPUCommandBuffer::copyBufferToBuffer(): Copy must be aligned to a multiple of 4 bytes!");
+        return;
+    }
+#endif
+
+    auto srcLength = checkedSum<unsigned long>(size, srcOffset);
+    auto dstLength = checkedSum<unsigned long>(size, dstOffset);
+    if (srcLength.hasOverflowed() || dstLength.hasOverflowed()
+        || srcLength.unsafeGet() > src->byteLength() || dstLength.unsafeGet() > dst->byteLength()) {
+        LOG(WebGPU, "GPUCommandBuffer::copyBufferToBuffer(): Invalid offset or copy size!");
+        return;
+    }
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+    [blitEncoder()
+        copyFromBuffer:src->platformBuffer()
+        sourceOffset:srcOffset
+        toBuffer:dst->platformBuffer()
+        destinationOffset:dstOffset
+        size:size];
+
+    END_BLOCK_OBJC_EXCEPTIONS;
+
+    useBuffer(WTFMove(src));
+    useBuffer(WTFMove(dst));
+}
+
+void GPUCommandBuffer::copyBufferToTexture(const GPUBufferCopyView& srcBuffer, const GPUTextureCopyView& dstTexture, const GPUExtent3D& size)
+{
+    if (!srcBuffer.buffer->isTransferSource() || !dstTexture.texture->isTransferDestination()) {
+        LOG(WebGPU, "GPUComandBuffer::copyBufferToTexture(): Invalid operation!");
+        return;
+    }
+
+    // FIXME: Add Metal validation.
+
+    // GPUBufferCopyView::offset: The location must be aligned to the size of the destination texture's pixel format. The value must be a multiple of the destination texture's pixel size, in bytes.
+
+    // GPUBufferCopyView::rowPitch: The value must be a multiple of the destination texture's pixel size, in bytes. The value must be less than or equal to 32,767 multiplied by the destination texture’s pixel size.
+
+    // GPUBufferCopyView::imageHeight: The value must be a multiple of the destination texture's pixel size, in bytes.
+
+    // GPUExtent3D: When you copy to a 1D texture, height and depth must be 1. When you copy to a 2D texture, depth must be 1.
+
+    // GPUTextureCopyView::texture: The value must not be a framebufferOnly texture and must not have a PVRTC pixel format.
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+    [blitEncoder()
+        copyFromBuffer:srcBuffer.buffer->platformBuffer()
+        sourceOffset:srcBuffer.offset
+        sourceBytesPerRow:srcBuffer.rowPitch
+        sourceBytesPerImage:srcBuffer.imageHeight
+        sourceSize:MTLSizeMake(size.width, size.height, size.depth)
+        toTexture:dstTexture.texture->platformTexture()
+        destinationSlice:dstTexture.arrayLayer
+        destinationLevel:dstTexture.mipLevel
+        destinationOrigin:MTLOriginMake(dstTexture.origin.x, dstTexture.origin.y, dstTexture.origin.z)];
+
+    END_BLOCK_OBJC_EXCEPTIONS;
+
+    useBuffer(srcBuffer.buffer.copyRef());
+}
+
+void GPUCommandBuffer::copyTextureToBuffer(const GPUTextureCopyView& srcTexture, const GPUBufferCopyView& dstBuffer, const GPUExtent3D& size)
+{
+    if (!srcTexture.texture->isTransferSource() || !dstBuffer.buffer->isTransferDestination()) {
+        LOG(WebGPU, "GPUCommandBuffer::copyTextureToBuffer(): Invalid operation!");
+        return;
+    }
+
+    // FIXME: Add Metal validation?
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+    [blitEncoder()
+        copyFromTexture:srcTexture.texture->platformTexture()
+        sourceSlice:srcTexture.arrayLayer
+        sourceLevel:srcTexture.mipLevel
+        sourceOrigin:MTLOriginMake(srcTexture.origin.x, srcTexture.origin.y, srcTexture.origin.z)
+        sourceSize:MTLSizeMake(size.width, size.height, size.depth)
+        toBuffer:dstBuffer.buffer->platformBuffer()
+        destinationOffset:dstBuffer.offset
+        destinationBytesPerRow:dstBuffer.rowPitch
+        destinationBytesPerImage:dstBuffer.imageHeight];
+
+    END_BLOCK_OBJC_EXCEPTIONS;
+
+    useBuffer(dstBuffer.buffer.copyRef());
+}
+
+void GPUCommandBuffer::copyTextureToTexture(const GPUTextureCopyView& src, const GPUTextureCopyView& dst, const GPUExtent3D& size)
+{
+    if (!src.texture->isTransferSource() || !dst.texture->isTransferDestination()) {
+        LOG(WebGPU, "GPUCommandBuffer::copyTextureToTexture(): Invalid operation!");
+        return;
+    }
+
+    // FIXME: Add Metal validation?
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+    [blitEncoder()
+        copyFromTexture:src.texture->platformTexture()
+        sourceSlice:src.arrayLayer
+        sourceLevel:src.mipLevel
+        sourceOrigin:MTLOriginMake(src.origin.x, src.origin.y, src.origin.z)
+        sourceSize:MTLSizeMake(size.width, size.height, size.depth)
+        toTexture:dst.texture->platformTexture()
+        destinationSlice:src.arrayLayer
+        destinationLevel:src.mipLevel
+        destinationOrigin:MTLOriginMake(dst.origin.x, dst.origin.y, dst.origin.z)];
+
+    END_BLOCK_OBJC_EXCEPTIONS;
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(WEBGPU)
index 91bbd5a..b99e3c6 100644 (file)
@@ -72,7 +72,11 @@ GPUQueue::GPUQueue(PlatformQueueSmartPtr&& queue)
 
 void GPUQueue::submit(Vector<Ref<const GPUCommandBuffer>>&& commandBuffers)
 {
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
     for (auto& commandBuffer : commandBuffers) {
+        if (commandBuffer->blitEncoder())
+            [commandBuffer->blitEncoder() endEncoding];
         // Prevent any buffer mapping callbacks from executing until command buffer is complete.
         for (auto& buffer : commandBuffer->usedBuffers()) {
             if (buffer->state() != GPUBuffer::State::Unmapped) {
@@ -84,6 +88,8 @@ void GPUQueue::submit(Vector<Ref<const GPUCommandBuffer>>&& commandBuffers)
 
         [commandBuffer->platformCommandBuffer() commit];
     }
+
+    END_BLOCK_OBJC_EXCEPTIONS;
 }
 
 String GPUQueue::label() const
index 15502e9..d2cb824 100644 (file)
@@ -117,7 +117,7 @@ RefPtr<GPUTexture> GPUSwapChain::getNextTexture()
         return nullptr;
     }
 
-    return GPUTexture::create(WTFMove(mtlTexture));
+    return GPUTexture::create(WTFMove(mtlTexture), GPUTextureUsage::Flags::OutputAttachment);
 }
 
 void GPUSwapChain::present()
index b793e02..1a157bc 100644 (file)
@@ -54,25 +54,32 @@ static MTLTextureType mtlTextureTypeForGPUTextureDescriptor(const GPUTextureDesc
     }
 }
 
-static Optional<MTLTextureUsage> mtlTextureUsageForGPUTextureUsageFlags(GPUTextureUsageFlags flags)
+static Optional<MTLTextureUsage> mtlTextureUsageForGPUTextureUsageFlags(OptionSet<GPUTextureUsage::Flags> flags, const char* const functionName)
 {
-    MTLTextureUsage usage = MTLTextureUsageUnknown;
-
-    if (flags & GPUTextureUsage::Storage)
-        usage |= MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead | MTLTextureUsagePixelFormatView;
+#if LOG_DISABLED
+    UNUSED_PARAM(functionName);
+#endif
+    if (flags.containsAny({ GPUTextureUsage::Flags::TransferSource, GPUTextureUsage::Flags::Sampled }) && (flags & GPUTextureUsage::Flags::Storage)) {
+        LOG(WebGPU, "%s: Texture cannot have both STORAGE and a read-only usage!", functionName);
+        return WTF::nullopt;
+    }
 
-    if (flags & GPUTextureUsage::Sampled) {
-        // SAMPLED is a read-only usage.
-        if (flags & GPUTextureUsage::Storage)
+    if (flags & GPUTextureUsage::Flags::OutputAttachment) {
+        if (flags.containsAny({ GPUTextureUsage::Flags::Storage, GPUTextureUsage::Flags::Sampled })) {
+            LOG(WebGPU, "%s: Texture cannot have OUTPUT_ATTACHMENT usage with STORAGE or SAMPLED usages!", functionName);
             return WTF::nullopt;
+        }
 
-        usage |= MTLTextureUsageShaderRead | MTLTextureUsagePixelFormatView;
+        return MTLTextureUsageRenderTarget | MTLTextureUsagePixelFormatView;
     }
 
-    if (flags & GPUTextureUsage::OutputAttachment)
-        usage |= MTLTextureUsageRenderTarget;
+    if (flags & GPUTextureUsage::Flags::Storage)
+        return MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead | MTLTextureUsagePixelFormatView;
+
+    if (flags & GPUTextureUsage::Flags::Sampled)
+        return MTLTextureUsageShaderRead | MTLTextureUsagePixelFormatView;
 
-    return usage;
+    return MTLTextureUsageUnknown;
 }
 
 static MTLStorageMode storageModeForPixelFormatAndSampleCount(MTLPixelFormat format, unsigned long samples)
@@ -88,12 +95,8 @@ static MTLStorageMode storageModeForPixelFormatAndSampleCount(MTLPixelFormat for
 #endif
 }
 
-static RetainPtr<MTLTextureDescriptor> tryCreateMtlTextureDescriptor(const char* const functionName, const GPUTextureDescriptor&& descriptor)
+static RetainPtr<MTLTextureDescriptor> tryCreateMtlTextureDescriptor(const char* const functionName, const GPUTextureDescriptor& descriptor, OptionSet<GPUTextureUsage::Flags> usage)
 {
-#if LOG_DISABLED
-    UNUSED_PARAM(functionName);
-#endif
-
     RetainPtr<MTLTextureDescriptor> mtlDescriptor;
 
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
@@ -110,11 +113,9 @@ static RetainPtr<MTLTextureDescriptor> tryCreateMtlTextureDescriptor(const char*
     // FIXME: Add more validation as constraints are added to spec.
     auto pixelFormat = static_cast<MTLPixelFormat>(platformTextureFormatForGPUTextureFormat(descriptor.format));
 
-    auto usage = mtlTextureUsageForGPUTextureUsageFlags(descriptor.usage);
-    if (!usage) {
-        LOG(WebGPU, "%s: Invalid GPUTextureUsageFlags!", functionName);
+    auto mtlUsage = mtlTextureUsageForGPUTextureUsageFlags(usage, functionName);
+    if (!mtlUsage)
         return nullptr;
-    }
 
     auto storageMode = storageModeForPixelFormatAndSampleCount(pixelFormat, descriptor.sampleCount);
 
@@ -128,7 +129,7 @@ static RetainPtr<MTLTextureDescriptor> tryCreateMtlTextureDescriptor(const char*
     [mtlDescriptor setSampleCount:descriptor.sampleCount];
     [mtlDescriptor setTextureType:mtlTextureTypeForGPUTextureDescriptor(descriptor)];
     [mtlDescriptor setPixelFormat:pixelFormat];
-    [mtlDescriptor setUsage:*usage];
+    [mtlDescriptor setUsage:*mtlUsage];
 
     [mtlDescriptor setStorageMode:storageMode];
 
@@ -137,7 +138,7 @@ static RetainPtr<MTLTextureDescriptor> tryCreateMtlTextureDescriptor(const char*
     return mtlDescriptor;
 }
 
-RefPtr<GPUTexture> GPUTexture::tryCreate(const GPUDevice& device, GPUTextureDescriptor&& descriptor)
+RefPtr<GPUTexture> GPUTexture::tryCreate(const GPUDevice& device, const GPUTextureDescriptor& descriptor)
 {
     const char* const functionName = "GPUTexture::tryCreate()";
 
@@ -146,7 +147,8 @@ RefPtr<GPUTexture> GPUTexture::tryCreate(const GPUDevice& device, GPUTextureDesc
         return nullptr;
     }
 
-    auto mtlDescriptor = tryCreateMtlTextureDescriptor(functionName, WTFMove(descriptor));
+    auto usage = OptionSet<GPUTextureUsage::Flags>::fromRaw(descriptor.usage);
+    auto mtlDescriptor = tryCreateMtlTextureDescriptor(functionName, descriptor, usage);
     if (!mtlDescriptor)
         return nullptr;
 
@@ -163,16 +165,17 @@ RefPtr<GPUTexture> GPUTexture::tryCreate(const GPUDevice& device, GPUTextureDesc
         return nullptr;
     }
 
-    return adoptRef(new GPUTexture(WTFMove(mtlTexture)));
+    return adoptRef(new GPUTexture(WTFMove(mtlTexture), usage));
 }
 
-Ref<GPUTexture> GPUTexture::create(PlatformTextureSmartPtr&& texture)
+Ref<GPUTexture> GPUTexture::create(PlatformTextureSmartPtr&& texture, OptionSet<GPUTextureUsage::Flags> usage)
 {
-    return adoptRef(*new GPUTexture(WTFMove(texture)));
+    return adoptRef(*new GPUTexture(WTFMove(texture), usage));
 }
 
-GPUTexture::GPUTexture(PlatformTextureSmartPtr&& texture)
+GPUTexture::GPUTexture(PlatformTextureSmartPtr&& texture, OptionSet<GPUTextureUsage::Flags> usage)
     : m_platformTexture(WTFMove(texture))
+    , m_usage(usage)
 {
 }
 
@@ -191,7 +194,7 @@ RefPtr<GPUTexture> GPUTexture::createDefaultTextureView()
         return nullptr;
     }
 
-    return GPUTexture::create(WTFMove(texture));
+    return GPUTexture::create(WTFMove(texture), m_usage);
 }
 
 } // namespace WebCore