Title: [241996] trunk
Revision
241996
Author
justin_...@apple.com
Date
2019-02-23 15:24:27 -0800 (Sat, 23 Feb 2019)

Log Message

[WebGPU] Buffer updates part 1: async mapping functions, unmap, and destroy
https://bugs.webkit.org/show_bug.cgi?id=194665

Reviewed by Dean Jackson.

Source/WebCore:

Test: map-write-buffers.html. Other tests updated to match new API.

* Modules/webgpu/WebGPUBindGroupDescriptor.cpp: Added.
(WebCore::validateBufferBindingType): Ensure buffer binding usages match the binding type.
(WebCore::WebGPUBindGroupDescriptor::asGPUBindGroupDescriptor const): Logic moved out from WebGPUDevice.cpp.
* Modules/webgpu/WebGPUBindGroupDescriptor.h:
* Modules/webgpu/WebGPUBuffer.cpp: Added GPUBuffer functionality.
(WebCore::WebGPUBuffer::create):
(WebCore::WebGPUBuffer::WebGPUBuffer):
(WebCore::WebGPUBuffer::mapReadAsync):
(WebCore::WebGPUBuffer::mapWriteAsync):
(WebCore::WebGPUBuffer::unmap):
(WebCore::WebGPUBuffer::destroy):
(WebCore::WebGPUBuffer::rejectOrRegisterPromiseCallback): Register a mapping request on the GPUBuffer, if valid.
* Modules/webgpu/WebGPUBuffer.h:
(WebCore::WebGPUBuffer::buffer const):
(WebCore::WebGPUBuffer::mapping const): Deleted.
* Modules/webgpu/WebGPUBuffer.idl: Update to latest API and enable every function except setSubData.
* Modules/webgpu/WebGPUCommandBuffer.cpp:
(WebCore::WebGPUCommandBuffer::beginRenderPass): Renamed descriptor conversion method.
* Modules/webgpu/WebGPUDevice.cpp:
(WebCore::WebGPUDevice::createBuffer const): Update to non-nullable return type.
(WebCore::WebGPUDevice::createBindGroup const): Move descriptor validation logic to descriptor implementation.
* Modules/webgpu/WebGPUDevice.h:
* Modules/webgpu/WebGPURenderPassDescriptor.cpp:
(WebCore::WebGPURenderPassDescriptor::asGPURenderPassDescriptor const): Renamed from validateAndConvertToGPUVersion.
* Modules/webgpu/WebGPURenderPassEncoder.cpp:
(WebCore::WebGPURenderPassEncoder::setVertexBuffers): Add validation for submitted buffers.
* platform/graphics/gpu/GPUBuffer.cpp: Added.
(WebCore::GPUBuffer::PendingMappingCallback::PendingMappingCallback): New struct for retaining a reference to mapping callbacks.
* platform/graphics/gpu/GPUBuffer.h: Add functionality to retain callbacks and usage bits.
(WebCore::GPUBuffer::isVertex const):
(WebCore::GPUBuffer::isUniform const):
(WebCore::GPUBuffer::isStorage const):
(WebCore::GPUBuffer::isReadOnly const):
(WebCore::GPUBuffer::PendingMapPromise::create):
(WebCore::GPUBuffer::isMappable const):
(WebCore::GPUBuffer::isMapWriteable const):
(WebCore::GPUBuffer::isMapReadable const):
(WebCore::GPUBuffer::mapping const): Deleted.
* platform/graphics/gpu/GPUBufferUsage.h: enum class cannot be logical ORed together.
* platform/graphics/gpu/GPUDevice.cpp:
(WebCore::GPUDevice::tryCreateBuffer const): Renamed from createBuffer.
(WebCore::GPUDevice::createBuffer const): Deleted.
* platform/graphics/gpu/GPUDevice.h:
* platform/graphics/gpu/cocoa/GPUBufferMetal.mm:
(WebCore::GPUBuffer::tryCreateSharedBuffer): Attempt to create a MTLBuffer with shared memory.
(WebCore::GPUBuffer::tryCreate): No longer use Gigacage-allocated memory for MTLBuffer.
(WebCore::GPUBuffer::GPUBuffer):
(WebCore::GPUBuffer::~GPUBuffer):
(WebCore::GPUBuffer::registerMappingCallback): Register the provided callback to be executed when the staging buffer can be safely exposed.
(WebCore::GPUBuffer::stagingBufferForRead): Prepare the arrayBuffer for reading and run the mapping callback.
(WebCore::GPUBuffer::stagingBufferForWrite): Ditto, but for writing.
(WebCore::GPUBuffer::unmap): If needed, copy the staging ArrayBuffer to the MTLBuffer. Unregister any mapping callback.
(WebCore::GPUBuffer::destroy): Stub implementation for now. Frees the MTLBuffer as soon as possible.
(WebCore::GPUBuffer::create): Deleted.
* platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm:
(WebCore::GPUProgrammablePassEncoder::setResourceAsBufferOnEncoder): Ensure only read-only GPUBuffers are used as read-only on the GPU.

Add symbols for new files:
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:

LayoutTests:

Rewrite buffers.html -> map-write-buffers.html to test new functionality. Rewrite other affected
tests to use mapWriteAsync.

* webgpu/buffer-resource-triangles.html:
* webgpu/buffers-expected.txt: Renamed to map-write-buffers-expected.txt.
* webgpu/buffers.html: Renamed to map-write-buffers.html.
* webgpu/depth-enabled-triangle-strip.html:
* webgpu/map-write-buffers-expected.txt: Renamed from buffers-expected.txt.
* webgpu/map-write-buffers.html: Renamed from buffers.html.
* webgpu/vertex-buffer-triangle-strip.html:

* platform/mac/TestExpectations: Skip all webgpu tests on macOS 10.12 bots.

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (241995 => 241996)


--- trunk/LayoutTests/ChangeLog	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/LayoutTests/ChangeLog	2019-02-23 23:24:27 UTC (rev 241996)
@@ -1,3 +1,23 @@
+2019-02-23  Justin Fan  <justin_...@apple.com>
+
+        [WebGPU] Buffer updates part 1: async mapping functions, unmap, and destroy
+        https://bugs.webkit.org/show_bug.cgi?id=194665
+
+        Reviewed by Dean Jackson.
+
+        Rewrite buffers.html -> map-write-buffers.html to test new functionality. Rewrite other affected
+        tests to use mapWriteAsync.
+
+        * webgpu/buffer-resource-triangles.html:
+        * webgpu/buffers-expected.txt: Renamed to map-write-buffers-expected.txt.
+        * webgpu/buffers.html: Renamed to map-write-buffers.html.
+        * webgpu/depth-enabled-triangle-strip.html:
+        * webgpu/map-write-buffers-expected.txt: Renamed from buffers-expected.txt.
+        * webgpu/map-write-buffers.html: Renamed from buffers.html.
+        * webgpu/vertex-buffer-triangle-strip.html:
+
+        * platform/mac/TestExpectations: Skip all webgpu tests on macOS 10.12 bots.
+
 2019-02-23  chris fleizach  <cfleiz...@apple.com>
 
         AX: WebKit is incorrectly mapping the <meter> element to progressbar

Modified: trunk/LayoutTests/platform/mac/TestExpectations (241995 => 241996)


--- trunk/LayoutTests/platform/mac/TestExpectations	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/LayoutTests/platform/mac/TestExpectations	2019-02-23 23:24:27 UTC (rev 241996)
@@ -1785,18 +1785,6 @@
 
 webkit.org/b/190976 imported/w3c/web-platform-tests/media-source/mediasource-changetype-play.html [ Pass Failure ]
 
-webkit.org/b/192956 [ Sierra ] webgpu/buffers.html [ Skip ]
-webkit.org/b/192956 [ Sierra ] webgpu/command-buffers.html [ Skip ]
-webkit.org/b/192956 [ Sierra ] webgpu/pipeline-layouts.html [ Skip ]
-webkit.org/b/192956 [ Sierra ] webgpu/queue-creation.html [ Skip ]
-webkit.org/b/192956 [ Sierra ] webgpu/render-command-encoding.html [ Skip ]
-webkit.org/b/192956 [ Sierra ] webgpu/render-passes.html [ Skip ]
-webkit.org/b/192956 [ Sierra ] webgpu/render-pipelines.html [ Skip ]
-webkit.org/b/192956 [ Sierra ] webgpu/shader-modules.html [ Skip ]
-webkit.org/b/192956 [ Sierra ] webgpu/textures-textureviews.html [ Skip ]
-webkit.org/b/192956 [ Sierra ] webgpu/webgpu-basics.html [ Skip ]
-webkit.org/b/192956 [ Sierra ] webgpu/webgpu-enabled.html [ Skip ]
-webkit.org/b/192956 [ Sierra ] webgpu/simple-triangle-strip.html [ Skip ]
-webkit.org/b/192956 [ Sierra ] webgpu/vertex-buffer-triangle-strip.html [ Skip ]
+webkit.org/b/192956 [ Sierra ] webgpu [ Skip ]
 
 webkit.org/b/189680 platform/mac/media/audio-session-category-video-paused.html [ Pass Timeout ]

