Changeset 246217 in webkit


Ignore:
Timestamp:
Jun 7, 2019 3:24:55 PM (5 years ago)
Author:
Justin Fan
Message:

[WebGPU] Remove GPUBuffer.setSubData and implement GPUDevice.createBufferMapped
https://bugs.webkit.org/show_bug.cgi?id=198591

Reviewed by Myles C. Maxfield.

Source/WebCore:

Remove GPUBuffer.setSubData from the WebGPU API.
Add GPUDevice.createBufferMapped to the WebGPU API.

Existing tests have been updated.

  • Modules/webgpu/WebGPUBuffer.cpp:

(WebCore::WebGPUBuffer::setSubData): Deleted.

  • Modules/webgpu/WebGPUBuffer.h:
  • Modules/webgpu/WebGPUBuffer.idl:
  • Modules/webgpu/WebGPUDevice.cpp:

(WebCore::WebGPUDevice::createBufferMapped const):

  • Modules/webgpu/WebGPUDevice.h:
  • Modules/webgpu/WebGPUDevice.idl:
  • platform/graphics/gpu/GPUBuffer.h:
  • platform/graphics/gpu/GPUCommandBuffer.h:
  • platform/graphics/gpu/GPUDevice.cpp:

(WebCore::GPUDevice::tryCreateBuffer):

  • platform/graphics/gpu/GPUDevice.h:
  • platform/graphics/gpu/cocoa/GPUBufferMetal.mm:

(WebCore::GPUBuffer::tryCreate):
(WebCore::GPUBuffer::GPUBuffer):
(WebCore::GPUBuffer::state const):
(WebCore::GPUBuffer::mapOnCreation):
(WebCore::GPUBuffer::commandBufferCompleted):
(WebCore::GPUBuffer::copyStagingBufferToGPU):

Required to unmap GPUBuffers created with GPU-private storage.

(WebCore::GPUBuffer::unmap):
(WebCore::GPUBuffer::setSubData): Deleted.
(WebCore::GPUBuffer::reuseSubDataBuffer): Deleted.

LayoutTests:

GPUBuffer.setSubData has been removed from the WebGPU implementation.
GPUDevice.createBufferMapped has been added to the WebGPU implementation.
Replace all setSubData calls with appropriate replacements.

  • webgpu/blend-triangle-strip.html:
  • webgpu/blit-commands.html:
  • webgpu/buffer-command-buffer-races.html:
  • webgpu/buffer-resource-triangles.html:
  • webgpu/compute-squares.html:
  • webgpu/depth-enabled-triangle-strip.html:
  • webgpu/draw-indexed-triangles.html:
  • webgpu/js/webgpu-functions.js:

(createBufferWithData):
(async.mapWriteDataToBuffer):

  • webgpu/map-read-buffers-expected.txt:
  • webgpu/map-read-buffers.html:
  • webgpu/texture-triangle-strip.html:
  • webgpu/vertex-buffer-triangle-strip.html:
