Changeset 241996 in webkit


Ignore:
Timestamp:
Feb 23, 2019 3:24:27 PM (5 years ago)
Author:
Justin Fan
Message:

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

Reviewed by Dean Jackson.

Source/WebCore:

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

  • Modules/webgpu/WebGPUBindGroupDescriptor.cpp: Added.

(WebCore::validateBufferBindingType): Ensure buffer binding usages match the binding type.
(WebCore::WebGPUBindGroupDescriptor::asGPUBindGroupDescriptor const): Logic moved out from WebGPUDevice.cpp.

  • Modules/webgpu/WebGPUBindGroupDescriptor.h:
  • Modules/webgpu/WebGPUBuffer.cpp: Added GPUBuffer functionality.

(WebCore::WebGPUBuffer::create):
(WebCore::WebGPUBuffer::WebGPUBuffer):
(WebCore::WebGPUBuffer::mapReadAsync):
(WebCore::WebGPUBuffer::mapWriteAsync):
(WebCore::WebGPUBuffer::unmap):
(WebCore::WebGPUBuffer::destroy):
(WebCore::WebGPUBuffer::rejectOrRegisterPromiseCallback): Register a mapping request on the GPUBuffer, if valid.

  • Modules/webgpu/WebGPUBuffer.h:

(WebCore::WebGPUBuffer::buffer const):
(WebCore::WebGPUBuffer::mapping const): Deleted.

  • Modules/webgpu/WebGPUBuffer.idl: Update to latest API and enable every function except setSubData.
  • Modules/webgpu/WebGPUCommandBuffer.cpp:

(WebCore::WebGPUCommandBuffer::beginRenderPass): Renamed descriptor conversion method.

  • Modules/webgpu/WebGPUDevice.cpp:

(WebCore::WebGPUDevice::createBuffer const): Update to non-nullable return type.
(WebCore::WebGPUDevice::createBindGroup const): Move descriptor validation logic to descriptor implementation.

  • Modules/webgpu/WebGPUDevice.h:
  • Modules/webgpu/WebGPURenderPassDescriptor.cpp:

(WebCore::WebGPURenderPassDescriptor::asGPURenderPassDescriptor const): Renamed from validateAndConvertToGPUVersion.

  • Modules/webgpu/WebGPURenderPassEncoder.cpp:

(WebCore::WebGPURenderPassEncoder::setVertexBuffers): Add validation for submitted buffers.

  • platform/graphics/gpu/GPUBuffer.cpp: Added.

(WebCore::GPUBuffer::PendingMappingCallback::PendingMappingCallback): New struct for retaining a reference to mapping callbacks.

  • platform/graphics/gpu/GPUBuffer.h: Add functionality to retain callbacks and usage bits.

(WebCore::GPUBuffer::isVertex const):
(WebCore::GPUBuffer::isUniform const):
(WebCore::GPUBuffer::isStorage const):
(WebCore::GPUBuffer::isReadOnly const):
(WebCore::GPUBuffer::PendingMapPromise::create):
(WebCore::GPUBuffer::isMappable const):
(WebCore::GPUBuffer::isMapWriteable const):
(WebCore::GPUBuffer::isMapReadable const):
(WebCore::GPUBuffer::mapping const): Deleted.

  • platform/graphics/gpu/GPUBufferUsage.h: enum class cannot be logical ORed together.
  • platform/graphics/gpu/GPUDevice.cpp:

(WebCore::GPUDevice::tryCreateBuffer const): Renamed from createBuffer.
(WebCore::GPUDevice::createBuffer const): Deleted.

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

(WebCore::GPUBuffer::tryCreateSharedBuffer): Attempt to create a MTLBuffer with shared memory.
(WebCore::GPUBuffer::tryCreate): No longer use Gigacage-allocated memory for MTLBuffer.
(WebCore::GPUBuffer::GPUBuffer):
(WebCore::GPUBuffer::~GPUBuffer):
(WebCore::GPUBuffer::registerMappingCallback): Register the provided callback to be executed when the staging buffer can be safely exposed.
(WebCore::GPUBuffer::stagingBufferForRead): Prepare the arrayBuffer for reading and run the mapping callback.
(WebCore::GPUBuffer::stagingBufferForWrite): Ditto, but for writing.
(WebCore::GPUBuffer::unmap): If needed, copy the staging ArrayBuffer to the MTLBuffer. Unregister any mapping callback.
(WebCore::GPUBuffer::destroy): Stub implementation for now. Frees the MTLBuffer as soon as possible.
(WebCore::GPUBuffer::create): Deleted.

  • platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm:

(WebCore::GPUProgrammablePassEncoder::setResourceAsBufferOnEncoder): Ensure only read-only GPUBuffers are used as read-only on the GPU.

Add symbols for new files:

  • Sources.txt:
  • WebCore.xcodeproj/project.pbxproj:

LayoutTests:

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

  • webgpu/buffer-resource-triangles.html:
  • webgpu/buffers-expected.txt: Renamed to map-write-buffers-expected.txt.
  • webgpu/buffers.html: Renamed to map-write-buffers.html.
  • webgpu/depth-enabled-triangle-strip.html:
  • webgpu/map-write-buffers-expected.txt: Renamed from buffers-expected.txt.
  • webgpu/map-write-buffers.html: Renamed from buffers.html.
  • webgpu/vertex-buffer-triangle-strip.html:
  • platform/mac/TestExpectations: Skip all webgpu tests on macOS 10.12 bots.