Modified: trunk/LayoutTests/webgpu/buffer-resource-triangles.html (241995 => 241996)


--- trunk/LayoutTests/webgpu/buffer-resource-triangles.html	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/LayoutTests/webgpu/buffer-resource-triangles.html	2019-02-23 23:24:27 UTC (rev 241996)
@@ -79,34 +79,33 @@
 
 const vertexSize = 4 * 4;
 const verticesBufferSize = vertexSize * 3;
+function createAndUploadVerticesBuffer(device, promises) {
+    const buffer = device.createBuffer({ size:verticesBufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE });
 
-// FIXME: Keep up to date with buffer upload decisions.
-function createVerticesBuffer(device) {
-    const buffer = device.createBuffer({ size:verticesBufferSize, usage: GPUBufferUsage.VERTEX });
+    const promise = buffer.mapWriteAsync().then(mapping => {
+        const mappedArray = new Float32Array(mapping);
+        mappedArray.set([
+            0, 1, 0, 1,
+            -1, -1, 0, 1,
+            1, -1, 0, 1
+        ]);
+        buffer.unmap();
+    });
 
-    const vertices = [
-        0, 1, 0, 1,
-        -1, -1, 0, 1,
-        1, -1, 0, 1
-    ];
-
-    const mappedArray = new Float32Array(buffer.mapping);
-    mappedArray.set(vertices);
-
+    promises.push(promise);
     return buffer;
 }
 
-function createFloat4Buffer(device, a, b) {
-    const buffer = device.createBuffer({ size: vertexSize, usage: GPUBufferUsage.UNIFORM });
-    
-    const arrayBuffer = buffer.mapping;
-    const floatArray = new Float32Array(arrayBuffer);
+function createFloat4Buffer(device, a, b, promises) {
+    const buffer = device.createBuffer({ size: vertexSize, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE });
 
-    floatArray[0] = a;
-    floatArray[1] = b;
-    floatArray[2] = 0;
-    floatArray[3] = 1;
+    const promise = buffer.mapWriteAsync().then(mapping => {
+        const mappedArray = new Float32Array(mapping);
+        mappedArray.set([a, b, 0, 1]);
+        buffer.unmap();
+    });
 
+    promises.push(promise);
     return buffer;
 }
 
@@ -126,16 +125,18 @@
     const shaderModule = device.createShaderModule({ code: shaderCode });
 
     // Create vertex data WebGPUBuffers.
-    const verticesBuffer = createVerticesBuffer(device);
+    let bufferPromises = [];
 
-    const upperLeft = createFloat4Buffer(device, -1, 1);
-    const upperMiddle = createFloat4Buffer(device, 0, 1);
-    const upperRight = createFloat4Buffer(device, 1, 1);
-    const lowerLeft = createFloat4Buffer(device, -1, -1);
-    const lowerRight = createFloat4Buffer(device, 1, -1);
+    const verticesBuffer = createAndUploadVerticesBuffer(device, bufferPromises);
 
+    const upperLeft = createFloat4Buffer(device, -1, 1, bufferPromises);
+    const upperMiddle = createFloat4Buffer(device, 0, 1, bufferPromises);
+    const upperRight = createFloat4Buffer(device, 1, 1, bufferPromises);
+    const lowerLeft = createFloat4Buffer(device, -1, -1, bufferPromises);
+    const lowerRight = createFloat4Buffer(device, 1, -1, bufferPromises);
+
     // Color data buffer.
-    const green = createFloat4Buffer(device, 0, 1);
+    const green = createFloat4Buffer(device, 0, 1, bufferPromises);
 
     // Create vertex input state.
     const inputState = {
@@ -195,21 +196,23 @@
         bindings: [bgBindingUR, bgBindingUM, bgBindingLR]
     });
 
-    const commandBuffer = device.createCommandBuffer();
-    const passEncoder = beginBasicRenderPass(context, commandBuffer);
-    passEncoder.setPipeline(pipeline);
+    Promise.all(bufferPromises).then(() => {
+        const commandBuffer = device.createCommandBuffer();
+        const passEncoder = beginBasicRenderPass(context, commandBuffer);
+        passEncoder.setPipeline(pipeline);
 
-    // Vertex data for upper triangles.
-    passEncoder.setBindGroup(0, leftTriangleBG);
-    passEncoder.setBindGroup(1, rightTriangleBG);
-    // Lower triangle.
-    passEncoder.setVertexBuffers(0, [verticesBuffer], [0]);
-    passEncoder.draw(9, 1, 0, 0);
+        // Vertex data for upper triangles.
+        passEncoder.setBindGroup(0, leftTriangleBG);
+        passEncoder.setBindGroup(1, rightTriangleBG);
+        // Lower triangle.
+        passEncoder.setVertexBuffers(0, [verticesBuffer], [0]);
+        passEncoder.draw(9, 1, 0, 0);
 
-    const endCommandBuffer = passEncoder.endPass();
-    const queue = device.getQueue();
-    queue.submit([endCommandBuffer]);
-    context.present();
+        const endCommandBuffer = passEncoder.endPass();
+        const queue = device.getQueue();
+        queue.submit([endCommandBuffer]);
+        context.present();
+    });
 }
 
 test();

Deleted: trunk/LayoutTests/webgpu/buffers-expected.txt (241995 => 241996)


--- trunk/LayoutTests/webgpu/buffers-expected.txt	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/LayoutTests/webgpu/buffers-expected.txt	2019-02-23 23:24:27 UTC (rev 241996)
@@ -1,4 +0,0 @@
-PASS [object WebGPU] is defined.
-
-PASS createBuffer() on WebGPUDevice. 
-

Deleted: trunk/LayoutTests/webgpu/buffers.html (241995 => 241996)


--- trunk/LayoutTests/webgpu/buffers.html	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/LayoutTests/webgpu/buffers.html	2019-02-23 23:24:27 UTC (rev 241996)
@@ -1,31 +0,0 @@
-<!DOCTYPE html><!-- webkit-test-runner [ experimental:WebGPUEnabled=true ] -->
-<meta charset=utf-8>
-<title>Get the WebGPUDevice, create a WebGPUBuffer, and write vertex data to it.</title>
-<body>
-<script src=""
-<script src=""
-<script src=""
-<script src=""
-<script>
-function createBuffer() {
-    const buffer = defaultDevice.createBuffer({ size: 16, usage: GPUBufferUsage.MAP_WRITE });
-    assert_true(buffer instanceof WebGPUBuffer, "createBuffer returned a WebGPUBuffer");
-    
-    let arrayBuffer = buffer.mapping;
-    let floatArray = new Float32Array(arrayBuffer);
-    assert_equals(floatArray.length, 4);
-
-    floatArray[0] = -1;
-    floatArray[1] = 1;
-    floatArray[2] = 0;
-    floatArray[3] = 1;
-}
-
-promise_test(async t => {
-    const canvas = document.createElement("canvas");
-    await setUpContexts(canvas);
-    createBuffer();
-}, "createBuffer() on WebGPUDevice.");
-
-</script>
-</body>

Modified: trunk/LayoutTests/webgpu/depth-enabled-triangle-strip.html (241995 => 241996)