Location:
trunk
Files:
25 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r246214 r246217  
     12019-06-07  Justin Fan  <justin_fan@apple.com>
     2
     3        [WebGPU] Remove GPUBuffer.setSubData and implement GPUDevice.createBufferMapped
     4        https://bugs.webkit.org/show_bug.cgi?id=198591
     5
     6        Reviewed by Myles C. Maxfield.
     7
     8        GPUBuffer.setSubData has been removed from the WebGPU implementation.
     9        GPUDevice.createBufferMapped has been added to the WebGPU implementation.
     10        Replace all setSubData calls with appropriate replacements.
     11
     12        * webgpu/blend-triangle-strip.html:
     13        * webgpu/blit-commands.html:
     14        * webgpu/buffer-command-buffer-races.html:
     15        * webgpu/buffer-resource-triangles.html:
     16        * webgpu/compute-squares.html:
     17        * webgpu/depth-enabled-triangle-strip.html:
     18        * webgpu/draw-indexed-triangles.html:
     19        * webgpu/js/webgpu-functions.js:
     20        (createBufferWithData):
     21        (async.mapWriteDataToBuffer):
     22        * webgpu/map-read-buffers-expected.txt:
     23        * webgpu/map-read-buffers.html:
     24        * webgpu/texture-triangle-strip.html:
     25        * webgpu/vertex-buffer-triangle-strip.html:
     26
    1272019-06-07  Per Arne Vollan  <pvollan@apple.com>
    228
  • trunk/LayoutTests/webgpu/blend-triangle-strip.html

    r245905 r246217  
    7676        1, -1, 0, 1
    7777    ]);
    78     const vertexBuffer = device.createBuffer({ size: vertexData.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST });
    79     vertexBuffer.setSubData(0, vertexData.buffer);
     78    const vertexBuffer = createBufferWithData(device, { size: vertexData.byteLength, usage: GPUBufferUsage.VERTEX }, vertexData.buffer);
    8079
    8180    const context = canvas.getContext("gpu");
  • trunk/LayoutTests/webgpu/blit-commands.html

    r244442 r246217  
    3131    const bufferDescriptor = {
    3232        size: imageData.data.byteLength,
    33         usage: GPUBufferUsage.TRANSFER_SRC | GPUBufferUsage.TRANSFER_DST
     33        usage: GPUBufferUsage.TRANSFER_SRC
    3434    };
    35     const bufferA = device.createBuffer(bufferDescriptor);
    36     bufferA.setSubData(0, imageData.data.buffer);
     35    bufferA = createBufferWithData(device, bufferDescriptor, imageData.data.buffer);
    3736
     37    bufferDescriptor.usage |= GPUBufferUsage.TRANSFER_DST;
    3838    const bufferB = device.createBuffer(bufferDescriptor);
    3939    const bufferViewB = {
  • trunk/LayoutTests/webgpu/buffer-command-buffer-races.html

    r245905 r246217  
    6464
    6565function createAndSetVertexBuffer(device, vertices) {
    66     const floatArray = new Float32Array(vertices);
    67     const buffer = device.createBuffer({ size: floatArray.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST });
    68     buffer.setSubData(0, floatArray.buffer);
    69     return buffer;
     66    const vertexArray = new Float32Array(vertices)
     67    return createBufferWithData(device, { size: vertexArray.byteLength, usage: GPUBufferUsage.VERTEX }, vertexArray.buffer);
    7068}
    7169
     
    9896    const blueArray = new Float32Array(blue);
    9997
    100     const colorBuffer = device.createBuffer({ size: greenArray.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_WRITE });
    101     colorBuffer.setSubData(0, greenArray.buffer);
     98    const colorBuffer = createBufferWithData(device, { size: greenArray.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE }, greenArray.buffer);
    10299
    103100    const attachment = {
     
    127124    colorBuffer.unmap();
    128125
    129     /* setSubData immediately after a submit should not affect the preceding draw call. */
     126    /* Writing data immediately after a submit should not affect the preceding draw call. */
    130127    drawAndSubmitCommands(device, pipeline, attachment, middleBuffer, colorBuffer);
    131     colorBuffer.setSubData(0, blueArray.buffer);
     128    await mapWriteDataToBuffer(colorBuffer, blueArray.buffer);
    132129
    133130    /* destroy right after a submit should not affect the draw call. */
    134     colorBuffer.setSubData(0, greenArray.buffer);
     131    await mapWriteDataToBuffer(colorBuffer, greenArray.buffer);
    135132    drawAndSubmitCommands(device, pipeline, attachment, upperRightBuffer, colorBuffer);
    136133    upperRightBuffer.destroy();
  • trunk/LayoutTests/webgpu/buffer-resource-triangles.html

    r245905 r246217  
    8282
    8383const vertexSize = 4 * 4;
    84 const verticesBufferSize = vertexSize * 3;
    8584function createAndUploadVerticesBuffer(device) {
    86     const buffer = device.createBuffer({ size:verticesBufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST });
    87     const arrayBuffer = new Float32Array([
     85    const vertexArray = new Float32Array([
    8886        0, 1, 0, 1,
    8987        -1, -1, 0, 1,
    9088        1, -1, 0, 1
    91     ]).buffer;
    92 
    93     buffer.setSubData(0, arrayBuffer);
    94     return buffer;
     89    ]);
     90    return createBufferWithData(device, { size: vertexArray.byteLength, usage: GPUBufferUsage.VERTEX }, vertexArray.buffer);
    9591}
    9692
  • trunk/LayoutTests/webgpu/compute-squares.html

    r244442 r246217  
    4040    const pipeline = device.createComputePipeline({ computeStage: computeStageDescriptor });
    4141   
    42     const dataBuffer = device.createBuffer({ size: data.byteLength, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ });
    43     dataBuffer.setSubData(0, data.buffer);
     42    const dataBuffer = createBufferWithData(device, { size: data.byteLength, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.MAP_READ }, data.buffer);
    4443   
    4544    const bgLayoutBinding = { binding: dataBinding, visibility: GPUShaderStageBit.COMPUTE, type: "storage-buffer" };
  • trunk/LayoutTests/webgpu/depth-enabled-triangle-strip.html

    r245905 r246217  
    4949
    5050function createVertexBuffer(device) {
    51     const bufferSize = 4 * 4 * 4;
    52     const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST });
    53     const arrayBuffer = new Float32Array([
     51    const vertexArray = new Float32Array([
    5452        // float4 xyzw
    5553        -1, 1, 0, 1,
     
    5755        1, 1, 0, 1,
    5856        1, -1, 0, 1
    59     ]).buffer;
    60    
    61     buffer.setSubData(0, arrayBuffer);
    62     return buffer;
     57    ]);
     58    return createBufferWithData(device, { size: vertexArray.byteLength, usage: GPUBufferUsage.VERTEX }, vertexArray.buffer);
    6359}
    6460
  • trunk/LayoutTests/webgpu/draw-indexed-triangles.html

    r245905 r246217  
    5454        1, -1, 0, 1, 1
    5555    ]);
    56     const buffer = device.createBuffer({ size: vertexArray.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST });
    57     buffer.setSubData(0, vertexArray.buffer);
    58 
    59     return buffer;
     56    return createBufferWithData(device, { size: vertexArray.byteLength, usage: GPUBufferUsage.VERTEX }, vertexArray.buffer);
    6057}
    6158
     
    6663    const offsetArray = [1, 3, 5, 3, 5, 7].map(v => { return v - indexOffset; });
    6764    const indexArray = new Uint32Array([1, 3, 5, 3, 5, 7].map(v => { return v - indexOffset; }));
    68     const buffer = device.createBuffer({ size: indexArray.byteLength + indexBufferOffset, usage: GPUBufferUsage.INDEX | GPUBufferUsage.TRANSFER_DST });
    69     buffer.setSubData(indexBufferOffset, indexArray.buffer);
     65    const buffer = createBufferWithData(
     66        device,
     67        {
     68            size: indexArray.byteLength + indexBufferOffset,
     69            usage: GPUBufferUsage.INDEX
     70        },
     71        indexArray.buffer,
     72        indexBufferOffset
     73    );
    7074
    7175    return buffer;
  • trunk/LayoutTests/webgpu/js/webgpu-functions.js

    r245905 r246217  
    8989    renderPassEncoder.endPass();
    9090}
     91
     92function createBufferWithData(device, descriptor, data, offset = 0) {
     93    const mappedBuffer = device.createBufferMapped(descriptor);
     94    const dataArray = new Uint8Array(mappedBuffer[1]);
     95    dataArray.set(new Uint8Array(data), offset);
     96    mappedBuffer[0].unmap();
     97    return mappedBuffer[0];
     98}
     99
     100async function mapWriteDataToBuffer(buffer, data, offset = 0) {
     101    const arrayBuffer = await buffer.mapWriteAsync();
     102    const writeArray = new Uint8Array(arrayBuffer);
     103    writeArray.set(new Uint8Array(data), offset);
     104    buffer.unmap();
     105}
  • trunk/LayoutTests/webgpu/map-read-buffers-expected.txt

    r242148 r246217  
    11
    2 PASS setSubData, mapReadAsync, unmap, and destroy on a GPUBuffer.
     2PASS mapReadAsync, unmap, and destroy on a GPUBuffer.
     3PASS GPUBuffer.mapReadAsync on a buffer created via GPUDevice.createBufferMapped.
    34PASS Reject a map read on a buffer not created with MAP_READ usage.
    45PASS Reject a map read on a mapped GPUBuffer.
  • trunk/LayoutTests/webgpu/map-read-buffers.html

    r244856 r246217  
    11<!DOCTYPE html><!-- webkit-test-runner [ experimental:WebGPUEnabled=true ] -->
    22<meta charset=utf-8>
    3 <title>Tests for setSubData and mapReadAsync on a GPUBuffer.</title>
     3<title>Tests for createBufferMapped and mapReadAsync on a GPUBuffer.</title>
    44<body>
    55<script src="../resources/testharness.js"></script>
     
    1212    // Basic mapReadAsync functionality
    1313    promise_test(async () => {
    14         const buffer = device.createBuffer({ size: 16, usage: GPUBufferUsage.TRANSFER_DST | GPUBufferUsage.MAP_READ });
     14        const buffer = device.createBuffer({ size: 16, usage: GPUBufferUsage.MAP_READ });
    1515        assert_true(buffer instanceof GPUBuffer, "createBuffer returned a GPUBuffer");
    16 
    17         let array = new Float32Array([1, 2, 3, 4]);
    18         buffer.setSubData(0, array.buffer);
    1916
    2017        let arrayBuffer = await buffer.mapReadAsync();
     
    2219
    2320        const readArray = new Float32Array(arrayBuffer);
    24         assert_equals(readArray[3], 4, "successfully map-read value set by setSubData");
    25 
    26         buffer.unmap();
    27 
    28         buffer.setSubData(4 * 3, array.slice(0, 1).buffer);
    29         let arrayBuffer1 = await buffer.mapReadAsync();
    30         const readArray1 = new Float32Array(arrayBuffer1);
    31         assert_equals(readArray[3], 1, "successfully setSubData with an offset");
     21        assert_equals(readArray[0], 0, "successfully access a value from a map read");
    3222
    3323        buffer.unmap();
     
    4131        }, () => {});
    4232
    43     }, "setSubData, mapReadAsync, unmap, and destroy on a GPUBuffer.");
     33    }, "mapReadAsync, unmap, and destroy on a GPUBuffer.");
     34
     35    // GPUDevice.createBufferMapped
     36    promise_test(async () => {
     37        const bufferResult = device.createBufferMapped({ size: 16, usage: GPUBufferUsage.MAP_READ });
     38        const buffer = bufferResult[0];
     39        const arrayBuffer = bufferResult[1];
     40
     41        assert_true(buffer instanceof GPUBuffer, "createBufferMapped returned a GPUBuffer");
     42        assert_true(arrayBuffer instanceof ArrayBuffer, "createBufferMapped returned an ArrayBuffer");
     43
     44        let array = new Float32Array(arrayBuffer);
     45        array.set([1, 2, 3, 4]);
     46
     47        // Buffer should already be "mapped".
     48        await buffer.mapReadAsync().then(() => {
     49            assert_unreached("GPUBuffer created via GPUBufferMapped cannot be mapped until after first unmap!");
     50        }, () => {});
     51
     52        buffer.unmap();
     53
     54        // Buffer should not be re-mappable for writes.
     55        await buffer.mapWriteAsync().then(() => {
     56            assert_unreached("Buffer was not created with MAP_WRITE!");
     57        }, () => {});
     58
     59        // Read results of original writes.
     60        let resultArrayBuffer = await buffer.mapReadAsync();
     61        const resultArray = new Float32Array(resultArrayBuffer);
     62        resultArray.forEach((v, i) => {
     63            assert_equals(v, array[i], "Successfully map-read value written to GPUBuffer mapped on creation");
     64        })
     65       
     66        buffer.destroy();
     67    }, "GPUBuffer.mapReadAsync on a buffer created via GPUDevice.createBufferMapped.");
    4468
    4569    /* Basic validation */
  • trunk/LayoutTests/webgpu/texture-triangle-strip.html

    r245905 r246217  
    9090        1, -1, 0, 1
    9191    ]);
    92     const positionBuffer = device.createBuffer({ size: positionArray.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST });
    93     positionBuffer.setSubData(0, positionArray.buffer);
     92    const positionBuffer = createBufferWithData(device, { size: positionArray.byteLength, usage: GPUBufferUsage.VERTEX }, positionArray.buffer);
    9493
    9594    const texCoordsArray = new Float32Array([
     
    10099        1, 1
    101100    ]);
    102     const textureCoordBuffer = device.createBuffer({ size: texCoordsArray.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST });
    103     textureCoordBuffer.setSubData(0, texCoordsArray.buffer);
     101    const textureCoordBuffer = createBufferWithData(device, { size: texCoordsArray.byteLength, usage: GPUBufferUsage.VERTEX }, texCoordsArray.buffer);
    104102
    105103    const vertexInputDescriptor = createVertexInputDescriptor();
     
    123121    const textureBufferDescriptor = {
    124122        size: imageData.data.length,
    125         usage: GPUBufferUsage.TRANSFER_SRC | GPUBufferUsage.TRANSFER_DST
    126     };
    127     const textureBuffer = device.createBuffer(textureBufferDescriptor);
    128     textureBuffer.setSubData(0, imageData.data.buffer);
     123        usage: GPUBufferUsage.TRANSFER_SRC
     124    };
     125    const textureBuffer = createBufferWithData(device, textureBufferDescriptor, imageData.data.buffer);
    129126
    130127    // Create GPUTexture
  • trunk/LayoutTests/webgpu/vertex-buffer-triangle-strip.html

    r245905 r246217  
    4343
    4444function createVertexBuffer(device) {
    45     const bufferSize = 4 * 5 * 4;
    46     const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST });
    47     const vertexArrayBuffer0 = new Float32Array([
     45    const vertexArray = new Float32Array([
    4846        // float4 xyzw, float g
    4947        -1, 1, 0, 1, 1,
    50         -1, -1, 0, 1, 1
    51     ]).buffer;
    52     const vertexArrayBuffer1 = new Float32Array([
     48        -1, -1, 0, 1, 1,
    5349        1, 1, 0, 1, 1,
    5450        1, -1, 0, 1, 1
    55     ]).buffer;
     51    ]);
    5652
    57     buffer.setSubData(0, vertexArrayBuffer0);
    58     buffer.setSubData(4 * 5 * 2, vertexArrayBuffer1);
    59 
    60     return buffer;
     53    return createBufferWithData(
     54        device,
     55        {
     56            size: vertexArray.byteLength,
     57            usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE
     58        },
     59        vertexArray.buffer
     60    );
    6161}
    6262
  • trunk/Source/WebCore/ChangeLog

    r246216 r246217  
     12019-06-07  Justin Fan  <justin_fan@apple.com>
     2
     3        [WebGPU] Remove GPUBuffer.setSubData and implement GPUDevice.createBufferMapped
     4        https://bugs.webkit.org/show_bug.cgi?id=198591
     5
     6        Reviewed by Myles C. Maxfield.
     7
     8        Remove GPUBuffer.setSubData from the WebGPU API.
     9        Add GPUDevice.createBufferMapped to the WebGPU API.
     10
     11        Existing tests have been updated.
     12
     13        * Modules/webgpu/WebGPUBuffer.cpp:
     14        (WebCore::WebGPUBuffer::setSubData): Deleted.
     15        * Modules/webgpu/WebGPUBuffer.h:
     16        * Modules/webgpu/WebGPUBuffer.idl:
     17        * Modules/webgpu/WebGPUDevice.cpp:
     18        (WebCore::WebGPUDevice::createBufferMapped const):
     19        * Modules/webgpu/WebGPUDevice.h:
     20        * Modules/webgpu/WebGPUDevice.idl:
     21        * platform/graphics/gpu/GPUBuffer.h:
     22        * platform/graphics/gpu/GPUCommandBuffer.h:
     23        * platform/graphics/gpu/GPUDevice.cpp:
     24        (WebCore::GPUDevice::tryCreateBuffer):
     25        * platform/graphics/gpu/GPUDevice.h:
     26        * platform/graphics/gpu/cocoa/GPUBufferMetal.mm:
     27        (WebCore::GPUBuffer::tryCreate):
     28        (WebCore::GPUBuffer::GPUBuffer):
     29        (WebCore::GPUBuffer::state const):
     30        (WebCore::GPUBuffer::mapOnCreation):
     31        (WebCore::GPUBuffer::commandBufferCompleted):
     32        (WebCore::GPUBuffer::copyStagingBufferToGPU):
     33                Required to unmap GPUBuffers created with GPU-private storage.
     34        (WebCore::GPUBuffer::unmap):
     35        (WebCore::GPUBuffer::setSubData): Deleted.
     36        (WebCore::GPUBuffer::reuseSubDataBuffer): Deleted.
     37
    1382019-06-07  Michael Catanzaro  <mcatanzaro@igalia.com>
    239
  • trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.cpp

    r243658 r246217  
    4141    : m_buffer(WTFMove(buffer))
    4242{
    43 }
    44 
    45 void WebGPUBuffer::setSubData(uint64_t offset, const JSC::ArrayBuffer& data)
    46 {
    47     if (!m_buffer)
    48         LOG(WebGPU, "GPUBuffer::setSubData(): Invalid operation!");
    49     else
    50         m_buffer->setSubData(offset, data);
    5143}
    5244
  • trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.h

    r243658 r246217  
    4949    const GPUBuffer* buffer() const { return m_buffer.get(); }
    5050
    51     void setSubData(uint64_t, const JSC::ArrayBuffer&);
    5251    using BufferMappingPromise = DOMPromiseDeferred<IDLInterface<JSC::ArrayBuffer>>;
    5352    void mapReadAsync(BufferMappingPromise&&);
  • trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.idl

    r244856 r246217  
    3333    InterfaceName=GPUBuffer
    3434] interface WebGPUBuffer {
    35     void setSubData(u64 offset, ArrayBuffer data);
    36 
    3735    Promise<ArrayBuffer> mapReadAsync();
    3836    Promise<ArrayBuffer> mapWriteAsync();
  • trunk/Source/WebCore/Modules/webgpu/WebGPUDevice.cpp

    r244507 r246217  
    4242#include "GPUShaderModuleDescriptor.h"
    4343#include "GPUTextureDescriptor.h"
     44#include "JSDOMConvertBufferSource.h"
     45#include "JSWebGPUBuffer.h"
    4446#include "Logging.h"
    4547#include "WebGPUBindGroup.h"
     
    4749#include "WebGPUBindGroupDescriptor.h"
    4850#include "WebGPUBindGroupLayout.h"
    49 #include "WebGPUBuffer.h"
    5051#include "WebGPUBufferBinding.h"
    5152#include "WebGPUCommandEncoder.h"
     
    8384    auto buffer = m_device->tryCreateBuffer(descriptor);
    8485    return WebGPUBuffer::create(WTFMove(buffer));
     86}
     87
     88Vector<JSC::JSValue> WebGPUDevice::createBufferMapped(JSC::ExecState& state, const GPUBufferDescriptor& descriptor) const
     89{
     90    JSC::JSValue wrappedArrayBuffer = JSC::jsNull();
     91
     92    auto buffer = m_device->tryCreateBuffer(descriptor, true);
     93    if (buffer) {
     94        auto arrayBuffer = buffer->mapOnCreation();
     95        wrappedArrayBuffer = toJS(&state, JSC::jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject()), arrayBuffer);
     96    }
     97
     98    auto webBuffer = WebGPUBuffer::create(WTFMove(buffer));
     99    auto wrappedWebBuffer = toJS(&state, JSC::jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject()), webBuffer);
     100
     101    return { wrappedWebBuffer, wrappedArrayBuffer };
    85102}
    86103
  • trunk/Source/WebCore/Modules/webgpu/WebGPUDevice.h

    r244507 r246217  
    3535#include <wtf/RefCounted.h>
    3636#include <wtf/RefPtr.h>
     37#include <wtf/Vector.h>
     38
     39namespace JSC {
     40class ArrayBuffer;
     41class JSValue;
     42}
    3743
    3844namespace WebCore {
     
    7076
    7177    Ref<WebGPUBuffer> createBuffer(const GPUBufferDescriptor&) const;
     78    Vector<JSC::JSValue> createBufferMapped(JSC::ExecState&, const GPUBufferDescriptor&) const;
    7279    Ref<WebGPUTexture> createTexture(const GPUTextureDescriptor&) const;
    7380    Ref<WebGPUSampler> createSampler(const GPUSamplerDescriptor&) const;
  • trunk/Source/WebCore/Modules/webgpu/WebGPUDevice.idl

    r244856 r246217  
    2525// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
    2626
     27typedef sequence<any> GPUMappedBuffer;  // [GPUBuffer, ArrayBuffer]
     28
    2729[
    2830    Conditional=WEBGPU,
     
    3436
    3537    WebGPUBuffer createBuffer(GPUBufferDescriptor descriptor);
     38    [CallWith=ExecState] GPUMappedBuffer createBufferMapped(GPUBufferDescriptor descriptor);
    3639    WebGPUTexture createTexture(GPUTextureDescriptor descriptor);
    3740    WebGPUSampler createSampler(GPUSamplerDescriptor descriptor);
  • trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.h

    r244235 r246217  
    6969    ~GPUBuffer();
    7070
    71     static RefPtr<GPUBuffer> tryCreate(Ref<GPUDevice>&&, const GPUBufferDescriptor&);
     71    static RefPtr<GPUBuffer> tryCreate(Ref<GPUDevice>&&, const GPUBufferDescriptor&, bool isMappedOnCreation);
    7272
    7373    PlatformBuffer *platformBuffer() const { return m_platformBuffer.get(); }
     
    8383    State state() const;
    8484
     85    JSC::ArrayBuffer* mapOnCreation();
     86
    8587#if USE(METAL)
    8688    void commandBufferCommitted(MTLCommandBuffer *);
    8789    void commandBufferCompleted();
    88 
    89     void reuseSubDataBuffer(RetainPtr<MTLBuffer>&&);
    9090#endif
    9191
    92     void setSubData(uint64_t, const JSC::ArrayBuffer&);
    9392    using MappingCallback = WTF::Function<void(JSC::ArrayBuffer*)>;
    9493    void registerMappingCallback(MappingCallback&&, bool);
     
    109108    };
    110109
     110    GPUBuffer(PlatformBufferSmartPtr&&, Ref<GPUDevice>&&, size_t, OptionSet<GPUBufferUsage::Flags>, bool);
    111111    static bool validateBufferUsage(const GPUDevice&, OptionSet<GPUBufferUsage::Flags>);
    112 
    113     GPUBuffer(PlatformBufferSmartPtr&&, size_t, OptionSet<GPUBufferUsage::Flags>, Ref<GPUDevice>&&);
    114112
    115113    JSC::ArrayBuffer* stagingBufferForRead();
    116114    JSC::ArrayBuffer* stagingBufferForWrite();
    117115    void runMappingCallback();
     116    void copyStagingBufferToGPU();
    118117
    119118    bool isMapWrite() const { return m_usage.contains(GPUBufferUsage::Flags::MapWrite); }
     
    125124    Ref<GPUDevice> m_device;
    126125
    127 #if USE(METAL)
    128     Vector<RetainPtr<MTLBuffer>> m_subDataBuffers;
    129 #endif
    130 
    131126    RefPtr<JSC::ArrayBuffer> m_stagingBuffer;
    132127    RefPtr<PendingMappingCallback> m_mappingCallback;
     
    136131    OptionSet<GPUBufferUsage::Flags> m_usage;
    137132    unsigned m_numScheduledCommandBuffers { 0 };
     133    bool m_isMappedFromCreation { false };
    138134};
    139135
  • trunk/Source/WebCore/platform/graphics/gpu/GPUCommandBuffer.h

    r243658 r246217  
    109109    Vector<Ref<GPUBuffer>> m_usedBuffers;
    110110    Vector<Ref<GPUTexture>> m_usedTextures;
    111     bool m_isEncodingPass = false;
     111    bool m_isEncodingPass { false };
    112112#if USE(METAL)
    113113    MTLBlitCommandEncoder *blitEncoder() const;
  • trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.cpp

    r244507 r246217  
    5151namespace WebCore {
    5252
    53 RefPtr<GPUBuffer> GPUDevice::tryCreateBuffer(const GPUBufferDescriptor& descriptor)
     53RefPtr<GPUBuffer> GPUDevice::tryCreateBuffer(const GPUBufferDescriptor& descriptor, bool isMappedOnCreation)
    5454{
    55     return GPUBuffer::tryCreate(makeRef(*this), descriptor);
     55    return GPUBuffer::tryCreate(makeRef(*this), descriptor, isMappedOnCreation);
    5656}
    5757
  • trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.h

    r244507 r246217  
    6666    static RefPtr<GPUDevice> tryCreate(const Optional<GPURequestAdapterOptions>&);
    6767
    68     RefPtr<GPUBuffer> tryCreateBuffer(const GPUBufferDescriptor&);
     68    RefPtr<GPUBuffer> tryCreateBuffer(const GPUBufferDescriptor&, bool isMappedOnCreation = false);
    6969    RefPtr<GPUTexture> tryCreateTexture(const GPUTextureDescriptor&) const;
    7070    RefPtr<GPUSampler> tryCreateSampler(const GPUSamplerDescriptor&) const;
  • trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm

    r244297 r246217  
    6363}
    6464
    65 RefPtr<GPUBuffer> GPUBuffer::tryCreate(Ref<GPUDevice>&& device, const GPUBufferDescriptor& descriptor)
     65RefPtr<GPUBuffer> GPUBuffer::tryCreate(Ref<GPUDevice>&& device, const GPUBufferDescriptor& descriptor, bool isMappedOnCreation)
    6666{
    6767    // MTLBuffer size (NSUInteger) is 32 bits on some platforms.
     
    7676        return nullptr;
    7777
     78#if PLATFORM(MAC)
     79    // copyBufferToBuffer calls require 4-byte alignment. "Unmapping" a mapped-on-creation GPUBuffer
     80    // that is otherwise unmappable requires such a copy to upload data.
     81    if (isMappedOnCreation
     82        && !usage.containsAny({ GPUBufferUsage::Flags::MapWrite, GPUBufferUsage::Flags::MapRead })
     83        && descriptor.size % 4) {
     84        LOG(WebGPU, "GPUBuffer::tryCreate(): Data must be aligned to a multiple of 4 bytes!");
     85        return nullptr;
     86    }
     87#endif
     88
    7889    // 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.
    7990
     
    96107    }
    97108
    98     return adoptRef(*new GPUBuffer(WTFMove(mtlBuffer), size, usage, WTFMove(device)));
    99 }
    100 
    101 GPUBuffer::GPUBuffer(RetainPtr<MTLBuffer>&& buffer, size_t size, OptionSet<GPUBufferUsage::Flags> usage, Ref<GPUDevice>&& device)
     109    return adoptRef(*new GPUBuffer(WTFMove(mtlBuffer), WTFMove(device), size, usage, isMappedOnCreation));
     110}
     111
     112GPUBuffer::GPUBuffer(RetainPtr<MTLBuffer>&& buffer, Ref<GPUDevice>&& device, size_t size, OptionSet<GPUBufferUsage::Flags> usage, bool isMapped)
    102113    : m_platformBuffer(WTFMove(buffer))
    103114    , m_device(WTFMove(device))
    104115    , m_byteLength(size)
    105116    , m_usage(usage)
     117    , m_isMappedFromCreation(isMapped)
    106118{
    107119}
     
    121133    if (!m_platformBuffer)
    122134        return State::Destroyed;
    123     if (m_mappingCallback)
     135    if (m_isMappedFromCreation || m_mappingCallback)
    124136        return State::Mapped;
    125137
     
    127139}
    128140
    129 void GPUBuffer::setSubData(uint64_t offset, const JSC::ArrayBuffer& data)
    130 {
    131     MTLCommandQueue *queue;
    132     if (!m_device->tryGetQueue() || !(queue = m_device->tryGetQueue()->platformQueue()))
    133         return;
    134    
    135     if (!isTransferDestination() || state() != State::Unmapped) {
    136         LOG(WebGPU, "GPUBuffer::setSubData(): Invalid operation!");
    137         return;
    138     }
    139 
    140 #if PLATFORM(MAC)
    141     if (offset % 4 || data.byteLength() % 4) {
    142         LOG(WebGPU, "GPUBuffer::setSubData(): Data must be aligned to a multiple of 4 bytes!");
    143         return;
    144     }
    145 #endif
    146     // MTLBuffer size (NSUInteger) is 32 bits on some platforms.
    147     auto subDataLength = checkedSum<NSUInteger>(data.byteLength(), offset);
    148     if (subDataLength.hasOverflowed() || subDataLength.unsafeGet() > m_byteLength) {
    149         LOG(WebGPU, "GPUBuffer::setSubData(): Invalid offset or data size!");
    150         return;
    151     }
    152 
    153     if (m_subDataBuffers.isEmpty()) {
    154         BEGIN_BLOCK_OBJC_EXCEPTIONS;
    155         m_subDataBuffers.append(adoptNS([m_platformBuffer.get().device newBufferWithLength:static_cast<NSUInteger>(m_byteLength) options:MTLResourceCPUCacheModeDefaultCache]));
    156         END_BLOCK_OBJC_EXCEPTIONS;
    157     }
    158 
    159     __block auto stagingMtlBuffer = m_subDataBuffers.takeLast();
    160 
    161     if (!stagingMtlBuffer || stagingMtlBuffer.get().length < data.byteLength()) {
    162         LOG(WebGPU, "GPUBuffer::setSubData(): Unable to get staging buffer for provided data!");
    163         return;
    164     }
    165 
    166     memcpy(stagingMtlBuffer.get().contents, data.data(), data.byteLength());
    167 
    168     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    169 
    170     auto commandBuffer = retainPtr([queue commandBuffer]);
    171     auto blitEncoder = retainPtr([commandBuffer blitCommandEncoder]);
    172 
    173     [blitEncoder copyFromBuffer:stagingMtlBuffer.get() sourceOffset:0 toBuffer:m_platformBuffer.get() destinationOffset:static_cast<NSUInteger>(offset) size:stagingMtlBuffer.get().length];
    174     [blitEncoder endEncoding];
    175 
    176     if (isMappable())
    177         commandBufferCommitted(commandBuffer.get());
    178 
    179     auto protectedThis = makeRefPtr(this);
    180     [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>) {
    181         protectedThis->reuseSubDataBuffer(WTFMove(stagingMtlBuffer));
    182     }];
    183     [commandBuffer commit];
    184 
    185     END_BLOCK_OBJC_EXCEPTIONS;
     141JSC::ArrayBuffer* GPUBuffer::mapOnCreation()
     142{
     143    ASSERT(m_isMappedFromCreation);
     144    return stagingBufferForWrite();
    186145}
    187146
     
    210169
    211170    --m_numScheduledCommandBuffers;
    212 }
    213 
    214 void GPUBuffer::reuseSubDataBuffer(RetainPtr<MTLBuffer>&& buffer)
    215 {
    216     m_subDataBuffers.append(WTFMove(buffer));
    217171}
    218172#endif // USE(METAL)
     
    267221}
    268222
     223void GPUBuffer::copyStagingBufferToGPU()
     224{
     225    MTLCommandQueue *queue;
     226    if (!m_device->tryGetQueue() || !(queue = m_device->tryGetQueue()->platformQueue()))
     227        return;
     228
     229    RetainPtr<MTLBuffer> stagingMtlBuffer;
     230
     231    BEGIN_BLOCK_OBJC_EXCEPTIONS;
     232    // GPUBuffer creation validation ensures m_byteSize fits in NSUInteger.
     233    stagingMtlBuffer = adoptNS([m_device->platformDevice() newBufferWithLength:static_cast<NSUInteger>(m_byteLength) options:MTLResourceCPUCacheModeDefaultCache]);
     234    END_BLOCK_OBJC_EXCEPTIONS;
     235
     236    if (!stagingMtlBuffer) {
     237        LOG(WebGPU, "GPUBuffer::unmap(): Unable to create staging buffer!");
     238        return;
     239    }
     240
     241    memcpy(stagingMtlBuffer.get().contents, m_stagingBuffer->data(), m_byteLength);
     242
     243    BEGIN_BLOCK_OBJC_EXCEPTIONS;
     244
     245    auto commandBuffer = retainPtr([queue commandBuffer]);
     246    auto blitEncoder = retainPtr([commandBuffer blitCommandEncoder]);
     247
     248    [blitEncoder copyFromBuffer:stagingMtlBuffer.get() sourceOffset:0 toBuffer:m_platformBuffer.get() destinationOffset:0 size:static_cast<NSUInteger>(m_byteLength)];
     249    [blitEncoder endEncoding];
     250    [commandBuffer commit];
     251
     252    END_BLOCK_OBJC_EXCEPTIONS;
     253}
     254
    269255void GPUBuffer::unmap()
    270256{
    271     if (!isMappable()) {
    272         LOG(WebGPU, "GPUBuffer::unmap(): Buffer is not mappable!");
    273         return;
    274     }
    275 
    276     if (m_stagingBuffer && isMapWrite()) {
    277         ASSERT(m_platformBuffer);
    278         memcpy(m_platformBuffer.get().contents, m_stagingBuffer->data(), m_byteLength);
     257    if (!m_isMappedFromCreation && !isMappable()) {
     258        LOG(WebGPU, "GPUBuffer::unmap(): Invalid operation: buffer is not mappable!");
     259        return;
     260    }
     261
     262    if (m_stagingBuffer) {
     263        if (isMappable()) {
     264            // MAP_WRITE and MAP_READ buffers have shared, CPU-accessible storage.
     265            ASSERT(m_platformBuffer && m_platformBuffer.get().contents);
     266            memcpy(m_platformBuffer.get().contents, m_stagingBuffer->data(), m_byteLength);
     267        } else if (m_isMappedFromCreation)
     268            copyStagingBufferToGPU();
     269
     270        m_isMappedFromCreation = false;
    279271        m_stagingBuffer = nullptr;
    280272    }
Note: See TracChangeset for help on using the changeset viewer.