[dawn][emscripten] Implements mapAsync future entry points.
Bug: 369445681
Change-Id: I34f930635da0067d2caa9022e0c4d78ae3979e3b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/207615
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Loko Kung <lokokung@google.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/third_party/emdawnwebgpu/library_webgpu.js b/third_party/emdawnwebgpu/library_webgpu.js
index 8cbd00d..5efc983 100644
--- a/third_party/emdawnwebgpu/library_webgpu.js
+++ b/third_party/emdawnwebgpu/library_webgpu.js
@@ -593,7 +593,7 @@
},
emwgpuAdapterRequestDevice__i53abi: false,
- emwgpuAdapterRequestDevice__deps: ['$stringToUTF8OnStack', 'emwgpuCreateQueue', 'emwgpuOnDeviceLostCompleted', 'emwgpuOnRequestDeviceCompleted', 'emwgpuOnUncapturedError'],
+ emwgpuAdapterRequestDevice__deps: ['emwgpuCreateQueue', 'emwgpuOnDeviceLostCompleted', 'emwgpuOnRequestDeviceCompleted', 'emwgpuOnUncapturedError'],
emwgpuAdapterRequestDevice: (
adapterPtr,
futureIdL, futureIdH,
@@ -752,7 +752,7 @@
// Methods of Buffer
// --------------------------------------------------------------------------
- wgpuBufferDestroy: (bufferPtr) => {
+ emwgpuBufferDestroy: (bufferPtr) => {
var bufferWrapper = WebGPU._tableGet(bufferPtr);
{{{ gpu.makeCheckDefined('bufferWrapper') }}}
if (bufferWrapper.onUnmap) {
@@ -767,8 +767,8 @@
// In webgpu.h offset and size are passed in as size_t.
// And library_webgpu assumes that size_t is always 32bit in emscripten.
- wgpuBufferGetConstMappedRange__deps: ['$warnOnce', 'memalign', 'free'],
- wgpuBufferGetConstMappedRange: (bufferPtr, offset, size) => {
+ emwgpuBufferGetConstMappedRange__deps: ['$warnOnce', 'memalign', 'free'],
+ emwgpuBufferGetConstMappedRange: (bufferPtr, offset, size) => {
var bufferWrapper = WebGPU._tableGet(bufferPtr);
{{{ gpu.makeCheckDefined('bufferWrapper') }}}
@@ -792,15 +792,10 @@
return data;
},
- wgpuBufferGetMapState: (bufferPtr) => {
- var buffer = WebGPU._tableGet(bufferPtr).object;
- return WebGPU.Int_BufferMapState[buffer.mapState];
- },
-
// In webgpu.h offset and size are passed in as size_t.
// And library_webgpu assumes that size_t is always 32bit in emscripten.
- wgpuBufferGetMappedRange__deps: ['$warnOnce', 'memalign', 'free'],
- wgpuBufferGetMappedRange: (bufferPtr, offset, size) => {
+ emwgpuBufferGetMappedRange__deps: ['$warnOnce', 'memalign', 'free'],
+ emwgpuBufferGetMappedRange: (bufferPtr, offset, size) => {
var bufferWrapper = WebGPU._tableGet(bufferPtr);
{{{ gpu.makeCheckDefined('bufferWrapper') }}}
@@ -808,14 +803,6 @@
{{{ gpu.convertSentinelToUndefined('size') }}}
- if (bufferWrapper.mapMode !== {{{ gpu.MapMode.Write }}}) {
-#if ASSERTIONS
- abort("GetMappedRange called, but buffer not mapped for writing");
-#endif
- // TODO(kainino0x): Somehow inject a validation error?
- return 0;
- }
-
var mapped;
try {
mapped = bufferWrapper.object.getMappedRange(offset, size);
@@ -849,31 +836,30 @@
// In webgpu.h offset and size are passed in as size_t.
// And library_webgpu assumes that size_t is always 32bit in emscripten.
- wgpuBufferMapAsync__deps: ['$callUserCallback'],
- wgpuBufferMapAsync: (bufferPtr, mode, offset, size, callback, userdata) => {
+ emwgpuBufferMapAsync__i53abi: false,
+ emwgpuBufferMapAsync__deps: ['emwgpuOnMapAsyncCompleted'],
+ emwgpuBufferMapAsync: (bufferPtr, futureIdL, futureIdH, mode, offset, size) => {
var bufferWrapper = WebGPU._tableGet(bufferPtr);
{{{ gpu.makeCheckDefined('bufferWrapper') }}}
- bufferWrapper.mapMode = mode;
bufferWrapper.onUnmap = [];
var buffer = bufferWrapper.object;
{{{ gpu.convertSentinelToUndefined('size') }}}
- // `callback` takes (WGPUBufferMapAsyncStatus status, void * userdata)
-
{{{ runtimeKeepalivePush() }}}
- buffer.mapAsync(mode, offset, size).then(() => {
+ WebGPU._futureInsert(futureIdL, futureIdH, buffer.mapAsync(mode, offset, size).then(() => {
{{{ runtimeKeepalivePop() }}}
- callUserCallback(() => {
- {{{ makeDynCall('vip', 'callback') }}}({{{ gpu.BufferMapAsyncStatus.Success }}}, userdata);
- });
- }, () => {
+ _emwgpuOnMapAsyncCompleted(futureIdL, futureIdH, {{{ gpu.MapAsyncStatus.Success }}}, 0);
+ }, (ex) => {
{{{ runtimeKeepalivePop() }}}
- callUserCallback(() => {
- // TODO(kainino0x): Figure out how to pick other error status values.
- {{{ makeDynCall('vip', 'callback') }}}({{{ gpu.BufferMapAsyncStatus.ValidationError }}}, userdata);
- });
- });
+ var sp = stackSave();
+ var messagePtr = stringToUTF8OnStack(ex.message);
+ var status =
+ ex instanceof AbortError ? {{{ gpu.MapAsyncStatus.Aborted }}} :
+ ex instanceof OperationError ? {{{ gpu.MapAsyncStatus.Error }}} :
+ {{{ gpu.MapAsyncStatus.Unknown }}};
+ _emwgpuOnMapAsyncCompleted(futureIdL, futureIdH, status, messagePtr);
+ }));
},
wgpuBufferSetLabel: (bufferPtr, labelPtr) => {
@@ -881,7 +867,7 @@
buffer.label = UTF8ToString(labelPtr);
},
- wgpuBufferUnmap: (bufferPtr) => {
+ emwgpuBufferUnmap: (bufferPtr) => {
var bufferWrapper = WebGPU._tableGet(bufferPtr);
{{{ gpu.makeCheckDefined('bufferWrapper') }}}
@@ -1400,8 +1386,7 @@
return ptr;
},
- wgpuDeviceCreateBuffer__deps: ['emwgpuCreateBuffer'],
- wgpuDeviceCreateBuffer: (devicePtr, descriptor) => {
+ emwgpuDeviceCreateBuffer: (devicePtr, descriptor, bufferPtr) => {
{{{ gpu.makeCheckDescriptor('descriptor') }}}
var mappedAtCreation = {{{ gpu.makeGetBool('descriptor', C_STRUCTS.WGPUBufferDescriptor.mappedAtCreation) }}};
@@ -1419,13 +1404,10 @@
var bufferWrapper = {
object: device.createBuffer(desc),
};
- var ptr = _emwgpuCreateBuffer();
- WebGPU._tableInsert(ptr, bufferWrapper);
+ WebGPU._tableInsert(bufferPtr, bufferWrapper);
if (mappedAtCreation) {
- bufferWrapper.mapMode = {{{ gpu.MapMode.Write }}};
bufferWrapper.onUnmap = [];
}
- return ptr;
},
wgpuDeviceCreateCommandEncoder__deps: ['emwgpuCreateCommandEncoder'],
@@ -1455,7 +1437,7 @@
},
emwgpuDeviceCreateComputePipelineAsync__i53abi:false,
- emwgpuDeviceCreateComputePipelineAsync__deps: ['$stringToUTF8OnStack', 'emwgpuCreateComputePipeline', 'emwgpuOnDeviceCreateComputePipelineCompleted'],
+ emwgpuDeviceCreateComputePipelineAsync__deps: ['emwgpuCreateComputePipeline', 'emwgpuOnCreateComputePipelineCompleted'],
emwgpuDeviceCreateComputePipelineAsync: (devicePtr, futureIdL, futureIdH, descriptor) => {
var desc = WebGPU.makeComputePipelineDesc(descriptor);
var device = WebGPU._tableGet(devicePtr);
@@ -1464,7 +1446,7 @@
{{{ runtimeKeepalivePop() }}}
var pipelinePtr = _emwgpuCreateComputePipeline();
WebGPU._tableInsert(pipelinePtr, pipeline);
- _emwgpuOnDeviceCreateComputePipelineCompleted(futureIdL, futureIdH, {{{ gpu.CreatePipelineAsyncStatus.Success }}}, pipelinePtr, 0);
+ _emwgpuOnCreateComputePipelineCompleted(futureIdL, futureIdH, {{{ gpu.CreatePipelineAsyncStatus.Success }}}, pipelinePtr, 0);
}, (pipelineError) => {
{{{ runtimeKeepalivePop() }}}
var sp = stackSave();
@@ -1473,7 +1455,7 @@
pipeline.reason === 'validation' ? {{{ gpu.CreatePipelineAsyncStatus.ValidationError }}} :
pipeline.reason === 'internal' ? {{{ gpu.CreatePipelineAsyncStatus.InternalError }}} :
{{{ gpu.CreatePipelineAsyncStatus.Unknown }}};
- _emwgpuOnDeviceCreateComputePipelineCompleted(futureIdL, futureIdH, status, 0, messagePtr);
+ _emwgpuOnCreateComputePipelineCompleted(futureIdL, futureIdH, status, 0, messagePtr);
stackRestore(sp);
}));
},
@@ -1565,7 +1547,7 @@
},
emwgpuDeviceCreateRenderPipelineAsync__i53abi:false,
- emwgpuDeviceCreateRenderPipelineAsync__deps: ['$stringToUTF8OnStack', 'emwgpuCreateRenderPipeline', 'emwgpuOnDeviceCreateRenderPipelineCompleted'],
+ emwgpuDeviceCreateRenderPipelineAsync__deps: ['emwgpuCreateRenderPipeline', 'emwgpuOnCreateRenderPipelineCompleted'],
emwgpuDeviceCreateRenderPipelineAsync: (devicePtr, futureIdL, futureIdH, descriptor) => {
var desc = WebGPU.makeRenderPipelineDesc(descriptor);
var device = WebGPU._tableGet(devicePtr);
@@ -1574,7 +1556,7 @@
{{{ runtimeKeepalivePop() }}}
var pipelinePtr = _emwgpuCreateRenderPipeline();
WebGPU._tableInsert(pipelinePtr, pipeline);
- _emwgpuOnDeviceCreateRenderPipelineCompleted(futureIdL, futureIdH, {{{ gpu.CreatePipelineAsyncStatus.Success }}}, pipelinePtr, 0);
+ _emwgpuOnCreateRenderPipelineCompleted(futureIdL, futureIdH, {{{ gpu.CreatePipelineAsyncStatus.Success }}}, pipelinePtr, 0);
}, (pipelineError) => {
{{{ runtimeKeepalivePop() }}}
var sp = stackSave();
@@ -1583,7 +1565,7 @@
pipeline.reason === 'validation' ? {{{ gpu.CreatePipelineAsyncStatus.ValidationError }}} :
pipeline.reason === 'internal' ? {{{ gpu.CreatePipelineAsyncStatus.InternalError }}} :
{{{ gpu.CreatePipelineAsyncStatus.Unknown }}};
- _emwgpuOnDeviceCreateRenderPipelineCompleted(futureIdL, futureIdH, status, 0, messagePtr);
+ _emwgpuOnCreateRenderPipelineCompleted(futureIdL, futureIdH, status, 0, messagePtr);
stackRestore(sp);
}));
},
@@ -1840,7 +1822,7 @@
},
emwgpuInstanceRequestAdapter__i53abi: false,
- emwgpuInstanceRequestAdapter__deps: ['$callUserCallback', '$stringToUTF8OnStack', 'emwgpuCreateAdapter', 'emwgpuOnRequestAdapterCompleted'],
+ emwgpuInstanceRequestAdapter__deps: ['emwgpuCreateAdapter', 'emwgpuOnRequestAdapterCompleted'],
emwgpuInstanceRequestAdapter: (instancePtr, futureIdL, futureIdH, options) => {
var opts;
if (options) {
diff --git a/third_party/emdawnwebgpu/webgpu.cpp b/third_party/emdawnwebgpu/webgpu.cpp
index efc9a98..55f714c 100644
--- a/third_party/emdawnwebgpu/webgpu.cpp
+++ b/third_party/emdawnwebgpu/webgpu.cpp
@@ -41,6 +41,19 @@
uint64_t const* timeoutNSPtr);
WGPUTextureFormat emwgpuGetPreferredFormat();
+// Creation functions to create JS backing objects given a pre-allocated handle.
+void emwgpuDeviceCreateBuffer(WGPUDevice device,
+ const WGPUBufferDescriptor* descriptor,
+ WGPUBuffer buffer);
+
+// Buffer mapping operations that has work that needs to be done on the JS side.
+void emwgpuBufferDestroy(WGPUBuffer buffer);
+const void* emwgpuBufferGetConstMappedRange(WGPUBuffer buffer,
+ size_t offset,
+ size_t size);
+void* emwgpuBufferGetMappedRange(WGPUBuffer buffer, size_t offset, size_t size);
+void emwgpuBufferUnmap(WGPUBuffer buffer);
+
// Future/async operation that need to be forwarded to JS.
void emwgpuAdapterRequestDevice(WGPUAdapter adapter,
FutureID futureId,
@@ -48,6 +61,11 @@
WGPUDevice device,
WGPUQueue queue,
const WGPUDeviceDescriptor* descriptor);
+void emwgpuBufferMapAsync(WGPUBuffer buffer,
+ FutureID futureID,
+ WGPUMapMode mode,
+ size_t offset,
+ size_t size);
void emwgpuDeviceCreateComputePipelineAsync(
WGPUDevice device,
FutureID futureId,
@@ -260,7 +278,6 @@
#define WGPU_PASSTHROUGH_OBJECTS(X) \
X(BindGroup) \
X(BindGroupLayout) \
- X(Buffer) \
X(CommandBuffer) \
X(CommandEncoder) \
X(ComputePassEncoder) \
@@ -291,6 +308,7 @@
CreateComputePipeline,
CreateRenderPipeline,
DeviceLost,
+ MapAsync,
RequestAdapter,
RequestDevice,
};
@@ -583,6 +601,41 @@
WGPUAdapterImpl(const EventSource* source);
};
+struct WGPUBufferImpl final : public RefCountedWithExternalCount,
+ public EventSource {
+ public:
+ WGPUBufferImpl(const EventSource* source, bool mappedAtCreation);
+
+ void Destroy();
+ const void* GetConstMappedRange(size_t offset, size_t size);
+ WGPUBufferMapState GetMapState() const;
+ void* GetMappedRange(size_t offset, size_t size);
+ WGPUFuture MapAsync(WGPUMapMode mode,
+ size_t offset,
+ size_t size,
+ WGPUBufferMapCallbackInfo2 callbackInfo);
+ void Unmap();
+
+ private:
+ friend class MapAsyncEvent;
+
+ void WillDropLastExternalRef() override;
+
+ bool IsPendingMapRequest(FutureID futureID) const;
+ void AbortPendingMap(const char* message);
+
+ // Encapsulates information about a map request. Note that when
+ // futureID == kNullFutureId, there are no pending map requests, however, it
+ // is still possible that we are still "mapped" because of mappedAtCreation
+ // which is not associated with a particular async map / future.
+ struct MapRequest {
+ FutureID futureID = kNullFutureId;
+ WGPUMapMode mode = WGPUMapMode_None;
+ };
+ MapRequest mPendingMapRequest;
+ WGPUBufferMapState mMapState;
+};
+
// Device is specially implemented in order to handle refcounting the Queue.
struct WGPUDeviceImpl final : public RefCountedWithExternalCount,
public EventSource {
@@ -732,6 +785,65 @@
std::optional<std::string> mMessage;
};
+class MapAsyncEvent final : public TrackedEvent {
+ public:
+ static constexpr EventType kType = EventType::MapAsync;
+
+ MapAsyncEvent(InstanceID instance,
+ WGPUBuffer buffer,
+ const WGPUBufferMapCallbackInfo2& callbackInfo)
+ : TrackedEvent(instance, callbackInfo.mode), mBuffer(buffer) {}
+
+ EventType GetType() override { return kType; }
+
+ void ReadyHook(WGPUMapAsyncStatus status, const char* message) {
+ // For mapping, this hook may be called more than once if we are not in
+ // Spontaneous mode. The precedence of which status should follow
+ // Success < Error < Aborted. Luckily, the enum is defined such that the
+ // precedence holds true already, so we can exploit that here.
+ static_assert(WGPUMapAsyncStatus_Success < WGPUMapAsyncStatus_Error);
+ static_assert(WGPUMapAsyncStatus_Error < WGPUMapAsyncStatus_Aborted);
+ if (status > mStatus) {
+ mStatus = status;
+ if (message) {
+ mMessage = message;
+ }
+ }
+ }
+
+ void Complete(FutureID futureID, EventCompletionType type) override {
+ if (type == EventCompletionType::Shutdown) {
+ mStatus = WGPUMapAsyncStatus_InstanceDropped;
+ mMessage = "A valid external Instance reference no longer exists.";
+ }
+
+ if (mBuffer->IsPendingMapRequest(futureID)) {
+ if (mStatus == WGPUMapAsyncStatus_Success) {
+ mBuffer->mMapState = WGPUBufferMapState_Mapped;
+ } else {
+ mBuffer->mMapState = WGPUBufferMapState_Unmapped;
+ mBuffer->mPendingMapRequest = {};
+ }
+ } else {
+ assert(mStatus != WGPUMapAsyncStatus_Success);
+ }
+
+ if (mCallback) {
+ mCallback(mStatus, mMessage ? mMessage->c_str() : nullptr, mUserdata1,
+ mUserdata2);
+ }
+ }
+
+ private:
+ WGPUBufferMapCallback2 mCallback = nullptr;
+ void* mUserdata1 = nullptr;
+ void* mUserdata2 = nullptr;
+
+ Ref<WGPUBuffer> mBuffer;
+ WGPUMapAsyncStatus mStatus = WGPUMapAsyncStatus_Success;
+ std::optional<std::string> mMessage = std::nullopt;
+};
+
class RequestAdapterEvent final : public TrackedEvent {
public:
static constexpr EventType kType = EventType::RequestAdapter;
@@ -834,8 +946,106 @@
// WGPUAdapterImpl implementations.
// ----------------------------------------------------------------------------
-WGPUAdapterImpl::WGPUAdapterImpl(const EventSource* source)
- : EventSource(source->GetInstanceId()) {}
+WGPUAdapterImpl::WGPUAdapterImpl(const EventSource* instance)
+ : EventSource(instance->GetInstanceId()) {}
+
+// ----------------------------------------------------------------------------
+// WGPUBuffer implementations.
+// ----------------------------------------------------------------------------
+
+WGPUBufferImpl::WGPUBufferImpl(const EventSource* source, bool mappedAtCreation)
+ : EventSource(source->GetInstanceId()),
+ mMapState(mappedAtCreation ? WGPUBufferMapState_Mapped
+ : WGPUBufferMapState_Unmapped) {
+ if (mappedAtCreation) {
+ mPendingMapRequest = {kNullFutureId, WGPUMapMode_Write};
+ }
+}
+
+void WGPUBufferImpl::Destroy() {
+ emwgpuBufferDestroy(this);
+ AbortPendingMap("Buffer was destroyed before mapping was resolved.");
+}
+
+const void* WGPUBufferImpl::GetConstMappedRange(size_t offset, size_t size) {
+ if (mMapState != WGPUBufferMapState_Mapped) {
+ return nullptr;
+ }
+ return emwgpuBufferGetConstMappedRange(this, offset, size);
+}
+
+WGPUBufferMapState WGPUBufferImpl::GetMapState() const {
+ return mMapState;
+}
+
+void* WGPUBufferImpl::GetMappedRange(size_t offset, size_t size) {
+ if (mMapState != WGPUBufferMapState_Mapped) {
+ return nullptr;
+ }
+ if (mPendingMapRequest.mode != WGPUMapMode_Write) {
+ assert(false);
+ return nullptr;
+ }
+
+ return emwgpuBufferGetMappedRange(this, offset, size);
+}
+
+WGPUFuture WGPUBufferImpl::MapAsync(WGPUMapMode mode,
+ size_t offset,
+ size_t size,
+ WGPUBufferMapCallbackInfo2 callbackInfo) {
+ auto [futureId, tracked] = GetEventManager().TrackEvent(
+ std::make_unique<MapAsyncEvent>(GetInstanceId(), this, callbackInfo));
+ if (!tracked) {
+ return WGPUFuture{kNullFutureId};
+ }
+
+ if (mMapState == WGPUBufferMapState_Pending) {
+ GetEventManager().SetFutureReady<MapAsyncEvent>(
+ futureId, WGPUMapAsyncStatus_Error,
+ "Buffer already has an outstanding map pending.");
+ return WGPUFuture{futureId};
+ }
+
+ assert(mPendingMapRequest.mode == WGPUMapMode_None);
+ mMapState = WGPUBufferMapState_Pending;
+ mPendingMapRequest = {futureId, mode};
+
+ emwgpuBufferMapAsync(this, futureId, mode, offset, size);
+ return WGPUFuture{futureId};
+}
+
+void WGPUBufferImpl::Unmap() {
+ emwgpuBufferUnmap(this);
+ AbortPendingMap("Buffer was unmapped before mapping was resolved.");
+}
+
+bool WGPUBufferImpl::IsPendingMapRequest(FutureID futureID) const {
+ assert(futureID != kNullFutureId);
+ return mPendingMapRequest.futureID == futureID;
+}
+
+void WGPUBufferImpl::AbortPendingMap(const char* message) {
+ if (mMapState == WGPUBufferMapState_Unmapped) {
+ return;
+ }
+
+ mMapState = WGPUBufferMapState_Unmapped;
+
+ FutureID futureId = mPendingMapRequest.futureID;
+ if (futureId == kNullFutureId) {
+ // If we were mappedAtCreation, then there is no pending map request so we
+ // don't need to resolve any futures.
+ return;
+ }
+ mPendingMapRequest = {};
+ GetEventManager().SetFutureReady<MapAsyncEvent>(
+ futureId, WGPUMapAsyncStatus_Aborted, message);
+}
+
+void WGPUBufferImpl::WillDropLastExternalRef() {
+ AbortPendingMap("Buffer was destroyed before mapping was resolved.");
+}
// ----------------------------------------------------------------------------
// WGPUDeviceImpl implementations.
@@ -934,7 +1144,7 @@
}
// Future event callbacks.
-void emwgpuOnDeviceCreateComputePipelineCompleted(
+void emwgpuOnCreateComputePipelineCompleted(
FutureID futureId,
WGPUCreatePipelineAsyncStatus status,
WGPUComputePipeline pipeline,
@@ -942,11 +1152,10 @@
GetEventManager().SetFutureReady<CreateComputePipelineEvent>(
futureId, status, pipeline, message);
}
-void emwgpuOnDeviceCreateRenderPipelineCompleted(
- FutureID futureId,
- WGPUCreatePipelineAsyncStatus status,
- WGPURenderPipeline pipeline,
- const char* message) {
+void emwgpuOnCreateRenderPipelineCompleted(FutureID futureId,
+ WGPUCreatePipelineAsyncStatus status,
+ WGPURenderPipeline pipeline,
+ const char* message) {
GetEventManager().SetFutureReady<CreateRenderPipelineEvent>(
futureId, status, pipeline, message);
}
@@ -955,6 +1164,11 @@
const char* message) {
GetEventManager().SetFutureReady<DeviceLostEvent>(futureId, reason, message);
}
+void emwgpuOnMapAsyncCompleted(FutureID futureId,
+ WGPUMapAsyncStatus status,
+ const char* message) {
+ GetEventManager().SetFutureReady<MapAsyncEvent>(futureId, status, message);
+}
void emwgpuOnRequestAdapterCompleted(FutureID futureId,
WGPURequestAdapterStatus status,
WGPUAdapter adapter,
@@ -1098,6 +1312,36 @@
// Methods of Buffer
// ----------------------------------------------------------------------------
+void wgpuBufferDestroy(WGPUBuffer buffer) {
+ buffer->Destroy();
+}
+
+const void* wgpuBufferGetConstMappedRange(WGPUBuffer buffer,
+ size_t offset,
+ size_t size) {
+ return buffer->GetConstMappedRange(offset, size);
+}
+
+WGPUBufferMapState wgpuBufferGetMapState(WGPUBuffer buffer) {
+ return buffer->GetMapState();
+}
+
+void* wgpuBufferGetMappedRange(WGPUBuffer buffer, size_t offset, size_t size) {
+ return buffer->GetMappedRange(offset, size);
+}
+
+WGPUFuture wgpuBufferMapAsync2(WGPUBuffer buffer,
+ WGPUMapMode mode,
+ size_t offset,
+ size_t size,
+ WGPUBufferMapCallbackInfo2 callbackInfo) {
+ return buffer->MapAsync(mode, offset, size, callbackInfo);
+}
+
+void wgpuBufferUnmap(WGPUBuffer buffer) {
+ buffer->Unmap();
+}
+
// ----------------------------------------------------------------------------
// Methods of CommandBuffer
// ----------------------------------------------------------------------------
@@ -1118,6 +1362,13 @@
// Methods of Device
// ----------------------------------------------------------------------------
+WGPUBuffer wgpuDeviceCreateBuffer(WGPUDevice device,
+ const WGPUBufferDescriptor* descriptor) {
+ WGPUBuffer buffer = new WGPUBufferImpl(device, descriptor->mappedAtCreation);
+ emwgpuDeviceCreateBuffer(device, descriptor, buffer);
+ return buffer;
+}
+
void wgpuDeviceCreateComputePipelineAsync(
WGPUDevice device,
const WGPUComputePipelineDescriptor* descriptor,