--- trunk/LayoutTests/webgpu/depth-enabled-triangle-strip.html	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/LayoutTests/webgpu/depth-enabled-triangle-strip.html	2019-02-23 23:24:27 UTC (rev 241996)
@@ -44,22 +44,23 @@
 }
 `
 
-function createVertexBuffer(device) {
+async function createVertexBuffer(device) {
     const bufferSize = 4 * 4 * 4;
-    const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.MAP_WRITE });
+    const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE });
     
     let floatArray = new Float32Array(buffer.mapping);
+    await buffer.mapWriteAsync().then(mapping => {
+        let mappedArray = new Float32Array(mapping);
+        mappedArray.set([
+            // float4 xyzw
+            -1, 1, 0, 1,
+            -1, -1, 0, 1,
+            1, 1, 0, 1,
+            1, -1, 0, 1
+        ]);
+        buffer.unmap();
+    });
 
-    const vertices = [
-        // float4 xyzw
-        -1, 1, 0, 1,
-        -1, -1, 0, 1,
-        1, 1, 0, 1,
-        1, -1, 0, 1
-    ];
-
-    floatArray.set(vertices);
-
     return buffer;
 }
 
@@ -86,7 +87,7 @@
     const context = createBasicContext(canvas, device);
     // FIXME: Replace with non-MSL shaders.
     const shaderModule = device.createShaderModule({ code: shaderCode });
-    const vertexBuffer = createVertexBuffer(device);
+    const vertexBuffer =  await createVertexBuffer(device);
     const inputStateDescriptor = createInputStateDescriptor();
     const depthStateDescriptor = createBasicDepthStateDescriptor();
     const pipeline = createBasicPipeline(shaderModule, device, null, inputStateDescriptor, depthStateDescriptor);

Added: trunk/LayoutTests/webgpu/map-write-buffers-expected.txt (0 => 241996)


--- trunk/LayoutTests/webgpu/map-write-buffers-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webgpu/map-write-buffers-expected.txt	2019-02-23 23:24:27 UTC (rev 241996)
@@ -0,0 +1,6 @@
+
+PASS Map write, unmap, and destroy a GPUBuffer. 
+PASS Reject a map write on a buffer not created with MAP_WRITE usage. 
+PASS Reject a map write on a mapped GPUBuffer. 
+PASS Reject a pending map write if GPUBuffer is unmapped. 
+

Added: trunk/LayoutTests/webgpu/map-write-buffers.html (0 => 241996)


--- trunk/LayoutTests/webgpu/map-write-buffers.html	                        (rev 0)
+++ trunk/LayoutTests/webgpu/map-write-buffers.html	2019-02-23 23:24:27 UTC (rev 241996)
@@ -0,0 +1,78 @@
+<!DOCTYPE html><!-- webkit-test-runner [ experimental:WebGPUEnabled=true ] -->
+<meta charset=utf-8>
+<title>Tests for mapWriteAsync on a GPUBuffer.</title>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script>
+async function runTests() {
+    const device =  await getBasicDevice();
+
+    // Basic mapWriteAsync functionality
+    promise_test(async () => {
+        const buffer = device.createBuffer({ size: 16, usage: GPUBufferUsage.MAP_WRITE });
+        assert_true(buffer instanceof WebGPUBuffer, "createBuffer returned a WebGPUBuffer");
+
+        let arrayBuffer = await buffer.mapWriteAsync();
+
+        assert_true(arrayBuffer instanceof ArrayBuffer, "first mapWriteAsync resolved successfully");
+        
+        let array = new Float32Array(arrayBuffer);
+        assert_equals(array[0], 0, "mapWriteAsync zeroed out storage");
+        array.set([1, 2, 3, 4]);
+        
+        buffer.unmap();
+
+        const promise = buffer.mapWriteAsync(); // This will eventually reject due to buffer.destroy()
+
+        buffer.destroy();
+
+        await promise.then(() => {
+            assert_unreached("Buffer was destroyed!");
+        }, () => {});
+
+    }, "Map write, unmap, and destroy a GPUBuffer.");
+
+    /* Basic validation */
+    // FIXME: Test invalid combinations of GPUBufferUsage after implementing error handling.
+
+    promise_test(async () => {
+        const buffer = device.createBuffer({ size: 16, usage: GPUBufferUsage.MAP_READ });
+
+        await buffer.mapWriteAsync().then(() => {
+            assert_unreached("Buffer was not created with MAP_WRITE!");
+        }, () => {});
+    }, "Reject a map write on a buffer not created with MAP_WRITE usage.");
+
+    /* Extended unmap/destroy and promise settling testing */
+
+    promise_test(async () => {
+        const buffer = device.createBuffer({ size: 16, usage: GPUBufferUsage.MAP_WRITE });
+
+        buffer.mapWriteAsync().then(() => {
+            buffer.unmap();
+        }, () => { 
+            assert_unreached(); 
+        });
+
+        await buffer.mapWriteAsync().then(() => {
+            assert_unreached("Map operation was invalid!"); // buffer was still in mapped state during promise creation
+        }, () => {});
+    }, "Reject a map write on a mapped GPUBuffer.");
+
+    promise_test(async () => {
+        const buffer = device.createBuffer({ size: 16, usage: GPUBufferUsage.MAP_WRITE });
+
+        const promise = buffer.mapWriteAsync();
+        buffer.unmap();
+
+        await promise.then(() => {
+            assert_unreached("Buffer was unmapped!"); // buffer was unmapped, which rejects pending promises
+        },() => {});
+    }, "Reject a pending map write if GPUBuffer is unmapped.");
+}
+
+runTests();
+</script>
+</body>

Modified: trunk/LayoutTests/webgpu/vertex-buffer-triangle-strip.html (241995 => 241996)


--- trunk/LayoutTests/webgpu/vertex-buffer-triangle-strip.html	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/LayoutTests/webgpu/vertex-buffer-triangle-strip.html	2019-02-23 23:24:27 UTC (rev 241996)
@@ -38,24 +38,22 @@
 }
 `
 
-function createVertexBuffer(device) {
+async function createVertexBuffer(device) {
     const bufferSize = 4 * 5 * 4;
-    const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.MAP_WRITE });
+    const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE });
     
-    let floatArray = new Float32Array(buffer.mapping);
+    await buffer.mapWriteAsync().then(mapping => {
+        let mappedArray = new Float32Array(mapping);
+        mappedArray.set([
+            // float4 xyzw, float g
+            -1, 1, 0, 1, 1,
+            -1, -1, 0, 1, 1,
+            1, 1, 0, 1, 1,
+            1, -1, 0, 1, 1
+        ]);
+        buffer.unmap();
+    });
 
-    const vertices = [
-        // float4 xyzw, float g
-        -1, 1, 0, 1, 1,
-        -1, -1, 0, 1, 1,
-        1, 1, 0, 1, 1,
-        1, -1, 0, 1, 1
-    ];
-
-    for (let i = 0; i < vertices.length; ++i) {
-        floatArray[i] = vertices[i];
-    }
-
     return buffer;
 }
 
@@ -87,7 +85,7 @@
     const context = createBasicContext(canvas, device);
     // FIXME: Replace with non-MSL shaders.
     const shaderModule = device.createShaderModule({ code: shaderCode });
-    const vertexBuffer = createVertexBuffer(device);
+    const vertexBuffer = await createVertexBuffer(device);
     const inputStateDescriptor = createInputStateDescriptor();
     const pipeline = createBasicPipeline(shaderModule, device, null, inputStateDescriptor);
     const commandBuffer = device.createCommandBuffer();

Modified: trunk/Source/WebCore/ChangeLog (241995 => 241996)