Location:
trunk
Files:
3 added
2 deleted
24 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r241989 r241996  
     12019-02-23  Justin Fan  <justin_fan@apple.com>
     2
     3        [WebGPU] Buffer updates part 1: async mapping functions, unmap, and destroy
     4        https://bugs.webkit.org/show_bug.cgi?id=194665
     5
     6        Reviewed by Dean Jackson.
     7
     8        Rewrite buffers.html -> map-write-buffers.html to test new functionality. Rewrite other affected
     9        tests to use mapWriteAsync.
     10
     11        * webgpu/buffer-resource-triangles.html:
     12        * webgpu/buffers-expected.txt: Renamed to map-write-buffers-expected.txt.
     13        * webgpu/buffers.html: Renamed to map-write-buffers.html.
     14        * webgpu/depth-enabled-triangle-strip.html:
     15        * webgpu/map-write-buffers-expected.txt: Renamed from buffers-expected.txt.
     16        * webgpu/map-write-buffers.html: Renamed from buffers.html.
     17        * webgpu/vertex-buffer-triangle-strip.html:
     18
     19        * platform/mac/TestExpectations: Skip all webgpu tests on macOS 10.12 bots.
     20
    1212019-02-23  chris fleizach  <cfleizach@apple.com>
    222
  • trunk/LayoutTests/platform/mac/TestExpectations

    r241219 r241996  
    17861786webkit.org/b/190976 imported/w3c/web-platform-tests/media-source/mediasource-changetype-play.html [ Pass Failure ]
    17871787
    1788 webkit.org/b/192956 [ Sierra ] webgpu/buffers.html [ Skip ]
    1789 webkit.org/b/192956 [ Sierra ] webgpu/command-buffers.html [ Skip ]
    1790 webkit.org/b/192956 [ Sierra ] webgpu/pipeline-layouts.html [ Skip ]
    1791 webkit.org/b/192956 [ Sierra ] webgpu/queue-creation.html [ Skip ]
    1792 webkit.org/b/192956 [ Sierra ] webgpu/render-command-encoding.html [ Skip ]
    1793 webkit.org/b/192956 [ Sierra ] webgpu/render-passes.html [ Skip ]
    1794 webkit.org/b/192956 [ Sierra ] webgpu/render-pipelines.html [ Skip ]
    1795 webkit.org/b/192956 [ Sierra ] webgpu/shader-modules.html [ Skip ]
    1796 webkit.org/b/192956 [ Sierra ] webgpu/textures-textureviews.html [ Skip ]
    1797 webkit.org/b/192956 [ Sierra ] webgpu/webgpu-basics.html [ Skip ]
    1798 webkit.org/b/192956 [ Sierra ] webgpu/webgpu-enabled.html [ Skip ]
    1799 webkit.org/b/192956 [ Sierra ] webgpu/simple-triangle-strip.html [ Skip ]
    1800 webkit.org/b/192956 [ Sierra ] webgpu/vertex-buffer-triangle-strip.html [ Skip ]
     1788webkit.org/b/192956 [ Sierra ] webgpu [ Skip ]
    18011789
    18021790webkit.org/b/189680 platform/mac/media/audio-session-category-video-paused.html [ Pass Timeout ]
  • trunk/LayoutTests/webgpu/buffer-resource-triangles.html

    r241328 r241996  
    8080const vertexSize = 4 * 4;
    8181const verticesBufferSize = vertexSize * 3;
    82 
    83 // FIXME: Keep up to date with buffer upload decisions.
    84 function createVerticesBuffer(device) {
    85     const buffer = device.createBuffer({ size:verticesBufferSize, usage: GPUBufferUsage.VERTEX });
    86 
    87     const vertices = [
    88         0, 1, 0, 1,
    89         -1, -1, 0, 1,
    90         1, -1, 0, 1
    91     ];
    92 
    93     const mappedArray = new Float32Array(buffer.mapping);
    94     mappedArray.set(vertices);
    95 
     82function createAndUploadVerticesBuffer(device, promises) {
     83    const buffer = device.createBuffer({ size:verticesBufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE });
     84
     85    const promise = buffer.mapWriteAsync().then(mapping => {
     86        const mappedArray = new Float32Array(mapping);
     87        mappedArray.set([
     88            0, 1, 0, 1,
     89            -1, -1, 0, 1,
     90            1, -1, 0, 1
     91        ]);
     92        buffer.unmap();
     93    });
     94
     95    promises.push(promise);
    9696    return buffer;
    9797}
    9898
    99 function createFloat4Buffer(device, a, b) {
    100     const buffer = device.createBuffer({ size: vertexSize, usage: GPUBufferUsage.UNIFORM });
    101    
    102     const arrayBuffer = buffer.mapping;
    103     const floatArray = new Float32Array(arrayBuffer);
    104 
    105     floatArray[0] = a;
    106     floatArray[1] = b;
    107     floatArray[2] = 0;
    108     floatArray[3] = 1;
    109 
     99function createFloat4Buffer(device, a, b, promises) {
     100    const buffer = device.createBuffer({ size: vertexSize, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE });
     101
     102    const promise = buffer.mapWriteAsync().then(mapping => {
     103        const mappedArray = new Float32Array(mapping);
     104        mappedArray.set([a, b, 0, 1]);
     105        buffer.unmap();
     106    });
     107
     108    promises.push(promise);
    110109    return buffer;
    111110}
     
    127126
    128127    // Create vertex data WebGPUBuffers.
    129     const verticesBuffer = createVerticesBuffer(device);
    130 
    131     const upperLeft = createFloat4Buffer(device, -1, 1);
    132     const upperMiddle = createFloat4Buffer(device, 0, 1);
    133     const upperRight = createFloat4Buffer(device, 1, 1);
    134     const lowerLeft = createFloat4Buffer(device, -1, -1);
    135     const lowerRight = createFloat4Buffer(device, 1, -1);
     128    let bufferPromises = [];
     129
     130    const verticesBuffer = createAndUploadVerticesBuffer(device, bufferPromises);
     131
     132    const upperLeft = createFloat4Buffer(device, -1, 1, bufferPromises);
     133    const upperMiddle = createFloat4Buffer(device, 0, 1, bufferPromises);
     134    const upperRight = createFloat4Buffer(device, 1, 1, bufferPromises);
     135    const lowerLeft = createFloat4Buffer(device, -1, -1, bufferPromises);
     136    const lowerRight = createFloat4Buffer(device, 1, -1, bufferPromises);
    136137
    137138    // Color data buffer.
    138     const green = createFloat4Buffer(device, 0, 1);
     139    const green = createFloat4Buffer(device, 0, 1, bufferPromises);
    139140
    140141    // Create vertex input state.
     
    196197    });
    197198
    198     const commandBuffer = device.createCommandBuffer();
    199     const passEncoder = beginBasicRenderPass(context, commandBuffer);
    200     passEncoder.setPipeline(pipeline);
    201 
    202     // Vertex data for upper triangles.
    203     passEncoder.setBindGroup(0, leftTriangleBG);
    204     passEncoder.setBindGroup(1, rightTriangleBG);
    205     // Lower triangle.
    206     passEncoder.setVertexBuffers(0, [verticesBuffer], [0]);
    207     passEncoder.draw(9, 1, 0, 0);
    208 
    209     const endCommandBuffer = passEncoder.endPass();
    210     const queue = device.getQueue();
    211     queue.submit([endCommandBuffer]);
    212     context.present();
     199    Promise.all(bufferPromises).then(() => {
     200        const commandBuffer = device.createCommandBuffer();
     201        const passEncoder = beginBasicRenderPass(context, commandBuffer);
     202        passEncoder.setPipeline(pipeline);
     203
     204        // Vertex data for upper triangles.
     205        passEncoder.setBindGroup(0, leftTriangleBG);
     206        passEncoder.setBindGroup(1, rightTriangleBG);
     207        // Lower triangle.
     208        passEncoder.setVertexBuffers(0, [verticesBuffer], [0]);
     209        passEncoder.draw(9, 1, 0, 0);
     210
     211        const endCommandBuffer = passEncoder.endPass();
     212        const queue = device.getQueue();
     213        queue.submit([endCommandBuffer]);
     214        context.present();
     215    });
    213216}
    214217
  • trunk/LayoutTests/webgpu/depth-enabled-triangle-strip.html

    r241328 r241996  
    4545`
    4646
    47 function createVertexBuffer(device) {
     47async function createVertexBuffer(device) {
    4848    const bufferSize = 4 * 4 * 4;
    49     const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.MAP_WRITE });
     49    const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE });
    5050   
    5151    let floatArray = new Float32Array(buffer.mapping);
    52 
    53     const vertices = [
    54         // float4 xyzw
    55         -1, 1, 0, 1,
    56         -1, -1, 0, 1,
    57         1, 1, 0, 1,
    58         1, -1, 0, 1
    59     ];
    60 
    61     floatArray.set(vertices);
     52    await buffer.mapWriteAsync().then(mapping => {
     53        let mappedArray = new Float32Array(mapping);
     54        mappedArray.set([
     55            // float4 xyzw
     56            -1, 1, 0, 1,
     57            -1, -1, 0, 1,
     58            1, 1, 0, 1,
     59            1, -1, 0, 1
     60        ]);
     61        buffer.unmap();
     62    });
    6263
    6364    return buffer;
     
    8788    // FIXME: Replace with non-MSL shaders.
    8889    const shaderModule = device.createShaderModule({ code: shaderCode });
    89     const vertexBuffer = createVertexBuffer(device);
     90    const vertexBuffer =  await createVertexBuffer(device);
    9091    const inputStateDescriptor = createInputStateDescriptor();
    9192    const depthStateDescriptor = createBasicDepthStateDescriptor();
  • trunk/LayoutTests/webgpu/vertex-buffer-triangle-strip.html

    r241328 r241996  
    3939`
    4040
    41 function createVertexBuffer(device) {
     41async function createVertexBuffer(device) {
    4242    const bufferSize = 4 * 5 * 4;
    43     const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.MAP_WRITE });
     43    const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE });
    4444   
    45     let floatArray = new Float32Array(buffer.mapping);
    46 
    47     const vertices = [
    48         // float4 xyzw, float g
    49         -1, 1, 0, 1, 1,
    50         -1, -1, 0, 1, 1,
    51         1, 1, 0, 1, 1,
    52         1, -1, 0, 1, 1
    53     ];
    54 
    55     for (let i = 0; i < vertices.length; ++i) {
    56         floatArray[i] = vertices[i];
    57     }
     45    await buffer.mapWriteAsync().then(mapping => {
     46        let mappedArray = new Float32Array(mapping);
     47        mappedArray.set([
     48            // float4 xyzw, float g
     49            -1, 1, 0, 1, 1,
     50            -1, -1, 0, 1, 1,
     51            1, 1, 0, 1, 1,
     52            1, -1, 0, 1, 1
     53        ]);
     54        buffer.unmap();
     55    });
    5856
    5957    return buffer;
     
    8886    // FIXME: Replace with non-MSL shaders.
    8987    const shaderModule = device.createShaderModule({ code: shaderCode });
    90     const vertexBuffer = createVertexBuffer(device);
     88    const vertexBuffer = await createVertexBuffer(device);
    9189    const inputStateDescriptor = createInputStateDescriptor();
    9290    const pipeline = createBasicPipeline(shaderModule, device, null, inputStateDescriptor);
  • trunk/Source/WebCore/ChangeLog

    r241990 r241996  
     12019-02-23  Justin Fan  <justin_fan@apple.com>
     2
     3        [WebGPU] Buffer updates part 1: async mapping functions, unmap, and destroy
     4        https://bugs.webkit.org/show_bug.cgi?id=194665
     5
     6        Reviewed by Dean Jackson.
     7
     8        Test: map-write-buffers.html. Other tests updated to match new API.
     9
     10        * Modules/webgpu/WebGPUBindGroupDescriptor.cpp: Added.
     11        (WebCore::validateBufferBindingType): Ensure buffer binding usages match the binding type.
     12        (WebCore::WebGPUBindGroupDescriptor::asGPUBindGroupDescriptor const): Logic moved out from WebGPUDevice.cpp.
     13        * Modules/webgpu/WebGPUBindGroupDescriptor.h:
     14        * Modules/webgpu/WebGPUBuffer.cpp: Added GPUBuffer functionality.
     15        (WebCore::WebGPUBuffer::create):
     16        (WebCore::WebGPUBuffer::WebGPUBuffer):
     17        (WebCore::WebGPUBuffer::mapReadAsync):
     18        (WebCore::WebGPUBuffer::mapWriteAsync):
     19        (WebCore::WebGPUBuffer::unmap):
     20        (WebCore::WebGPUBuffer::destroy):
     21        (WebCore::WebGPUBuffer::rejectOrRegisterPromiseCallback): Register a mapping request on the GPUBuffer, if valid.
     22        * Modules/webgpu/WebGPUBuffer.h:
     23        (WebCore::WebGPUBuffer::buffer const):
     24        (WebCore::WebGPUBuffer::mapping const): Deleted.
     25        * Modules/webgpu/WebGPUBuffer.idl: Update to latest API and enable every function except setSubData.
     26        * Modules/webgpu/WebGPUCommandBuffer.cpp:
     27        (WebCore::WebGPUCommandBuffer::beginRenderPass): Renamed descriptor conversion method.
     28        * Modules/webgpu/WebGPUDevice.cpp:
     29        (WebCore::WebGPUDevice::createBuffer const): Update to non-nullable return type.
     30        (WebCore::WebGPUDevice::createBindGroup const): Move descriptor validation logic to descriptor implementation.
     31        * Modules/webgpu/WebGPUDevice.h:
     32        * Modules/webgpu/WebGPURenderPassDescriptor.cpp:
     33        (WebCore::WebGPURenderPassDescriptor::asGPURenderPassDescriptor const): Renamed from validateAndConvertToGPUVersion.
     34        * Modules/webgpu/WebGPURenderPassEncoder.cpp:
     35        (WebCore::WebGPURenderPassEncoder::setVertexBuffers): Add validation for submitted buffers.
     36        * platform/graphics/gpu/GPUBuffer.cpp: Added.
     37        (WebCore::GPUBuffer::PendingMappingCallback::PendingMappingCallback): New struct for retaining a reference to mapping callbacks.
     38        * platform/graphics/gpu/GPUBuffer.h: Add functionality to retain callbacks and usage bits.
     39        (WebCore::GPUBuffer::isVertex const):
     40        (WebCore::GPUBuffer::isUniform const):
     41        (WebCore::GPUBuffer::isStorage const):
     42        (WebCore::GPUBuffer::isReadOnly const):
     43        (WebCore::GPUBuffer::PendingMapPromise::create):
     44        (WebCore::GPUBuffer::isMappable const):
     45        (WebCore::GPUBuffer::isMapWriteable const):
     46        (WebCore::GPUBuffer::isMapReadable const):
     47        (WebCore::GPUBuffer::mapping const): Deleted.
     48        * platform/graphics/gpu/GPUBufferUsage.h: enum class cannot be logical ORed together.
     49        * platform/graphics/gpu/GPUDevice.cpp:
     50        (WebCore::GPUDevice::tryCreateBuffer const): Renamed from createBuffer.
     51        (WebCore::GPUDevice::createBuffer const): Deleted.
     52        * platform/graphics/gpu/GPUDevice.h:
     53        * platform/graphics/gpu/cocoa/GPUBufferMetal.mm:
     54        (WebCore::GPUBuffer::tryCreateSharedBuffer): Attempt to create a MTLBuffer with shared memory.
     55        (WebCore::GPUBuffer::tryCreate): No longer use Gigacage-allocated memory for MTLBuffer.
     56        (WebCore::GPUBuffer::GPUBuffer):
     57        (WebCore::GPUBuffer::~GPUBuffer):
     58        (WebCore::GPUBuffer::registerMappingCallback): Register the provided callback to be executed when the staging buffer can be safely exposed.
     59        (WebCore::GPUBuffer::stagingBufferForRead): Prepare the arrayBuffer for reading and run the mapping callback.
     60        (WebCore::GPUBuffer::stagingBufferForWrite): Ditto, but for writing.
     61        (WebCore::GPUBuffer::unmap): If needed, copy the staging ArrayBuffer to the MTLBuffer. Unregister any mapping callback.
     62        (WebCore::GPUBuffer::destroy): Stub implementation for now. Frees the MTLBuffer as soon as possible.
     63        (WebCore::GPUBuffer::create): Deleted.
     64        * platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm:
     65        (WebCore::GPUProgrammablePassEncoder::setResourceAsBufferOnEncoder): Ensure only read-only GPUBuffers are used as read-only on the GPU.
     66
     67        Add symbols for new files:
     68        * Sources.txt:
     69        * WebCore.xcodeproj/project.pbxproj:
     70
    1712019-02-23  Keith Miller  <keith_miller@apple.com>
    272
  • trunk/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.h

    r239837 r241996  
    3030#include "WebGPUBindGroupBinding.h"
    3131#include "WebGPUBindGroupLayout.h"
     32#include <wtf/Optional.h>
    3233#include <wtf/RefPtr.h>
    3334#include <wtf/Vector.h>
     
    3536namespace WebCore {
    3637
     38struct GPUBindGroupDescriptor;
     39
    3740struct WebGPUBindGroupDescriptor {
     41    Optional<GPUBindGroupDescriptor> asGPUBindGroupDescriptor() const;
     42
    3843    RefPtr<WebGPUBindGroupLayout> layout;
    3944    Vector<WebGPUBindGroupBinding> bindings;
  • trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.cpp

    r239535 r241996  
    2929#if ENABLE(WEBGPU)
    3030
     31#include "Logging.h"
     32
    3133namespace WebCore {
    3234
    33 Ref<WebGPUBuffer> WebGPUBuffer::create(Ref<GPUBuffer>&& buffer)
     35Ref<WebGPUBuffer> WebGPUBuffer::create(RefPtr<GPUBuffer>&& buffer)
    3436{
    3537    return adoptRef(*new WebGPUBuffer(WTFMove(buffer)));
    3638}
    3739
    38 WebGPUBuffer::WebGPUBuffer(Ref<GPUBuffer>&& buffer)
     40WebGPUBuffer::WebGPUBuffer(RefPtr<GPUBuffer>&& buffer)
    3941    : m_buffer(WTFMove(buffer))
    4042{
     43}
     44
     45void WebGPUBuffer::mapReadAsync(BufferMappingPromise&& promise)
     46{
     47    rejectOrRegisterPromiseCallback(WTFMove(promise), true);
     48}
     49
     50void WebGPUBuffer::mapWriteAsync(BufferMappingPromise&& promise)
     51{
     52    rejectOrRegisterPromiseCallback(WTFMove(promise), false);
     53}
     54
     55void WebGPUBuffer::unmap()
     56{
     57    if (m_buffer)
     58        m_buffer->unmap();
     59}
     60
     61void WebGPUBuffer::destroy()
     62{
     63    if (!m_buffer)
     64        LOG(WebGPU, "GPUBuffer::destroy(): Invalid operation!");
     65    else {
     66        m_buffer->destroy();
     67        // FIXME: Ensure that GPUBuffer is kept alive by resource bindings if still being used by GPU.
     68        m_buffer = nullptr;
     69    }
     70}
     71
     72void WebGPUBuffer::rejectOrRegisterPromiseCallback(BufferMappingPromise&& promise, bool isRead)
     73{
     74    if (!m_buffer) {
     75        LOG(WebGPU, "GPUBuffer::map%sAsync(): Invalid operation!", isRead ? "Read" : "Write");
     76        promise.reject();
     77        return;
     78    }
     79
     80    m_buffer->registerMappingCallback([promise = WTFMove(promise)] (JSC::ArrayBuffer* arrayBuffer) mutable {
     81        if (!arrayBuffer) {
     82            promise.reject();
     83            return;
     84        }
     85
     86        promise.resolve(arrayBuffer);
     87    }, isRead);
    4188}
    4289
  • trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.h

    r239535 r241996  
    2929
    3030#include "GPUBuffer.h"
    31 
     31#include "GPUBufferUsage.h"
     32#include "JSDOMPromiseDeferred.h"
    3233#include <wtf/RefCounted.h>
    3334#include <wtf/RefPtr.h>
    3435
     36namespace JSC {
     37class ArrayBuffer;
     38}
     39
    3540namespace WebCore {
     41
     42struct GPUBufferDescriptor;
    3643
    3744class WebGPUBuffer : public RefCounted<WebGPUBuffer> {
    3845public:
    39     static Ref<WebGPUBuffer> create(Ref<GPUBuffer>&&);
     46    static Ref<WebGPUBuffer> create(RefPtr<GPUBuffer>&&);
    4047
    41     const GPUBuffer& buffer() const { return m_buffer.get(); }
     48    RefPtr<const GPUBuffer> buffer() const { return m_buffer; }
    4249
    43     JSC::ArrayBuffer* mapping() const { return m_buffer->mapping(); }
    44     void unmap() { /* FIXME: Unimplemented stub. */ }
    45     void destroy() { /* FIXME: Unimplemented stub. */ }
     50    using BufferMappingPromise = DOMPromiseDeferred<IDLInterface<JSC::ArrayBuffer*>>;
     51    void mapReadAsync(BufferMappingPromise&&);
     52    void mapWriteAsync(BufferMappingPromise&&);
     53    void unmap();
     54    void destroy();
    4655
    4756private:
    48     explicit WebGPUBuffer(Ref<GPUBuffer>&&);
     57    explicit WebGPUBuffer(RefPtr<GPUBuffer>&&);
    4958
    50     Ref<GPUBuffer> m_buffer;
     59    void rejectOrRegisterPromiseCallback(BufferMappingPromise&&, bool);
     60
     61    RefPtr<GPUBuffer> m_buffer;
    5162};
    5263
  • trunk/Source/WebCore/Modules/webgpu/WebGPUBuffer.idl

    r239094 r241996  
    2929    ImplementationLacksVTable
    3030] interface WebGPUBuffer {
    31     readonly attribute ArrayBuffer? mapping;
     31    //void setSubData(u32 offset, ArrayBuffer data);
     32
     33    Promise<ArrayBuffer> mapReadAsync();
     34    Promise<ArrayBuffer> mapWriteAsync();
    3235    void unmap();
    3336
  • trunk/Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.cpp

    r241310 r241996  
    4848RefPtr<WebGPURenderPassEncoder> WebGPUCommandBuffer::beginRenderPass(WebGPURenderPassDescriptor&& descriptor)
    4949{
    50     auto gpuDescriptor = descriptor.validateAndConvertToGPUVersion();
     50    auto gpuDescriptor = descriptor.asGPURenderPassDescriptor();
    5151    if (!gpuDescriptor)
    5252        return nullptr;
  • trunk/Source/WebCore/Modules/webgpu/WebGPUDevice.cpp

    r241328 r241996  
    5656#include "WebGPUShaderModuleDescriptor.h"
    5757#include "WebGPUTexture.h"
    58 #include <wtf/Variant.h>
    5958
    6059namespace WebCore {
     
    7473}
    7574
    76 RefPtr<WebGPUBuffer> WebGPUDevice::createBuffer(GPUBufferDescriptor&& descriptor) const
     75Ref<WebGPUBuffer> WebGPUDevice::createBuffer(GPUBufferDescriptor&& descriptor) const
    7776{
    78     if (auto buffer = m_device->createBuffer(WTFMove(descriptor)))
    79         return WebGPUBuffer::create(buffer.releaseNonNull());
    80     return nullptr;
     77    auto buffer = m_device->tryCreateBuffer(WTFMove(descriptor));
     78    return WebGPUBuffer::create(WTFMove(buffer));
    8179}
    8280
     
    105103Ref<WebGPUBindGroup> WebGPUDevice::createBindGroup(WebGPUBindGroupDescriptor&& descriptor) const
    106104{
    107     if (!descriptor.layout || !descriptor.layout->bindGroupLayout()) {
    108         LOG(WebGPU, "WebGPUDevice::createBindGroup(): Invalid WebGPUBindGroupLayout!");
     105    auto gpuDescriptor = descriptor.asGPUBindGroupDescriptor();
     106    if (!gpuDescriptor)
    109107        return WebGPUBindGroup::create(nullptr);
    110     }
    111108
    112     if (descriptor.bindings.size() != descriptor.layout->bindGroupLayout()->bindingsMap().size()) {
    113         LOG(WebGPU, "WebGPUDevice::createBindGroup(): Mismatched number of WebGPUBindGroupLayoutBindings and WebGPUBindGroupBindings!");
    114         return WebGPUBindGroup::create(nullptr);
    115     }
    116 
    117     auto bindingResourceVisitor = WTF::makeVisitor([] (RefPtr<WebGPUTextureView> view) -> Optional<GPUBindingResource> {
    118         if (view)
    119             return static_cast<GPUBindingResource>(view->texture());
    120         return WTF::nullopt;
    121     }, [] (const WebGPUBufferBinding& binding) -> Optional<GPUBindingResource> {
    122         if (binding.buffer)
    123             return static_cast<GPUBindingResource>(GPUBufferBinding { binding.buffer->buffer(), binding.offset, binding.size });
    124         return WTF::nullopt;
    125     });
    126 
    127     Vector<GPUBindGroupBinding> bindGroupBindings;
    128     bindGroupBindings.reserveCapacity(descriptor.bindings.size());
    129 
    130     for (const auto& binding : descriptor.bindings) {
    131         if (!descriptor.layout->bindGroupLayout()->bindingsMap().contains(binding.binding)) {
    132             LOG(WebGPU, "WebGPUDevice::createBindGroup(): WebGPUBindGroupBinding %lu not found in WebGPUBindGroupLayout!", binding.binding);
    133             return WebGPUBindGroup::create(nullptr);
    134         }
    135 
    136         auto bindingResource = WTF::visit(bindingResourceVisitor, binding.resource);
    137         if (bindingResource)
    138             bindGroupBindings.uncheckedAppend(GPUBindGroupBinding { binding.binding, WTFMove(bindingResource.value()) });
    139         else {
    140             LOG(WebGPU, "WebGPUDevice::createBindGroup(): Invalid WebGPUBindingResource for binding %lu in WebGPUBindGroupBindings!", binding.binding);
    141             return WebGPUBindGroup::create(nullptr);
    142         }
    143     }
    144     auto bindGroup = GPUBindGroup::create(GPUBindGroupDescriptor { descriptor.layout->bindGroupLayout().releaseNonNull(), WTFMove(bindGroupBindings) });
     109    auto bindGroup = GPUBindGroup::create(WTFMove(*gpuDescriptor));
    145110    return WebGPUBindGroup::create(WTFMove(bindGroup));
    146111}
  • trunk/Source/WebCore/Modules/webgpu/WebGPUDevice.h

    r241328 r241996  
    6363    const GPUDevice& device() const { return m_device.get(); }
    6464
    65     RefPtr<WebGPUBuffer> createBuffer(GPUBufferDescriptor&&) const;
     65    Ref<WebGPUBuffer> createBuffer(GPUBufferDescriptor&&) const;
    6666    Ref<WebGPUTexture> createTexture(GPUTextureDescriptor&&) const;
    6767
  • trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassDescriptor.cpp

    r241310 r241996  
    4646}
    4747
    48 Optional<GPURenderPassDescriptor> WebGPURenderPassDescriptor::validateAndConvertToGPUVersion() const
     48Optional<GPURenderPassDescriptor> WebGPURenderPassDescriptor::asGPURenderPassDescriptor() const
    4949{
    5050    // FIXME: Improve error checking as WebGPURenderPassDescriptor is added to spec.
  • trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassDescriptor.h

    r241310 r241996  
    4747
    4848struct WebGPURenderPassDescriptor {
    49     Optional<GPURenderPassDescriptor> validateAndConvertToGPUVersion() const;
     49    Optional<GPURenderPassDescriptor> asGPURenderPassDescriptor() const;
    5050
    5151    Vector<WebGPURenderPassColorAttachmentDescriptor> colorAttachments;
  • trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp

    r240898 r241996  
    5050void WebGPURenderPassEncoder::setVertexBuffers(unsigned long startSlot, Vector<RefPtr<WebGPUBuffer>>&& buffers, Vector<unsigned long long>&& offsets)
    5151{
     52#if !LOG_DISABLED
     53    const char* const functionName = "GPURenderPassEncoder::setVertexBuffers()";
     54#endif
    5255    if (buffers.isEmpty() || buffers.size() != offsets.size()) {
    53         LOG(WebGPU, "WebGPURenderPassEncoder::setVertexBuffers: Invalid number of buffers or offsets!");
     56        LOG(WebGPU, "%s: Invalid number of buffers or offsets!", functionName);
    5457        return;
    5558    }
    5659
    5760    if (startSlot + buffers.size() > maxVertexBuffers) {
    58         LOG(WebGPU, "WebGPURenderPassEncoder::setVertexBuffers: Invalid startSlot %lu for %lu buffers!", startSlot, buffers.size());
     61        LOG(WebGPU, "%s: Invalid startSlot %lu for %lu buffers!", functionName, startSlot, buffers.size());
    5962        return;
    6063    }
    6164
    62     auto gpuBuffers = buffers.map([] (const auto& buffer) -> Ref<const GPUBuffer> {
    63         return buffer->buffer();
    64     });
     65    Vector<Ref<const GPUBuffer>> gpuBuffers;
     66    gpuBuffers.reserveCapacity(buffers.size());
     67
     68    for (const auto& buffer : buffers) {
     69        if (!buffer || !buffer->buffer()) {
     70            LOG(WebGPU, "%s: Invalid or destroyed buffer in list!", functionName);
     71            return;
     72        }
     73
     74        if (!buffer->buffer()->isVertex()) {
     75            LOG(WebGPU, "%s: Buffer was not created with VERTEX usage!", functionName);
     76            return;
     77        }
     78
     79        gpuBuffers.uncheckedAppend(buffer->buffer().releaseNonNull());
     80    }
    6581
    6682    m_passEncoder->setVertexBuffers(startSlot, WTFMove(gpuBuffers), WTFMove(offsets));
  • trunk/Source/WebCore/Sources.txt

    r241328 r241996  
    349349Modules/webgpu/WebGPU.cpp
    350350Modules/webgpu/WebGPUBindGroup.cpp
     351Modules/webgpu/WebGPUBindGroupDescriptor.cpp
    351352Modules/webgpu/WebGPUAdapter.cpp
    352353Modules/webgpu/WebGPUBindGroupLayout.cpp
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r241841 r241996  
    42564256                D06C0D8F0CFD11460065F43F /* RemoveFormatCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D06C0D8D0CFD11460065F43F /* RemoveFormatCommand.h */; };
    42574257                D07DEABA0A36554A00CA30F8 /* InsertListCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D07DEAB80A36554A00CA30F8 /* InsertListCommand.h */; };
     4258                D084033C221CBF6900007205 /* GPUBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D084033A221CBF5400007205 /* GPUBuffer.cpp */; };
    42584259                D0843A4B20FEBE3D00FE860E /* GraphicsContext3DManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D0843A4A20FEBE3D00FE860E /* GraphicsContext3DManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
    42594260                D086FE9809D53AAB005BC74D /* UnlinkCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D086FE9609D53AAB005BC74D /* UnlinkCommand.h */; };
     
    1407614077                D083D98421C48050008E8EFF /* GPUBindGroupLayoutDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPUBindGroupLayoutDescriptor.h; sourceTree = "<group>"; };
    1407714078                D083D98621C4813E008E8EFF /* WebGPUBindGroupLayoutDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WebGPUBindGroupLayoutDescriptor.h; path = Modules/streams/WebGPUBindGroupLayoutDescriptor.h; sourceTree = SOURCE_ROOT; };
     14079                D084033A221CBF5400007205 /* GPUBuffer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GPUBuffer.cpp; sourceTree = "<group>"; };
     14080                D084033D221E186400007205 /* WebGPUBindGroupDescriptor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebGPUBindGroupDescriptor.cpp; sourceTree = "<group>"; };
    1407814081                D0843A4A20FEBE3D00FE860E /* GraphicsContext3DManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GraphicsContext3DManager.h; sourceTree = "<group>"; };
    1407914082                D0843A4C20FEC16500FE860E /* GraphicsContext3DManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GraphicsContext3DManager.cpp; sourceTree = "<group>"; };
     
    1848218485                                D0B8BB0121C46E78000C7681 /* GPUBindGroupLayoutBinding.h */,
    1848318486                                D083D98421C48050008E8EFF /* GPUBindGroupLayoutDescriptor.h */,
     18487                                D084033A221CBF5400007205 /* GPUBuffer.cpp */,
    1848418488                                D0D8649221B760F2003C983C /* GPUBuffer.h */,
    1848518489                                D0BE104A21E6872F00E42A89 /* GPUBufferBinding.h */,
     
    2610826112                                D0BE104F21E69F8300E42A89 /* WebGPUBindGroupBinding.h */,
    2610926113                                D0BE105021E69F8300E42A89 /* WebGPUBindGroupBinding.idl */,
     26114                                D084033D221E186400007205 /* WebGPUBindGroupDescriptor.cpp */,
    2611026115                                D0BE105221E6AA0D00E42A89 /* WebGPUBindGroupDescriptor.h */,
    2611126116                                D0BE105321E6AA0D00E42A89 /* WebGPUBindGroupDescriptor.idl */,
     
    3294632951                                515BE1911D54F5FB00DD7C68 /* GamepadProvider.cpp in Sources */,
    3294732952                                837964CF1F8DB69D00218EA0 /* GeolocationPositionIOS.mm in Sources */,
     32953                                D084033C221CBF6900007205 /* GPUBuffer.cpp in Sources */,
    3294832954                                6E21C6C01126338500A7BE02 /* GraphicsContext3D.cpp in Sources */,
    3294932955                                7C3E510B18DF8F3500C112F7 /* HTMLConverter.mm in Sources */,
  • trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.cpp

    r241995 r241996  
    2424 */
    2525
    26 #pragma once
     26#include "config.h"
     27#include "GPUBuffer.h"
    2728
    2829#if ENABLE(WEBGPU)
    2930
    30 #include "WebGPUBindGroupBinding.h"
    31 #include "WebGPUBindGroupLayout.h"
    32 #include <wtf/RefPtr.h>
    33 #include <wtf/Vector.h>
    34 
    3531namespace WebCore {
    3632
    37 struct WebGPUBindGroupDescriptor {
    38     RefPtr<WebGPUBindGroupLayout> layout;
    39     Vector<WebGPUBindGroupBinding> bindings;
    40 };
     33GPUBuffer::PendingMappingCallback::PendingMappingCallback(MappingCallback&& pending)
     34    : callback(WTFMove(pending))
     35{
     36}
    4137
    4238} // namespace WebCore
  • trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.h

    r239094 r241996  
    2828#if ENABLE(WEBGPU)
    2929
     30#include "DeferrableTask.h"
     31#include "GPUBufferUsage.h"
     32#include <wtf/Function.h>
    3033#include <wtf/Ref.h>
    3134#include <wtf/RefCounted.h>
     
    5154    ~GPUBuffer();
    5255
    53     static RefPtr<GPUBuffer> create(const GPUDevice&, GPUBufferDescriptor&&);
     56    static RefPtr<GPUBuffer> tryCreate(const GPUDevice&, GPUBufferDescriptor&&);
    5457
    5558    PlatformBuffer *platformBuffer() const { return m_platformBuffer.get(); }
     59    bool isVertex() const { return m_isVertex; }
     60    bool isUniform() const { return m_isUniform; }
     61    bool isStorage() const { return m_isStorage; }
     62    bool isReadOnly() const { return m_isReadOnly; }
    5663
    57     JSC::ArrayBuffer* mapping() const { return m_mapping.get(); }
     64    using MappingCallback = WTF::Function<void(JSC::ArrayBuffer*)>;
     65    void registerMappingCallback(MappingCallback&&, bool);
     66    void unmap();
     67    void destroy();
    5868
    5969private:
    60     explicit GPUBuffer(PlatformBufferSmartPtr&&, RefPtr<JSC::ArrayBuffer>&&);
     70    struct PendingMappingCallback : public RefCounted<PendingMappingCallback> {
     71        static Ref<PendingMappingCallback> create(MappingCallback&& callback)
     72        {
     73            return adoptRef(*new PendingMappingCallback(WTFMove(callback)));
     74        }
     75
     76        MappingCallback callback;
     77
     78    private:
     79        PendingMappingCallback(MappingCallback&&);
     80    };
     81
     82    GPUBuffer(PlatformBufferSmartPtr&&, const GPUBufferDescriptor&);
     83
     84    static RefPtr<GPUBuffer> tryCreateSharedBuffer(const GPUDevice&, const GPUBufferDescriptor&);
     85    JSC::ArrayBuffer* stagingBufferForRead();
     86    JSC::ArrayBuffer* stagingBufferForWrite();
     87
     88    bool isMappable() const { return m_isMapWrite || m_isMapRead; }
     89    bool isMapWriteable() const { return m_isMapWrite && !m_pendingCallback; }
     90    bool isMapReadable() const { return m_isMapRead && !m_pendingCallback; }
    6191
    6292    PlatformBufferSmartPtr m_platformBuffer;
    63     RefPtr<JSC::ArrayBuffer> m_mapping;
     93
     94    RefPtr<JSC::ArrayBuffer> m_stagingBuffer;
     95    RefPtr<PendingMappingCallback> m_pendingCallback;
     96    DeferrableTask<Timer> m_mappingCallbackTask;
     97
     98    unsigned long m_byteLength;
     99    unsigned m_numScheduledCommandBuffers = 0;
     100    bool m_isMapWrite;
     101    bool m_isMapRead;
     102    bool m_isDestroyed = false;
     103    bool m_isVertex;
     104    bool m_isUniform;
     105    bool m_isStorage;
     106    bool m_isReadOnly;
    64107};
    65108
  • trunk/Source/WebCore/platform/graphics/gpu/GPUBufferUsage.h

    r241328 r241996  
    3636class GPUBufferUsage : public RefCounted<GPUBufferUsage> {
    3737public:
    38     enum class Flags : GPUBufferUsageFlags {
     38    enum Flags : GPUBufferUsageFlags {
    3939        None = 0,
    4040        MapRead = 1,
  • trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.cpp

    r241181 r241996  
    4545namespace WebCore {
    4646
    47 RefPtr<GPUBuffer> GPUDevice::createBuffer(GPUBufferDescriptor&& descriptor) const
     47RefPtr<GPUBuffer> GPUDevice::tryCreateBuffer(GPUBufferDescriptor&& descriptor) const
    4848{
    49     return GPUBuffer::create(*this, WTFMove(descriptor));
     49    return GPUBuffer::tryCreate(*this, WTFMove(descriptor));
    5050}
    5151
  • trunk/Source/WebCore/platform/graphics/gpu/GPUDevice.h

    r241181 r241996  
    6161    static RefPtr<GPUDevice> create(Optional<GPURequestAdapterOptions>&&);
    6262
    63     RefPtr<GPUBuffer> createBuffer(GPUBufferDescriptor&&) const;
     63    RefPtr<GPUBuffer> tryCreateBuffer(GPUBufferDescriptor&&) const;
    6464    RefPtr<GPUTexture> tryCreateTexture(GPUTextureDescriptor&&) const;
    6565
  • trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm

    r239535 r241996  
    3232#import "GPUDevice.h"
    3333#import "Logging.h"
    34 
    35 #import <Foundation/NSRange.h>
    3634#import <JavaScriptCore/ArrayBuffer.h>
    3735#import <Metal/Metal.h>
    38 #import <wtf/Gigacage.h>
    39 #import <wtf/PageBlock.h>
     36#import <wtf/BlockObjCExceptions.h>
    4037
    4138namespace WebCore {
    4239
    43 RefPtr<GPUBuffer> GPUBuffer::create(const GPUDevice& device, GPUBufferDescriptor&& descriptor)
     40RefPtr<GPUBuffer> GPUBuffer::tryCreateSharedBuffer(const GPUDevice& device, const GPUBufferDescriptor& descriptor)
     41{
     42    ASSERT(device.platformDevice());
     43
     44    RetainPtr<MTLBuffer> mtlBuffer;
     45
     46    BEGIN_BLOCK_OBJC_EXCEPTIONS;
     47
     48    mtlBuffer = adoptNS([device.platformDevice() newBufferWithLength:descriptor.size options: MTLResourceCPUCacheModeDefaultCache]);
     49
     50    END_BLOCK_OBJC_EXCEPTIONS;
     51
     52    if (!mtlBuffer) {
     53        LOG(WebGPU, "GPUBuffer::create(): Unable to create MTLBuffer!");
     54        return nullptr;
     55    }
     56
     57    return adoptRef(*new GPUBuffer(WTFMove(mtlBuffer), descriptor));
     58}
     59
     60static const auto readOnlyMask = GPUBufferUsage::Index | GPUBufferUsage::Vertex | GPUBufferUsage::Uniform | GPUBufferUsage::TransferSrc;
     61
     62RefPtr<GPUBuffer> GPUBuffer::tryCreate(const GPUDevice& device, GPUBufferDescriptor&& descriptor)
    4463{
    4564    if (!device.platformDevice()) {
     
    4867    }
    4968
    50     size_t pageSize = WTF::pageSize();
    51     size_t pageAlignedSize = roundUpToMultipleOf(pageSize, descriptor.size);
    52     void* pageAlignedCopy = Gigacage::tryAlignedMalloc(Gigacage::Primitive, pageSize, pageAlignedSize);
    53     if (!pageAlignedCopy) {
    54         LOG(WebGPU, "GPUBuffer::create(): Unable to allocate memory!");
     69    if ((descriptor.usage & GPUBufferUsage::MapWrite) && (descriptor.usage & GPUBufferUsage::MapRead)) {
     70        LOG(WebGPU, "GPUBuffer::create(): Buffer cannot have both MAP_READ and MAP_WRITE usage!");
    5571        return nullptr;
    5672    }
    5773
    58     auto arrayBuffer = ArrayBuffer::createFromBytes(pageAlignedCopy, descriptor.size, [] (void* ptr) {
    59         Gigacage::alignedFree(Gigacage::Primitive, ptr);
    60     });
    61     arrayBuffer->ref();
    62     ArrayBuffer* arrayBufferContents = arrayBuffer.ptr();
    63     // FIXME: Default this MTLResourceOptions.
    64     PlatformBufferSmartPtr mtlBuffer = adoptNS([device.platformDevice()
    65         newBufferWithBytesNoCopy:arrayBuffer->data()
    66         length:pageAlignedSize
    67         options:MTLResourceCPUCacheModeDefaultCache
    68         deallocator:^(void*, NSUInteger) {
    69             arrayBufferContents->deref();
    70         }]);
    71 
    72     if (!mtlBuffer) {
    73         LOG(WebGPU, "GPUBuffer::create(): Unable to create MTLBuffer!");
    74         arrayBuffer->deref();
     74    if ((descriptor.usage & readOnlyMask) && (descriptor.usage & GPUBufferUsage::Storage)) {
     75        LOG(WebGPU, "GPUBuffer::create(): Buffer cannot have both STORAGE and a read-only usage!");
    7576        return nullptr;
    7677    }
    7778
    78     return adoptRef(*new GPUBuffer(WTFMove(mtlBuffer), WTFMove(arrayBuffer)));
     79    // Mappable buffers need (default) shared storage allocation.
     80    if (descriptor.usage & (GPUBufferUsage::MapWrite | GPUBufferUsage::MapRead))
     81        return tryCreateSharedBuffer(device, descriptor);
     82
     83    LOG(WebGPU, "GPUBuffer::create(): Support for non-mapped buffers not implemented!");
     84    return nullptr;
    7985}
    8086
    81 GPUBuffer::GPUBuffer(PlatformBufferSmartPtr&& platformBuffer, RefPtr<ArrayBuffer>&& arrayBuffer)
    82     : m_platformBuffer(WTFMove(platformBuffer))
    83     , m_mapping(WTFMove(arrayBuffer))
     87GPUBuffer::GPUBuffer(RetainPtr<MTLBuffer>&& buffer, const GPUBufferDescriptor& descriptor)
     88    : m_platformBuffer(WTFMove(buffer))
     89    , m_byteLength(descriptor.size)
     90    , m_isMapWrite(descriptor.usage & GPUBufferUsage::MapWrite)
     91    , m_isMapRead(descriptor.usage & GPUBufferUsage::MapRead)
     92    , m_isVertex(descriptor.usage & GPUBufferUsage::Vertex)
     93    , m_isUniform(descriptor.usage & GPUBufferUsage::Uniform)
     94    , m_isStorage(descriptor.usage & GPUBufferUsage::Storage)
     95    , m_isReadOnly(descriptor.usage & readOnlyMask)
    8496{
    8597}
     
    8799GPUBuffer::~GPUBuffer()
    88100{
    89     if (m_mapping) {
    90         m_mapping->deref();
    91         m_mapping = nullptr;
     101    unmap();
     102}
     103
     104void GPUBuffer::registerMappingCallback(MappingCallback&& callback, bool isRead)
     105{
     106    // Reject if request is invalid.
     107    if (isRead && !isMapReadable()) {
     108        LOG(WebGPU, "GPUBuffer::mapReadAsync(): Invalid operation!");
     109        callback(nullptr);
     110        return;
    92111    }
     112    if (!isRead && !isMapWriteable()) {
     113        LOG(WebGPU, "GPUBuffer::mapWriteAsync(): Invalid operation!");
     114        callback(nullptr);
     115        return;
     116    }
     117
     118    ASSERT(!m_pendingCallback && !m_mappingCallbackTask.hasPendingTask());
     119
     120    // An existing callback means this buffer is in the mapped state.
     121    m_pendingCallback = PendingMappingCallback::create(WTFMove(callback));
     122
     123    // If GPU is not using this buffer, run the callback ASAP.
     124    if (!m_numScheduledCommandBuffers) {
     125        m_mappingCallbackTask.scheduleTask([this, protectedThis = makeRef(*this)] () mutable {
     126            ASSERT(m_pendingCallback);
     127
     128            m_pendingCallback->callback(m_isMapRead ? stagingBufferForRead() : stagingBufferForWrite());
     129        });
     130    }
     131}
     132
     133JSC::ArrayBuffer* GPUBuffer::stagingBufferForRead()
     134{
     135    if (!m_stagingBuffer)
     136        m_stagingBuffer = ArrayBuffer::create(m_platformBuffer.get().contents, m_byteLength);
     137    else
     138        memcpy(m_stagingBuffer->data(), m_platformBuffer.get().contents, m_byteLength);
     139
     140    return m_stagingBuffer.get();
     141}
     142
     143JSC::ArrayBuffer* GPUBuffer::stagingBufferForWrite()
     144{
     145    m_stagingBuffer = ArrayBuffer::create(1, m_byteLength);
     146    return m_stagingBuffer.get();
     147}
     148
     149void GPUBuffer::unmap()
     150{
     151    if (!isMappable()) {
     152        LOG(WebGPU, "GPUBuffer::unmap(): Buffer is not mappable!");
     153        return;
     154    }
     155
     156    if (m_stagingBuffer && m_isMapWrite) {
     157        memcpy(m_platformBuffer.get().contents, m_stagingBuffer->data(), m_byteLength);
     158        m_stagingBuffer = nullptr;
     159    }
     160
     161    if (m_pendingCallback) {
     162        m_mappingCallbackTask.cancelTask();
     163        m_pendingCallback->callback(nullptr);
     164        m_pendingCallback = nullptr;
     165    }
     166}
     167
     168void GPUBuffer::destroy()
     169{
     170    if (isMappable())
     171        unmap();
     172
     173    m_isDestroyed = true;
     174
     175    // FIXME: If GPU is still using the MTLBuffer, it will be released after all relevant commands have executed.
     176    if (!m_numScheduledCommandBuffers)
     177        m_platformBuffer = nullptr;
    93178}
    94179
  • trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm

    r240180 r241996  
    6262
    6363    auto& bufferBinding = WTF::get<GPUBufferBinding>(resource);
    64     auto buffer = bufferBinding.buffer->platformBuffer();
     64    auto mtlBuffer = bufferBinding.buffer->platformBuffer();
    6565
    66     if (!buffer) {
     66    if (!mtlBuffer) {
    6767        LOG(WebGPU, "%s: Invalid MTLBuffer in GPUBufferBinding!", functionName);
    6868        return;
     
    7171    BEGIN_BLOCK_OBJC_EXCEPTIONS;
    7272
    73     [argumentEncoder setBuffer:buffer offset:bufferBinding.offset atIndex:index];
    74     useResource(buffer, MTLResourceUsageRead);
     73    [argumentEncoder setBuffer:mtlBuffer offset:bufferBinding.offset atIndex:index];
     74    useResource(mtlBuffer, bufferBinding.buffer->isReadOnly() ? MTLResourceUsageRead : MTLResourceUsageRead | MTLResourceUsageWrite);
    7575
    7676    END_BLOCK_OBJC_EXCEPTIONS;
Note: See TracChangeset for help on using the changeset viewer.