Diff
Modified: trunk/LayoutTests/ChangeLog (242147 => 242148)
--- trunk/LayoutTests/ChangeLog 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/LayoutTests/ChangeLog 2019-02-27 21:10:24 UTC (rev 242148)
@@ -1,3 +1,22 @@
+2019-02-27 Justin Fan <justin_...@apple.com>
+
+ [Web GPU] Buffer updates part 2: setSubData, GPU/CPU synchronization
+ https://bugs.webkit.org/show_bug.cgi?id=195077
+ <rdar://problem/47805229>
+
+ Reviewed by Dean Jackson.
+
+ Add tests for mapReadAysnc and setSubData calls. Nofity testRunner when done on some drawing tests
+ that may take more time.
+
+ * webgpu/buffer-command-buffer-races-expected.html: Added.
+ * webgpu/buffer-command-buffer-races.html: Added.
+ * webgpu/buffer-resource-triangles.html: Use setSubData.
+ * webgpu/depth-enabled-triangle-strip.html: Ditto.
+ * webgpu/map-read-buffers-expected.txt: Added.
+ * webgpu/map-read-buffers.html: Added.
+ * webgpu/vertex-buffer-triangle-strip.html: Use setSubData.
+
2019-02-27 Antoine Quint <grao...@apple.com>
Support Pointer Events on macOS
Added: trunk/LayoutTests/webgpu/buffer-command-buffer-races-expected.html (0 => 242148)
--- trunk/LayoutTests/webgpu/buffer-command-buffer-races-expected.html (rev 0)
+++ trunk/LayoutTests/webgpu/buffer-command-buffer-races-expected.html 2019-02-27 21:10:24 UTC (rev 242148)
@@ -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
Added: trunk/LayoutTests/webgpu/buffer-command-buffer-races.html (0 => 242148)
--- trunk/LayoutTests/webgpu/buffer-command-buffer-races.html (rev 0)
+++ trunk/LayoutTests/webgpu/buffer-command-buffer-races.html 2019-02-27 21:10:24 UTC (rev 242148)
@@ -0,0 +1,159 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebGPU Hello Triangles</title>
+<meta name="assert" content="WebGPU correctly renders a green canvas.">
+<link rel="match" href=""
+<p>Pass if square canvas below is completely green.</p>
+<canvas width="400" height="400"></canvas>
+<script src=""
+<script>
+if (window.testRunner)
+ testRunner.waitUntilDone();
+
+const shaderCode = `
+#include <metal_stdlib>
+
+using namespace metal;
+
+struct VertexIn
+{
+ float2 xy [[attribute(0)]];
+ float3 rgb [[attribute(1)]];
+};
+
+struct VertexOut
+{
+ float4 position [[position]];
+ float4 color;
+};
+
+vertex VertexOut vertex_main(VertexIn vertexIn [[stage_in]])
+{
+ VertexOut vOut;
+ vOut.position = float4(vertexIn.xy, 0, 1);
+ vOut.color = float4(vertexIn.rgb, 1);
+
+ return vOut;
+}
+
+fragment float4 fragment_main(VertexOut v [[stage_in]])
+{
+ return v.color;
+}
+`
+
+function createInputStateDescriptor() {
+ return {
+ indexFormat: WebGPUIndexFormat.UINT32,
+ attributes: [{
+ shaderLocation: 0,
+ inputSlot: 0,
+ offset: 0,
+ format: WebGPUVertexFormat.FLOAT_R32_G32
+ }, {
+ shaderLocation: 1,
+ inputSlot: 1,
+ offset: 0,
+ format: WebGPUVertexFormat.FLOAT_R32_G32_B32
+ }],
+ inputs: [{
+ inputSlot: 0,
+ stride: 4 * 2,
+ stepMode: WebGPUInputStepMode.VERTEX
+ }, {
+ inputSlot: 1,
+ stride: 4 * 3,
+ stepMode: WebGPUInputStepMode.INSTANCE
+ }]
+ }
+}
+
+function createAndSetVertexBuffer(device, vertices) {
+ const floatArray = new Float32Array(vertices);
+ const buffer = device.createBuffer({ size: floatArray.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST });
+ buffer.setSubData(0, floatArray.buffer);
+ return buffer;
+}
+
+function drawAndSubmitCommands(device, pipeline, attachment, vertexBuffer, colorBuffer) {
+ const commandBuffer = device.createCommandBuffer();
+ const encoder = commandBuffer.beginRenderPass({ colorAttachments: [attachment] });
+ encoder.setVertexBuffers(0, [vertexBuffer, colorBuffer], [0, 0]);
+ encoder.setPipeline(pipeline);
+ encoder.draw(3, 1, 0, 0);
+ encoder.endPass();
+ device.getQueue().submit([commandBuffer]);
+}
+
+async function test() {
+ const device = await getBasicDevice();
+ const canvas = document.querySelector("canvas");
+ const context = createBasicContext(canvas, device);
+ // FIXME: Replace with non-MSL shaders.
+ const shaderModule = device.createShaderModule({ code: shaderCode });
+ const inputStateDescriptor = createInputStateDescriptor();
+ const pipeline = createBasicPipeline(shaderModule, device, null, inputStateDescriptor);
+
+ const upperLeftBuffer = createAndSetVertexBuffer(device, [-1, 1, -1, -1, 0, 1]);
+ const middleBuffer = createAndSetVertexBuffer(device, [0, 1, -1, -1, 1, -1]);
+ const upperRightBuffer = createAndSetVertexBuffer(device, [0, 1, 1, 1, 1, -1]);
+
+ const green = [0, 1, 0];
+ const blue = [0, 0, 1];
+ const greenArray = new Float32Array(green);
+ const blueArray = new Float32Array(blue);
+
+ const colorBuffer = device.createBuffer({ size: greenArray.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_WRITE });
+ colorBuffer.setSubData(0, greenArray.buffer);
+
+ const attachment = {
+ attachment: context.getNextTexture().createDefaultTextureView(),
+ loadOp: "load",
+ storeOp: "store",
+ clearColor: { r: 1, g: 0, b: 0, a: 1 }
+ };
+
+ /* mapWriteAsync should resolve after GPU commands are complete, so triangle should be green. */
+ drawAndSubmitCommands(device, pipeline, attachment, upperLeftBuffer, colorBuffer);
+ await colorBuffer.mapWriteAsync().then(ab => {
+ let array = new Float32Array(ab);
+ array.set(blue);
+ colorBuffer.unmap();
+ });
+
+ await colorBuffer.mapWriteAsync().then(ab => {
+ let array = new Float32Array(ab);
+ array.set(green);
+ });
+
+ /* colorBuffer that is still mapped should be not submitted to draw a blue triangle. */
+ drawAndSubmitCommands(device, pipeline, attachment, upperLeftBuffer, colorBuffer);
+
+ /* colorBuffer does not actually contain "green" again until this call. */
+ colorBuffer.unmap();
+
+ /* setSubData immediately after a submit should not affect the preceding draw call. */
+ drawAndSubmitCommands(device, pipeline, attachment, middleBuffer, colorBuffer);
+ colorBuffer.setSubData(0, blueArray.buffer);
+
+ /* destroy right after a submit should not affect the draw call. */
+ colorBuffer.setSubData(0, greenArray.buffer);
+ drawAndSubmitCommands(device, pipeline, attachment, upperRightBuffer, colorBuffer);
+ upperRightBuffer.destroy();
+
+ /* draw command with a destroyed buffer should fail */
+ colorBuffer.destroy();
+ drawAndSubmitCommands(device, pipeline, attachment, middleBuffer, colorBuffer);
+
+ upperLeftBuffer.destroy();
+ middleBuffer.destroy();
+ upperRightBuffer.destroy();
+
+ context.present();
+
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+
+test();
+</script>
\ No newline at end of file
Modified: trunk/LayoutTests/webgpu/buffer-resource-triangles.html (242147 => 242148)
--- trunk/LayoutTests/webgpu/buffer-resource-triangles.html 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/LayoutTests/webgpu/buffer-resource-triangles.html 2019-02-27 21:10:24 UTC (rev 242148)
@@ -7,6 +7,9 @@
<canvas width="400" height="400"></canvas>
<script src=""
<script>
+if (window.testRunner)
+ testRunner.waitUntilDone();
+
const shaderCode = `
#include <metal_stdlib>
@@ -79,20 +82,15 @@
const vertexSize = 4 * 4;
const verticesBufferSize = vertexSize * 3;
-function createAndUploadVerticesBuffer(device, promises) {
- const buffer = device.createBuffer({ size:verticesBufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE });
+function createAndUploadVerticesBuffer(device) {
+ const buffer = device.createBuffer({ size:verticesBufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST });
+ const arrayBuffer = new Float32Array([
+ 0, 1, 0, 1,
+ -1, -1, 0, 1,
+ 1, -1, 0, 1
+ ]).buffer;
- 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();
- });
-
- promises.push(promise);
+ buffer.setSubData(0, arrayBuffer);
return buffer;
}
@@ -125,10 +123,9 @@
const shaderModule = device.createShaderModule({ code: shaderCode });
// Create vertex data WebGPUBuffers.
+ const verticesBuffer = createAndUploadVerticesBuffer(device);
+
let bufferPromises = [];
-
- 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);
@@ -212,6 +209,9 @@
const queue = device.getQueue();
queue.submit([endCommandBuffer]);
context.present();
+
+ if (window.testRunner)
+ testRunner.notifyDone();
});
}
Modified: trunk/LayoutTests/webgpu/depth-enabled-triangle-strip.html (242147 => 242148)
--- trunk/LayoutTests/webgpu/depth-enabled-triangle-strip.html 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/LayoutTests/webgpu/depth-enabled-triangle-strip.html 2019-02-27 21:10:24 UTC (rev 242148)
@@ -7,6 +7,9 @@
<canvas width="400" height="400"></canvas>
<script src=""
<script>
+if (window.testRunner)
+ testRunner.waitUntilDone();
+
const shaderCode = `
#include <metal_stdlib>
@@ -44,23 +47,18 @@
}
`
-async function createVertexBuffer(device) {
+function createVertexBuffer(device) {
const bufferSize = 4 * 4 * 4;
- const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE });
+ const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST });
+ const arrayBuffer = new Float32Array([
+ // float4 xyzw
+ -1, 1, 0, 1,
+ -1, -1, 0, 1,
+ 1, 1, 0, 1,
+ 1, -1, 0, 1
+ ]).buffer;
- 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();
- });
-
+ buffer.setSubData(0, arrayBuffer);
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 = await createVertexBuffer(device);
+ const vertexBuffer = createVertexBuffer(device);
const inputStateDescriptor = createInputStateDescriptor();
const depthStateDescriptor = createBasicDepthStateDescriptor();
const pipeline = createBasicPipeline(shaderModule, device, null, inputStateDescriptor, depthStateDescriptor);
@@ -119,6 +117,9 @@
device.getQueue().submit([commandBuffer]);
context.present();
+
+ if (window.testRunner)
+ testRunner.notifyDone();
}
test();
Added: trunk/LayoutTests/webgpu/map-read-buffers-expected.txt (0 => 242148)
--- trunk/LayoutTests/webgpu/map-read-buffers-expected.txt (rev 0)
+++ trunk/LayoutTests/webgpu/map-read-buffers-expected.txt 2019-02-27 21:10:24 UTC (rev 242148)
@@ -0,0 +1,6 @@
+
+PASS setSubData, mapReadAsync, unmap, and destroy on a GPUBuffer.
+PASS Reject a map read on a buffer not created with MAP_READ usage.
+PASS Reject a map read on a mapped GPUBuffer.
+PASS Reject a pending map read if GPUBuffer is unmapped.
+
Added: trunk/LayoutTests/webgpu/map-read-buffers.html (0 => 242148)
--- trunk/LayoutTests/webgpu/map-read-buffers.html (rev 0)
+++ trunk/LayoutTests/webgpu/map-read-buffers.html 2019-02-27 21:10:24 UTC (rev 242148)
@@ -0,0 +1,86 @@
+<!DOCTYPE html><!-- webkit-test-runner [ experimental:WebGPUEnabled=true ] -->
+<meta charset=utf-8>
+<title>Tests for setSubData and mapReadAsync on a GPUBuffer.</title>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script>
+async function runTests() {
+ const device = await getBasicDevice();
+
+ // Basic mapReadAsync functionality
+ promise_test(async () => {
+ const buffer = device.createBuffer({ size: 16, usage: GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ });
+ assert_true(buffer instanceof WebGPUBuffer, "createBuffer returned a WebGPUBuffer");
+
+ let array = new Float32Array([1, 2, 3, 4]);
+ buffer.setSubData(0, array.buffer);
+
+ let arrayBuffer = await buffer.mapReadAsync();
+ assert_true(arrayBuffer instanceof ArrayBuffer, "first mapReadAsync resolved successfully");
+
+ const readArray = new Float32Array(arrayBuffer);
+ assert_equals(readArray[3], 4, "successfully map-read value set by setSubData");
+
+ buffer.unmap();
+
+ buffer.setSubData(4 * 3, array.slice(0, 1).buffer);
+ let arrayBuffer1 = await buffer.mapReadAsync();
+ const readArray1 = new Float32Array(arrayBuffer1);
+ assert_equals(readArray[3], 1, "successfully setSubData with an offset");
+
+ buffer.unmap();
+
+ const promise = buffer.mapReadAsync(); // This will eventually reject due to buffer.destroy()
+
+ buffer.destroy();
+
+ await promise.then(() => {
+ assert_unreached("Buffer was destroyed!");
+ }, () => {});
+
+ }, "setSubData, mapReadAsync, unmap, and destroy on 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_WRITE });
+
+ await buffer.mapReadAsync().then(() => {
+ assert_unreached("Buffer was not created with MAP_READ!");
+ }, () => {});
+ }, "Reject a map read on a buffer not created with MAP_READ usage.");
+
+ /* Extended unmap/destroy and promise settling testing */
+
+ promise_test(async () => {
+ const buffer = device.createBuffer({ size: 16, usage: GPUBufferUsage.MAP_READ });
+
+ buffer.mapReadAsync().then(() => {
+ buffer.unmap();
+ }, () => {
+ assert_unreached();
+ });
+
+ await buffer.mapReadAsync().then(() => {
+ assert_unreached("Map operation was invalid!"); // buffer was still in mapped state during promise creation
+ }, () => {});
+ }, "Reject a map read on a mapped GPUBuffer.");
+
+ promise_test(async () => {
+ const buffer = device.createBuffer({ size: 16, usage: GPUBufferUsage.MAP_READ });
+
+ const promise = buffer.mapReadAsync();
+ buffer.unmap();
+
+ await promise.then(() => {
+ assert_unreached("Buffer was unmapped!"); // buffer was unmapped, which rejects pending promises
+ },() => {});
+ }, "Reject a pending map read if GPUBuffer is unmapped.");
+}
+
+runTests();
+</script>
+</body>
Modified: trunk/LayoutTests/webgpu/vertex-buffer-triangle-strip.html (242147 => 242148)
--- trunk/LayoutTests/webgpu/vertex-buffer-triangle-strip.html 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/LayoutTests/webgpu/vertex-buffer-triangle-strip.html 2019-02-27 21:10:24 UTC (rev 242148)
@@ -7,6 +7,9 @@
<canvas width="400" height="400"></canvas>
<script src=""
<script>
+if (window.testRunner)
+ testRunner.waitUntilDone();
+
const shaderCode = `
#include <metal_stdlib>
@@ -38,22 +41,22 @@
}
`
-async function createVertexBuffer(device) {
+function createVertexBuffer(device) {
const bufferSize = 4 * 5 * 4;
- const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE });
-
- 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 buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST });
+ const vertexArrayBuffer0 = new Float32Array([
+ // float4 xyzw, float g
+ -1, 1, 0, 1, 1,
+ -1, -1, 0, 1, 1
+ ]).buffer;
+ const vertexArrayBuffer1 = new Float32Array([
+ 1, 1, 0, 1, 1,
+ 1, -1, 0, 1, 1
+ ]).buffer;
+ buffer.setSubData(0, vertexArrayBuffer0);
+ buffer.setSubData(4 * 5 * 2, vertexArrayBuffer1);
+
return buffer;
}
@@ -85,7 +88,7 @@
const context = createBasicContext(canvas, device);
// FIXME: Replace with non-MSL shaders.
const shaderModule = device.createShaderModule({ code: shaderCode });
- const vertexBuffer = await createVertexBuffer(device);
+ const vertexBuffer = createVertexBuffer(device);
const inputStateDescriptor = createInputStateDescriptor();
const pipeline = createBasicPipeline(shaderModule, device, null, inputStateDescriptor);
const commandBuffer = device.createCommandBuffer();
@@ -92,9 +95,12 @@
const passEncoder = beginBasicRenderPass(context, commandBuffer);
const endCommandBuffer = encodeBasicCommands(passEncoder, pipeline, vertexBuffer);
const queue = device.getQueue();
-
queue.submit([endCommandBuffer]);
+ vertexBuffer.destroy();
context.present();
+
+ if (window.testRunner)
+ testRunner.notifyDone();
}
test();
Modified: trunk/Source/WebCore/ChangeLog (242147 => 242148)
--- trunk/Source/WebCore/ChangeLog 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/ChangeLog 2019-02-27 21:10:24 UTC (rev 242148)
@@ -1,3 +1,98 @@
+2019-02-27 Justin Fan <justin_...@apple.com>
+
+ [Web GPU] Buffer updates part 2: setSubData, GPU/CPU synchronization
+ https://bugs.webkit.org/show_bug.cgi?id=195077
+ <rdar://problem/47805229>
+
+ Reviewed by Dean Jackson.
+
+ Implement GPUBuffer.setSubData and prevent the resolving of mapping promises if the buffer is scheduled to be
+ used on the GPU, and add handlers to resolve such promises after command buffer execution completes. In addition,
+ update buffer sizes to u64 (unsigned long in C++) as per the updated Web GPU API.
+
+ Tests: webgpu/buffer-command-buffer-races.html
+ webgpu/map-read-buffers.html
+
+ * Modules/webgpu/WebGPUBindGroup.h:
+ (WebCore::WebGPUBindGroup::bindGroup const):
+ * Modules/webgpu/WebGPUBindGroupDescriptor.cpp:
+ (WebCore::WebGPUBindGroupDescriptor::asGPUBindGroupDescriptor const): Rename binding -> bufferBinding to reduce confusion.
+ * Modules/webgpu/WebGPUBuffer.cpp: Small tweaks.
+ (WebCore::WebGPUBuffer::setSubData):
+ (WebCore::WebGPUBuffer::unmap): Correctly fail if buffer is destroyed.
+ (WebCore::WebGPUBuffer::destroy):
+ (WebCore::WebGPUBuffer::rejectOrRegisterPromiseCallback):
+ * Modules/webgpu/WebGPUBuffer.h:
+ (WebCore::WebGPUBuffer::buffer const): Returned buffer is no longer const so that it can be used in completed handler callbacks.
+ * Modules/webgpu/WebGPUBuffer.idl: Enable setSubData.
+ * Modules/webgpu/WebGPUCommandBuffer.cpp:
+ (WebCore::WebGPUCommandBuffer::beginRenderPass):
+ * Modules/webgpu/WebGPUProgrammablePassEncoder.cpp:
+ (WebCore::WebGPUProgrammablePassEncoder::setBindGroup const):
+ * Modules/webgpu/WebGPUProgrammablePassEncoder.h:
+ * Modules/webgpu/WebGPURenderPassEncoder.cpp:
+ (WebCore::WebGPURenderPassEncoder::setVertexBuffers):
+ * Sources.txt:
+ * WebCore.xcodeproj/project.pbxproj:
+ * platform/graphics/gpu/GPUBuffer.h:
+ (WebCore::GPUBuffer::isTransferDst const): Added various state and flag getters.
+ (WebCore::GPUBuffer::isVertex const):
+ (WebCore::GPUBuffer::isUniform const):
+ (WebCore::GPUBuffer::isStorage const):
+ (WebCore::GPUBuffer::isReadOnly const):
+ (WebCore::GPUBuffer::isMappable const):
+ (WebCore::GPUBuffer::isMapWrite const):
+ (WebCore::GPUBuffer::isMapRead const):
+ (WebCore::GPUBuffer::isMapWriteable const):
+ (WebCore::GPUBuffer::isMapReadable const):
+ * platform/graphics/gpu/GPUBufferBinding.h:
+ * platform/graphics/gpu/GPUCommandBuffer.h:
+ (WebCore::GPUCommandBuffer::usedBuffers const):
+ (WebCore::GPUCommandBuffer::useBuffer):
+ * platform/graphics/gpu/GPUDevice.cpp:
+ (WebCore::GPUDevice::tryCreateBuffer): Pass Ref of itself for Buffer to request the Queue later, if needed.
+ (WebCore::GPUDevice::tryCreateBuffer const): Deleted.
+ * platform/graphics/gpu/GPUDevice.h:
+ * platform/graphics/gpu/GPUProgrammablePassEncoder.cpp: Retain the encoder's commandBuffer to reference its used resource buffers.
+ (WebCore::GPUProgrammablePassEncoder::GPUProgrammablePassEncoder):
+ * platform/graphics/gpu/GPUProgrammablePassEncoder.h:
+ (WebCore::GPUProgrammablePassEncoder::commandBuffer const):
+ * platform/graphics/gpu/GPURenderPassEncoder.h:
+ * platform/graphics/gpu/cocoa/GPUBufferMetal.mm:
+ (WebCore::GPUBuffer::validateBufferCreate): Move validation out of tryCreate.
+ (WebCore::GPUBuffer::tryCreate): Create both shared and private buffers, depending on usage.
+ (WebCore::GPUBuffer::GPUBuffer):
+ (WebCore::GPUBuffer::~GPUBuffer): Call destroy instead of just unmap.
+ (WebCore::GPUBuffer::state const):
+ (WebCore::GPUBuffer::setSubData): Uses a cached collection of staging MTLBuffers to encode data copies to the implementation MTLBuffer.
+ (WebCore::GPUBuffer::commandBufferCommitted): Register on the GPUBuffer that the provided MTLCommandBuffer uses it, and is about to be committed.
+ (WebCore::GPUBuffer::commandBufferCompleted): MTLCommandBuffer's onCompletedHandler calls this.
+ (WebCore::GPUBuffer::reuseSubDataBuffer): SetSubData's blit command buffers call this to return a staging buffer to the pool.
+ (WebCore::GPUBuffer::registerMappingCallback):
+ (WebCore::GPUBuffer::runMappingCallback):
+ (WebCore::GPUBuffer::unmap):
+ (WebCore::GPUBuffer::destroy):
+ (WebCore::GPUBuffer::tryCreateSharedBuffer): Deleted.
+ * platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm:
+ (WebCore::GPUProgrammablePassEncoder::setResourceAsBufferOnEncoder):
+ (WebCore::GPUProgrammablePassEncoder::setBindGroup):
+ * platform/graphics/gpu/cocoa/GPUQueueMetal.mm:
+ (WebCore::GPUQueue::submit): Ensure submitted buffers are in the correct state, and add completed handlers for synchronization.
+ * platform/graphics/gpu/cocoa/GPURenderPassEncoderMetal.mm:
+ (WebCore::GPURenderPassEncoder::tryCreate):
+ (WebCore::GPURenderPassEncoder::GPURenderPassEncoder): Retain the commandBuffer for later reference.
+ (WebCore::GPURenderPassEncoder::setVertexBuffers): Mark vertex buffers as used before submission.
+ (WebCore::GPURenderPassEncoder::create): Deleted.
+
+ Buffer size updates in the IDL:
+ * Modules/webgpu/GPUBufferDescriptor.idl:
+ * Modules/webgpu/WebGPUBuffer.idl:
+ * Modules/webgpu/WebGPUBufferBinding.idl:
+ * Modules/webgpu/WebGPUCommandBuffer.idl:
+ * Modules/webgpu/WebGPURenderPassEncoder.idl:
+ * Modules/webgpu/WebGPUVertexAttributeDescriptor.idl:
+ * Modules/webgpu/WebGPUVertexInputDescriptor.idl:
+
2019-02-27 Youenn Fablet <you...@apple.com>
Remove LeetCode FetchRequest quirk
Modified: trunk/Source/WebCore/Modules/webgpu/GPUBufferDescriptor.idl (242147 => 242148)
--- trunk/Source/WebCore/Modules/webgpu/GPUBufferDescriptor.idl 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Modules/webgpu/GPUBufferDescriptor.idl 2019-02-27 21:10:24 UTC (rev 242148)
@@ -24,13 +24,13 @@
*/
// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
-typedef unsigned long u32;
-typedef u32 GPUBufferUsageFlags;
+typedef unsigned long long u64;
+typedef unsigned long GPUBufferUsageFlags;
[
Conditional=WEBGPU,
EnabledAtRuntime=WebGPU
] dictionary GPUBufferDescriptor {
- u32 size;
+ u64 size;
GPUBufferUsageFlags usage;
};
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUBindGroup.h (242147 => 242148)
--- trunk/Source/WebCore/Modules/webgpu/WebGPUBindGroup.h 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUBindGroup.h 2019-02-27 21:10:24 UTC (rev 242148)
@@ -37,7 +37,7 @@
public:
static Ref<WebGPUBindGroup> create(RefPtr<GPUBindGroup>&&);
- const GPUBindGroup* bindGroup() const { return m_bindGroup.get(); }
+ GPUBindGroup* bindGroup() const { return m_bindGroup.get(); }
private:
explicit WebGPUBindGroup(RefPtr<GPUBindGroup>&&);
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.cpp (242147 => 242148)
--- trunk/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.cpp 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.cpp 2019-02-27 21:10:24 UTC (rev 242148)
@@ -86,7 +86,7 @@
return WTF::nullopt;
}
- auto layoutBinding = iterator->value;
+ const auto layoutBinding = iterator->value;
auto bindingResourceVisitor = WTF::makeVisitor([] (RefPtr<WebGPUTextureView> view) -> Optional<GPUBindingResource> {
// FIXME: Validate binding type with the texture's usage flags.
@@ -94,15 +94,15 @@
return WTF::nullopt;
return static_cast<GPUBindingResource>(view->texture());
- }, [&layoutBinding, functionName] (const WebGPUBufferBinding& binding) -> Optional<GPUBindingResource> {
- if (!binding.buffer || !binding.buffer->buffer()) {
+ }, [&layoutBinding, functionName] (WebGPUBufferBinding bufferBinding) -> Optional<GPUBindingResource> {
+ if (!bufferBinding.buffer || !bufferBinding.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))
+ if (!validateBufferBindingType(bufferBinding.buffer->buffer().get(), layoutBinding, functionName))
return WTF::nullopt;
- return static_cast<GPUBindingResource>(GPUBufferBinding { binding.buffer->buffer().releaseNonNull(), binding.offset, binding.size });
+ return static_cast<GPUBindingResource>(GPUBufferBinding { bufferBinding.buffer->buffer().releaseNonNull(), bufferBinding.offset, bufferBinding.size });
});
auto bindingResource = WTF::visit(bindingResourceVisitor, binding.resource);
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.cpp (242147 => 242148)
--- trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.cpp 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.cpp 2019-02-27 21:10:24 UTC (rev 242148)
@@ -42,6 +42,14 @@
{
}
+void WebGPUBuffer::setSubData(unsigned long offset, const JSC::ArrayBuffer& data)
+{
+ if (!m_buffer)
+ LOG(WebGPU, "GPUBuffer::setSubData(): Invalid operation!");
+ else
+ m_buffer->setSubData(offset, data);
+}
+
void WebGPUBuffer::mapReadAsync(BufferMappingPromise&& promise)
{
rejectOrRegisterPromiseCallback(WTFMove(promise), true);
@@ -54,7 +62,9 @@
void WebGPUBuffer::unmap()
{
- if (m_buffer)
+ if (!m_buffer)
+ LOG(WebGPU, "GPUBuffer::unmap(): Invalid operation!");
+ else
m_buffer->unmap();
}
@@ -64,7 +74,6 @@
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;
}
}
@@ -78,12 +87,10 @@
}
m_buffer->registerMappingCallback([promise = WTFMove(promise)] (JSC::ArrayBuffer* arrayBuffer) mutable {
- if (!arrayBuffer) {
+ if (arrayBuffer)
+ promise.resolve(*arrayBuffer);
+ else
promise.reject();
- return;
- }
-
- promise.resolve(arrayBuffer);
}, isRead);
}
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.h (242147 => 242148)
--- trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.h 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.h 2019-02-27 21:10:24 UTC (rev 242148)
@@ -45,9 +45,10 @@
public:
static Ref<WebGPUBuffer> create(RefPtr<GPUBuffer>&&);
- RefPtr<const GPUBuffer> buffer() const { return m_buffer; }
+ RefPtr<GPUBuffer> buffer() const { return m_buffer; }
- using BufferMappingPromise = DOMPromiseDeferred<IDLInterface<JSC::ArrayBuffer*>>;
+ void setSubData(unsigned long, const JSC::ArrayBuffer&);
+ using BufferMappingPromise = DOMPromiseDeferred<IDLInterface<JSC::ArrayBuffer>>;
void mapReadAsync(BufferMappingPromise&&);
void mapWriteAsync(BufferMappingPromise&&);
void unmap();
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.idl (242147 => 242148)
--- trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.idl 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.idl 2019-02-27 21:10:24 UTC (rev 242148)
@@ -22,13 +22,16 @@
* 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 long u64;
+
[
Conditional=WEBGPU,
EnabledAtRuntime=WebGPU,
ImplementationLacksVTable
] interface WebGPUBuffer {
- //void setSubData(u32 offset, ArrayBuffer data);
+ void setSubData(u64 offset, ArrayBuffer data);
Promise<ArrayBuffer> mapReadAsync();
Promise<ArrayBuffer> mapWriteAsync();
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUBufferBinding.idl (242147 => 242148)
--- trunk/Source/WebCore/Modules/webgpu/WebGPUBufferBinding.idl 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUBufferBinding.idl 2019-02-27 21:10:24 UTC (rev 242148)
@@ -24,7 +24,7 @@
*/
// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
-typedef unsigned long u32;
+typedef unsigned long long u64;
[
Conditional=WEBGPU,
@@ -31,6 +31,6 @@
EnabledAtRuntime=WebGPU
] dictionary WebGPUBufferBinding {
WebGPUBuffer buffer;
- u32 offset;
- u32 size;
+ u64 offset;
+ u64 size;
};
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.cpp (242147 => 242148)
--- trunk/Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.cpp 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.cpp 2019-02-27 21:10:24 UTC (rev 242148)
@@ -51,7 +51,7 @@
if (!gpuDescriptor)
return nullptr;
- if (auto encoder = GPURenderPassEncoder::create(m_commandBuffer.get(), WTFMove(*gpuDescriptor)))
+ if (auto encoder = GPURenderPassEncoder::tryCreate(m_commandBuffer.copyRef(), WTFMove(*gpuDescriptor)))
return WebGPURenderPassEncoder::create(*this, encoder.releaseNonNull());
return nullptr;
}
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.idl (242147 => 242148)
--- trunk/Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.idl 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.idl 2019-02-27 21:10:24 UTC (rev 242148)
@@ -37,10 +37,10 @@
// Commands allowed outside of "passes"
void copyBufferToBuffer(
WebGPUBuffer src,
- u32 srcOffset,
+ u64 srcOffset,
WebGPUBuffer dst,
- u32 dstOffset,
- u32 size);
+ u64 dstOffset,
+ u64 size);
void copyBufferToTexture(
WebGPUBufferCopyView source,
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUProgrammablePassEncoder.cpp (242147 => 242148)
--- trunk/Source/WebCore/Modules/webgpu/WebGPUProgrammablePassEncoder.cpp 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUProgrammablePassEncoder.cpp 2019-02-27 21:10:24 UTC (rev 242148)
@@ -45,7 +45,7 @@
return m_commandBuffer.copyRef();
}
-void WebGPUProgrammablePassEncoder::setBindGroup(unsigned long index, const WebGPUBindGroup& bindGroup) const
+void WebGPUProgrammablePassEncoder::setBindGroup(unsigned long index, WebGPUBindGroup& bindGroup) const
{
// Maximum number of bind groups supported in Web GPU.
if (index >= 4) {
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUProgrammablePassEncoder.h (242147 => 242148)
--- trunk/Source/WebCore/Modules/webgpu/WebGPUProgrammablePassEncoder.h 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUProgrammablePassEncoder.h 2019-02-27 21:10:24 UTC (rev 242148)
@@ -41,7 +41,7 @@
virtual ~WebGPUProgrammablePassEncoder() = default;
Ref<WebGPUCommandBuffer> endPass();
- void setBindGroup(unsigned long, const WebGPUBindGroup&) const;
+ void setBindGroup(unsigned long, WebGPUBindGroup&) const;
void setPipeline(Ref<WebGPURenderPipeline>&&);
protected:
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp (242147 => 242148)
--- trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp 2019-02-27 21:10:24 UTC (rev 242148)
@@ -62,7 +62,7 @@
return;
}
- Vector<Ref<const GPUBuffer>> gpuBuffers;
+ Vector<Ref<GPUBuffer>> gpuBuffers;
gpuBuffers.reserveCapacity(buffers.size());
for (const auto& buffer : buffers) {
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.idl (242147 => 242148)
--- trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.idl 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.idl 2019-02-27 21:10:24 UTC (rev 242148)
@@ -25,6 +25,7 @@
// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
typedef unsigned long u32;
+typedef unsigned long long u64;
[
Conditional=WEBGPU,
@@ -31,14 +32,14 @@
EnabledAtRuntime=WebGPU,
JSGenerateToJSObject
] interface WebGPURenderPassEncoder : WebGPUProgrammablePassEncoder {
- // FIXME: (<rdar://problem/47717832>) Last argument should be sequence<unsigned long>, but bindings generates Vector<unsigned int>.
- void setVertexBuffers(u32 startSlot, sequence<WebGPUBuffer> buffers, sequence<unsigned long long> offsets);
+ // FIXME: (<rdar://problem/47717832>) Last argument should be generated to Vector<unsigned long>, but bindings generates Vector<unsigned long long>.
+ void setVertexBuffers(u32 startSlot, sequence<WebGPUBuffer> buffers, sequence<u64> offsets);
void draw(u32 vertexCount, u32 instanceCount, u32 firstVertex, u32 firstInstance);
/* Not Yet Implemented
void setBlendColor(float r, float g, float b, float a);
- void setIndexBuffer(WebGPUBuffer buffer, u32 offset);
+ void setIndexBuffer(WebGPUBuffer buffer, u64 offset);
void drawIndexed(u32 indexCount, u32 instanceCount, u32 firstIndex, i32 baseVertex, u32 firstInstance);
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUVertexAttributeDescriptor.idl (242147 => 242148)
--- trunk/Source/WebCore/Modules/webgpu/WebGPUVertexAttributeDescriptor.idl 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUVertexAttributeDescriptor.idl 2019-02-27 21:10:24 UTC (rev 242148)
@@ -25,6 +25,7 @@
// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
typedef unsigned long u32;
+typedef unsigned long long u64;
typedef u32 WebGPUVertexFormatEnum;
[
@@ -33,6 +34,6 @@
] dictionary WebGPUVertexAttributeDescriptor {
u32 shaderLocation;
u32 inputSlot;
- u32 offset;
+ u64 offset;
WebGPUVertexFormatEnum format;
};
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUVertexInputDescriptor.idl (242147 => 242148)
--- trunk/Source/WebCore/Modules/webgpu/WebGPUVertexInputDescriptor.idl 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUVertexInputDescriptor.idl 2019-02-27 21:10:24 UTC (rev 242148)
@@ -25,6 +25,7 @@
// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
typedef unsigned long u32;
+typedef unsigned long long u64;
typedef u32 WebGPUInputStepModeEnum;
[
@@ -32,6 +33,6 @@
EnabledAtRuntime=WebGPU
] dictionary WebGPUVertexInputDescriptor {
u32 inputSlot;
- u32 stride;
+ u64 stride;
WebGPUInputStepModeEnum stepMode;
};
Modified: trunk/Source/WebCore/Sources.txt (242147 => 242148)
--- trunk/Source/WebCore/Sources.txt 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/Sources.txt 2019-02-27 21:10:24 UTC (rev 242148)
@@ -1811,6 +1811,7 @@
platform/graphics/gpu/GPUBindGroup.cpp
platform/graphics/gpu/GPUDevice.cpp
platform/graphics/gpu/GPUPipelineLayout.cpp
+platform/graphics/gpu/GPUProgrammablePassEncoder.cpp
platform/graphics/gpu/legacy/GPULegacyBuffer.cpp
platform/graphics/gpu/legacy/GPULegacyCommandBuffer.cpp
platform/graphics/gpu/legacy/GPULegacyCommandQueue.cpp
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (242147 => 242148)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2019-02-27 21:10:24 UTC (rev 242148)
@@ -13939,6 +13939,7 @@
D003288421C9A20D00622AA6 /* GPUPipelineLayoutDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPUPipelineLayoutDescriptor.h; sourceTree = "<group>"; };
D003288621C9A4E500622AA6 /* GPUPipelineLayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPUPipelineLayout.h; sourceTree = "<group>"; };
D003288721C9A4E500622AA6 /* GPUPipelineLayout.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GPUPipelineLayout.cpp; sourceTree = "<group>"; };
+ D003914122248D400098998C /* GPUProgrammablePassEncoder.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GPUProgrammablePassEncoder.cpp; sourceTree = "<group>"; };
D00F5940216ECC7A000D71DB /* DOMWindowWebGPU.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOMWindowWebGPU.h; sourceTree = "<group>"; };
D00F5941216ECC7A000D71DB /* DOMWindowWebGPU.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DOMWindowWebGPU.cpp; sourceTree = "<group>"; };
D00F5942216ECC7A000D71DB /* DOMWindowWebGPU.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = DOMWindowWebGPU.idl; sourceTree = "<group>"; };
@@ -18482,6 +18483,7 @@
D003288621C9A4E500622AA6 /* GPUPipelineLayout.h */,
D003288421C9A20D00622AA6 /* GPUPipelineLayoutDescriptor.h */,
312FF8C221A4C2F300EB199D /* GPUPipelineStageDescriptor.h */,
+ D003914122248D400098998C /* GPUProgrammablePassEncoder.cpp */,
D03211CF21AC954E00763CF2 /* GPUProgrammablePassEncoder.h */,
312FF8C121A4C2F200EB199D /* GPUQueue.h */,
D03211D021AC954F00763CF2 /* GPURenderPassDescriptor.h */,
Modified: trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.h (242147 => 242148)
--- trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.h 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.h 2019-02-27 21:10:24 UTC (rev 242148)
@@ -33,8 +33,12 @@
#include <wtf/Ref.h>
#include <wtf/RefCounted.h>
#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#if USE(METAL)
OBJC_PROTOCOL(MTLBuffer);
+OBJC_PROTOCOL(MTLCommandBuffer);
+#endif
namespace JSC {
class ArrayBuffer;
@@ -46,21 +50,42 @@
struct GPUBufferDescriptor;
+#if USE(METAL)
using PlatformBuffer = MTLBuffer;
-using PlatformBufferSmartPtr = RetainPtr<MTLBuffer>;
+#else
+using PlatformBuffer = void;
+#endif
+using PlatformBufferSmartPtr = RetainPtr<PlatformBuffer>;
class GPUBuffer : public RefCounted<GPUBuffer> {
public:
+ enum class State {
+ Mapped,
+ Unmapped,
+ Destroyed
+ };
+
~GPUBuffer();
- static RefPtr<GPUBuffer> tryCreate(const GPUDevice&, GPUBufferDescriptor&&);
+ static RefPtr<GPUBuffer> tryCreate(Ref<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; }
+ 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; }
+ bool isReadOnly() const;
+ bool isMappable() const { return m_usage & (GPUBufferUsage::MapWrite | GPUBufferUsage::MapRead); }
+ State state() const;
+#if USE(METAL)
+ void commandBufferCommitted(MTLCommandBuffer *);
+ void commandBufferCompleted();
+
+ void reuseSubDataBuffer(RetainPtr<MTLBuffer>&&);
+#endif
+
+ void setSubData(unsigned long, const JSC::ArrayBuffer&);
using MappingCallback = WTF::Function<void(JSC::ArrayBuffer*)>;
void registerMappingCallback(MappingCallback&&, bool);
void unmap();
@@ -79,31 +104,33 @@
PendingMappingCallback(MappingCallback&&);
};
- GPUBuffer(PlatformBufferSmartPtr&&, const GPUBufferDescriptor&);
+ static bool validateBufferCreate(const GPUDevice&, const GPUBufferDescriptor&);
- static RefPtr<GPUBuffer> tryCreateSharedBuffer(const GPUDevice&, const GPUBufferDescriptor&);
+ GPUBuffer(PlatformBufferSmartPtr&&, const GPUBufferDescriptor&, Ref<GPUDevice>&&);
+
JSC::ArrayBuffer* stagingBufferForRead();
JSC::ArrayBuffer* stagingBufferForWrite();
+ void runMappingCallback();
- bool isMappable() const { return m_isMapWrite || m_isMapRead; }
- bool isMapWriteable() const { return m_isMapWrite && !m_pendingCallback; }
- bool isMapReadable() const { return m_isMapRead && !m_pendingCallback; }
+ bool isMapWrite() const { return m_usage & GPUBufferUsage::MapWrite; }
+ bool isMapRead() const { return m_usage & GPUBufferUsage::MapRead; }
+ bool isMapWriteable() const { return isMapWrite() && state() == State::Unmapped; }
+ bool isMapReadable() const { return isMapRead() && state() == State::Unmapped; }
PlatformBufferSmartPtr m_platformBuffer;
+ Ref<GPUDevice> m_device;
+#if USE(METAL)
+ Vector<RetainPtr<MTLBuffer>> m_subDataBuffers;
+#endif
+
RefPtr<JSC::ArrayBuffer> m_stagingBuffer;
- RefPtr<PendingMappingCallback> m_pendingCallback;
+ RefPtr<PendingMappingCallback> m_mappingCallback;
DeferrableTask<Timer> m_mappingCallbackTask;
unsigned long m_byteLength;
+ GPUBufferUsage::Flags m_usage;
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/GPUBufferBinding.h (242147 => 242148)
--- trunk/Source/WebCore/platform/graphics/gpu/GPUBufferBinding.h 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPUBufferBinding.h 2019-02-27 21:10:24 UTC (rev 242148)
@@ -33,7 +33,7 @@
namespace WebCore {
struct GPUBufferBinding {
- Ref<const GPUBuffer> buffer;
+ Ref<GPUBuffer> buffer;
unsigned long offset;
unsigned long size;
};
Modified: trunk/Source/WebCore/platform/graphics/gpu/GPUCommandBuffer.h (242147 => 242148)
--- trunk/Source/WebCore/platform/graphics/gpu/GPUCommandBuffer.h 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPUCommandBuffer.h 2019-02-27 21:10:24 UTC (rev 242148)
@@ -30,11 +30,13 @@
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
OBJC_PROTOCOL(MTLCommandBuffer);
namespace WebCore {
+class GPUBuffer;
class GPUDevice;
using PlatformCommandBuffer = MTLCommandBuffer;
@@ -45,11 +47,15 @@
static RefPtr<GPUCommandBuffer> create(GPUDevice&);
PlatformCommandBuffer* platformCommandBuffer() const { return m_platformCommandBuffer.get(); }
+ const Vector<Ref<GPUBuffer>>& usedBuffers() const { return m_usedBuffers; }
+ void useBuffer(Ref<GPUBuffer>&& buffer) { m_usedBuffers.append(WTFMove(buffer)); }
+
private:
GPUCommandBuffer(PlatformCommandBufferSmartPtr&&);
PlatformCommandBufferSmartPtr m_platformCommandBuffer;
+ Vector<Ref<GPUBuffer>> m_usedBuffers;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.cpp (242147 => 242148)
--- trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.cpp 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.cpp 2019-02-27 21:10:24 UTC (rev 242148)
@@ -44,9 +44,9 @@
namespace WebCore {
-RefPtr<GPUBuffer> GPUDevice::tryCreateBuffer(GPUBufferDescriptor&& descriptor) const
+RefPtr<GPUBuffer> GPUDevice::tryCreateBuffer(GPUBufferDescriptor&& descriptor)
{
- return GPUBuffer::tryCreate(*this, WTFMove(descriptor));
+ return GPUBuffer::tryCreate(makeRef(*this), WTFMove(descriptor));
}
RefPtr<GPUTexture> GPUDevice::tryCreateTexture(GPUTextureDescriptor&& descriptor) const
Modified: trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.h (242147 => 242148)
--- trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.h 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.h 2019-02-27 21:10:24 UTC (rev 242148)
@@ -60,7 +60,7 @@
public:
static RefPtr<GPUDevice> create(Optional<GPURequestAdapterOptions>&&);
- RefPtr<GPUBuffer> tryCreateBuffer(GPUBufferDescriptor&&) const;
+ RefPtr<GPUBuffer> tryCreateBuffer(GPUBufferDescriptor&&);
RefPtr<GPUTexture> tryCreateTexture(GPUTextureDescriptor&&) const;
RefPtr<GPUBindGroupLayout> tryCreateBindGroupLayout(GPUBindGroupLayoutDescriptor&&) const;
Copied: trunk/Source/WebCore/platform/graphics/gpu/GPUProgrammablePassEncoder.cpp (from rev 242145, trunk/Source/WebCore/platform/graphics/gpu/GPUBufferBinding.h) (0 => 242148)
--- trunk/Source/WebCore/platform/graphics/gpu/GPUProgrammablePassEncoder.cpp (rev 0)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPUProgrammablePassEncoder.cpp 2019-02-27 21:10:24 UTC (rev 242148)
@@ -0,0 +1,42 @@
+/*
+ * 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 "GPUProgrammablePassEncoder.h"
+
+#if ENABLE(WEBGPU)
+
+#include "GPUCommandBuffer.h"
+
+namespace WebCore {
+
+GPUProgrammablePassEncoder::GPUProgrammablePassEncoder(Ref<GPUCommandBuffer>&& commandBuffer)
+ : m_commandBuffer(WTFMove(commandBuffer))
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBGPU)
Modified: trunk/Source/WebCore/platform/graphics/gpu/GPUProgrammablePassEncoder.h (242147 => 242148)
--- trunk/Source/WebCore/platform/graphics/gpu/GPUProgrammablePassEncoder.h 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPUProgrammablePassEncoder.h 2019-02-27 21:10:24 UTC (rev 242148)
@@ -40,6 +40,7 @@
namespace WebCore {
class GPUBindGroup;
+class GPUCommandBuffer;
class GPURenderPipeline;
using PlatformProgrammablePassEncoder = MTLCommandEncoder;
@@ -49,12 +50,15 @@
virtual ~GPUProgrammablePassEncoder() = default;
void endPass();
- void setBindGroup(unsigned long, const GPUBindGroup&);
+ void setBindGroup(unsigned long, GPUBindGroup&);
virtual void setPipeline(Ref<GPURenderPipeline>&&) = 0;
protected:
+ GPUProgrammablePassEncoder(Ref<GPUCommandBuffer>&&);
virtual PlatformProgrammablePassEncoder* platformPassEncoder() const = 0;
+ GPUCommandBuffer& commandBuffer() const { return m_commandBuffer.get(); }
+
private:
#if USE(METAL)
void setResourceAsBufferOnEncoder(MTLArgumentEncoder *, const GPUBindingResource&, unsigned long, const char* const);
@@ -65,6 +69,7 @@
virtual void setFragmentBuffer(MTLBuffer *, unsigned long, unsigned long) { }
#endif // USE(METAL)
+ Ref<GPUCommandBuffer> m_commandBuffer;
bool m_isEncoding { true };
};
Modified: trunk/Source/WebCore/platform/graphics/gpu/GPURenderPassEncoder.h (242147 => 242148)
--- trunk/Source/WebCore/platform/graphics/gpu/GPURenderPassEncoder.h 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPURenderPassEncoder.h 2019-02-27 21:10:24 UTC (rev 242148)
@@ -49,15 +49,15 @@
class GPURenderPassEncoder : public GPUProgrammablePassEncoder {
public:
- static RefPtr<GPURenderPassEncoder> create(const GPUCommandBuffer&, GPURenderPassDescriptor&&);
+ static RefPtr<GPURenderPassEncoder> tryCreate(Ref<GPUCommandBuffer>&&, GPURenderPassDescriptor&&);
void setPipeline(Ref<GPURenderPipeline>&&) final;
- void setVertexBuffers(unsigned long, Vector<Ref<const GPUBuffer>>&&, Vector<unsigned long long>&&);
+ void setVertexBuffers(unsigned long, Vector<Ref<GPUBuffer>>&&, Vector<unsigned long long>&&);
void draw(unsigned long vertexCount, unsigned long instanceCount, unsigned long firstVertex, unsigned long firstInstance);
private:
- GPURenderPassEncoder(PlatformRenderPassEncoderSmartPtr&&);
+ GPURenderPassEncoder(Ref<GPUCommandBuffer>&&, PlatformRenderPassEncoderSmartPtr&&);
~GPURenderPassEncoder() { endPass(); } // Ensure that encoding has ended before release.
PlatformProgrammablePassEncoder* platformPassEncoder() const final;
Modified: trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm (242147 => 242148)
--- trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm 2019-02-27 21:10:24 UTC (rev 242148)
@@ -34,18 +34,51 @@
#import <_javascript_Core/ArrayBuffer.h>
#import <Metal/Metal.h>
#import <wtf/BlockObjCExceptions.h>
+#import <wtf/CheckedArithmetic.h>
+#import <wtf/MainThread.h>
namespace WebCore {
-RefPtr<GPUBuffer> GPUBuffer::tryCreateSharedBuffer(const GPUDevice& device, const GPUBufferDescriptor& descriptor)
+static const auto readOnlyMask = GPUBufferUsage::Index | GPUBufferUsage::Vertex | GPUBufferUsage::Uniform | GPUBufferUsage::TransferSrc;
+
+
+bool GPUBuffer::validateBufferCreate(const GPUDevice& device, const GPUBufferDescriptor& descriptor)
{
- ASSERT(device.platformDevice());
+ if (!device.platformDevice()) {
+ LOG(WebGPU, "GPUBuffer::create(): Invalid GPUDevice!");
+ return false;
+ }
+ if ((descriptor.usage & GPUBufferUsage::MapWrite) && (descriptor.usage & GPUBufferUsage::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)) {
+ LOG(WebGPU, "GPUBuffer::create(): Buffer cannot have both STORAGE and a read-only usage!");
+ return false;
+ }
+
+ return true;
+}
+
+RefPtr<GPUBuffer> GPUBuffer::tryCreate(Ref<GPUDevice>&& device, GPUBufferDescriptor&& descriptor)
+{
+ if (!validateBufferCreate(device.get(), descriptor))
+ 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.
+
+ MTLResourceOptions resourceOptions = MTLResourceCPUCacheModeDefaultCache;
+
+ // Mappable buffers use shared storage allocation.
+ resourceOptions |= (descriptor.usage & (GPUBufferUsage::MapWrite | GPUBufferUsage::MapRead)) ? MTLResourceStorageModeShared : MTLResourceStorageModePrivate;
+
RetainPtr<MTLBuffer> mtlBuffer;
BEGIN_BLOCK_OBJC_EXCEPTIONS;
- mtlBuffer = adoptNS([device.platformDevice() newBufferWithLength:descriptor.size options: MTLResourceCPUCacheModeDefaultCache]);
+ mtlBuffer = adoptNS([device->platformDevice() newBufferWithLength:descriptor.size options:resourceOptions]);
END_BLOCK_OBJC_EXCEPTIONS;
@@ -54,53 +87,116 @@
return nullptr;
}
- return adoptRef(*new GPUBuffer(WTFMove(mtlBuffer), descriptor));
+ return adoptRef(*new GPUBuffer(WTFMove(mtlBuffer), descriptor, WTFMove(device)));
}
-static const auto readOnlyMask = GPUBufferUsage::Index | GPUBufferUsage::Vertex | GPUBufferUsage::Uniform | GPUBufferUsage::TransferSrc;
+GPUBuffer::GPUBuffer(RetainPtr<MTLBuffer>&& buffer, const GPUBufferDescriptor& descriptor, Ref<GPUDevice>&& device)
+ : m_platformBuffer(WTFMove(buffer))
+ , m_device(WTFMove(device))
+ , m_byteLength(descriptor.size)
+ , m_usage(static_cast<GPUBufferUsage::Flags>(descriptor.usage))
+{
+}
-RefPtr<GPUBuffer> GPUBuffer::tryCreate(const GPUDevice& device, GPUBufferDescriptor&& descriptor)
+GPUBuffer::~GPUBuffer()
{
- if (!device.platformDevice()) {
- LOG(WebGPU, "GPUBuffer::create(): Invalid GPUDevice!");
- return nullptr;
+ destroy();
+}
+
+bool GPUBuffer::isReadOnly() const
+{
+ return m_usage & readOnlyMask;
+}
+
+GPUBuffer::State GPUBuffer::state() const
+{
+ if (!m_platformBuffer)
+ return State::Destroyed;
+ if (m_mappingCallback)
+ return State::Mapped;
+
+ return State::Unmapped;
+}
+
+void GPUBuffer::setSubData(unsigned long offset, const JSC::ArrayBuffer& data)
+{
+ if (!isTransferDst() || state() != State::Unmapped) {
+ LOG(WebGPU, "GPUBuffer::setSubData(): Invalid operation!");
+ return;
}
+ 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;
+ }
- 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;
+ // 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]));
+ END_BLOCK_OBJC_EXCEPTIONS;
}
- if ((descriptor.usage & readOnlyMask) && (descriptor.usage & GPUBufferUsage::Storage)) {
- LOG(WebGPU, "GPUBuffer::create(): Buffer cannot have both STORAGE and a read-only usage!");
- return nullptr;
+ __block auto stagingMtlBuffer = m_subDataBuffers.takeLast();
+
+ if (!stagingMtlBuffer || stagingMtlBuffer.get().length < data.byteLength()) {
+ LOG(WebGPU, "GPUBuffer::setSubData(): Unable to get staging buffer for provided data!");
+ return;
}
- // Mappable buffers need (default) shared storage allocation.
- if (descriptor.usage & (GPUBufferUsage::MapWrite | GPUBufferUsage::MapRead))
- return tryCreateSharedBuffer(device, descriptor);
+ memcpy(stagingMtlBuffer.get().contents, data.data(), data.byteLength());
- LOG(WebGPU, "GPUBuffer::create(): Support for non-mapped buffers not implemented!");
- return nullptr;
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ auto commandBuffer = retainPtr([m_device->getQueue()->platformQueue() commandBuffer]);
+ auto blitEncoder = retainPtr([commandBuffer blitCommandEncoder]);
+
+ [blitEncoder copyFromBuffer:stagingMtlBuffer.get() sourceOffset:0 toBuffer:m_platformBuffer.get() destinationOffset:offset size:stagingMtlBuffer.get().length];
+ [blitEncoder endEncoding];
+
+ if (isMappable())
+ commandBufferCommitted(commandBuffer.get());
+
+ auto protectedThis = makeRefPtr(this);
+ [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>) {
+ protectedThis->reuseSubDataBuffer(WTFMove(stagingMtlBuffer));
+ }];
+ [commandBuffer commit];
+
+ END_BLOCK_OBJC_EXCEPTIONS;
}
-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)
+#if USE(METAL)
+void GPUBuffer::commandBufferCommitted(MTLCommandBuffer *commandBuffer)
{
+ ++m_numScheduledCommandBuffers;
+
+ auto protectedThis = makeRefPtr(this);
+ [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>) {
+ protectedThis->commandBufferCompleted();
+ }];
}
-GPUBuffer::~GPUBuffer()
+void GPUBuffer::commandBufferCompleted()
{
- unmap();
+ ASSERT(m_numScheduledCommandBuffers);
+
+ if (m_numScheduledCommandBuffers == 1 && state() == State::Mapped) {
+ callOnMainThread([this, protectedThis = makeRef(*this)] () {
+ runMappingCallback();
+ });
+ }
+
+ --m_numScheduledCommandBuffers;
}
+void GPUBuffer::reuseSubDataBuffer(RetainPtr<MTLBuffer>&& buffer)
+{
+ m_subDataBuffers.append(WTFMove(buffer));
+}
+#endif // USE(METAL)
+
void GPUBuffer::registerMappingCallback(MappingCallback&& callback, bool isRead)
{
// Reject if request is invalid.
@@ -115,21 +211,25 @@
return;
}
- ASSERT(!m_pendingCallback && !m_mappingCallbackTask.hasPendingTask());
+ ASSERT(!m_mappingCallback && !m_mappingCallbackTask.hasPendingTask());
// An existing callback means this buffer is in the mapped state.
- m_pendingCallback = PendingMappingCallback::create(WTFMove(callback));
+ m_mappingCallback = 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());
+ runMappingCallback();
});
}
}
+void GPUBuffer::runMappingCallback()
+{
+ if (m_mappingCallback)
+ m_mappingCallback->callback(isMapRead() ? stagingBufferForRead() : stagingBufferForWrite());
+}
+
JSC::ArrayBuffer* GPUBuffer::stagingBufferForRead()
{
if (!m_stagingBuffer)
@@ -153,28 +253,25 @@
return;
}
- if (m_stagingBuffer && m_isMapWrite) {
+ if (m_stagingBuffer && isMapWrite()) {
+ ASSERT(m_platformBuffer);
memcpy(m_platformBuffer.get().contents, m_stagingBuffer->data(), m_byteLength);
m_stagingBuffer = nullptr;
}
- if (m_pendingCallback) {
+ if (m_mappingCallback) {
m_mappingCallbackTask.cancelTask();
- m_pendingCallback->callback(nullptr);
- m_pendingCallback = nullptr;
+ m_mappingCallback->callback(nullptr);
+ m_mappingCallback = nullptr;
}
}
void GPUBuffer::destroy()
{
- if (isMappable())
+ if (state() == State::Mapped)
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;
+ m_platformBuffer = nullptr;
}
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm (242147 => 242148)
--- trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm 2019-02-27 21:10:24 UTC (rev 242148)
@@ -61,7 +61,8 @@
}
auto& bufferBinding = WTF::get<GPUBufferBinding>(resource);
- auto mtlBuffer = bufferBinding.buffer->platformBuffer();
+ auto& bufferRef = bufferBinding.buffer;
+ auto mtlBuffer = bufferRef->platformBuffer();
if (!mtlBuffer) {
LOG(WebGPU, "%s: Invalid MTLBuffer in GPUBufferBinding!", functionName);
@@ -71,12 +72,14 @@
BEGIN_BLOCK_OBJC_EXCEPTIONS;
[argumentEncoder setBuffer:mtlBuffer offset:bufferBinding.offset atIndex:index];
- useResource(mtlBuffer, bufferBinding.buffer->isReadOnly() ? MTLResourceUsageRead : MTLResourceUsageRead | MTLResourceUsageWrite);
+ useResource(mtlBuffer, bufferRef->isReadOnly() ? MTLResourceUsageRead : MTLResourceUsageRead | MTLResourceUsageWrite);
END_BLOCK_OBJC_EXCEPTIONS;
+
+ m_commandBuffer->useBuffer(bufferRef.copyRef());
}
-void GPUProgrammablePassEncoder::setBindGroup(unsigned long index, const GPUBindGroup& bindGroup)
+void GPUProgrammablePassEncoder::setBindGroup(unsigned long index, GPUBindGroup& bindGroup)
{
const char* const functionName = "GPUProgrammablePassEncoder::setBindGroup()";
#if LOG_DISABLED
Modified: trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUQueueMetal.mm (242147 => 242148)
--- trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUQueueMetal.mm 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUQueueMetal.mm 2019-02-27 21:10:24 UTC (rev 242148)
@@ -70,10 +70,20 @@
{
}
-void GPUQueue::submit(Vector<Ref<const GPUCommandBuffer>>&& buffers)
+void GPUQueue::submit(Vector<Ref<const GPUCommandBuffer>>&& commandBuffers)
{
- for (auto& buffer : buffers)
- [buffer->platformCommandBuffer() commit];
+ for (auto& commandBuffer : commandBuffers) {
+ // Prevent any buffer mapping callbacks from executing until command buffer is complete.
+ for (auto& buffer : commandBuffer->usedBuffers()) {
+ if (buffer->state() != GPUBuffer::State::Unmapped) {
+ LOG(WebGPU, "GPUQueue::submit(): Invalid GPUBuffer set on a GPUCommandBuffer!");
+ return;
+ }
+ buffer->commandBufferCommitted(commandBuffer->platformCommandBuffer());
+ }
+
+ [commandBuffer->platformCommandBuffer() commit];
+ }
}
String GPUQueue::label() const
Modified: trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPassEncoderMetal.mm (242147 => 242148)
--- trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPassEncoderMetal.mm 2019-02-27 21:05:39 UTC (rev 242147)
+++ trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPassEncoderMetal.mm 2019-02-27 21:10:24 UTC (rev 242148)
@@ -113,9 +113,9 @@
return true;
}
-RefPtr<GPURenderPassEncoder> GPURenderPassEncoder::create(const GPUCommandBuffer& buffer, GPURenderPassDescriptor&& descriptor)
+RefPtr<GPURenderPassEncoder> GPURenderPassEncoder::tryCreate(Ref<GPUCommandBuffer>&& buffer, GPURenderPassDescriptor&& descriptor)
{
- const char* const functionName = "GPURenderPassEncoder::create()";
+ const char* const functionName = "GPURenderPassEncoder::tryCreate()";
RetainPtr<MTLRenderPassDescriptor> mtlDescriptor;
@@ -137,11 +137,11 @@
&& !populateMtlDepthStencilAttachment(mtlDescriptor.get().depthAttachment, *descriptor.depthStencilAttachment, functionName))
return nullptr;
- PlatformRenderPassEncoderSmartPtr mtlEncoder;
+ RetainPtr<MTLRenderCommandEncoder> mtlEncoder;
BEGIN_BLOCK_OBJC_EXCEPTIONS;
- mtlEncoder = retainPtr([buffer.platformCommandBuffer() renderCommandEncoderWithDescriptor:mtlDescriptor.get()]);
+ mtlEncoder = retainPtr([buffer->platformCommandBuffer() renderCommandEncoderWithDescriptor:mtlDescriptor.get()]);
END_BLOCK_OBJC_EXCEPTIONS;
@@ -150,11 +150,12 @@
return nullptr;
}
- return adoptRef(new GPURenderPassEncoder(WTFMove(mtlEncoder)));
+ return adoptRef(new GPURenderPassEncoder(WTFMove(buffer), WTFMove(mtlEncoder)));
}
-GPURenderPassEncoder::GPURenderPassEncoder(PlatformRenderPassEncoderSmartPtr&& encoder)
- : m_platformRenderPassEncoder(WTFMove(encoder))
+GPURenderPassEncoder::GPURenderPassEncoder(Ref<GPUCommandBuffer>&& commandBuffer, RetainPtr<MTLRenderCommandEncoder>&& encoder)
+ : GPUProgrammablePassEncoder(WTFMove(commandBuffer))
+ , m_platformRenderPassEncoder(WTFMove(encoder))
{
}
@@ -177,13 +178,14 @@
m_pipeline = WTFMove(pipeline);
}
-void GPURenderPassEncoder::setVertexBuffers(unsigned long index, Vector<Ref<const GPUBuffer>>&& buffers, Vector<unsigned long long>&& offsets)
+void GPURenderPassEncoder::setVertexBuffers(unsigned long index, Vector<Ref<GPUBuffer>>&& buffers, Vector<unsigned long long>&& offsets)
{
ASSERT(buffers.size() && offsets.size() == buffers.size());
BEGIN_BLOCK_OBJC_EXCEPTIONS;
- auto mtlBuffers = buffers.map([] (const auto& buffer) {
+ auto mtlBuffers = buffers.map([this] (auto& buffer) {
+ commandBuffer().useBuffer(buffer.copyRef());
return buffer->platformBuffer();
});