--- trunk/Source/WebCore/ChangeLog	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/ChangeLog	2019-02-23 23:24:27 UTC (rev 241996)
@@ -1,3 +1,73 @@
+2019-02-23  Justin Fan  <justin_...@apple.com>
+
+        [WebGPU] Buffer updates part 1: async mapping functions, unmap, and destroy
+        https://bugs.webkit.org/show_bug.cgi?id=194665
+
+        Reviewed by Dean Jackson.
+
+        Test: map-write-buffers.html. Other tests updated to match new API.
+
+        * Modules/webgpu/WebGPUBindGroupDescriptor.cpp: Added.
+        (WebCore::validateBufferBindingType): Ensure buffer binding usages match the binding type.
+        (WebCore::WebGPUBindGroupDescriptor::asGPUBindGroupDescriptor const): Logic moved out from WebGPUDevice.cpp.
+        * Modules/webgpu/WebGPUBindGroupDescriptor.h:
+        * Modules/webgpu/WebGPUBuffer.cpp: Added GPUBuffer functionality.
+        (WebCore::WebGPUBuffer::create):
+        (WebCore::WebGPUBuffer::WebGPUBuffer):
+        (WebCore::WebGPUBuffer::mapReadAsync):
+        (WebCore::WebGPUBuffer::mapWriteAsync):
+        (WebCore::WebGPUBuffer::unmap):
+        (WebCore::WebGPUBuffer::destroy):
+        (WebCore::WebGPUBuffer::rejectOrRegisterPromiseCallback): Register a mapping request on the GPUBuffer, if valid.
+        * Modules/webgpu/WebGPUBuffer.h:
+        (WebCore::WebGPUBuffer::buffer const):
+        (WebCore::WebGPUBuffer::mapping const): Deleted.
+        * Modules/webgpu/WebGPUBuffer.idl: Update to latest API and enable every function except setSubData.
+        * Modules/webgpu/WebGPUCommandBuffer.cpp:
+        (WebCore::WebGPUCommandBuffer::beginRenderPass): Renamed descriptor conversion method.
+        * Modules/webgpu/WebGPUDevice.cpp:
+        (WebCore::WebGPUDevice::createBuffer const): Update to non-nullable return type.
+        (WebCore::WebGPUDevice::createBindGroup const): Move descriptor validation logic to descriptor implementation.
+        * Modules/webgpu/WebGPUDevice.h:
+        * Modules/webgpu/WebGPURenderPassDescriptor.cpp:
+        (WebCore::WebGPURenderPassDescriptor::asGPURenderPassDescriptor const): Renamed from validateAndConvertToGPUVersion.
+        * Modules/webgpu/WebGPURenderPassEncoder.cpp:
+        (WebCore::WebGPURenderPassEncoder::setVertexBuffers): Add validation for submitted buffers.
+        * platform/graphics/gpu/GPUBuffer.cpp: Added.
+        (WebCore::GPUBuffer::PendingMappingCallback::PendingMappingCallback): New struct for retaining a reference to mapping callbacks.
+        * platform/graphics/gpu/GPUBuffer.h: Add functionality to retain callbacks and usage bits.
+        (WebCore::GPUBuffer::isVertex const):
+        (WebCore::GPUBuffer::isUniform const):
+        (WebCore::GPUBuffer::isStorage const):
+        (WebCore::GPUBuffer::isReadOnly const):
+        (WebCore::GPUBuffer::PendingMapPromise::create):
+        (WebCore::GPUBuffer::isMappable const):
+        (WebCore::GPUBuffer::isMapWriteable const):
+        (WebCore::GPUBuffer::isMapReadable const):
+        (WebCore::GPUBuffer::mapping const): Deleted.
+        * platform/graphics/gpu/GPUBufferUsage.h: enum class cannot be logical ORed together.
+        * platform/graphics/gpu/GPUDevice.cpp:
+        (WebCore::GPUDevice::tryCreateBuffer const): Renamed from createBuffer. 
+        (WebCore::GPUDevice::createBuffer const): Deleted.
+        * platform/graphics/gpu/GPUDevice.h:
+        * platform/graphics/gpu/cocoa/GPUBufferMetal.mm:
+        (WebCore::GPUBuffer::tryCreateSharedBuffer): Attempt to create a MTLBuffer with shared memory.
+        (WebCore::GPUBuffer::tryCreate): No longer use Gigacage-allocated memory for MTLBuffer.
+        (WebCore::GPUBuffer::GPUBuffer):
+        (WebCore::GPUBuffer::~GPUBuffer):
+        (WebCore::GPUBuffer::registerMappingCallback): Register the provided callback to be executed when the staging buffer can be safely exposed.
+        (WebCore::GPUBuffer::stagingBufferForRead): Prepare the arrayBuffer for reading and run the mapping callback.
+        (WebCore::GPUBuffer::stagingBufferForWrite): Ditto, but for writing.
+        (WebCore::GPUBuffer::unmap): If needed, copy the staging ArrayBuffer to the MTLBuffer. Unregister any mapping callback.
+        (WebCore::GPUBuffer::destroy): Stub implementation for now. Frees the MTLBuffer as soon as possible.
+        (WebCore::GPUBuffer::create): Deleted.
+        * platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm:
+        (WebCore::GPUProgrammablePassEncoder::setResourceAsBufferOnEncoder): Ensure only read-only GPUBuffers are used as read-only on the GPU.
+
+        Add symbols for new files:
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+
 2019-02-23  Keith Miller  <keith_mil...@apple.com>
 
         Add new mac target numbers

Added: trunk/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.cpp (0 => 241996)


--- trunk/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.cpp	                        (rev 0)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.cpp	2019-02-23 23:24:27 UTC (rev 241996)
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "WebGPUBindGroupDescriptor.h"
+
+#if ENABLE(WEBGPU)
+
+#include "GPUBindGroupDescriptor.h"
+#include "GPUBuffer.h"
+#include "Logging.h"
+#include <wtf/Variant.h>
+
+namespace WebCore {
+
+static bool validateBufferBindingType(const GPUBuffer* buffer, const GPUBindGroupLayoutBinding& binding, const char* const functionName)
+{
+#if LOG_DISABLED
+    UNUSED_PARAM(functionName);
+#endif
+
+    switch (binding.type) {
+    case GPUBindGroupLayoutBinding::BindingType::UniformBuffer:
+        if (!buffer->isUniform()) {
+            LOG(WebGPU, "%s: GPUBuffer resource for binding %lu does not have UNIFORM usage!", functionName, binding.binding);
+            return false;
+        }
+        return true;
+    case GPUBindGroupLayoutBinding::BindingType::StorageBuffer:
+        if (!buffer->isStorage()) {
+            LOG(WebGPU, "%s: GPUBuffer resource for binding %lu does not have STORAGE usage!", functionName, binding.binding);
+            return false;
+        }
+        return true;
+    default:
+        LOG(WebGPU, "%s: Layout binding %lu is not a buffer-type resource!", functionName, binding.binding);
+        return false;
+    }
+}
+
+Optional<GPUBindGroupDescriptor> WebGPUBindGroupDescriptor::asGPUBindGroupDescriptor() const
+{
+    const char* const functionName = "GPUDevice::createBindGroup()";
+
+    if (!layout || !layout->bindGroupLayout()) {
+        LOG(WebGPU, "%s: Invalid GPUBindGroupLayout!", functionName);
+        return WTF::nullopt;
+    }
+
+    if (bindings.size() != layout->bindGroupLayout()->bindingsMap().size()) {
+        LOG(WebGPU, "%s: Mismatched number of GPUBindGroupLayoutBindings and GPUBindGroupBindings!", functionName);
+        return WTF::nullopt;
+    }
+
+    auto layoutMap = layout->bindGroupLayout()->bindingsMap();
+
+    Vector<GPUBindGroupBinding> bindGroupBindings;
+    bindGroupBindings.reserveCapacity(bindings.size());
+
+    for (const auto& binding : bindings) {
+        auto iterator = layoutMap.find(binding.binding);
+        if (iterator == layoutMap.end()) {
+            LOG(WebGPU, "%s: GPUBindGroupLayoutBinding %lu not found in GPUBindGroupLayout!", functionName, binding.binding);
+            return WTF::nullopt;
+        }
+
+        auto layoutBinding = iterator->value;
+
+        auto bindingResourceVisitor = WTF::makeVisitor([] (RefPtr<WebGPUTextureView> view) -> Optional<GPUBindingResource> {
+            // FIXME: Validate binding type with the texture's usage flags.
+            if (!view)
+                return WTF::nullopt;
+
+            return static_cast<GPUBindingResource>(view->texture());
+        }, [&layoutBinding, functionName] (const WebGPUBufferBinding& binding) -> Optional<GPUBindingResource> {
+            if (!binding.buffer || !binding.buffer->buffer()) {
+                LOG(WebGPU, "%s: Invalid GPUBufferBinding for binding %lu in GPUBindGroupBindings!", functionName, layoutBinding.binding);
+                return WTF::nullopt;
+            }
+            if (!validateBufferBindingType(binding.buffer->buffer().get(), layoutBinding, functionName))
+                return WTF::nullopt;
+
+            return static_cast<GPUBindingResource>(GPUBufferBinding { binding.buffer->buffer().releaseNonNull(), binding.offset, binding.size });
+        });
+
+        auto bindingResource = WTF::visit(bindingResourceVisitor, binding.resource);
+        if (!bindingResource)
+            return WTF::nullopt;
+
+        bindGroupBindings.uncheckedAppend(GPUBindGroupBinding { binding.binding, WTFMove(bindingResource.value()) });
+    }
+
+    return GPUBindGroupDescriptor { layout->bindGroupLayout().releaseNonNull(), WTFMove(bindGroupBindings) };
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBGPU)

Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.h (241995 => 241996)


--- trunk/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.h	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.h	2019-02-23 23:24:27 UTC (rev 241996)
@@ -29,12 +29,17 @@
 
 #include "WebGPUBindGroupBinding.h"
 #include "WebGPUBindGroupLayout.h"
+#include <wtf/Optional.h>
 #include <wtf/RefPtr.h>
 #include <wtf/Vector.h>
 
 namespace WebCore {
 
+struct GPUBindGroupDescriptor;
+
 struct WebGPUBindGroupDescriptor {
+    Optional<GPUBindGroupDescriptor> asGPUBindGroupDescriptor() const;
+
     RefPtr<WebGPUBindGroupLayout> layout;
     Vector<WebGPUBindGroupBinding> bindings;
 };

Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.cpp (241995 => 241996)


--- trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.cpp	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.cpp	2019-02-23 23:24:27 UTC (rev 241996)
@@ -28,18 +28,65 @@
 
 #if ENABLE(WEBGPU)
 
+#include "Logging.h"
+
 namespace WebCore {
 
-Ref<WebGPUBuffer> WebGPUBuffer::create(Ref<GPUBuffer>&& buffer)
+Ref<WebGPUBuffer> WebGPUBuffer::create(RefPtr<GPUBuffer>&& buffer)
 {
     return adoptRef(*new WebGPUBuffer(WTFMove(buffer)));
 }
 
-WebGPUBuffer::WebGPUBuffer(Ref<GPUBuffer>&& buffer)
+WebGPUBuffer::WebGPUBuffer(RefPtr<GPUBuffer>&& buffer)
     : m_buffer(WTFMove(buffer))
 {
 }
 
+void WebGPUBuffer::mapReadAsync(BufferMappingPromise&& promise)
+{
+    rejectOrRegisterPromiseCallback(WTFMove(promise), true);
+}
+
+void WebGPUBuffer::mapWriteAsync(BufferMappingPromise&& promise)
+{
+    rejectOrRegisterPromiseCallback(WTFMove(promise), false);
+}
+
+void WebGPUBuffer::unmap()
+{
+    if (m_buffer)
+        m_buffer->unmap();
+}
+
+void WebGPUBuffer::destroy()
+{
+    if (!m_buffer)
+        LOG(WebGPU, "GPUBuffer::destroy(): Invalid operation!");
+    else {
+        m_buffer->destroy();
+        // FIXME: Ensure that GPUBuffer is kept alive by resource bindings if still being used by GPU.
+        m_buffer = nullptr;
+    }
+}
+
+void WebGPUBuffer::rejectOrRegisterPromiseCallback(BufferMappingPromise&& promise, bool isRead)
+{
+    if (!m_buffer) {
+        LOG(WebGPU, "GPUBuffer::map%sAsync(): Invalid operation!", isRead ? "Read" : "Write");
+        promise.reject();
+        return;
+    }
+
+    m_buffer->registerMappingCallback([promise = WTFMove(promise)] (JSC::ArrayBuffer* arrayBuffer) mutable {
+        if (!arrayBuffer) {
+            promise.reject();
+            return;
+        }
+
+        promise.resolve(arrayBuffer);
+    }, isRead);
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(WEBGPU)

Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.h (241995 => 241996)


--- trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.h	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.h	2019-02-23 23:24:27 UTC (rev 241996)
@@ -28,26 +28,37 @@
 #if ENABLE(WEBGPU)
 
 #include "GPUBuffer.h"
-
+#include "GPUBufferUsage.h"
+#include "JSDOMPromiseDeferred.h"
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
 
+namespace JSC {
+class ArrayBuffer;
+}
+
 namespace WebCore {
 
+struct GPUBufferDescriptor;
+
 class WebGPUBuffer : public RefCounted<WebGPUBuffer> {
 public:
-    static Ref<WebGPUBuffer> create(Ref<GPUBuffer>&&);
+    static Ref<WebGPUBuffer> create(RefPtr<GPUBuffer>&&);
 
-    const GPUBuffer& buffer() const { return m_buffer.get(); }
+    RefPtr<const GPUBuffer> buffer() const { return m_buffer; }
 
-    JSC::ArrayBuffer* mapping() const { return m_buffer->mapping(); }
-    void unmap() { /* FIXME: Unimplemented stub. */ }
-    void destroy() { /* FIXME: Unimplemented stub. */ }
+    using BufferMappingPromise = DOMPromiseDeferred<IDLInterface<JSC::ArrayBuffer*>>;
+    void mapReadAsync(BufferMappingPromise&&);
+    void mapWriteAsync(BufferMappingPromise&&);
+    void unmap();
+    void destroy();
 
 private:
-    explicit WebGPUBuffer(Ref<GPUBuffer>&&);
+    explicit WebGPUBuffer(RefPtr<GPUBuffer>&&);
 
-    Ref<GPUBuffer> m_buffer;
+    void rejectOrRegisterPromiseCallback(BufferMappingPromise&&, bool);
+
+    RefPtr<GPUBuffer> m_buffer;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.idl (241995 => 241996)


--- trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.idl	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.idl	2019-02-23 23:24:27 UTC (rev 241996)
@@ -28,7 +28,10 @@
     EnabledAtRuntime=WebGPU,
     ImplementationLacksVTable
 ] interface WebGPUBuffer {
-    readonly attribute ArrayBuffer? mapping;
+    //void setSubData(u32 offset, ArrayBuffer data);
+
+    Promise<ArrayBuffer> mapReadAsync();
+    Promise<ArrayBuffer> mapWriteAsync();
     void unmap();
 
     void destroy();

Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.cpp (241995 => 241996)


--- trunk/Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.cpp	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.cpp	2019-02-23 23:24:27 UTC (rev 241996)
@@ -47,7 +47,7 @@
 
 RefPtr<WebGPURenderPassEncoder> WebGPUCommandBuffer::beginRenderPass(WebGPURenderPassDescriptor&& descriptor)
 {
-    auto gpuDescriptor = descriptor.validateAndConvertToGPUVersion();
+    auto gpuDescriptor = descriptor.asGPURenderPassDescriptor();
     if (!gpuDescriptor)
         return nullptr;
 

Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUDevice.cpp (241995 => 241996)


--- trunk/Source/WebCore/Modules/webgpu/WebGPUDevice.cpp	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUDevice.cpp	2019-02-23 23:24:27 UTC (rev 241996)
@@ -55,7 +55,6 @@
 #include "WebGPUShaderModule.h"
 #include "WebGPUShaderModuleDescriptor.h"
 #include "WebGPUTexture.h"
-#include <wtf/Variant.h>
 
 namespace WebCore {
 
@@ -73,11 +72,10 @@
     UNUSED_PARAM(m_adapter);
 }
 
-RefPtr<WebGPUBuffer> WebGPUDevice::createBuffer(GPUBufferDescriptor&& descriptor) const
+Ref<WebGPUBuffer> WebGPUDevice::createBuffer(GPUBufferDescriptor&& descriptor) const
 {
-    if (auto buffer = m_device->createBuffer(WTFMove(descriptor)))
-        return WebGPUBuffer::create(buffer.releaseNonNull());
-    return nullptr;
+    auto buffer = m_device->tryCreateBuffer(WTFMove(descriptor));
+    return WebGPUBuffer::create(WTFMove(buffer));
 }
 
 Ref<WebGPUTexture> WebGPUDevice::createTexture(GPUTextureDescriptor&& descriptor) const
@@ -104,44 +102,11 @@
 
 Ref<WebGPUBindGroup> WebGPUDevice::createBindGroup(WebGPUBindGroupDescriptor&& descriptor) const
 {
-    if (!descriptor.layout || !descriptor.layout->bindGroupLayout()) {
-        LOG(WebGPU, "WebGPUDevice::createBindGroup(): Invalid WebGPUBindGroupLayout!");
+    auto gpuDescriptor = descriptor.asGPUBindGroupDescriptor();
+    if (!gpuDescriptor)
         return WebGPUBindGroup::create(nullptr);
-    }
 
-    if (descriptor.bindings.size() != descriptor.layout->bindGroupLayout()->bindingsMap().size()) {
-        LOG(WebGPU, "WebGPUDevice::createBindGroup(): Mismatched number of WebGPUBindGroupLayoutBindings and WebGPUBindGroupBindings!");
-        return WebGPUBindGroup::create(nullptr);
-    }
-
-    auto bindingResourceVisitor = WTF::makeVisitor([] (RefPtr<WebGPUTextureView> view) -> Optional<GPUBindingResource> {
-        if (view)
-            return static_cast<GPUBindingResource>(view->texture());
-        return WTF::nullopt;
-    }, [] (const WebGPUBufferBinding& binding) -> Optional<GPUBindingResource> {
-        if (binding.buffer)
-            return static_cast<GPUBindingResource>(GPUBufferBinding { binding.buffer->buffer(), binding.offset, binding.size });
-        return WTF::nullopt;
-    });
-
-    Vector<GPUBindGroupBinding> bindGroupBindings;
-    bindGroupBindings.reserveCapacity(descriptor.bindings.size());
-
-    for (const auto& binding : descriptor.bindings) {
-        if (!descriptor.layout->bindGroupLayout()->bindingsMap().contains(binding.binding)) {
-            LOG(WebGPU, "WebGPUDevice::createBindGroup(): WebGPUBindGroupBinding %lu not found in WebGPUBindGroupLayout!", binding.binding);
-            return WebGPUBindGroup::create(nullptr);
-        }
-
-        auto bindingResource = WTF::visit(bindingResourceVisitor, binding.resource);
-        if (bindingResource)
-            bindGroupBindings.uncheckedAppend(GPUBindGroupBinding { binding.binding, WTFMove(bindingResource.value()) });
-        else {
-            LOG(WebGPU, "WebGPUDevice::createBindGroup(): Invalid WebGPUBindingResource for binding %lu in WebGPUBindGroupBindings!", binding.binding);
-            return WebGPUBindGroup::create(nullptr);
-        }
-    }
-    auto bindGroup = GPUBindGroup::create(GPUBindGroupDescriptor { descriptor.layout->bindGroupLayout().releaseNonNull(), WTFMove(bindGroupBindings) });
+    auto bindGroup = GPUBindGroup::create(WTFMove(*gpuDescriptor));
     return WebGPUBindGroup::create(WTFMove(bindGroup));
 }
 

Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUDevice.h (241995 => 241996)


--- trunk/Source/WebCore/Modules/webgpu/WebGPUDevice.h	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUDevice.h	2019-02-23 23:24:27 UTC (rev 241996)
@@ -62,7 +62,7 @@
     const WebGPUAdapter& adapter() const { return m_adapter.get(); }
     const GPUDevice& device() const { return m_device.get(); }
 
-    RefPtr<WebGPUBuffer> createBuffer(GPUBufferDescriptor&&) const;
+    Ref<WebGPUBuffer> createBuffer(GPUBufferDescriptor&&) const;
     Ref<WebGPUTexture> createTexture(GPUTextureDescriptor&&) const;
 
     Ref<WebGPUBindGroupLayout> createBindGroupLayout(WebGPUBindGroupLayoutDescriptor&&) const;

Modified: trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassDescriptor.cpp (241995 => 241996)


--- trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassDescriptor.cpp	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassDescriptor.cpp	2019-02-23 23:24:27 UTC (rev 241996)
@@ -45,7 +45,7 @@
 {
 }
 
-Optional<GPURenderPassDescriptor> WebGPURenderPassDescriptor::validateAndConvertToGPUVersion() const
+Optional<GPURenderPassDescriptor> WebGPURenderPassDescriptor::asGPURenderPassDescriptor() const
 {
     // FIXME: Improve error checking as WebGPURenderPassDescriptor is added to spec.
     if (colorAttachments.isEmpty()) {

Modified: trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassDescriptor.h (241995 => 241996)


--- trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassDescriptor.h	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassDescriptor.h	2019-02-23 23:24:27 UTC (rev 241996)
@@ -46,7 +46,7 @@
 };
 
 struct WebGPURenderPassDescriptor {
-    Optional<GPURenderPassDescriptor> validateAndConvertToGPUVersion() const;
+    Optional<GPURenderPassDescriptor> asGPURenderPassDescriptor() const;
 
     Vector<WebGPURenderPassColorAttachmentDescriptor> colorAttachments;
     Optional<WebGPURenderPassDepthStencilAttachmentDescriptor> depthStencilAttachment;

Modified: trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp (241995 => 241996)


--- trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp	2019-02-23 23:24:27 UTC (rev 241996)
@@ -49,20 +49,36 @@
 
 void WebGPURenderPassEncoder::setVertexBuffers(unsigned long startSlot, Vector<RefPtr<WebGPUBuffer>>&& buffers, Vector<unsigned long long>&& offsets)
 {
+#if !LOG_DISABLED
+    const char* const functionName = "GPURenderPassEncoder::setVertexBuffers()";
+#endif
     if (buffers.isEmpty() || buffers.size() != offsets.size()) {
-        LOG(WebGPU, "WebGPURenderPassEncoder::setVertexBuffers: Invalid number of buffers or offsets!");
+        LOG(WebGPU, "%s: Invalid number of buffers or offsets!", functionName);
         return;
     }
 
     if (startSlot + buffers.size() > maxVertexBuffers) {
-        LOG(WebGPU, "WebGPURenderPassEncoder::setVertexBuffers: Invalid startSlot %lu for %lu buffers!", startSlot, buffers.size());
+        LOG(WebGPU, "%s: Invalid startSlot %lu for %lu buffers!", functionName, startSlot, buffers.size());
         return;
     }
 
-    auto gpuBuffers = buffers.map([] (const auto& buffer) -> Ref<const GPUBuffer> {
-        return buffer->buffer();
-    });
+    Vector<Ref<const GPUBuffer>> gpuBuffers;
+    gpuBuffers.reserveCapacity(buffers.size());
 
+    for (const auto& buffer : buffers) {
+        if (!buffer || !buffer->buffer()) {
+            LOG(WebGPU, "%s: Invalid or destroyed buffer in list!", functionName);
+            return;
+        }
+
+        if (!buffer->buffer()->isVertex()) {
+            LOG(WebGPU, "%s: Buffer was not created with VERTEX usage!", functionName);
+            return;
+        }
+
+        gpuBuffers.uncheckedAppend(buffer->buffer().releaseNonNull());
+    }
+
     m_passEncoder->setVertexBuffers(startSlot, WTFMove(gpuBuffers), WTFMove(offsets));
 }
 

Modified: trunk/Source/WebCore/Sources.txt (241995 => 241996)


--- trunk/Source/WebCore/Sources.txt	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/Sources.txt	2019-02-23 23:24:27 UTC (rev 241996)
@@ -348,6 +348,7 @@
 Modules/webgpu/WHLSL/AST/WHLSLUnsignedIntegerLiteral.cpp
 Modules/webgpu/WebGPU.cpp
 Modules/webgpu/WebGPUBindGroup.cpp
+Modules/webgpu/WebGPUBindGroupDescriptor.cpp
 Modules/webgpu/WebGPUAdapter.cpp
 Modules/webgpu/WebGPUBindGroupLayout.cpp
 Modules/webgpu/WebGPUBuffer.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (241995 => 241996)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-02-23 23:24:27 UTC (rev 241996)
@@ -4255,6 +4255,7 @@
 		D05CED2A0A40BB2C00C5AF38 /* FormatBlockCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D05CED280A40BB2C00C5AF38 /* FormatBlockCommand.h */; };
 		D06C0D8F0CFD11460065F43F /* RemoveFormatCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D06C0D8D0CFD11460065F43F /* RemoveFormatCommand.h */; };
 		D07DEABA0A36554A00CA30F8 /* InsertListCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D07DEAB80A36554A00CA30F8 /* InsertListCommand.h */; };
+		D084033C221CBF6900007205 /* GPUBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D084033A221CBF5400007205 /* GPUBuffer.cpp */; };
 		D0843A4B20FEBE3D00FE860E /* GraphicsContext3DManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D0843A4A20FEBE3D00FE860E /* GraphicsContext3DManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		D086FE9809D53AAB005BC74D /* UnlinkCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D086FE9609D53AAB005BC74D /* UnlinkCommand.h */; };
 		D08B00E220A282490004BC0A /* WebGLCompressedTextureASTC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A20D562092A0A600E0C259 /* WebGLCompressedTextureASTC.cpp */; };
@@ -14075,6 +14076,8 @@
 		D07DEAB80A36554A00CA30F8 /* InsertListCommand.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = InsertListCommand.h; sourceTree = "<group>"; };
 		D083D98421C48050008E8EFF /* GPUBindGroupLayoutDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPUBindGroupLayoutDescriptor.h; sourceTree = "<group>"; };
 		D083D98621C4813E008E8EFF /* WebGPUBindGroupLayoutDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WebGPUBindGroupLayoutDescriptor.h; path = Modules/streams/WebGPUBindGroupLayoutDescriptor.h; sourceTree = SOURCE_ROOT; };
+		D084033A221CBF5400007205 /* GPUBuffer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GPUBuffer.cpp; sourceTree = "<group>"; };
+		D084033D221E186400007205 /* WebGPUBindGroupDescriptor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebGPUBindGroupDescriptor.cpp; sourceTree = "<group>"; };
 		D0843A4A20FEBE3D00FE860E /* GraphicsContext3DManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GraphicsContext3DManager.h; sourceTree = "<group>"; };
 		D0843A4C20FEC16500FE860E /* GraphicsContext3DManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GraphicsContext3DManager.cpp; sourceTree = "<group>"; };
 		D086FE9609D53AAB005BC74D /* UnlinkCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnlinkCommand.h; sourceTree = "<group>"; };
@@ -18481,6 +18484,7 @@
 				D02454D021C4A41C00B73628 /* GPUBindGroupLayout.h */,
 				D0B8BB0121C46E78000C7681 /* GPUBindGroupLayoutBinding.h */,
 				D083D98421C48050008E8EFF /* GPUBindGroupLayoutDescriptor.h */,
+				D084033A221CBF5400007205 /* GPUBuffer.cpp */,
 				D0D8649221B760F2003C983C /* GPUBuffer.h */,
 				D0BE104A21E6872F00E42A89 /* GPUBufferBinding.h */,
 				D0D8648721B64CAA003C983C /* GPUBufferDescriptor.h */,
@@ -26107,6 +26111,7 @@
 				D0BE106221E6C0EB00E42A89 /* WebGPUBindGroup.idl */,
 				D0BE104F21E69F8300E42A89 /* WebGPUBindGroupBinding.h */,
 				D0BE105021E69F8300E42A89 /* WebGPUBindGroupBinding.idl */,
+				D084033D221E186400007205 /* WebGPUBindGroupDescriptor.cpp */,
 				D0BE105221E6AA0D00E42A89 /* WebGPUBindGroupDescriptor.h */,
 				D0BE105321E6AA0D00E42A89 /* WebGPUBindGroupDescriptor.idl */,
 				D003287A21C8645B00622AA6 /* WebGPUBindGroupLayout.cpp */,
@@ -32945,6 +32950,7 @@
 				51A9D9E9195B931F001B2B5C /* GamepadManager.cpp in Sources */,
 				515BE1911D54F5FB00DD7C68 /* GamepadProvider.cpp in Sources */,
 				837964CF1F8DB69D00218EA0 /* GeolocationPositionIOS.mm in Sources */,
+				D084033C221CBF6900007205 /* GPUBuffer.cpp in Sources */,
 				6E21C6C01126338500A7BE02 /* GraphicsContext3D.cpp in Sources */,
 				7C3E510B18DF8F3500C112F7 /* HTMLConverter.mm in Sources */,
 				A8D06B3A0A265DCD005E7203 /* HTMLNames.cpp in Sources */,

Copied: trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.cpp (from rev 241995, trunk/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.h) (0 => 241996)


--- trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.cpp	                        (rev 0)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.cpp	2019-02-23 23:24:27 UTC (rev 241996)
@@ -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.
+ */
+
+#include "config.h"
+#include "GPUBuffer.h"
+
+#if ENABLE(WEBGPU)
+
+namespace WebCore {
+
+GPUBuffer::PendingMappingCallback::PendingMappingCallback(MappingCallback&& pending)
+    : callback(WTFMove(pending))
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBGPU)

Modified: trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.h (241995 => 241996)


--- trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.h	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.h	2019-02-23 23:24:27 UTC (rev 241996)
@@ -27,6 +27,9 @@
 
 #if ENABLE(WEBGPU)
 
+#include "DeferrableTask.h"
+#include "GPUBufferUsage.h"
+#include <wtf/Function.h>
 #include <wtf/Ref.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RetainPtr.h>
@@ -50,17 +53,57 @@
 public:
     ~GPUBuffer();
 
-    static RefPtr<GPUBuffer> create(const GPUDevice&, GPUBufferDescriptor&&);
+    static RefPtr<GPUBuffer> tryCreate(const GPUDevice&, GPUBufferDescriptor&&);
 
     PlatformBuffer *platformBuffer() const { return m_platformBuffer.get(); }
+    bool isVertex() const { return m_isVertex; }
+    bool isUniform() const { return m_isUniform; }
+    bool isStorage() const { return m_isStorage; }
+    bool isReadOnly() const { return m_isReadOnly; }
 
-    JSC::ArrayBuffer* mapping() const { return m_mapping.get(); }
+    using MappingCallback = WTF::Function<void(JSC::ArrayBuffer*)>;
+    void registerMappingCallback(MappingCallback&&, bool);
+    void unmap();
+    void destroy();
 
 private:
-    explicit GPUBuffer(PlatformBufferSmartPtr&&, RefPtr<JSC::ArrayBuffer>&&);
+    struct PendingMappingCallback : public RefCounted<PendingMappingCallback> {
+        static Ref<PendingMappingCallback> create(MappingCallback&& callback)
+        {
+            return adoptRef(*new PendingMappingCallback(WTFMove(callback)));
+        }
 
+        MappingCallback callback;
+
+    private:
+        PendingMappingCallback(MappingCallback&&);
+    };
+
+    GPUBuffer(PlatformBufferSmartPtr&&, const GPUBufferDescriptor&);
+
+    static RefPtr<GPUBuffer> tryCreateSharedBuffer(const GPUDevice&, const GPUBufferDescriptor&);
+    JSC::ArrayBuffer* stagingBufferForRead();
+    JSC::ArrayBuffer* stagingBufferForWrite();
+
+    bool isMappable() const { return m_isMapWrite || m_isMapRead; }
+    bool isMapWriteable() const { return m_isMapWrite && !m_pendingCallback; }
+    bool isMapReadable() const { return m_isMapRead && !m_pendingCallback; }
+
     PlatformBufferSmartPtr m_platformBuffer;
-    RefPtr<JSC::ArrayBuffer> m_mapping;
+
+    RefPtr<JSC::ArrayBuffer> m_stagingBuffer;
+    RefPtr<PendingMappingCallback> m_pendingCallback;
+    DeferrableTask<Timer> m_mappingCallbackTask;
+
+    unsigned long m_byteLength;
+    unsigned m_numScheduledCommandBuffers = 0;
+    bool m_isMapWrite;
+    bool m_isMapRead;
+    bool m_isDestroyed = false;
+    bool m_isVertex;
+    bool m_isUniform;
+    bool m_isStorage;
+    bool m_isReadOnly;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/graphics/gpu/GPUBufferUsage.h (241995 => 241996)


--- trunk/Source/WebCore/platform/graphics/gpu/GPUBufferUsage.h	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPUBufferUsage.h	2019-02-23 23:24:27 UTC (rev 241996)
@@ -35,7 +35,7 @@
 
 class GPUBufferUsage : public RefCounted<GPUBufferUsage> {
 public:
-    enum class Flags : GPUBufferUsageFlags {
+    enum Flags : GPUBufferUsageFlags {
         None = 0,
         MapRead = 1,
         MapWrite = 2,

Modified: trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.cpp (241995 => 241996)


--- trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.cpp	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.cpp	2019-02-23 23:24:27 UTC (rev 241996)
@@ -44,9 +44,9 @@
 
 namespace WebCore {
 
-RefPtr<GPUBuffer> GPUDevice::createBuffer(GPUBufferDescriptor&& descriptor) const
+RefPtr<GPUBuffer> GPUDevice::tryCreateBuffer(GPUBufferDescriptor&& descriptor) const
 {
-    return GPUBuffer::create(*this, WTFMove(descriptor));
+    return GPUBuffer::tryCreate(*this, WTFMove(descriptor));
 }
 
 RefPtr<GPUTexture> GPUDevice::tryCreateTexture(GPUTextureDescriptor&& descriptor) const

Modified: trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.h (241995 => 241996)


--- trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.h	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.h	2019-02-23 23:24:27 UTC (rev 241996)
@@ -60,7 +60,7 @@
 public:
     static RefPtr<GPUDevice> create(Optional<GPURequestAdapterOptions>&&);
 
-    RefPtr<GPUBuffer> createBuffer(GPUBufferDescriptor&&) const;
+    RefPtr<GPUBuffer> tryCreateBuffer(GPUBufferDescriptor&&) const;
     RefPtr<GPUTexture> tryCreateTexture(GPUTextureDescriptor&&) const;
 
     RefPtr<GPUBindGroupLayout> tryCreateBindGroupLayout(GPUBindGroupLayoutDescriptor&&) const;

Modified: trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm (241995 => 241996)


--- trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm	2019-02-23 23:24:27 UTC (rev 241996)
@@ -31,67 +31,152 @@
 #import "GPUBufferDescriptor.h"
 #import "GPUDevice.h"
 #import "Logging.h"
-
-#import <Foundation/NSRange.h>
 #import <_javascript_Core/ArrayBuffer.h>
 #import <Metal/Metal.h>
-#import <wtf/Gigacage.h>
-#import <wtf/PageBlock.h>
+#import <wtf/BlockObjCExceptions.h>
 
 namespace WebCore {
 
-RefPtr<GPUBuffer> GPUBuffer::create(const GPUDevice& device, GPUBufferDescriptor&& descriptor)
+RefPtr<GPUBuffer> GPUBuffer::tryCreateSharedBuffer(const GPUDevice& device, const GPUBufferDescriptor& descriptor)
 {
+    ASSERT(device.platformDevice());
+
+    RetainPtr<MTLBuffer> mtlBuffer;
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+    mtlBuffer = adoptNS([device.platformDevice() newBufferWithLength:descriptor.size options: MTLResourceCPUCacheModeDefaultCache]);
+
+    END_BLOCK_OBJC_EXCEPTIONS;
+
+    if (!mtlBuffer) {
+        LOG(WebGPU, "GPUBuffer::create(): Unable to create MTLBuffer!");
+        return nullptr;
+    }
+
+    return adoptRef(*new GPUBuffer(WTFMove(mtlBuffer), descriptor));
+}
+
+static const auto readOnlyMask = GPUBufferUsage::Index | GPUBufferUsage::Vertex | GPUBufferUsage::Uniform | GPUBufferUsage::TransferSrc;
+
+RefPtr<GPUBuffer> GPUBuffer::tryCreate(const GPUDevice& device, GPUBufferDescriptor&& descriptor)
+{
     if (!device.platformDevice()) {
         LOG(WebGPU, "GPUBuffer::create(): Invalid GPUDevice!");
         return nullptr;
     }
 
-    size_t pageSize = WTF::pageSize();
-    size_t pageAlignedSize = roundUpToMultipleOf(pageSize, descriptor.size);
-    void* pageAlignedCopy = Gigacage::tryAlignedMalloc(Gigacage::Primitive, pageSize, pageAlignedSize);
-    if (!pageAlignedCopy) {
-        LOG(WebGPU, "GPUBuffer::create(): Unable to allocate memory!");
+    if ((descriptor.usage & GPUBufferUsage::MapWrite) && (descriptor.usage & GPUBufferUsage::MapRead)) {
+        LOG(WebGPU, "GPUBuffer::create(): Buffer cannot have both MAP_READ and MAP_WRITE usage!");
         return nullptr;
     }
 
-    auto arrayBuffer = ArrayBuffer::createFromBytes(pageAlignedCopy, descriptor.size, [] (void* ptr) {
-        Gigacage::alignedFree(Gigacage::Primitive, ptr);
-    });
-    arrayBuffer->ref();
-    ArrayBuffer* arrayBufferContents = arrayBuffer.ptr();
-    // FIXME: Default this MTLResourceOptions.
-    PlatformBufferSmartPtr mtlBuffer = adoptNS([device.platformDevice()
-        newBufferWithBytesNoCopy:arrayBuffer->data()
-        length:pageAlignedSize
-        options:MTLResourceCPUCacheModeDefaultCache
-        deallocator:^(void*, NSUInteger) {
-            arrayBufferContents->deref();
-        }]);
-
-    if (!mtlBuffer) {
-        LOG(WebGPU, "GPUBuffer::create(): Unable to create MTLBuffer!");
-        arrayBuffer->deref();
+    if ((descriptor.usage & readOnlyMask) && (descriptor.usage & GPUBufferUsage::Storage)) {
+        LOG(WebGPU, "GPUBuffer::create(): Buffer cannot have both STORAGE and a read-only usage!");
         return nullptr;
     }
 
-    return adoptRef(*new GPUBuffer(WTFMove(mtlBuffer), WTFMove(arrayBuffer)));
+    // Mappable buffers need (default) shared storage allocation.
+    if (descriptor.usage & (GPUBufferUsage::MapWrite | GPUBufferUsage::MapRead))
+        return tryCreateSharedBuffer(device, descriptor);
+
+    LOG(WebGPU, "GPUBuffer::create(): Support for non-mapped buffers not implemented!");
+    return nullptr;
 }
 
-GPUBuffer::GPUBuffer(PlatformBufferSmartPtr&& platformBuffer, RefPtr<ArrayBuffer>&& arrayBuffer)
-    : m_platformBuffer(WTFMove(platformBuffer))
-    , m_mapping(WTFMove(arrayBuffer))
+GPUBuffer::GPUBuffer(RetainPtr<MTLBuffer>&& buffer, const GPUBufferDescriptor& descriptor)
+    : m_platformBuffer(WTFMove(buffer))
+    , m_byteLength(descriptor.size)
+    , m_isMapWrite(descriptor.usage & GPUBufferUsage::MapWrite)
+    , m_isMapRead(descriptor.usage & GPUBufferUsage::MapRead)
+    , m_isVertex(descriptor.usage & GPUBufferUsage::Vertex)
+    , m_isUniform(descriptor.usage & GPUBufferUsage::Uniform)
+    , m_isStorage(descriptor.usage & GPUBufferUsage::Storage)
+    , m_isReadOnly(descriptor.usage & readOnlyMask)
 {
 }
 
 GPUBuffer::~GPUBuffer()
 {
-    if (m_mapping) {
-        m_mapping->deref();
-        m_mapping = nullptr;
+    unmap();
+}
+
+void GPUBuffer::registerMappingCallback(MappingCallback&& callback, bool isRead)
+{
+    // Reject if request is invalid.
+    if (isRead && !isMapReadable()) {
+        LOG(WebGPU, "GPUBuffer::mapReadAsync(): Invalid operation!");
+        callback(nullptr);
+        return;
     }
+    if (!isRead && !isMapWriteable()) {
+        LOG(WebGPU, "GPUBuffer::mapWriteAsync(): Invalid operation!");
+        callback(nullptr);
+        return;
+    }
+
+    ASSERT(!m_pendingCallback && !m_mappingCallbackTask.hasPendingTask());
+
+    // An existing callback means this buffer is in the mapped state.
+    m_pendingCallback = PendingMappingCallback::create(WTFMove(callback));
+
+    // If GPU is not using this buffer, run the callback ASAP.
+    if (!m_numScheduledCommandBuffers) {
+        m_mappingCallbackTask.scheduleTask([this, protectedThis = makeRef(*this)] () mutable {
+            ASSERT(m_pendingCallback);
+
+            m_pendingCallback->callback(m_isMapRead ? stagingBufferForRead() : stagingBufferForWrite());
+        });
+    }
 }
 
+JSC::ArrayBuffer* GPUBuffer::stagingBufferForRead()
+{
+    if (!m_stagingBuffer)
+        m_stagingBuffer = ArrayBuffer::create(m_platformBuffer.get().contents, m_byteLength);
+    else
+        memcpy(m_stagingBuffer->data(), m_platformBuffer.get().contents, m_byteLength);
+
+    return m_stagingBuffer.get();
+}
+
+JSC::ArrayBuffer* GPUBuffer::stagingBufferForWrite()
+{
+    m_stagingBuffer = ArrayBuffer::create(1, m_byteLength);
+    return m_stagingBuffer.get();
+}
+
+void GPUBuffer::unmap()
+{
+    if (!isMappable()) {
+        LOG(WebGPU, "GPUBuffer::unmap(): Buffer is not mappable!");
+        return;
+    }
+
+    if (m_stagingBuffer && m_isMapWrite) {
+        memcpy(m_platformBuffer.get().contents, m_stagingBuffer->data(), m_byteLength);
+        m_stagingBuffer = nullptr;
+    }
+
+    if (m_pendingCallback) {
+        m_mappingCallbackTask.cancelTask();
+        m_pendingCallback->callback(nullptr);
+        m_pendingCallback = nullptr;
+    }
+}
+
+void GPUBuffer::destroy()
+{
+    if (isMappable())
+        unmap();
+
+    m_isDestroyed = true;
+
+    // FIXME: If GPU is still using the MTLBuffer, it will be released after all relevant commands have executed.
+    if (!m_numScheduledCommandBuffers)
+        m_platformBuffer = nullptr;
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(WEBGPU)

Modified: trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm (241995 => 241996)


--- trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm	2019-02-23 20:49:39 UTC (rev 241995)
+++ trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm	2019-02-23 23:24:27 UTC (rev 241996)
@@ -61,9 +61,9 @@
     }
 
     auto& bufferBinding = WTF::get<GPUBufferBinding>(resource);
-    auto buffer = bufferBinding.buffer->platformBuffer();
+    auto mtlBuffer = bufferBinding.buffer->platformBuffer();
 
-    if (!buffer) {
+    if (!mtlBuffer) {
         LOG(WebGPU, "%s: Invalid MTLBuffer in GPUBufferBinding!", functionName);
         return;
     }
@@ -70,8 +70,8 @@
 
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
-    [argumentEncoder setBuffer:buffer offset:bufferBinding.offset atIndex:index];
-    useResource(buffer, MTLResourceUsageRead);
+    [argumentEncoder setBuffer:mtlBuffer offset:bufferBinding.offset atIndex:index];
+    useResource(mtlBuffer, bufferBinding.buffer->isReadOnly() ? MTLResourceUsageRead : MTLResourceUsageRead | MTLResourceUsageWrite);
 
     END_BLOCK_OBJC_EXCEPTIONS;
 }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to