Copy Emscripten's WebGPU bindings into Dawn
These are the original unmodified files from Emscripten, at revision:
https://github.com/emscripten-core/emscripten/commit/0c504193efb3d0b51d30c07895544b29cbad1950
Bug: 346806934
Change-Id: I27ee46dee6d96a896db03c61adbb0eb598500ac7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/193725
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/third_party/emdawnwebgpu/CONTRIBUTING.md b/third_party/emdawnwebgpu/CONTRIBUTING.md
new file mode 100644
index 0000000..a81b7cd
--- /dev/null
+++ b/third_party/emdawnwebgpu/CONTRIBUTING.md
@@ -0,0 +1,3 @@
+Contributions to this directory must be made under Emscripten's license.
+
+See: <https://github.com/emscripten-core/emscripten/blob/main/CONTRIBUTING.md>
diff --git a/third_party/emdawnwebgpu/LICENSE b/third_party/emdawnwebgpu/LICENSE
new file mode 100644
index 0000000..08d1be5
--- /dev/null
+++ b/third_party/emdawnwebgpu/LICENSE
@@ -0,0 +1,68 @@
+Emscripten is available under 2 licenses, the MIT license and the
+University of Illinois/NCSA Open Source License.
+
+Both are permissive open source licenses, with little if any
+practical difference between them.
+
+The reason for offering both is that (1) the MIT license is
+well-known, while (2) the University of Illinois/NCSA Open Source
+License allows Emscripten's code to be integrated upstream into
+LLVM, which uses that license, should the opportunity arise.
+
+The full text of both licenses follows.
+
+==============================================================================
+
+Copyright (c) 2010-2014 Emscripten authors, see AUTHORS file.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+==============================================================================
+
+Copyright (c) 2010-2014 Emscripten authors, see AUTHORS file.
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal with the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+ Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimers.
+
+ Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimers
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ Neither the names of Mozilla,
+ nor the names of its contributors may be used to endorse
+ or promote products derived from this Software without specific prior
+ written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
diff --git a/third_party/emdawnwebgpu/OWNERS b/third_party/emdawnwebgpu/OWNERS
new file mode 100644
index 0000000..7986535
--- /dev/null
+++ b/third_party/emdawnwebgpu/OWNERS
@@ -0,0 +1 @@
+file:../../src/emdawnwebgpu/OWNERS
diff --git a/third_party/emdawnwebgpu/README.md b/third_party/emdawnwebgpu/README.md
new file mode 100644
index 0000000..ad23eaa
--- /dev/null
+++ b/third_party/emdawnwebgpu/README.md
@@ -0,0 +1,4 @@
+The source files in this directory are copied out of Emscripten, and will be
+contributed back upstream after webgpu.h becomes stable.
+See [`//src/emdawnwebgpu/README.md`](../../src/emdawnwebgpu/README.md)
+for details.
diff --git a/third_party/emdawnwebgpu/library_html5_webgpu.js b/third_party/emdawnwebgpu/library_html5_webgpu.js
new file mode 100644
index 0000000..b735979
--- /dev/null
+++ b/third_party/emdawnwebgpu/library_html5_webgpu.js
@@ -0,0 +1,93 @@
+{{{
+ // Helper functions for code generation
+ globalThis.html5_gpu = {
+ makeImportExport: (snake_case, CamelCase) => {
+ return `
+LibraryHTML5WebGPU.emscripten_webgpu_import_${snake_case}__deps = ['$WebGPU', '$JsValStore'];
+LibraryHTML5WebGPU.emscripten_webgpu_import_${snake_case} = (handle) =>
+ WebGPU.mgr${CamelCase}.create(JsValStore.get(handle));
+
+LibraryHTML5WebGPU.emscripten_webgpu_export_${snake_case}__deps = ['$WebGPU', '$JsValStore'];
+LibraryHTML5WebGPU.emscripten_webgpu_export_${snake_case} = (handle) =>
+ JsValStore.add(WebGPU.mgr${CamelCase}.get(handle));`
+ },
+ };
+ null;
+}}}
+
+
+var LibraryHTML5WebGPU = {
+ $JsValStore: {
+ values: {},
+ next_id: 1,
+
+ add(js_val) {
+ var id;
+ do {
+ id = JsValStore.next_id++;
+ if (JsValStore.next_id > 2147483647) JsValStore.next_id = 1; // Wraparound signed int32.
+ } while (id in JsValStore.values);
+
+ JsValStore.values[id] = js_val;
+ return id;
+ },
+ remove(id) {
+#if ASSERTIONS
+ assert(id in JsValStore.values);
+#endif
+ delete JsValStore.values[id];
+ },
+ get(id) {
+#if ASSERTIONS
+ assert(id === 0 || id in JsValStore.values);
+#endif
+ return JsValStore.values[id];
+ },
+ },
+
+ emscripten_webgpu_release_js_handle__deps: ['$JsValStore'],
+ emscripten_webgpu_release_js_handle: (id) => JsValStore.remove(id),
+
+ emscripten_webgpu_get_device__deps: ['$WebGPU'],
+ emscripten_webgpu_get_device: () => {
+#if ASSERTIONS
+ assert(Module['preinitializedWebGPUDevice']);
+#endif
+ if (WebGPU.preinitializedDeviceId === undefined) {
+ var device = Module['preinitializedWebGPUDevice'];
+ var deviceWrapper = { queueId: WebGPU.mgrQueue.create(device["queue"]) };
+ WebGPU.preinitializedDeviceId = WebGPU.mgrDevice.create(device, deviceWrapper);
+ }
+ WebGPU.mgrDevice.reference(WebGPU.preinitializedDeviceId);
+ return WebGPU.preinitializedDeviceId;
+ },
+};
+
+{{{ html5_gpu.makeImportExport('surface', 'Surface') }}}
+{{{ html5_gpu.makeImportExport('swap_chain', 'SwapChain') }}}
+
+{{{ html5_gpu.makeImportExport('device', 'Device') }}}
+{{{ html5_gpu.makeImportExport('queue', 'Queue') }}}
+
+{{{ html5_gpu.makeImportExport('command_buffer', 'CommandBuffer') }}}
+{{{ html5_gpu.makeImportExport('command_encoder', 'CommandEncoder') }}}
+{{{ html5_gpu.makeImportExport('render_pass_encoder', 'RenderPassEncoder') }}}
+{{{ html5_gpu.makeImportExport('compute_pass_encoder', 'ComputePassEncoder') }}}
+
+{{{ html5_gpu.makeImportExport('bind_group', 'BindGroup') }}}
+{{{ html5_gpu.makeImportExport('buffer', 'Buffer') }}}
+{{{ html5_gpu.makeImportExport('sampler', 'Sampler') }}}
+{{{ html5_gpu.makeImportExport('texture', 'Texture') }}}
+{{{ html5_gpu.makeImportExport('texture_view', 'TextureView') }}}
+{{{ html5_gpu.makeImportExport('query_set', 'QuerySet') }}}
+
+{{{ html5_gpu.makeImportExport('bind_group_layout', 'BindGroupLayout') }}}
+{{{ html5_gpu.makeImportExport('pipeline_layout', 'PipelineLayout') }}}
+{{{ html5_gpu.makeImportExport('render_pipeline', 'RenderPipeline') }}}
+{{{ html5_gpu.makeImportExport('compute_pipeline', 'ComputePipeline') }}}
+{{{ html5_gpu.makeImportExport('shader_module', 'ShaderModule') }}}
+
+{{{ html5_gpu.makeImportExport('render_bundle_encoder', 'RenderBundleEncoder') }}}
+{{{ html5_gpu.makeImportExport('render_bundle', 'RenderBundle') }}}
+
+addToLibrary(LibraryHTML5WebGPU);
diff --git a/third_party/emdawnwebgpu/library_webgpu.js b/third_party/emdawnwebgpu/library_webgpu.js
new file mode 100644
index 0000000..f67f81f
--- /dev/null
+++ b/third_party/emdawnwebgpu/library_webgpu.js
@@ -0,0 +1,2882 @@
+/**
+ * @license
+ * Copyright 2019 The Emscripten Authors
+ * SPDX-License-Identifier: MIT
+ */
+
+/*
+ * WebGPU support.
+ *
+ * This file implements the common C header <webgpu/webgpu.h> on top of the
+ * browser's native JS WebGPU implementation. This allows applications targeting
+ * wgpu-native (https://github.com/gfx-rs/wgpu) or
+ * Dawn (https://dawn.googlesource.com/dawn/) to also target the Web with the
+ * same graphics API and fairly minimal changes - similar to OpenGL ES 2.0/3.0
+ * on WebGL 1.0/2.0.
+ *
+ * To test this, run the following tests:
+ * - test/runner.py 'other.test_webgpu*'
+ * - EMTEST_BROWSER="/path/to/chrome --user-data-dir=chromeuserdata --enable-unsafe-webgpu" \
+ * test/runner.py 'browser.test_webgpu*'
+ */
+
+{{{
+ // Helper functions for code generation
+ globalThis.gpu = {
+ makeInitManager: function(type) {
+ var mgr = `WebGPU.mgr${type}`;
+ return `${mgr} = ${mgr} || new Manager();`;
+ },
+
+ makeReferenceRelease: function(type) {
+ return `
+wgpu${type}Reference: (id) => WebGPU.mgr${type}.reference(id),
+wgpu${type}Release: (id) => WebGPU.mgr${type}.release(id),`;
+ },
+
+ convertSentinelToUndefined: function(name) {
+ return `if (${name} == -1) ${name} = undefined;`;
+ },
+
+ makeGetBool: function(struct, offset) {
+ return `!!(${makeGetValue(struct, offset, 'u32')})`;
+ },
+ makeGetU32: function(struct, offset) {
+ return makeGetValue(struct, offset, 'u32');
+ },
+ makeGetU64: function(struct, offset) {
+ var l = makeGetValue(struct, offset, 'u32');
+ var h = makeGetValue(`(${struct} + 4)`, offset, 'u32')
+ return `${h} * 0x100000000 + ${l}`
+ },
+ makeCheck: function(str) {
+ if (!ASSERTIONS) return '';
+ return `assert(${str});`;
+ },
+ makeCheckDefined: function(name) {
+ return this.makeCheck(`typeof ${name} != "undefined"`);
+ },
+ makeCheckDescriptor: function(descriptor) {
+ // Assert descriptor is non-null, then that its nextInChain is null.
+ // For descriptors that aren't the first in the chain (e.g
+ // ShaderModuleSPIRVDescriptor), there is no .nextInChain pointer, but
+ // instead a ChainedStruct object: .chain. So we need to check if
+ // .chain.nextInChain is null. As long as nextInChain and chain are always
+ // the first member in the struct, descriptor.nextInChain and
+ // descriptor.chain.nextInChain should have the same offset (0) to the
+ // descriptor pointer and we can check it to be null.
+ var OffsetOfNextInChainMember = 0;
+ return this.makeCheck(descriptor) + this.makeCheck(makeGetValue(descriptor, OffsetOfNextInChainMember, '*') + ' === 0');
+ },
+
+ // Compile-time table for enum integer values used with templating.
+ // Must be in sync with webgpu.h.
+ // TODO: Generate this to keep it in sync with webgpu.h
+ COPY_STRIDE_UNDEFINED: 0xFFFFFFFF,
+ LIMIT_U32_UNDEFINED: 0xFFFFFFFF,
+ MIP_LEVEL_COUNT_UNDEFINED: 0xFFFFFFFF,
+ ARRAY_LAYER_COUNT_UNDEFINED: 0xFFFFFFFF,
+ AdapterType: {
+ CPU: 3,
+ Unknown: 4,
+ },
+ BackendType: {
+ WebGPU: 2,
+ },
+ BufferMapAsyncStatus: {
+ Success: 0,
+ ValidationError: 1,
+ Unknown: 2,
+ DeviceLost: 3,
+ DestroyedBeforeCallback: 4,
+ UnmappedBeforeCallback: 5,
+ MappingAlreadyPending: 6,
+ OffsetOutOfRange: 7,
+ SizeOutOfRange: 8,
+ },
+ CompilationInfoRequestStatus: {
+ Success: 0,
+ Error: 1,
+ DeviceLost: 2,
+ Unknown: 3,
+ },
+ CompositeAlphaMode: {
+ Auto: 0,
+ Opaque: 1,
+ },
+ CreatePipelineAsyncStatus: {
+ Success: 0,
+ ValidationError: 1,
+ InternalError: 2,
+ DeviceLost: 3,
+ DeviceDestroyed: 4,
+ Unknown: 5,
+ },
+ ErrorType: {
+ NoError: 0,
+ Validation: 1,
+ OutOfMemory: 2,
+ Internal: 3,
+ Unknown: 4,
+ DeviceLost: 5,
+ },
+ PresentMode: {
+ Fifo: 1,
+ Immediate: 3,
+ Mailbox: 4,
+ },
+ LoadOp: {
+ Undefined: 0,
+ Clear: 1,
+ Load: 2,
+ },
+ StoreOp: {
+ Undefined: 0,
+ Store: 1,
+ Discard: 2,
+ },
+ MapMode: {
+ None: 0,
+ Read: 1,
+ Write: 2
+ },
+ RequestAdapterStatus: {
+ Success: 0,
+ Unavailable: 1,
+ Error: 2,
+ Unknown: 3,
+ },
+ RequestDeviceStatus: {
+ Success: 0,
+ Error: 1,
+ Unknown: 1,
+ },
+ SType: {
+ SurfaceDescriptorFromCanvasHTMLSelector: 0x4,
+ ShaderModuleSPIRVDescriptor: 0x5,
+ ShaderModuleWGSLDescriptor: 0x6,
+ PrimitiveDepthClipControl: 0x7,
+ RenderPassDescriptorMaxDrawCount: 0xF,
+ TextureBindingViewDimensionDescriptor: 0x11,
+ },
+ SurfaceGetCurrentTextureStatus: {
+ Success: 0,
+ DeviceLost: 5,
+ },
+ QueueWorkDoneStatus: {
+ Success: 0,
+ Error: 1,
+ Unknown: 2,
+ DeviceLost: 3,
+ },
+ TextureFormat: {
+ Undefined: 0,
+ },
+ VertexStepMode: {
+ Undefined: 0,
+ VertexBufferNotUsed: 1,
+ Vertex: 2,
+ Instance: 3,
+ },
+ };
+ null;
+}}}
+
+var LibraryWebGPU = {
+ $WebGPU__postset: 'WebGPU.initManagers();',
+ $WebGPU__deps: ['$stackSave', '$stackRestore', '$stringToUTF8OnStack'],
+ $WebGPU: {
+ errorCallback: (callback, type, message, userdata) => {
+ var sp = stackSave();
+ var messagePtr = stringToUTF8OnStack(message);
+ {{{ makeDynCall('vipp', 'callback') }}}(type, messagePtr, userdata);
+ stackRestore(sp);
+ },
+
+ initManagers: () => {
+ if (WebGPU.mgrDevice) return;
+
+ /** @constructor */
+ function Manager() {
+ this.objects = {};
+ this.nextId = 1;
+ this.create = function(object, wrapper = {}) {
+ var id = this.nextId++;
+ {{{ gpu.makeCheck("typeof this.objects[id] == 'undefined'") }}}
+ wrapper.refcount = 1;
+ wrapper.object = object;
+ this.objects[id] = wrapper;
+ return id;
+ };
+ this.get = function(id) {
+ if (!id) return undefined;
+ var o = this.objects[id];
+ {{{ gpu.makeCheckDefined('o') }}}
+ return o.object;
+ };
+ this.reference = function(id) {
+ var o = this.objects[id];
+ {{{ gpu.makeCheckDefined('o') }}}
+ o.refcount++;
+ };
+ this.release = function(id) {
+ var o = this.objects[id];
+ {{{ gpu.makeCheckDefined('o') }}}
+ {{{ gpu.makeCheck('o.refcount > 0') }}}
+ o.refcount--;
+ if (o.refcount <= 0) {
+ delete this.objects[id];
+ }
+ };
+ }
+
+ {{{ gpu.makeInitManager('Surface') }}}
+ {{{ gpu.makeInitManager('SwapChain') }}}
+
+ {{{ gpu.makeInitManager('Adapter') }}}
+ // TODO: Release() the device's default queue when the device is freed.
+ {{{ gpu.makeInitManager('Device') }}}
+ {{{ gpu.makeInitManager('Queue') }}}
+
+ {{{ gpu.makeInitManager('CommandBuffer') }}}
+ {{{ gpu.makeInitManager('CommandEncoder') }}}
+ {{{ gpu.makeInitManager('RenderPassEncoder') }}}
+ {{{ gpu.makeInitManager('ComputePassEncoder') }}}
+
+ {{{ gpu.makeInitManager('BindGroup') }}}
+ {{{ gpu.makeInitManager('Buffer') }}}
+ {{{ gpu.makeInitManager('Sampler') }}}
+ {{{ gpu.makeInitManager('Texture') }}}
+ {{{ gpu.makeInitManager('TextureView') }}}
+ {{{ gpu.makeInitManager('QuerySet') }}}
+
+ {{{ gpu.makeInitManager('BindGroupLayout') }}}
+ {{{ gpu.makeInitManager('PipelineLayout') }}}
+ {{{ gpu.makeInitManager('RenderPipeline') }}}
+ {{{ gpu.makeInitManager('ComputePipeline') }}}
+ {{{ gpu.makeInitManager('ShaderModule') }}}
+
+ {{{ gpu.makeInitManager('RenderBundleEncoder') }}}
+ {{{ gpu.makeInitManager('RenderBundle') }}}
+ },
+
+ makeColor: (ptr) => {
+ return {
+ "r": {{{ makeGetValue('ptr', 0, 'double') }}},
+ "g": {{{ makeGetValue('ptr', 8, 'double') }}},
+ "b": {{{ makeGetValue('ptr', 16, 'double') }}},
+ "a": {{{ makeGetValue('ptr', 24, 'double') }}},
+ };
+ },
+
+ makeExtent3D: (ptr) => {
+ return {
+ "width": {{{ gpu.makeGetU32('ptr', C_STRUCTS.WGPUExtent3D.width) }}},
+ "height": {{{ gpu.makeGetU32('ptr', C_STRUCTS.WGPUExtent3D.height) }}},
+ "depthOrArrayLayers": {{{ gpu.makeGetU32('ptr', C_STRUCTS.WGPUExtent3D.depthOrArrayLayers) }}},
+ };
+ },
+
+ makeOrigin3D: (ptr) => {
+ return {
+ "x": {{{ gpu.makeGetU32('ptr', C_STRUCTS.WGPUOrigin3D.x) }}},
+ "y": {{{ gpu.makeGetU32('ptr', C_STRUCTS.WGPUOrigin3D.y) }}},
+ "z": {{{ gpu.makeGetU32('ptr', C_STRUCTS.WGPUOrigin3D.z) }}},
+ };
+ },
+
+ makeImageCopyTexture: (ptr) => {
+ {{{ gpu.makeCheckDescriptor('ptr') }}}
+ return {
+ "texture": WebGPU.mgrTexture.get(
+ {{{ makeGetValue('ptr', C_STRUCTS.WGPUImageCopyTexture.texture, '*') }}}),
+ "mipLevel": {{{ gpu.makeGetU32('ptr', C_STRUCTS.WGPUImageCopyTexture.mipLevel) }}},
+ "origin": WebGPU.makeOrigin3D(ptr + {{{ C_STRUCTS.WGPUImageCopyTexture.origin }}}),
+ "aspect": WebGPU.TextureAspect[{{{ gpu.makeGetU32('ptr', C_STRUCTS.WGPUImageCopyTexture.aspect) }}}],
+ };
+ },
+
+ makeTextureDataLayout: (ptr) => {
+ {{{ gpu.makeCheckDescriptor('ptr') }}}
+ var bytesPerRow = {{{ gpu.makeGetU32('ptr', C_STRUCTS.WGPUTextureDataLayout.bytesPerRow) }}};
+ var rowsPerImage = {{{ gpu.makeGetU32('ptr', C_STRUCTS.WGPUTextureDataLayout.rowsPerImage) }}};
+ return {
+ "offset": {{{ gpu.makeGetU64('ptr', C_STRUCTS.WGPUTextureDataLayout.offset) }}},
+ "bytesPerRow": bytesPerRow === {{{ gpu.COPY_STRIDE_UNDEFINED }}} ? undefined : bytesPerRow,
+ "rowsPerImage": rowsPerImage === {{{ gpu.COPY_STRIDE_UNDEFINED }}} ? undefined : rowsPerImage,
+ };
+ },
+
+ makeImageCopyBuffer: (ptr) => {
+ {{{ gpu.makeCheckDescriptor('ptr') }}}
+ var layoutPtr = ptr + {{{ C_STRUCTS.WGPUImageCopyBuffer.layout }}};
+ var bufferCopyView = WebGPU.makeTextureDataLayout(layoutPtr);
+ bufferCopyView["buffer"] = WebGPU.mgrBuffer.get(
+ {{{ makeGetValue('ptr', C_STRUCTS.WGPUImageCopyBuffer.buffer, '*') }}});
+ return bufferCopyView;
+ },
+
+ makePipelineConstants: (constantCount, constantsPtr) => {
+ if (!constantCount) return;
+ var constants = {};
+ for (var i = 0; i < constantCount; ++i) {
+ var entryPtr = constantsPtr + {{{ C_STRUCTS.WGPUConstantEntry.__size__ }}} * i;
+ var key = UTF8ToString({{{ makeGetValue('entryPtr', C_STRUCTS.WGPUConstantEntry.key, '*') }}});
+ constants[key] = {{{ makeGetValue('entryPtr', C_STRUCTS.WGPUConstantEntry.value, 'double') }}};
+ }
+ return constants;
+ },
+
+ makePipelineLayout: (layoutPtr) => {
+ if (!layoutPtr) return 'auto';
+ return WebGPU.mgrPipelineLayout.get(layoutPtr);
+ },
+
+ makeProgrammableStageDescriptor: (ptr) => {
+ if (!ptr) return undefined;
+ {{{ gpu.makeCheckDescriptor('ptr') }}}
+ var desc = {
+ "module": WebGPU.mgrShaderModule.get(
+ {{{ makeGetValue('ptr', C_STRUCTS.WGPUProgrammableStageDescriptor.module, '*') }}}),
+ "constants": WebGPU.makePipelineConstants(
+ {{{ gpu.makeGetU32('ptr', C_STRUCTS.WGPUProgrammableStageDescriptor.constantCount) }}},
+ {{{ makeGetValue('ptr', C_STRUCTS.WGPUProgrammableStageDescriptor.constants, '*') }}}),
+ };
+ var entryPointPtr = {{{ makeGetValue('ptr', C_STRUCTS.WGPUProgrammableStageDescriptor.entryPoint, '*') }}};
+ if (entryPointPtr) desc["entryPoint"] = UTF8ToString(entryPointPtr);
+ return desc;
+ },
+
+ fillLimitStruct: (limits, supportedLimitsOutPtr) => {
+ var limitsOutPtr = supportedLimitsOutPtr + {{{ C_STRUCTS.WGPUSupportedLimits.limits }}};
+
+ function setLimitValueU32(name, limitOffset) {
+ var limitValue = limits[name];
+ {{{ makeSetValue('limitsOutPtr', 'limitOffset', 'limitValue', 'i32') }}};
+ }
+ function setLimitValueU64(name, limitOffset) {
+ var limitValue = limits[name];
+ {{{ makeSetValue('limitsOutPtr', 'limitOffset', 'limitValue', 'i64') }}};
+ }
+
+ setLimitValueU32('maxTextureDimension1D', {{{ C_STRUCTS.WGPULimits.maxTextureDimension1D }}});
+ setLimitValueU32('maxTextureDimension2D', {{{ C_STRUCTS.WGPULimits.maxTextureDimension2D }}});
+ setLimitValueU32('maxTextureDimension3D', {{{ C_STRUCTS.WGPULimits.maxTextureDimension3D }}});
+ setLimitValueU32('maxTextureArrayLayers', {{{ C_STRUCTS.WGPULimits.maxTextureArrayLayers }}});
+ setLimitValueU32('maxBindGroups', {{{ C_STRUCTS.WGPULimits.maxBindGroups }}});
+ setLimitValueU32('maxBindGroupsPlusVertexBuffers', {{{ C_STRUCTS.WGPULimits.maxBindGroupsPlusVertexBuffers }}});
+ setLimitValueU32('maxBindingsPerBindGroup', {{{ C_STRUCTS.WGPULimits.maxBindingsPerBindGroup }}});
+ setLimitValueU32('maxDynamicUniformBuffersPerPipelineLayout', {{{ C_STRUCTS.WGPULimits.maxDynamicUniformBuffersPerPipelineLayout }}});
+ setLimitValueU32('maxDynamicStorageBuffersPerPipelineLayout', {{{ C_STRUCTS.WGPULimits.maxDynamicStorageBuffersPerPipelineLayout }}});
+ setLimitValueU32('maxSampledTexturesPerShaderStage', {{{ C_STRUCTS.WGPULimits.maxSampledTexturesPerShaderStage }}});
+ setLimitValueU32('maxSamplersPerShaderStage', {{{ C_STRUCTS.WGPULimits.maxSamplersPerShaderStage }}});
+ setLimitValueU32('maxStorageBuffersPerShaderStage', {{{ C_STRUCTS.WGPULimits.maxStorageBuffersPerShaderStage }}});
+ setLimitValueU32('maxStorageTexturesPerShaderStage', {{{ C_STRUCTS.WGPULimits.maxStorageTexturesPerShaderStage }}});
+ setLimitValueU32('maxUniformBuffersPerShaderStage', {{{ C_STRUCTS.WGPULimits.maxUniformBuffersPerShaderStage }}});
+ setLimitValueU32('minUniformBufferOffsetAlignment', {{{ C_STRUCTS.WGPULimits.minUniformBufferOffsetAlignment }}});
+ setLimitValueU32('minStorageBufferOffsetAlignment', {{{ C_STRUCTS.WGPULimits.minStorageBufferOffsetAlignment }}});
+
+ setLimitValueU64('maxUniformBufferBindingSize', {{{ C_STRUCTS.WGPULimits.maxUniformBufferBindingSize }}});
+ setLimitValueU64('maxStorageBufferBindingSize', {{{ C_STRUCTS.WGPULimits.maxStorageBufferBindingSize }}});
+
+ setLimitValueU32('maxVertexBuffers', {{{ C_STRUCTS.WGPULimits.maxVertexBuffers }}});
+ setLimitValueU32('maxBufferSize', {{{ C_STRUCTS.WGPULimits.maxBufferSize }}});
+ setLimitValueU32('maxVertexAttributes', {{{ C_STRUCTS.WGPULimits.maxVertexAttributes }}});
+ setLimitValueU32('maxVertexBufferArrayStride', {{{ C_STRUCTS.WGPULimits.maxVertexBufferArrayStride }}});
+ setLimitValueU32('maxInterStageShaderComponents', {{{ C_STRUCTS.WGPULimits.maxInterStageShaderComponents }}});
+ setLimitValueU32('maxInterStageShaderVariables', {{{ C_STRUCTS.WGPULimits.maxInterStageShaderVariables }}});
+ setLimitValueU32('maxColorAttachments', {{{ C_STRUCTS.WGPULimits.maxColorAttachments }}});
+ setLimitValueU32('maxColorAttachmentBytesPerSample', {{{ C_STRUCTS.WGPULimits.maxColorAttachmentBytesPerSample }}});
+ setLimitValueU32('maxComputeWorkgroupStorageSize', {{{ C_STRUCTS.WGPULimits.maxComputeWorkgroupStorageSize }}});
+ setLimitValueU32('maxComputeInvocationsPerWorkgroup', {{{ C_STRUCTS.WGPULimits.maxComputeInvocationsPerWorkgroup }}});
+ setLimitValueU32('maxComputeWorkgroupSizeX', {{{ C_STRUCTS.WGPULimits.maxComputeWorkgroupSizeX }}});
+ setLimitValueU32('maxComputeWorkgroupSizeY', {{{ C_STRUCTS.WGPULimits.maxComputeWorkgroupSizeY }}});
+ setLimitValueU32('maxComputeWorkgroupSizeZ', {{{ C_STRUCTS.WGPULimits.maxComputeWorkgroupSizeZ }}});
+ setLimitValueU32('maxComputeWorkgroupsPerDimension', {{{ C_STRUCTS.WGPULimits.maxComputeWorkgroupsPerDimension }}});
+ },
+
+ // Map from enum string back to enum number, for callbacks.
+ Int_BufferMapState: {
+ 'unmapped': 0,
+ 'pending': 1,
+ 'mapped': 2,
+ },
+ Int_CompilationMessageType : {
+ 'error': 0,
+ 'warning': 1,
+ 'info': 2,
+ },
+ Int_DeviceLostReason: {
+ 'undefined': 1,
+ 'unknown': 1,
+ 'destroyed': 2,
+ },
+ Int_PreferredFormat: {
+ 'rgba8unorm': 0x12,
+ 'bgra8unorm': 0x17,
+ },
+
+ // Map from enum number to enum string.
+ // This section is auto-generated. See system/include/webgpu/README.md for details.
+ WGSLFeatureName: [
+ undefined,
+ 'readonly_and_readwrite_storage_textures',
+ 'packed_4x8_integer_dot_product',
+ 'unrestricted_pointer_parameters',
+ 'pointer_composite_access',
+ ],
+ AddressMode: [
+ undefined,
+ 'clamp-to-edge',
+ 'repeat',
+ 'mirror-repeat',
+ ],
+ BlendFactor: [
+ undefined,
+ 'zero',
+ 'one',
+ 'src',
+ 'one-minus-src',
+ 'src-alpha',
+ 'one-minus-src-alpha',
+ 'dst',
+ 'one-minus-dst',
+ 'dst-alpha',
+ 'one-minus-dst-alpha',
+ 'src-alpha-saturated',
+ 'constant',
+ 'one-minus-constant',
+ ],
+ BlendOperation: [
+ undefined,
+ 'add',
+ 'subtract',
+ 'reverse-subtract',
+ 'min',
+ 'max',
+ ],
+ BufferBindingType: [
+ undefined,
+ 'uniform',
+ 'storage',
+ 'read-only-storage',
+ ],
+ BufferMapState: {
+ 1: 'unmapped',
+ 2: 'pending',
+ 3: 'mapped',
+ },
+ CompareFunction: [
+ undefined,
+ 'never',
+ 'less',
+ 'equal',
+ 'less-equal',
+ 'greater',
+ 'not-equal',
+ 'greater-equal',
+ 'always',
+ ],
+ CompilationInfoRequestStatus: [
+ 'success',
+ 'error',
+ 'device-lost',
+ 'unknown',
+ ],
+ CullMode: [
+ undefined,
+ 'none',
+ 'front',
+ 'back',
+ ],
+ ErrorFilter: {
+ 1: 'validation',
+ 2: 'out-of-memory',
+ 3: 'internal',
+ },
+ FeatureName: [
+ undefined,
+ 'depth-clip-control',
+ 'depth32float-stencil8',
+ 'timestamp-query',
+ 'texture-compression-bc',
+ 'texture-compression-etc2',
+ 'texture-compression-astc',
+ 'indirect-first-instance',
+ 'shader-f16',
+ 'rg11b10ufloat-renderable',
+ 'bgra8unorm-storage',
+ 'float32-filterable',
+ ],
+ FilterMode: [
+ undefined,
+ 'nearest',
+ 'linear',
+ ],
+ FrontFace: [
+ undefined,
+ 'ccw',
+ 'cw',
+ ],
+ IndexFormat: [
+ undefined,
+ 'uint16',
+ 'uint32',
+ ],
+ LoadOp: [
+ undefined,
+ 'clear',
+ 'load',
+ ],
+ MipmapFilterMode: [
+ undefined,
+ 'nearest',
+ 'linear',
+ ],
+ PowerPreference: [
+ undefined,
+ 'low-power',
+ 'high-performance',
+ ],
+ PrimitiveTopology: [
+ undefined,
+ 'point-list',
+ 'line-list',
+ 'line-strip',
+ 'triangle-list',
+ 'triangle-strip',
+ ],
+ QueryType: {
+ 1: 'occlusion',
+ 2: 'timestamp',
+ },
+ SamplerBindingType: [
+ undefined,
+ 'filtering',
+ 'non-filtering',
+ 'comparison',
+ ],
+ StencilOperation: [
+ undefined,
+ 'keep',
+ 'zero',
+ 'replace',
+ 'invert',
+ 'increment-clamp',
+ 'decrement-clamp',
+ 'increment-wrap',
+ 'decrement-wrap',
+ ],
+ StorageTextureAccess: [
+ undefined,
+ 'write-only',
+ 'read-only',
+ 'read-write',
+ ],
+ StoreOp: [
+ undefined,
+ 'store',
+ 'discard',
+ ],
+ TextureAspect: [
+ undefined,
+ 'all',
+ 'stencil-only',
+ 'depth-only',
+ ],
+ TextureDimension: [
+ undefined,
+ '1d',
+ '2d',
+ '3d',
+ ],
+ TextureFormat: [
+ undefined,
+ 'r8unorm',
+ 'r8snorm',
+ 'r8uint',
+ 'r8sint',
+ 'r16uint',
+ 'r16sint',
+ 'r16float',
+ 'rg8unorm',
+ 'rg8snorm',
+ 'rg8uint',
+ 'rg8sint',
+ 'r32float',
+ 'r32uint',
+ 'r32sint',
+ 'rg16uint',
+ 'rg16sint',
+ 'rg16float',
+ 'rgba8unorm',
+ 'rgba8unorm-srgb',
+ 'rgba8snorm',
+ 'rgba8uint',
+ 'rgba8sint',
+ 'bgra8unorm',
+ 'bgra8unorm-srgb',
+ 'rgb10a2uint',
+ 'rgb10a2unorm',
+ 'rg11b10ufloat',
+ 'rgb9e5ufloat',
+ 'rg32float',
+ 'rg32uint',
+ 'rg32sint',
+ 'rgba16uint',
+ 'rgba16sint',
+ 'rgba16float',
+ 'rgba32float',
+ 'rgba32uint',
+ 'rgba32sint',
+ 'stencil8',
+ 'depth16unorm',
+ 'depth24plus',
+ 'depth24plus-stencil8',
+ 'depth32float',
+ 'depth32float-stencil8',
+ 'bc1-rgba-unorm',
+ 'bc1-rgba-unorm-srgb',
+ 'bc2-rgba-unorm',
+ 'bc2-rgba-unorm-srgb',
+ 'bc3-rgba-unorm',
+ 'bc3-rgba-unorm-srgb',
+ 'bc4-r-unorm',
+ 'bc4-r-snorm',
+ 'bc5-rg-unorm',
+ 'bc5-rg-snorm',
+ 'bc6h-rgb-ufloat',
+ 'bc6h-rgb-float',
+ 'bc7-rgba-unorm',
+ 'bc7-rgba-unorm-srgb',
+ 'etc2-rgb8unorm',
+ 'etc2-rgb8unorm-srgb',
+ 'etc2-rgb8a1unorm',
+ 'etc2-rgb8a1unorm-srgb',
+ 'etc2-rgba8unorm',
+ 'etc2-rgba8unorm-srgb',
+ 'eac-r11unorm',
+ 'eac-r11snorm',
+ 'eac-rg11unorm',
+ 'eac-rg11snorm',
+ 'astc-4x4-unorm',
+ 'astc-4x4-unorm-srgb',
+ 'astc-5x4-unorm',
+ 'astc-5x4-unorm-srgb',
+ 'astc-5x5-unorm',
+ 'astc-5x5-unorm-srgb',
+ 'astc-6x5-unorm',
+ 'astc-6x5-unorm-srgb',
+ 'astc-6x6-unorm',
+ 'astc-6x6-unorm-srgb',
+ 'astc-8x5-unorm',
+ 'astc-8x5-unorm-srgb',
+ 'astc-8x6-unorm',
+ 'astc-8x6-unorm-srgb',
+ 'astc-8x8-unorm',
+ 'astc-8x8-unorm-srgb',
+ 'astc-10x5-unorm',
+ 'astc-10x5-unorm-srgb',
+ 'astc-10x6-unorm',
+ 'astc-10x6-unorm-srgb',
+ 'astc-10x8-unorm',
+ 'astc-10x8-unorm-srgb',
+ 'astc-10x10-unorm',
+ 'astc-10x10-unorm-srgb',
+ 'astc-12x10-unorm',
+ 'astc-12x10-unorm-srgb',
+ 'astc-12x12-unorm',
+ 'astc-12x12-unorm-srgb',
+ ],
+ TextureSampleType: [
+ undefined,
+ 'float',
+ 'unfilterable-float',
+ 'depth',
+ 'sint',
+ 'uint',
+ ],
+ TextureViewDimension: [
+ undefined,
+ '1d',
+ '2d',
+ '2d-array',
+ 'cube',
+ 'cube-array',
+ '3d',
+ ],
+ VertexFormat: [
+ undefined,
+ 'uint8x2',
+ 'uint8x4',
+ 'sint8x2',
+ 'sint8x4',
+ 'unorm8x2',
+ 'unorm8x4',
+ 'snorm8x2',
+ 'snorm8x4',
+ 'uint16x2',
+ 'uint16x4',
+ 'sint16x2',
+ 'sint16x4',
+ 'unorm16x2',
+ 'unorm16x4',
+ 'snorm16x2',
+ 'snorm16x4',
+ 'float16x2',
+ 'float16x4',
+ 'float32',
+ 'float32x2',
+ 'float32x3',
+ 'float32x4',
+ 'uint32',
+ 'uint32x2',
+ 'uint32x3',
+ 'uint32x4',
+ 'sint32',
+ 'sint32x2',
+ 'sint32x3',
+ 'sint32x4',
+ 'unorm10-10-10-2',
+ ],
+ VertexStepMode: [
+ undefined,
+ 'vertex-buffer-not-used',
+ 'vertex',
+ 'instance',
+ ],
+ },
+
+ // Non-method functions
+
+ wgpuGetInstanceFeatures: (featuresPtr) => {
+ abort('TODO: wgpuGetInstanceFeatures unimplemented');
+ return 0;
+ },
+
+ wgpuGetProcAddress: (device, procName) => {
+ abort('TODO(#11526): wgpuGetProcAddress unimplemented');
+ return 0;
+ },
+
+ // *Reference/*Release
+
+ {{{ gpu.makeReferenceRelease('Surface') }}}
+ {{{ gpu.makeReferenceRelease('SwapChain') }}}
+
+ {{{ gpu.makeReferenceRelease('Adapter') }}}
+ {{{ gpu.makeReferenceRelease('Device') }}}
+ {{{ gpu.makeReferenceRelease('Queue') }}}
+
+ {{{ gpu.makeReferenceRelease('CommandBuffer') }}}
+ {{{ gpu.makeReferenceRelease('CommandEncoder') }}}
+ {{{ gpu.makeReferenceRelease('RenderPassEncoder') }}}
+ {{{ gpu.makeReferenceRelease('ComputePassEncoder') }}}
+
+ {{{ gpu.makeReferenceRelease('BindGroup') }}}
+ {{{ gpu.makeReferenceRelease('Buffer') }}}
+ {{{ gpu.makeReferenceRelease('Sampler') }}}
+ {{{ gpu.makeReferenceRelease('Texture') }}}
+ {{{ gpu.makeReferenceRelease('TextureView') }}}
+ {{{ gpu.makeReferenceRelease('QuerySet') }}}
+
+ {{{ gpu.makeReferenceRelease('BindGroupLayout') }}}
+ {{{ gpu.makeReferenceRelease('PipelineLayout') }}}
+ {{{ gpu.makeReferenceRelease('RenderPipeline') }}}
+ {{{ gpu.makeReferenceRelease('ComputePipeline') }}}
+ {{{ gpu.makeReferenceRelease('ShaderModule') }}}
+
+ {{{ gpu.makeReferenceRelease('RenderBundleEncoder') }}}
+ {{{ gpu.makeReferenceRelease('RenderBundle') }}}
+
+ // *Destroy
+
+ wgpuBufferDestroy: (bufferId) => {
+ var bufferWrapper = WebGPU.mgrBuffer.objects[bufferId];
+ {{{ gpu.makeCheckDefined('bufferWrapper') }}}
+ if (bufferWrapper.onUnmap) {
+ for (var i = 0; i < bufferWrapper.onUnmap.length; ++i) {
+ bufferWrapper.onUnmap[i]();
+ }
+ bufferWrapper.onUnmap = undefined;
+ }
+
+ WebGPU.mgrBuffer.get(bufferId).destroy();
+ },
+ wgpuTextureDestroy: (textureId) => WebGPU.mgrTexture.get(textureId).destroy(),
+ wgpuQuerySetDestroy: (querySetId) => WebGPU.mgrQuerySet.get(querySetId).destroy(),
+
+ // wgpuDevice
+
+ wgpuDeviceEnumerateFeatures: (deviceId, featuresOutPtr) => {
+ var device = WebGPU.mgrDevice.get(deviceId);
+ if (featuresOutPtr !== 0) {
+ var offset = 0;
+ device.features.forEach(feature => {
+ var featureEnumValue = WebGPU.FeatureNameString2Enum[feature];
+ {{{ makeSetValue('featuresOutPtr', 'offset', 'featureEnumValue', 'i32') }}};
+ offset += 4;
+ });
+ }
+ return device.features.size;
+ },
+
+ wgpuDeviceDestroy: (deviceId) => WebGPU.mgrDevice.get(deviceId).destroy(),
+
+ wgpuDeviceGetLimits: (deviceId, limitsOutPtr) => {
+ var device = WebGPU.mgrDevice.objects[deviceId].object;
+ WebGPU.fillLimitStruct(device.limits, limitsOutPtr);
+ return 1;
+ },
+
+ wgpuDeviceGetQueue: (deviceId) => {
+ var queueId = WebGPU.mgrDevice.objects[deviceId].queueId;
+#if ASSERTIONS
+ assert(queueId, 'wgpuDeviceGetQueue: queue was missing or null');
+#endif
+ // Returns a new reference to the existing queue.
+ WebGPU.mgrQueue.reference(queueId);
+ return queueId;
+ },
+
+ wgpuDeviceHasFeature: (deviceId, featureEnumValue) => {
+ var device = WebGPU.mgrDevice.get(deviceId);
+ return device.features.has(WebGPU.FeatureName[featureEnumValue]);
+ },
+
+ wgpuDevicePushErrorScope: (deviceId, filter) => {
+ var device = WebGPU.mgrDevice.get(deviceId);
+ device.pushErrorScope(WebGPU.ErrorFilter[filter]);
+ },
+
+ wgpuDevicePopErrorScope__deps: ['$callUserCallback'],
+ wgpuDevicePopErrorScope: (deviceId, callback, userdata) => {
+ var device = WebGPU.mgrDevice.get(deviceId);
+ {{{ runtimeKeepalivePush() }}}
+ device.popErrorScope().then((gpuError) => {
+ {{{ runtimeKeepalivePop() }}}
+ callUserCallback(() => {
+ if (!gpuError) {
+ {{{ makeDynCall('vipp', 'callback') }}}(
+ {{{ gpu.ErrorType.NoError }}}, 0, userdata);
+ } else if (gpuError instanceof GPUOutOfMemoryError) {
+ {{{ makeDynCall('vipp', 'callback') }}}(
+ {{{ gpu.ErrorType.OutOfMemory }}}, 0, userdata);
+ } else {
+#if ASSERTIONS
+ // TODO: Implement GPUInternalError
+ assert(gpuError instanceof GPUValidationError);
+#endif
+ WebGPU.errorCallback(callback, {{{ gpu.ErrorType.Validation }}}, gpuError.message, userdata);
+ }
+ });
+ }, (ex) => {
+ {{{ runtimeKeepalivePop() }}}
+ callUserCallback(() => {
+ // TODO: This can mean either the device was lost or the error scope stack was empty. Figure
+ // out how to synthesize the DeviceLost error type. (Could be by simply tracking the error
+ // scope depth, but that isn't ideal.)
+ WebGPU.errorCallback(callback, {{{ gpu.ErrorType.Unknown }}}, ex.message, userdata);
+ });
+ });
+ },
+
+ wgpuDeviceSetLabel: (deviceId, labelPtr) => {
+ var device = WebGPU.mgrDevice.get(deviceId);
+ device.label = UTF8ToString(labelPtr);
+ },
+
+ wgpuDeviceSetUncapturedErrorCallback__deps: ['$callUserCallback'],
+ wgpuDeviceSetUncapturedErrorCallback: (deviceId, callback, userdata) => {
+ var device = WebGPU.mgrDevice.get(deviceId);
+ device.onuncapturederror = function(ev) {
+ // This will skip the callback if the runtime is no longer alive.
+ callUserCallback(() => {
+ // WGPUErrorType type, const char* message, void* userdata
+ var Validation = 0x00000001;
+ var OutOfMemory = 0x00000002;
+ var type;
+#if ASSERTIONS
+ assert(typeof GPUValidationError != 'undefined');
+ assert(typeof GPUOutOfMemoryError != 'undefined');
+#endif
+ if (ev.error instanceof GPUValidationError) type = Validation;
+ else if (ev.error instanceof GPUOutOfMemoryError) type = OutOfMemory;
+ // TODO: Implement GPUInternalError
+
+ WebGPU.errorCallback(callback, type, ev.error.message, userdata);
+ });
+ };
+ },
+
+ // wgpuDeviceCreate*
+
+ wgpuDeviceCreateCommandEncoder: (deviceId, descriptor) => {
+ var desc;
+ if (descriptor) {
+ {{{ gpu.makeCheckDescriptor('descriptor') }}}
+ desc = {
+ "label": undefined,
+ };
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUCommandEncoderDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+ }
+ var device = WebGPU.mgrDevice.get(deviceId);
+ return WebGPU.mgrCommandEncoder.create(device.createCommandEncoder(desc));
+ },
+
+ wgpuDeviceCreateBuffer: (deviceId, descriptor) => {
+ {{{ gpu.makeCheckDescriptor('descriptor') }}}
+
+ var mappedAtCreation = {{{ gpu.makeGetBool('descriptor', C_STRUCTS.WGPUBufferDescriptor.mappedAtCreation) }}};
+
+ var desc = {
+ "label": undefined,
+ "usage": {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUBufferDescriptor.usage) }}},
+ "size": {{{ gpu.makeGetU64('descriptor', C_STRUCTS.WGPUBufferDescriptor.size) }}},
+ "mappedAtCreation": mappedAtCreation,
+ };
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUBufferDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+
+ var device = WebGPU.mgrDevice.get(deviceId);
+ var bufferWrapper = {};
+ var id = WebGPU.mgrBuffer.create(device.createBuffer(desc), bufferWrapper);
+ if (mappedAtCreation) {
+ bufferWrapper.mapMode = {{{ gpu.MapMode.Write }}};
+ bufferWrapper.onUnmap = [];
+ }
+ return id;
+ },
+
+ wgpuDeviceCreateTexture: (deviceId, descriptor) => {
+ {{{ gpu.makeCheckDescriptor('descriptor') }}}
+
+ var desc = {
+ "label": undefined,
+ "size": WebGPU.makeExtent3D(descriptor + {{{ C_STRUCTS.WGPUTextureDescriptor.size }}}),
+ "mipLevelCount": {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUTextureDescriptor.mipLevelCount) }}},
+ "sampleCount": {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUTextureDescriptor.sampleCount) }}},
+ "dimension": WebGPU.TextureDimension[
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUTextureDescriptor.dimension) }}}],
+ "format": WebGPU.TextureFormat[
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUTextureDescriptor.format) }}}],
+ "usage": {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUTextureDescriptor.usage) }}},
+ };
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUTextureDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+
+ var viewFormatCount = {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUTextureDescriptor.viewFormatCount) }}};
+ if (viewFormatCount) {
+ var viewFormatsPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUTextureDescriptor.viewFormats, '*') }}};
+ // viewFormatsPtr pointer to an array of TextureFormat which is an enum of size uint32_t
+ desc["viewFormats"] = Array.from({{{ makeHEAPView('32', 'viewFormatsPtr', `viewFormatsPtr + viewFormatCount * 4`) }}},
+ function(format) { return WebGPU.TextureFormat[format]; });
+ }
+
+ var device = WebGPU.mgrDevice.get(deviceId);
+ return WebGPU.mgrTexture.create(device.createTexture(desc));
+ },
+
+ wgpuDeviceCreateSampler: (deviceId, descriptor) => {
+ var desc;
+ if (descriptor) {
+ {{{ gpu.makeCheckDescriptor('descriptor') }}}
+
+ desc = {
+ "label": undefined,
+ "addressModeU": WebGPU.AddressMode[
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSamplerDescriptor.addressModeU) }}}],
+ "addressModeV": WebGPU.AddressMode[
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSamplerDescriptor.addressModeV) }}}],
+ "addressModeW": WebGPU.AddressMode[
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSamplerDescriptor.addressModeW) }}}],
+ "magFilter": WebGPU.FilterMode[
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSamplerDescriptor.magFilter) }}}],
+ "minFilter": WebGPU.FilterMode[
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSamplerDescriptor.minFilter) }}}],
+ "mipmapFilter": WebGPU.MipmapFilterMode[
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSamplerDescriptor.mipmapFilter) }}}],
+ "lodMinClamp": {{{ makeGetValue('descriptor', C_STRUCTS.WGPUSamplerDescriptor.lodMinClamp, 'float') }}},
+ "lodMaxClamp": {{{ makeGetValue('descriptor', C_STRUCTS.WGPUSamplerDescriptor.lodMaxClamp, 'float') }}},
+ "compare": WebGPU.CompareFunction[
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSamplerDescriptor.compare) }}}],
+ };
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUSamplerDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+ }
+
+ var device = WebGPU.mgrDevice.get(deviceId);
+ return WebGPU.mgrSampler.create(device.createSampler(desc));
+ },
+
+ wgpuDeviceCreateBindGroupLayout: (deviceId, descriptor) => {
+ {{{ gpu.makeCheckDescriptor('descriptor') }}}
+
+ function makeBufferEntry(entryPtr) {
+ {{{ gpu.makeCheck('entryPtr') }}}
+
+ var typeInt =
+ {{{ gpu.makeGetU32('entryPtr', C_STRUCTS.WGPUBufferBindingLayout.type) }}};
+ if (!typeInt) return undefined;
+
+ return {
+ "type": WebGPU.BufferBindingType[typeInt],
+ "hasDynamicOffset":
+ {{{ gpu.makeGetBool('entryPtr', C_STRUCTS.WGPUBufferBindingLayout.hasDynamicOffset) }}},
+ "minBindingSize":
+ {{{ gpu.makeGetU64('entryPtr', C_STRUCTS.WGPUBufferBindingLayout.minBindingSize) }}},
+ };
+ }
+
+ function makeSamplerEntry(entryPtr) {
+ {{{ gpu.makeCheck('entryPtr') }}}
+
+ var typeInt =
+ {{{ gpu.makeGetU32('entryPtr', C_STRUCTS.WGPUSamplerBindingLayout.type) }}};
+ if (!typeInt) return undefined;
+
+ return {
+ "type": WebGPU.SamplerBindingType[typeInt],
+ };
+ }
+
+ function makeTextureEntry(entryPtr) {
+ {{{ gpu.makeCheck('entryPtr') }}}
+
+ var sampleTypeInt =
+ {{{ gpu.makeGetU32('entryPtr', C_STRUCTS.WGPUTextureBindingLayout.sampleType) }}};
+ if (!sampleTypeInt) return undefined;
+
+ return {
+ "sampleType": WebGPU.TextureSampleType[sampleTypeInt],
+ "viewDimension": WebGPU.TextureViewDimension[
+ {{{ gpu.makeGetU32('entryPtr', C_STRUCTS.WGPUTextureBindingLayout.viewDimension) }}}],
+ "multisampled":
+ {{{ gpu.makeGetBool('entryPtr', C_STRUCTS.WGPUTextureBindingLayout.multisampled) }}},
+ };
+ }
+
+ function makeStorageTextureEntry(entryPtr) {
+ {{{ gpu.makeCheck('entryPtr') }}}
+
+ var accessInt =
+ {{{ gpu.makeGetU32('entryPtr', C_STRUCTS.WGPUStorageTextureBindingLayout.access) }}}
+ if (!accessInt) return undefined;
+
+ return {
+ "access": WebGPU.StorageTextureAccess[accessInt],
+ "format": WebGPU.TextureFormat[
+ {{{ gpu.makeGetU32('entryPtr', C_STRUCTS.WGPUStorageTextureBindingLayout.format) }}}],
+ "viewDimension": WebGPU.TextureViewDimension[
+ {{{ gpu.makeGetU32('entryPtr', C_STRUCTS.WGPUStorageTextureBindingLayout.viewDimension) }}}],
+ };
+ }
+
+ function makeEntry(entryPtr) {
+ {{{ gpu.makeCheck('entryPtr') }}}
+
+ return {
+ "binding":
+ {{{ gpu.makeGetU32('entryPtr', C_STRUCTS.WGPUBindGroupLayoutEntry.binding) }}},
+ "visibility":
+ {{{ gpu.makeGetU32('entryPtr', C_STRUCTS.WGPUBindGroupLayoutEntry.visibility) }}},
+ "buffer": makeBufferEntry(entryPtr + {{{ C_STRUCTS.WGPUBindGroupLayoutEntry.buffer }}}),
+ "sampler": makeSamplerEntry(entryPtr + {{{ C_STRUCTS.WGPUBindGroupLayoutEntry.sampler }}}),
+ "texture": makeTextureEntry(entryPtr + {{{ C_STRUCTS.WGPUBindGroupLayoutEntry.texture }}}),
+ "storageTexture": makeStorageTextureEntry(entryPtr + {{{ C_STRUCTS.WGPUBindGroupLayoutEntry.storageTexture }}}),
+ };
+ }
+
+ function makeEntries(count, entriesPtrs) {
+ var entries = [];
+ for (var i = 0; i < count; ++i) {
+ entries.push(makeEntry(entriesPtrs +
+ {{{ C_STRUCTS.WGPUBindGroupLayoutEntry.__size__ }}} * i));
+ }
+ return entries;
+ }
+
+ var desc = {
+ "entries": makeEntries(
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUBindGroupLayoutDescriptor.entryCount) }}},
+ {{{ makeGetValue('descriptor', C_STRUCTS.WGPUBindGroupLayoutDescriptor.entries, '*') }}}
+ ),
+ };
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUBindGroupLayoutDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+
+ var device = WebGPU.mgrDevice.get(deviceId);
+ return WebGPU.mgrBindGroupLayout.create(device.createBindGroupLayout(desc));
+ },
+
+ wgpuDeviceCreateBindGroup__deps: ['$readI53FromI64'],
+ wgpuDeviceCreateBindGroup: (deviceId, descriptor) => {
+ {{{ gpu.makeCheckDescriptor('descriptor') }}}
+
+ function makeEntry(entryPtr) {
+ {{{ gpu.makeCheck('entryPtr') }}}
+
+ var bufferId = {{{ gpu.makeGetU32('entryPtr', C_STRUCTS.WGPUBindGroupEntry.buffer) }}};
+ var samplerId = {{{ gpu.makeGetU32('entryPtr', C_STRUCTS.WGPUBindGroupEntry.sampler) }}};
+ var textureViewId = {{{ gpu.makeGetU32('entryPtr', C_STRUCTS.WGPUBindGroupEntry.textureView) }}};
+#if ASSERTIONS
+ assert((bufferId !== 0) + (samplerId !== 0) + (textureViewId !== 0) === 1);
+#endif
+
+ var binding = {{{ gpu.makeGetU32('entryPtr', C_STRUCTS.WGPUBindGroupEntry.binding) }}};
+
+ if (bufferId) {
+ var size = {{{ makeGetValue('entryPtr', C_STRUCTS.WGPUBindGroupEntry.size, 'i53') }}};
+ {{{ gpu.convertSentinelToUndefined('size') }}}
+
+ return {
+ "binding": binding,
+ "resource": {
+ "buffer": WebGPU.mgrBuffer.get(bufferId),
+ "offset": {{{ gpu.makeGetU64('entryPtr', C_STRUCTS.WGPUBindGroupEntry.offset) }}},
+ "size": size
+ },
+ };
+ } else if (samplerId) {
+ return {
+ "binding": binding,
+ "resource": WebGPU.mgrSampler.get(samplerId),
+ };
+ } else {
+ return {
+ "binding": binding,
+ "resource": WebGPU.mgrTextureView.get(textureViewId),
+ };
+ }
+ }
+
+ function makeEntries(count, entriesPtrs) {
+ var entries = [];
+ for (var i = 0; i < count; ++i) {
+ entries.push(makeEntry(entriesPtrs +
+ {{{C_STRUCTS.WGPUBindGroupEntry.__size__}}} * i));
+ }
+ return entries;
+ }
+
+ var desc = {
+ "label": undefined,
+ "layout": WebGPU.mgrBindGroupLayout.get(
+ {{{ makeGetValue('descriptor', C_STRUCTS.WGPUBindGroupDescriptor.layout, '*') }}}),
+ "entries": makeEntries(
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUBindGroupDescriptor.entryCount) }}},
+ {{{ makeGetValue('descriptor', C_STRUCTS.WGPUBindGroupDescriptor.entries, '*') }}}
+ ),
+ };
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUBindGroupDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+
+ var device = WebGPU.mgrDevice.get(deviceId);
+ return WebGPU.mgrBindGroup.create(device.createBindGroup(desc));
+ },
+
+ wgpuDeviceCreatePipelineLayout: (deviceId, descriptor) => {
+ {{{ gpu.makeCheckDescriptor('descriptor') }}}
+ var bglCount = {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUPipelineLayoutDescriptor.bindGroupLayoutCount) }}};
+ var bglPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUPipelineLayoutDescriptor.bindGroupLayouts, '*') }}};
+ var bgls = [];
+ for (var i = 0; i < bglCount; ++i) {
+ bgls.push(WebGPU.mgrBindGroupLayout.get(
+ {{{ makeGetValue('bglPtr', `${POINTER_SIZE} * i`, '*') }}}));
+ }
+ var desc = {
+ "label": undefined,
+ "bindGroupLayouts": bgls,
+ };
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUPipelineLayoutDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+
+ var device = WebGPU.mgrDevice.get(deviceId);
+ return WebGPU.mgrPipelineLayout.create(device.createPipelineLayout(desc));
+ },
+
+ wgpuDeviceCreateQuerySet: (deviceId, descriptor) => {
+ {{{ gpu.makeCheckDescriptor('descriptor') }}}
+
+ var desc = {
+ "type": WebGPU.QueryType[
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUQuerySetDescriptor.type) }}}],
+ "count": {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUQuerySetDescriptor.count) }}},
+ };
+
+ var device = WebGPU.mgrDevice.get(deviceId);
+ return WebGPU.mgrQuerySet.create(device.createQuerySet(desc));
+ },
+
+ wgpuDeviceCreateRenderBundleEncoder: (deviceId, descriptor) => {
+ {{{ gpu.makeCheck('descriptor') }}}
+
+ function makeRenderBundleEncoderDescriptor(descriptor) {
+ {{{ gpu.makeCheck('descriptor') }}}
+
+ function makeColorFormats(count, formatsPtr) {
+ var formats = [];
+ for (var i = 0; i < count; ++i, formatsPtr += 4) {
+ // format could be undefined
+ formats.push(WebGPU.TextureFormat[{{{ gpu.makeGetU32('formatsPtr', 0) }}}]);
+ }
+ return formats;
+ }
+
+ var desc = {
+ "label": undefined,
+ "colorFormats": makeColorFormats(
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPURenderBundleEncoderDescriptor.colorFormatCount) }}},
+ {{{ makeGetValue('descriptor', C_STRUCTS.WGPURenderBundleEncoderDescriptor.colorFormats, '*') }}}),
+ "depthStencilFormat": WebGPU.TextureFormat[{{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPURenderBundleEncoderDescriptor.depthStencilFormat) }}}],
+ "sampleCount": {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPURenderBundleEncoderDescriptor.sampleCount) }}},
+ "depthReadOnly": {{{ gpu.makeGetBool('descriptor', C_STRUCTS.WGPURenderBundleEncoderDescriptor.depthReadOnly) }}},
+ "stencilReadOnly": {{{ gpu.makeGetBool('descriptor', C_STRUCTS.WGPURenderBundleEncoderDescriptor.stencilReadOnly) }}},
+ };
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPURenderBundleEncoderDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+ return desc;
+ }
+
+ var desc = makeRenderBundleEncoderDescriptor(descriptor);
+ var device = WebGPU.mgrDevice.get(deviceId);
+ return WebGPU.mgrRenderBundleEncoder.create(device.createRenderBundleEncoder(desc));
+ },
+
+ $generateComputePipelineDesc__internal: true,
+ $generateComputePipelineDesc: (descriptor) => {
+ {{{ gpu.makeCheckDescriptor('descriptor') }}}
+
+ var desc = {
+ "label": undefined,
+ "layout": WebGPU.makePipelineLayout(
+ {{{ makeGetValue('descriptor', C_STRUCTS.WGPUComputePipelineDescriptor.layout, '*') }}}),
+ "compute": WebGPU.makeProgrammableStageDescriptor(
+ descriptor + {{{ C_STRUCTS.WGPUComputePipelineDescriptor.compute }}}),
+ };
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUComputePipelineDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+ return desc;
+ },
+
+ wgpuDeviceCreateComputePipeline__deps: ['$generateComputePipelineDesc'],
+ wgpuDeviceCreateComputePipeline: (deviceId, descriptor) => {
+ var desc = generateComputePipelineDesc(descriptor);
+ var device = WebGPU.mgrDevice.get(deviceId);
+ return WebGPU.mgrComputePipeline.create(device.createComputePipeline(desc));
+ },
+
+ wgpuDeviceCreateComputePipelineAsync__deps: ['$callUserCallback', '$stringToUTF8OnStack', '$generateComputePipelineDesc'],
+ wgpuDeviceCreateComputePipelineAsync: (deviceId, descriptor, callback, userdata) => {
+ var desc = generateComputePipelineDesc(descriptor);
+ var device = WebGPU.mgrDevice.get(deviceId);
+ {{{ runtimeKeepalivePush() }}}
+ device.createComputePipelineAsync(desc).then((pipeline) => {
+ {{{ runtimeKeepalivePop() }}}
+ callUserCallback(() => {
+ var pipelineId = WebGPU.mgrComputePipeline.create(pipeline);
+ {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.Success }}}, pipelineId, 0, userdata);
+ });
+ }, (pipelineError) => {
+ {{{ runtimeKeepalivePop() }}}
+ callUserCallback(() => {
+ var sp = stackSave();
+ var messagePtr = stringToUTF8OnStack(pipelineError.message);
+ if (pipelineError.reason === 'validation') {
+ {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.ValidationError }}}, 0, messagePtr, userdata);
+ } else if (pipelineError.reason === 'internal') {
+ {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.InternalError }}}, 0, messagePtr, userdata);
+ } else {
+ {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.Unknown }}}, 0, messagePtr, userdata);
+ }
+ stackRestore(sp);
+ });
+ });
+ },
+
+ $generateRenderPipelineDesc__internal: true,
+ $generateRenderPipelineDesc: (descriptor) => {
+ {{{ gpu.makeCheckDescriptor('descriptor') }}}
+ function makePrimitiveState(rsPtr) {
+ if (!rsPtr) return undefined;
+ {{{ gpu.makeCheck('rsPtr') }}}
+
+ // TODO: This small hack assumes that there's only one type that can be in the chain of
+ // WGPUPrimitiveState. The correct thing would be to traverse the chain, but unclippedDepth
+ // is going to move into the core object soon, so we'll just do this for now. See:
+ // https://github.com/webgpu-native/webgpu-headers/issues/212#issuecomment-1682801259
+ var nextInChainPtr = {{{ makeGetValue('rsPtr', C_STRUCTS.WGPUPrimitiveState.nextInChain, '*') }}};
+ var sType = nextInChainPtr ? {{{ gpu.makeGetU32('nextInChainPtr', C_STRUCTS.WGPUChainedStruct.sType) }}} : 0;
+
+ return {
+ "topology": WebGPU.PrimitiveTopology[
+ {{{ gpu.makeGetU32('rsPtr', C_STRUCTS.WGPUPrimitiveState.topology) }}}],
+ "stripIndexFormat": WebGPU.IndexFormat[
+ {{{ gpu.makeGetU32('rsPtr', C_STRUCTS.WGPUPrimitiveState.stripIndexFormat) }}}],
+ "frontFace": WebGPU.FrontFace[
+ {{{ gpu.makeGetU32('rsPtr', C_STRUCTS.WGPUPrimitiveState.frontFace) }}}],
+ "cullMode": WebGPU.CullMode[
+ {{{ gpu.makeGetU32('rsPtr', C_STRUCTS.WGPUPrimitiveState.cullMode) }}}],
+ "unclippedDepth": sType === {{{ gpu.SType.PrimitiveDepthClipControl }}} && {{{ gpu.makeGetBool('nextInChainPtr', C_STRUCTS.WGPUPrimitiveDepthClipControl.unclippedDepth) }}},
+ };
+ }
+
+ function makeBlendComponent(bdPtr) {
+ if (!bdPtr) return undefined;
+ return {
+ "operation": WebGPU.BlendOperation[
+ {{{ gpu.makeGetU32('bdPtr', C_STRUCTS.WGPUBlendComponent.operation) }}}],
+ "srcFactor": WebGPU.BlendFactor[
+ {{{ gpu.makeGetU32('bdPtr', C_STRUCTS.WGPUBlendComponent.srcFactor) }}}],
+ "dstFactor": WebGPU.BlendFactor[
+ {{{ gpu.makeGetU32('bdPtr', C_STRUCTS.WGPUBlendComponent.dstFactor) }}}],
+ };
+ }
+
+ function makeBlendState(bsPtr) {
+ if (!bsPtr) return undefined;
+ return {
+ "alpha": makeBlendComponent(bsPtr + {{{ C_STRUCTS.WGPUBlendState.alpha }}}),
+ "color": makeBlendComponent(bsPtr + {{{ C_STRUCTS.WGPUBlendState.color }}}),
+ };
+ }
+
+ function makeColorState(csPtr) {
+ {{{ gpu.makeCheckDescriptor('csPtr') }}}
+ var formatInt = {{{ gpu.makeGetU32('csPtr', C_STRUCTS.WGPUColorTargetState.format) }}};
+ return formatInt === {{{ gpu.TextureFormat.Undefined }}} ? undefined : {
+ "format": WebGPU.TextureFormat[formatInt],
+ "blend": makeBlendState({{{ makeGetValue('csPtr', C_STRUCTS.WGPUColorTargetState.blend, '*') }}}),
+ "writeMask": {{{ gpu.makeGetU32('csPtr', C_STRUCTS.WGPUColorTargetState.writeMask) }}},
+ };
+ }
+
+ function makeColorStates(count, csArrayPtr) {
+ var states = [];
+ for (var i = 0; i < count; ++i) {
+ states.push(makeColorState(csArrayPtr + {{{ C_STRUCTS.WGPUColorTargetState.__size__ }}} * i));
+ }
+ return states;
+ }
+
+ function makeStencilStateFace(ssfPtr) {
+ {{{ gpu.makeCheck('ssfPtr') }}}
+ return {
+ "compare": WebGPU.CompareFunction[
+ {{{ gpu.makeGetU32('ssfPtr', C_STRUCTS.WGPUStencilFaceState.compare) }}}],
+ "failOp": WebGPU.StencilOperation[
+ {{{ gpu.makeGetU32('ssfPtr', C_STRUCTS.WGPUStencilFaceState.failOp) }}}],
+ "depthFailOp": WebGPU.StencilOperation[
+ {{{ gpu.makeGetU32('ssfPtr', C_STRUCTS.WGPUStencilFaceState.depthFailOp) }}}],
+ "passOp": WebGPU.StencilOperation[
+ {{{ gpu.makeGetU32('ssfPtr', C_STRUCTS.WGPUStencilFaceState.passOp) }}}],
+ };
+ }
+
+ function makeDepthStencilState(dssPtr) {
+ if (!dssPtr) return undefined;
+
+ {{{ gpu.makeCheck('dssPtr') }}}
+ return {
+ "format": WebGPU.TextureFormat[
+ {{{ gpu.makeGetU32('dssPtr', C_STRUCTS.WGPUDepthStencilState.format) }}}],
+ "depthWriteEnabled": {{{ gpu.makeGetBool('dssPtr', C_STRUCTS.WGPUDepthStencilState.depthWriteEnabled) }}},
+ "depthCompare": WebGPU.CompareFunction[
+ {{{ gpu.makeGetU32('dssPtr', C_STRUCTS.WGPUDepthStencilState.depthCompare) }}}],
+ "stencilFront": makeStencilStateFace(dssPtr + {{{ C_STRUCTS.WGPUDepthStencilState.stencilFront }}}),
+ "stencilBack": makeStencilStateFace(dssPtr + {{{ C_STRUCTS.WGPUDepthStencilState.stencilBack }}}),
+ "stencilReadMask": {{{ gpu.makeGetU32('dssPtr', C_STRUCTS.WGPUDepthStencilState.stencilReadMask) }}},
+ "stencilWriteMask": {{{ gpu.makeGetU32('dssPtr', C_STRUCTS.WGPUDepthStencilState.stencilWriteMask) }}},
+ "depthBias": {{{ makeGetValue('dssPtr', C_STRUCTS.WGPUDepthStencilState.depthBias, 'i32') }}},
+ "depthBiasSlopeScale": {{{ makeGetValue('dssPtr', C_STRUCTS.WGPUDepthStencilState.depthBiasSlopeScale, 'float') }}},
+ "depthBiasClamp": {{{ makeGetValue('dssPtr', C_STRUCTS.WGPUDepthStencilState.depthBiasClamp, 'float') }}},
+ };
+ }
+
+ function makeVertexAttribute(vaPtr) {
+ {{{ gpu.makeCheck('vaPtr') }}}
+ return {
+ "format": WebGPU.VertexFormat[
+ {{{ gpu.makeGetU32('vaPtr', C_STRUCTS.WGPUVertexAttribute.format) }}}],
+ "offset": {{{ gpu.makeGetU64('vaPtr', C_STRUCTS.WGPUVertexAttribute.offset) }}},
+ "shaderLocation": {{{ gpu.makeGetU32('vaPtr', C_STRUCTS.WGPUVertexAttribute.shaderLocation) }}},
+ };
+ }
+
+ function makeVertexAttributes(count, vaArrayPtr) {
+ var vas = [];
+ for (var i = 0; i < count; ++i) {
+ vas.push(makeVertexAttribute(vaArrayPtr + i * {{{ C_STRUCTS.WGPUVertexAttribute.__size__ }}}));
+ }
+ return vas;
+ }
+
+ function makeVertexBuffer(vbPtr) {
+ if (!vbPtr) return undefined;
+ var stepModeInt = {{{ gpu.makeGetU32('vbPtr', C_STRUCTS.WGPUVertexBufferLayout.stepMode) }}};
+ return stepModeInt === {{{ gpu.VertexStepMode.VertexBufferNotUsed }}} ? null : {
+ "arrayStride": {{{ gpu.makeGetU64('vbPtr', C_STRUCTS.WGPUVertexBufferLayout.arrayStride) }}},
+ "stepMode": WebGPU.VertexStepMode[stepModeInt],
+ "attributes": makeVertexAttributes(
+ {{{ gpu.makeGetU32('vbPtr', C_STRUCTS.WGPUVertexBufferLayout.attributeCount) }}},
+ {{{ makeGetValue('vbPtr', C_STRUCTS.WGPUVertexBufferLayout.attributes, '*') }}}),
+ };
+ }
+
+ function makeVertexBuffers(count, vbArrayPtr) {
+ if (!count) return undefined;
+
+ var vbs = [];
+ for (var i = 0; i < count; ++i) {
+ vbs.push(makeVertexBuffer(vbArrayPtr + i * {{{ C_STRUCTS.WGPUVertexBufferLayout.__size__ }}}));
+ }
+ return vbs;
+ }
+
+ function makeVertexState(viPtr) {
+ if (!viPtr) return undefined;
+ {{{ gpu.makeCheckDescriptor('viPtr') }}}
+ var desc = {
+ "module": WebGPU.mgrShaderModule.get(
+ {{{ makeGetValue('viPtr', C_STRUCTS.WGPUVertexState.module, '*') }}}),
+ "constants": WebGPU.makePipelineConstants(
+ {{{ gpu.makeGetU32('viPtr', C_STRUCTS.WGPUVertexState.constantCount) }}},
+ {{{ makeGetValue('viPtr', C_STRUCTS.WGPUVertexState.constants, '*') }}}),
+ "buffers": makeVertexBuffers(
+ {{{ gpu.makeGetU32('viPtr', C_STRUCTS.WGPUVertexState.bufferCount) }}},
+ {{{ makeGetValue('viPtr', C_STRUCTS.WGPUVertexState.buffers, '*') }}}),
+ };
+ var entryPointPtr = {{{ makeGetValue('viPtr', C_STRUCTS.WGPUVertexState.entryPoint, '*') }}};
+ if (entryPointPtr) desc["entryPoint"] = UTF8ToString(entryPointPtr);
+ return desc;
+ }
+
+ function makeMultisampleState(msPtr) {
+ if (!msPtr) return undefined;
+ {{{ gpu.makeCheckDescriptor('msPtr') }}}
+ return {
+ "count": {{{ gpu.makeGetU32('msPtr', C_STRUCTS.WGPUMultisampleState.count) }}},
+ "mask": {{{ gpu.makeGetU32('msPtr', C_STRUCTS.WGPUMultisampleState.mask) }}},
+ "alphaToCoverageEnabled": {{{ gpu.makeGetBool('msPtr', C_STRUCTS.WGPUMultisampleState.alphaToCoverageEnabled) }}},
+ };
+ }
+
+ function makeFragmentState(fsPtr) {
+ if (!fsPtr) return undefined;
+ {{{ gpu.makeCheckDescriptor('fsPtr') }}}
+ var desc = {
+ "module": WebGPU.mgrShaderModule.get(
+ {{{ makeGetValue('fsPtr', C_STRUCTS.WGPUFragmentState.module, '*') }}}),
+ "constants": WebGPU.makePipelineConstants(
+ {{{ gpu.makeGetU32('fsPtr', C_STRUCTS.WGPUFragmentState.constantCount) }}},
+ {{{ makeGetValue('fsPtr', C_STRUCTS.WGPUFragmentState.constants, '*') }}}),
+ "targets": makeColorStates(
+ {{{ gpu.makeGetU32('fsPtr', C_STRUCTS.WGPUFragmentState.targetCount) }}},
+ {{{ makeGetValue('fsPtr', C_STRUCTS.WGPUFragmentState.targets, '*') }}}),
+ };
+ var entryPointPtr = {{{ makeGetValue('fsPtr', C_STRUCTS.WGPUFragmentState.entryPoint, '*') }}};
+ if (entryPointPtr) desc["entryPoint"] = UTF8ToString(entryPointPtr);
+ return desc;
+ }
+
+ var desc = {
+ "label": undefined,
+ "layout": WebGPU.makePipelineLayout(
+ {{{ makeGetValue('descriptor', C_STRUCTS.WGPURenderPipelineDescriptor.layout, '*') }}}),
+ "vertex": makeVertexState(
+ descriptor + {{{ C_STRUCTS.WGPURenderPipelineDescriptor.vertex }}}),
+ "primitive": makePrimitiveState(
+ descriptor + {{{ C_STRUCTS.WGPURenderPipelineDescriptor.primitive }}}),
+ "depthStencil": makeDepthStencilState(
+ {{{ makeGetValue('descriptor', C_STRUCTS.WGPURenderPipelineDescriptor.depthStencil, '*') }}}),
+ "multisample": makeMultisampleState(
+ descriptor + {{{ C_STRUCTS.WGPURenderPipelineDescriptor.multisample }}}),
+ "fragment": makeFragmentState(
+ {{{ makeGetValue('descriptor', C_STRUCTS.WGPURenderPipelineDescriptor.fragment, '*') }}}),
+ };
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPURenderPipelineDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+ return desc;
+ },
+
+ wgpuDeviceCreateRenderPipeline__deps: ['$generateRenderPipelineDesc'],
+ wgpuDeviceCreateRenderPipeline: (deviceId, descriptor) => {
+ var desc = generateRenderPipelineDesc(descriptor);
+ var device = WebGPU.mgrDevice.get(deviceId);
+ return WebGPU.mgrRenderPipeline.create(device.createRenderPipeline(desc));
+ },
+
+ wgpuDeviceCreateRenderPipelineAsync__deps: ['$callUserCallback', '$stringToUTF8OnStack', '$generateRenderPipelineDesc'],
+ wgpuDeviceCreateRenderPipelineAsync: (deviceId, descriptor, callback, userdata) => {
+ var desc = generateRenderPipelineDesc(descriptor);
+ var device = WebGPU.mgrDevice.get(deviceId);
+ {{{ runtimeKeepalivePush() }}}
+ device.createRenderPipelineAsync(desc).then((pipeline) => {
+ {{{ runtimeKeepalivePop() }}}
+ callUserCallback(() => {
+ var pipelineId = WebGPU.mgrRenderPipeline.create(pipeline);
+ {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.Success }}}, pipelineId, 0, userdata);
+ });
+ }, (pipelineError) => {
+ {{{ runtimeKeepalivePop() }}}
+ callUserCallback(() => {
+ var sp = stackSave();
+ var messagePtr = stringToUTF8OnStack(pipelineError.message);
+ if (pipelineError.reason === 'validation') {
+ {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.ValidationError }}}, 0, messagePtr, userdata);
+ } else if (pipelineError.reason === 'internal') {
+ {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.InternalError }}}, 0, messagePtr, userdata);
+ } else {
+ {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.CreatePipelineAsyncStatus.Unknown }}}, 0, messagePtr, userdata);
+ }
+ stackRestore(sp);
+ });
+ });
+ },
+
+ wgpuDeviceCreateShaderModule: (deviceId, descriptor) => {
+ {{{ gpu.makeCheck('descriptor') }}}
+ var nextInChainPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUShaderModuleDescriptor.nextInChain, '*') }}};
+#if ASSERTIONS
+ assert(nextInChainPtr !== 0);
+#endif
+ var sType = {{{ gpu.makeGetU32('nextInChainPtr', C_STRUCTS.WGPUChainedStruct.sType) }}};
+
+ var desc = {
+ "label": undefined,
+ "code": "",
+ };
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUShaderModuleDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+
+ switch (sType) {
+ case {{{ gpu.SType.ShaderModuleSPIRVDescriptor }}}: {
+ var count = {{{ gpu.makeGetU32('nextInChainPtr', C_STRUCTS.WGPUShaderModuleSPIRVDescriptor.codeSize) }}};
+ var start = {{{ makeGetValue('nextInChainPtr', C_STRUCTS.WGPUShaderModuleSPIRVDescriptor.code, '*') }}};
+ var offset = {{{ getHeapOffset('start', 'u32') }}};
+#if PTHREADS
+ // Chrome can't currently handle a SharedArrayBuffer view here, so make a copy.
+ desc["code"] = HEAPU32.slice(offset, offset + count);
+#else
+ desc["code"] = HEAPU32.subarray(offset, offset + count);
+#endif
+ break;
+ }
+ case {{{ gpu.SType.ShaderModuleWGSLDescriptor }}}: {
+ var sourcePtr = {{{ makeGetValue('nextInChainPtr', C_STRUCTS.WGPUShaderModuleWGSLDescriptor.code, '*') }}};
+ if (sourcePtr) {
+ desc["code"] = UTF8ToString(sourcePtr);
+ }
+ break;
+ }
+#if ASSERTIONS
+ default: abort('unrecognized ShaderModule sType');
+#endif
+ }
+
+ var device = WebGPU.mgrDevice.get(deviceId);
+ return WebGPU.mgrShaderModule.create(device.createShaderModule(desc));
+ },
+
+ // wgpuQuerySet
+
+ wgpuQuerySetGetCount: (querySetId) => {
+ var querySet = WebGPU.mgrQuerySet.get(querySetId);
+ return querySet.count;
+ },
+
+ wgpuQuerySetGetType: (querySetId, labelPtr) => {
+ var querySet = WebGPU.mgrQuerySet.get(querySetId);
+ return querySet.type;
+ },
+
+ wgpuQuerySetSetLabel: (querySetId, labelPtr) => {
+ var querySet = WebGPU.mgrQuerySet.get(querySetId);
+ querySet.label = UTF8ToString(labelPtr);
+ },
+
+ // wgpuQueue
+
+ wgpuQueueSetLabel: (queueId, labelPtr) => {
+ var queue = WebGPU.mgrQueue.get(queueId);
+ queue.label = UTF8ToString(labelPtr);
+ },
+
+ wgpuQueueSubmit: (queueId, commandCount, commands) => {
+#if ASSERTIONS
+ assert(commands % 4 === 0);
+#endif
+ var queue = WebGPU.mgrQueue.get(queueId);
+ var cmds = Array.from({{{ makeHEAPView(`${POINTER_BITS}`, 'commands', `commands + commandCount * ${POINTER_SIZE}`)}}},
+ (id) => WebGPU.mgrCommandBuffer.get(id));
+ queue.submit(cmds);
+ },
+
+ wgpuQueueOnSubmittedWorkDone__deps: ['$callUserCallback'],
+ wgpuQueueOnSubmittedWorkDone: (queueId, callback, userdata) => {
+ var queue = WebGPU.mgrQueue.get(queueId);
+
+ {{{ runtimeKeepalivePush() }}}
+ queue.onSubmittedWorkDone().then(() => {
+ {{{ runtimeKeepalivePop() }}}
+ callUserCallback(() => {
+ {{{ makeDynCall('vip', 'callback') }}}({{{ gpu.QueueWorkDoneStatus.Success }}}, userdata);
+ });
+ }, () => {
+ {{{ runtimeKeepalivePop() }}}
+ callUserCallback(() => {
+ {{{ makeDynCall('vip', 'callback') }}}({{{ gpu.QueueWorkDoneStatus.Error }}}, userdata);
+ });
+ });
+ },
+
+ wgpuQueueWriteBuffer: (queueId, bufferId, bufferOffset, data, size) => {
+ var queue = WebGPU.mgrQueue.get(queueId);
+ var buffer = WebGPU.mgrBuffer.get(bufferId);
+ // There is a size limitation for ArrayBufferView. Work around by passing in a subarray
+ // instead of the whole heap. crbug.com/1201109
+ var subarray = HEAPU8.subarray(data, data + size);
+ queue.writeBuffer(buffer, bufferOffset, subarray, 0, size);
+ },
+
+ wgpuQueueWriteTexture: (queueId,
+ destinationPtr, data, dataSize, dataLayoutPtr, writeSizePtr) => {
+ var queue = WebGPU.mgrQueue.get(queueId);
+
+ var destination = WebGPU.makeImageCopyTexture(destinationPtr);
+ var dataLayout = WebGPU.makeTextureDataLayout(dataLayoutPtr);
+ var writeSize = WebGPU.makeExtent3D(writeSizePtr);
+ // This subarray isn't strictly necessary, but helps work around an issue
+ // where Chromium makes a copy of the entire heap. crbug.com/1134457
+ var subarray = HEAPU8.subarray(data, data + dataSize);
+ queue.writeTexture(destination, subarray, dataLayout, writeSize);
+ },
+
+ // wgpuCommandEncoder
+
+ wgpuCommandEncoderBeginComputePass: (encoderId, descriptor) => {
+ var desc;
+
+ function makeComputePassTimestampWrites(twPtr) {
+ if (twPtr === 0) return undefined;
+
+ return {
+ "querySet": WebGPU.mgrQuerySet.get(
+ {{{ makeGetValue('twPtr', C_STRUCTS.WGPUComputePassTimestampWrites.querySet, '*') }}}),
+ "beginningOfPassWriteIndex": {{{ gpu.makeGetU32('twPtr', C_STRUCTS.WGPUComputePassTimestampWrites.beginningOfPassWriteIndex) }}},
+ "endOfPassWriteIndex": {{{ gpu.makeGetU32('twPtr', C_STRUCTS.WGPUComputePassTimestampWrites.endOfPassWriteIndex) }}},
+ };
+ }
+
+ if (descriptor) {
+ {{{ gpu.makeCheckDescriptor('descriptor') }}}
+ desc = {
+ "label": undefined,
+ "timestampWrites": makeComputePassTimestampWrites(
+ {{{ makeGetValue('descriptor', C_STRUCTS.WGPUComputePassDescriptor.timestampWrites, '*') }}}),
+ };
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUComputePassDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+
+ }
+ var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId);
+ return WebGPU.mgrComputePassEncoder.create(commandEncoder.beginComputePass(desc));
+ },
+
+ wgpuCommandEncoderBeginRenderPass: (encoderId, descriptor) => {
+ {{{ gpu.makeCheck('descriptor') }}}
+
+ function makeColorAttachment(caPtr) {
+ var viewPtr = {{{ gpu.makeGetU32('caPtr', C_STRUCTS.WGPURenderPassColorAttachment.view) }}};
+ if (viewPtr === 0) {
+ // view could be undefined.
+ return undefined;
+ }
+
+ var depthSlice = {{{ makeGetValue('caPtr', C_STRUCTS.WGPURenderPassColorAttachment.depthSlice, 'i32') }}};
+ {{{ gpu.convertSentinelToUndefined('depthSlice') }}}
+
+ var loadOpInt = {{{ gpu.makeGetU32('caPtr', C_STRUCTS.WGPURenderPassColorAttachment.loadOp) }}};
+ #if ASSERTIONS
+ assert(loadOpInt !== {{{ gpu.LoadOp.Undefined }}});
+ #endif
+
+ var storeOpInt = {{{ gpu.makeGetU32('caPtr', C_STRUCTS.WGPURenderPassColorAttachment.storeOp) }}};
+ #if ASSERTIONS
+ assert(storeOpInt !== {{{ gpu.StoreOp.Undefined }}});
+ #endif
+
+ var clearValue = WebGPU.makeColor(caPtr + {{{ C_STRUCTS.WGPURenderPassColorAttachment.clearValue }}});
+
+ return {
+ "view": WebGPU.mgrTextureView.get(viewPtr),
+ "depthSlice": depthSlice,
+ "resolveTarget": WebGPU.mgrTextureView.get(
+ {{{ gpu.makeGetU32('caPtr', C_STRUCTS.WGPURenderPassColorAttachment.resolveTarget) }}}),
+ "clearValue": clearValue,
+ "loadOp": WebGPU.LoadOp[loadOpInt],
+ "storeOp": WebGPU.StoreOp[storeOpInt],
+ };
+ }
+
+ function makeColorAttachments(count, caPtr) {
+ var attachments = [];
+ for (var i = 0; i < count; ++i) {
+ attachments.push(makeColorAttachment(caPtr + {{{ C_STRUCTS.WGPURenderPassColorAttachment.__size__ }}} * i));
+ }
+ return attachments;
+ }
+
+ function makeDepthStencilAttachment(dsaPtr) {
+ if (dsaPtr === 0) return undefined;
+
+ return {
+ "view": WebGPU.mgrTextureView.get(
+ {{{ gpu.makeGetU32('dsaPtr', C_STRUCTS.WGPURenderPassDepthStencilAttachment.view) }}}),
+ "depthClearValue": {{{ makeGetValue('dsaPtr', C_STRUCTS.WGPURenderPassDepthStencilAttachment.depthClearValue, 'float') }}},
+ "depthLoadOp": WebGPU.LoadOp[
+ {{{ gpu.makeGetU32('dsaPtr', C_STRUCTS.WGPURenderPassDepthStencilAttachment.depthLoadOp) }}}],
+ "depthStoreOp": WebGPU.StoreOp[
+ {{{ gpu.makeGetU32('dsaPtr', C_STRUCTS.WGPURenderPassDepthStencilAttachment.depthStoreOp) }}}],
+ "depthReadOnly": {{{ gpu.makeGetBool('dsaPtr', C_STRUCTS.WGPURenderPassDepthStencilAttachment.depthReadOnly) }}},
+ "stencilClearValue": {{{ gpu.makeGetU32('dsaPtr', C_STRUCTS.WGPURenderPassDepthStencilAttachment.stencilClearValue) }}},
+ "stencilLoadOp": WebGPU.LoadOp[
+ {{{ gpu.makeGetU32('dsaPtr', C_STRUCTS.WGPURenderPassDepthStencilAttachment.stencilLoadOp) }}}],
+ "stencilStoreOp": WebGPU.StoreOp[
+ {{{ gpu.makeGetU32('dsaPtr', C_STRUCTS.WGPURenderPassDepthStencilAttachment.stencilStoreOp) }}}],
+ "stencilReadOnly": {{{ gpu.makeGetBool('dsaPtr', C_STRUCTS.WGPURenderPassDepthStencilAttachment.stencilReadOnly) }}},
+ };
+ }
+
+ function makeRenderPassTimestampWrites(twPtr) {
+ if (twPtr === 0) return undefined;
+
+ return {
+ "querySet": WebGPU.mgrQuerySet.get(
+ {{{ makeGetValue('twPtr', C_STRUCTS.WGPURenderPassTimestampWrites.querySet, '*') }}}),
+ "beginningOfPassWriteIndex": {{{ gpu.makeGetU32('twPtr', C_STRUCTS.WGPURenderPassTimestampWrites.beginningOfPassWriteIndex) }}},
+ "endOfPassWriteIndex": {{{ gpu.makeGetU32('twPtr', C_STRUCTS.WGPURenderPassTimestampWrites.endOfPassWriteIndex) }}},
+ };
+ }
+
+ function makeRenderPassDescriptor(descriptor) {
+ {{{ gpu.makeCheck('descriptor') }}}
+ var nextInChainPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPURenderPassDescriptor.nextInChain, '*') }}};
+
+ var maxDrawCount = undefined;
+ if (nextInChainPtr !== 0) {
+ var sType = {{{ gpu.makeGetU32('nextInChainPtr', C_STRUCTS.WGPUChainedStruct.sType) }}};
+#if ASSERTIONS
+ assert(sType === {{{ gpu.SType.RenderPassDescriptorMaxDrawCount }}});
+ assert(0 === {{{ makeGetValue('nextInChainPtr', C_STRUCTS.WGPUChainedStruct.next, '*') }}});
+#endif
+ var renderPassDescriptorMaxDrawCount = nextInChainPtr;
+ {{{ gpu.makeCheckDescriptor('renderPassDescriptorMaxDrawCount') }}}
+ maxDrawCount = {{{ gpu.makeGetU64('renderPassDescriptorMaxDrawCount', C_STRUCTS.WGPURenderPassDescriptorMaxDrawCount.maxDrawCount) }}};
+ }
+
+ var desc = {
+ "label": undefined,
+ "colorAttachments": makeColorAttachments(
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPURenderPassDescriptor.colorAttachmentCount) }}},
+ {{{ makeGetValue('descriptor', C_STRUCTS.WGPURenderPassDescriptor.colorAttachments, '*') }}}),
+ "depthStencilAttachment": makeDepthStencilAttachment(
+ {{{ makeGetValue('descriptor', C_STRUCTS.WGPURenderPassDescriptor.depthStencilAttachment, '*') }}}),
+ "occlusionQuerySet": WebGPU.mgrQuerySet.get(
+ {{{ makeGetValue('descriptor', C_STRUCTS.WGPURenderPassDescriptor.occlusionQuerySet, '*') }}}),
+ "timestampWrites": makeRenderPassTimestampWrites(
+ {{{ makeGetValue('descriptor', C_STRUCTS.WGPURenderPassDescriptor.timestampWrites, '*') }}}),
+ "maxDrawCount": maxDrawCount,
+ };
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPURenderPassDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+
+ return desc;
+ }
+
+ var desc = makeRenderPassDescriptor(descriptor);
+
+ var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId);
+ return WebGPU.mgrRenderPassEncoder.create(commandEncoder.beginRenderPass(desc));
+ },
+
+ wgpuCommandEncoderClearBuffer: (encoderId, bufferId, offset, size) => {
+ var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId);
+ {{{ gpu.convertSentinelToUndefined('size') }}}
+
+ var buffer = WebGPU.mgrBuffer.get(bufferId);
+ commandEncoder.clearBuffer(buffer, offset, size);
+ },
+
+ wgpuCommandEncoderCopyBufferToBuffer: (encoderId, srcId, srcOffset, dstId, dstOffset, size) => {
+ var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId);
+ var src = WebGPU.mgrBuffer.get(srcId);
+ var dst = WebGPU.mgrBuffer.get(dstId);
+ commandEncoder.copyBufferToBuffer(src, srcOffset, dst, dstOffset, size);
+ },
+
+ wgpuCommandEncoderCopyBufferToTexture: (encoderId, srcPtr, dstPtr, copySizePtr) => {
+ var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId);
+ var copySize = WebGPU.makeExtent3D(copySizePtr);
+ commandEncoder.copyBufferToTexture(
+ WebGPU.makeImageCopyBuffer(srcPtr), WebGPU.makeImageCopyTexture(dstPtr), copySize);
+ },
+
+ wgpuCommandEncoderCopyTextureToBuffer: (encoderId, srcPtr, dstPtr, copySizePtr) => {
+ var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId);
+ var copySize = WebGPU.makeExtent3D(copySizePtr);
+ commandEncoder.copyTextureToBuffer(
+ WebGPU.makeImageCopyTexture(srcPtr), WebGPU.makeImageCopyBuffer(dstPtr), copySize);
+ },
+
+ wgpuCommandEncoderCopyTextureToTexture: (encoderId, srcPtr, dstPtr, copySizePtr) => {
+ var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId);
+ var copySize = WebGPU.makeExtent3D(copySizePtr);
+ commandEncoder.copyTextureToTexture(
+ WebGPU.makeImageCopyTexture(srcPtr), WebGPU.makeImageCopyTexture(dstPtr), copySize);
+ },
+
+ wgpuCommandEncoderResolveQuerySet: (encoderId, querySetId, firstQuery, queryCount,
+ destinationId, destinationOffset) => {
+ var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId);
+ var querySet = WebGPU.mgrQuerySet.get(querySetId);
+ var destination = WebGPU.mgrBuffer.get(destinationId);
+
+ commandEncoder.resolveQuerySet(querySet, firstQuery, queryCount, destination, destinationOffset);
+ },
+
+ wgpuCommandEncoderWriteTimestamp: (encoderId, querySetId, queryIndex) => {
+ var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId);
+ var querySet = WebGPU.mgrQuerySet.get(querySetId);
+ commandEncoder.writeTimestamp(querySet, queryIndex);
+ },
+
+ wgpuCommandEncoderPushDebugGroup: (encoderId, groupLabelPtr) => {
+ var encoder = WebGPU.mgrCommandEncoder.get(encoderId);
+ encoder.pushDebugGroup(UTF8ToString(groupLabelPtr));
+ },
+ wgpuCommandEncoderPopDebugGroup: (encoderId) => {
+ var encoder = WebGPU.mgrCommandEncoder.get(encoderId);
+ encoder.popDebugGroup();
+ },
+ wgpuCommandEncoderInsertDebugMarker: (encoderId, markerLabelPtr) => {
+ var encoder = WebGPU.mgrCommandEncoder.get(encoderId);
+ encoder.insertDebugMarker(UTF8ToString(markerLabelPtr));
+ },
+
+ wgpuCommandEncoderFinish: (encoderId, descriptor) => {
+ // TODO: Use the descriptor.
+ var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId);
+ return WebGPU.mgrCommandBuffer.create(commandEncoder.finish());
+ },
+
+ wgpuCommandEncoderSetLabel: (encoderId, labelPtr) => {
+ var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId);
+ commandEncoder.label = UTF8ToString(labelPtr);
+ },
+
+ // wgpuCommandBuffer
+
+ wgpuCommandBufferSetLabel: (commandBufferId, labelPtr) => {
+ var commandBuffer = WebGPU.mgrCommandBuffer.get(commandBufferId);
+ commandBuffer.label = UTF8ToString(labelPtr);
+ },
+
+ // wgpuPipelineLayout
+
+ wgpuPipelineLayoutSetLabel: (pipelineLayoutId, labelPtr) => {
+ var pipelineLayout = WebGPU.mgrPipelineLayout.get(pipelineLayoutId);
+ pipelineLayout.label = UTF8ToString(labelPtr);
+ },
+
+ // wgpuShaderModule
+
+ wgpuShaderModuleGetCompilationInfo__deps: ['$callUserCallback', '$stringToUTF8', '$lengthBytesUTF8', 'malloc', 'free'],
+ wgpuShaderModuleGetCompilationInfo: (shaderModuleId, callback, userdata) => {
+ var shaderModule = WebGPU.mgrShaderModule.get(shaderModuleId);
+ {{{ runtimeKeepalivePush() }}}
+ shaderModule.getCompilationInfo().then((compilationInfo) => {
+ {{{ runtimeKeepalivePop() }}}
+ callUserCallback(() => {
+ var compilationMessagesPtr = _malloc({{{ C_STRUCTS.WGPUCompilationMessage.__size__ }}} * compilationInfo.messages.length);
+ var messageStringPtrs = []; // save these to free later
+ for (var i = 0; i < compilationInfo.messages.length; ++i) {
+ var compilationMessage = compilationInfo.messages[i];
+ var compilationMessagePtr = compilationMessagesPtr + {{{ C_STRUCTS.WGPUCompilationMessage.__size__ }}} * i;
+ var messageSize = lengthBytesUTF8(compilationMessage.message) + 1;
+ var messagePtr = _malloc(messageSize);
+ messageStringPtrs.push(messagePtr);
+ stringToUTF8(compilationMessage.message, messagePtr, messageSize);
+ {{{ makeSetValue('compilationMessagePtr', C_STRUCTS.WGPUCompilationMessage.message, 'messagePtr', '*') }}};
+ {{{ makeSetValue('compilationMessagePtr', C_STRUCTS.WGPUCompilationMessage.type, 'WebGPU.Int_CompilationMessageType[compilationMessage.type]', 'i32') }}};
+ {{{ makeSetValue('compilationMessagePtr', C_STRUCTS.WGPUCompilationMessage.lineNum, 'compilationMessage.lineNum', 'i64') }}};
+ {{{ makeSetValue('compilationMessagePtr', C_STRUCTS.WGPUCompilationMessage.linePos, 'compilationMessage.linePos', 'i64') }}};
+ {{{ makeSetValue('compilationMessagePtr', C_STRUCTS.WGPUCompilationMessage.offset, 'compilationMessage.offset', 'i64') }}};
+ {{{ makeSetValue('compilationMessagePtr', C_STRUCTS.WGPUCompilationMessage.length, 'compilationMessage.length', 'i64') }}};
+ // TODO: Convert JavaScript's UTF-16-code-unit offsets to UTF-8-code-unit offsets.
+ // https://github.com/webgpu-native/webgpu-headers/issues/246
+ {{{ makeSetValue('compilationMessagePtr', C_STRUCTS.WGPUCompilationMessage.utf16LinePos, 'compilationMessage.linePos', 'i64') }}};
+ {{{ makeSetValue('compilationMessagePtr', C_STRUCTS.WGPUCompilationMessage.utf16Offset, 'compilationMessage.offset', 'i64') }}};
+ {{{ makeSetValue('compilationMessagePtr', C_STRUCTS.WGPUCompilationMessage.utf16Length, 'compilationMessage.length', 'i64') }}};
+ }
+ var compilationInfoPtr = _malloc({{{ C_STRUCTS.WGPUCompilationInfo.__size__ }}});
+ {{{ makeSetValue('compilationInfoPtr', C_STRUCTS.WGPUCompilationInfo.messageCount, 'compilationInfo.messages.length', '*') }}}
+ {{{ makeSetValue('compilationInfoPtr', C_STRUCTS.WGPUCompilationInfo.messages, 'compilationMessagesPtr', '*') }}};
+
+ {{{ makeDynCall('vipp', 'callback') }}}({{{ gpu.CompilationInfoRequestStatus.Success }}}, compilationInfoPtr, userdata);
+
+ messageStringPtrs.forEach((ptr) => {
+ _free(ptr);
+ });
+ _free(compilationMessagesPtr);
+ _free(compilationInfoPtr);
+ });
+ });
+ },
+ wgpuShaderModuleSetLabel: (shaderModuleId, labelPtr) => {
+ var shaderModule = WebGPU.mgrShaderModule.get(shaderModuleId);
+ shaderModule.label = UTF8ToString(labelPtr);
+ },
+
+ // wgpuComputePipeline
+
+ wgpuComputePipelineGetBindGroupLayout: (pipelineId, groupIndex) => {
+ var pipeline = WebGPU.mgrComputePipeline.get(pipelineId);
+ return WebGPU.mgrBindGroupLayout.create(pipeline.getBindGroupLayout(groupIndex));
+ },
+ wgpuComputePipelineSetLabel: (pipelineId, labelPtr) => {
+ var pipeline = WebGPU.mgrComputePipeline.get(pipelineId);
+ pipeline.label = UTF8ToString(labelPtr);
+ },
+
+ // wgpuRenderPipeline
+
+ wgpuRenderPipelineGetBindGroupLayout: (pipelineId, groupIndex) => {
+ var pipeline = WebGPU.mgrRenderPipeline.get(pipelineId);
+ return WebGPU.mgrBindGroupLayout.create(pipeline.getBindGroupLayout(groupIndex));
+ },
+ wgpuRenderPipelineSetLabel: (pipelineId, labelPtr) => {
+ var pipeline = WebGPU.mgrRenderPipeline.get(pipelineId);
+ pipeline.label = UTF8ToString(labelPtr);
+ },
+
+ // wgpuBindGroup
+
+ wgpuBindGroupSetLabel: (bindGroupId, labelPtr) => {
+ var bindGroup = WebGPU.mgrBindGroup.get(bindGroupId);
+ bindGroup.label = UTF8ToString(labelPtr);
+ },
+
+ // wgpuBindGroupLayout
+
+ wgpuBindGroupLayoutSetLabel: (bindGroupLayoutId, labelPtr) => {
+ var bindGroupLayout = WebGPU.mgrBindGroupLayout.get(bindGroupLayoutId);
+ bindGroupLayout.label = UTF8ToString(labelPtr);
+ },
+
+ // wgpuBuffer
+
+ // 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: (bufferId, offset, size) => {
+ var bufferWrapper = WebGPU.mgrBuffer.objects[bufferId];
+ {{{ gpu.makeCheckDefined('bufferWrapper') }}}
+
+ if (size === 0) warnOnce('getMappedRange size=0 no longer means WGPU_WHOLE_MAP_SIZE');
+
+ {{{ gpu.convertSentinelToUndefined('size') }}}
+
+ var mapped;
+ try {
+ mapped = bufferWrapper.object.getMappedRange(offset, size);
+ } catch (ex) {
+#if ASSERTIONS
+ err(`wgpuBufferGetConstMappedRange(${offset}, ${size}) failed: ${ex}`);
+#endif
+ // TODO(kainino0x): Somehow inject a validation error?
+ return 0;
+ }
+ var data = _memalign(16, mapped.byteLength);
+ HEAPU8.set(new Uint8Array(mapped), data);
+ bufferWrapper.onUnmap.push(() => _free(data));
+ return data;
+ },
+
+ wgpuBufferGetMapState: (bufferId) => {
+ var buffer = WebGPU.mgrBuffer.get(bufferId);
+ 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: (bufferId, offset, size) => {
+ var bufferWrapper = WebGPU.mgrBuffer.objects[bufferId];
+ {{{ gpu.makeCheckDefined('bufferWrapper') }}}
+
+ if (size === 0) warnOnce('getMappedRange size=0 no longer means WGPU_WHOLE_MAP_SIZE');
+
+ {{{ 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);
+ } catch (ex) {
+#if ASSERTIONS
+ err(`wgpuBufferGetMappedRange(${offset}, ${size}) failed: ${ex}`);
+#endif
+ // TODO(kainino0x): Somehow inject a validation error?
+ return 0;
+ }
+
+ var data = _memalign(16, mapped.byteLength);
+ HEAPU8.fill(0, data, mapped.byteLength);
+ bufferWrapper.onUnmap.push(() => {
+ new Uint8Array(mapped).set(HEAPU8.subarray(data, data + mapped.byteLength));
+ _free(data);
+ });
+ return data;
+ },
+
+ // 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: (bufferId, mode, offset, size, callback, userdata) => {
+ var bufferWrapper = WebGPU.mgrBuffer.objects[bufferId];
+ {{{ 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(() => {
+ {{{ runtimeKeepalivePop() }}}
+ callUserCallback(() => {
+ {{{ makeDynCall('vip', 'callback') }}}({{{ gpu.BufferMapAsyncStatus.Success }}}, userdata);
+ });
+ }, () => {
+ {{{ runtimeKeepalivePop() }}}
+ callUserCallback(() => {
+ // TODO(kainino0x): Figure out how to pick other error status values.
+ {{{ makeDynCall('vip', 'callback') }}}({{{ gpu.BufferMapAsyncStatus.ValidationError }}}, userdata);
+ });
+ });
+ },
+
+ wgpuBufferGetSize: (bufferId) => {
+ var buffer = WebGPU.mgrBuffer.get(bufferId);
+ // 64-bit
+ return buffer.size;
+ },
+
+ wgpuBufferGetUsage: (bufferId) => {
+ var buffer = WebGPU.mgrBuffer.get(bufferId);
+ return buffer.usage;
+ },
+
+ wgpuBufferSetLabel: (bufferId, labelPtr) => {
+ var buffer = WebGPU.mgrBuffer.get(bufferId);
+ buffer.label = UTF8ToString(labelPtr);
+ },
+
+ wgpuBufferUnmap: (bufferId) => {
+ var bufferWrapper = WebGPU.mgrBuffer.objects[bufferId];
+ {{{ gpu.makeCheckDefined('bufferWrapper') }}}
+
+ if (!bufferWrapper.onUnmap) {
+ // Already unmapped
+ return;
+ }
+
+ for (var i = 0; i < bufferWrapper.onUnmap.length; ++i) {
+ bufferWrapper.onUnmap[i]();
+ }
+ bufferWrapper.onUnmap = undefined;
+
+ bufferWrapper.object.unmap();
+ },
+
+ // wgpuTexture
+
+ wgpuTextureGetDepthOrArrayLayers: (textureId) => {
+ var texture = WebGPU.mgrTexture.get(textureId);
+ return texture.depthOrArrayLayers;
+ },
+
+ wgpuTextureGetDimension: (textureId) => {
+ var texture = WebGPU.mgrTexture.get(textureId);
+ return WebGPU.TextureDimension.indexOf(texture.dimension);
+ },
+
+ wgpuTextureGetFormat: (textureId) => {
+ var texture = WebGPU.mgrTexture.get(textureId);
+ // Should return the enum integer instead of string.
+ return WebGPU.TextureFormat.indexOf(texture.format);
+ },
+
+ wgpuTextureGetHeight: (textureId) => {
+ var texture = WebGPU.mgrTexture.get(textureId);
+ return texture.height;
+ },
+
+ wgpuTextureGetMipLevelCount: (textureId) => {
+ var texture = WebGPU.mgrTexture.get(textureId);
+ return texture.mipLevelCount;
+ },
+
+ wgpuTextureGetSampleCount: (textureId) => {
+ var texture = WebGPU.mgrTexture.get(textureId);
+ return texture.sampleCount;
+ },
+
+ wgpuTextureGetUsage: (textureId) => {
+ var texture = WebGPU.mgrTexture.get(textureId);
+ return texture.usage;
+ },
+
+ wgpuTextureGetWidth: (textureId) => {
+ var texture = WebGPU.mgrTexture.get(textureId);
+ return texture.width;
+ },
+
+ wgpuTextureSetLabel: (textureId, labelPtr) => {
+ var texture = WebGPU.mgrTexture.get(textureId);
+ texture.label = UTF8ToString(labelPtr);
+ },
+
+ wgpuTextureCreateView: (textureId, descriptor) => {
+ var desc;
+ if (descriptor) {
+ {{{ gpu.makeCheckDescriptor('descriptor') }}}
+ var mipLevelCount = {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUTextureViewDescriptor.mipLevelCount) }}};
+ var arrayLayerCount = {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUTextureViewDescriptor.arrayLayerCount) }}};
+ desc = {
+ "format": WebGPU.TextureFormat[
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUTextureViewDescriptor.format) }}}],
+ "dimension": WebGPU.TextureViewDimension[
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUTextureViewDescriptor.dimension) }}}],
+ "baseMipLevel": {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUTextureViewDescriptor.baseMipLevel) }}},
+ "mipLevelCount": mipLevelCount === {{{ gpu.MIP_LEVEL_COUNT_UNDEFINED }}} ? undefined : mipLevelCount,
+ "baseArrayLayer": {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUTextureViewDescriptor.baseArrayLayer) }}},
+ "arrayLayerCount": arrayLayerCount === {{{ gpu.ARRAY_LAYER_COUNT_UNDEFINED }}} ? undefined : arrayLayerCount,
+ "aspect": WebGPU.TextureAspect[
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUTextureViewDescriptor.aspect) }}}],
+ };
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUTextureViewDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+ }
+
+ var texture = WebGPU.mgrTexture.get(textureId);
+ return WebGPU.mgrTextureView.create(texture.createView(desc));
+ },
+
+ // wgpuTextureView
+
+ wgpuTextureViewSetLabel: (textureViewId, labelPtr) => {
+ var textureView = WebGPU.mgrTextureView.get(textureViewId);
+ textureView.label = UTF8ToString(labelPtr);
+ },
+
+ // wgpuComputePass
+
+ wgpuComputePassEncoderSetBindGroup: (passId, groupIndex, groupId, dynamicOffsetCount, dynamicOffsetsPtr) => {
+ var pass = WebGPU.mgrComputePassEncoder.get(passId);
+ var group = WebGPU.mgrBindGroup.get(groupId);
+ if (dynamicOffsetCount == 0) {
+ pass.setBindGroup(groupIndex, group);
+ } else {
+ var offsets = [];
+ for (var i = 0; i < dynamicOffsetCount; i++, dynamicOffsetsPtr += 4) {
+ offsets.push({{{ gpu.makeGetU32('dynamicOffsetsPtr', 0) }}});
+ }
+ pass.setBindGroup(groupIndex, group, offsets);
+ }
+ },
+ wgpuComputePassEncoderSetLabel: (passId, labelPtr) => {
+ var pass = WebGPU.mgrComputePassEncoder.get(passId);
+ pass.label = UTF8ToString(labelPtr);
+ },
+ wgpuComputePassEncoderSetPipeline: (passId, pipelineId) => {
+ var pass = WebGPU.mgrComputePassEncoder.get(passId);
+ var pipeline = WebGPU.mgrComputePipeline.get(pipelineId);
+ pass.setPipeline(pipeline);
+ },
+
+ wgpuComputePassEncoderDispatchWorkgroups: (passId, x, y, z) => {
+ var pass = WebGPU.mgrComputePassEncoder.get(passId);
+ pass.dispatchWorkgroups(x, y, z);
+ },
+ wgpuComputePassEncoderDispatchWorkgroupsIndirect: (passId, indirectBufferId, indirectOffset) => {
+ var indirectBuffer = WebGPU.mgrBuffer.get(indirectBufferId);
+ var pass = WebGPU.mgrComputePassEncoder.get(passId);
+ pass.dispatchWorkgroupsIndirect(indirectBuffer, indirectOffset);
+ },
+
+ wgpuComputePassEncoderWriteTimestamp: (encoderId, querySetId, queryIndex) => {
+ var pass = WebGPU.mgrComputePassEncoder.get(encoderId);
+ var querySet = WebGPU.mgrQuerySet.get(querySetId);
+ pass.writeTimestamp(querySet, queryIndex);
+ },
+
+ wgpuComputePassEncoderPushDebugGroup: (encoderId, groupLabelPtr) => {
+ var encoder = WebGPU.mgrComputePassEncoder.get(encoderId);
+ encoder.pushDebugGroup(UTF8ToString(groupLabelPtr));
+ },
+ wgpuComputePassEncoderPopDebugGroup: (encoderId) => {
+ var encoder = WebGPU.mgrComputePassEncoder.get(encoderId);
+ encoder.popDebugGroup();
+ },
+ wgpuComputePassEncoderInsertDebugMarker: (encoderId, markerLabelPtr) => {
+ var encoder = WebGPU.mgrComputePassEncoder.get(encoderId);
+ encoder.insertDebugMarker(UTF8ToString(markerLabelPtr));
+ },
+
+ wgpuComputePassEncoderEnd: (passId) => {
+ var pass = WebGPU.mgrComputePassEncoder.get(passId);
+ pass.end();
+ },
+
+ // wgpuRenderPass
+
+ wgpuRenderPassEncoderSetLabel: (passId, labelPtr) => {
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+ pass.label = UTF8ToString(labelPtr);
+ },
+
+ wgpuRenderPassEncoderSetBindGroup: (passId, groupIndex, groupId, dynamicOffsetCount, dynamicOffsetsPtr) => {
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+ var group = WebGPU.mgrBindGroup.get(groupId);
+ if (dynamicOffsetCount == 0) {
+ pass.setBindGroup(groupIndex, group);
+ } else {
+ var offsets = [];
+ for (var i = 0; i < dynamicOffsetCount; i++, dynamicOffsetsPtr += 4) {
+ offsets.push({{{ gpu.makeGetU32('dynamicOffsetsPtr', 0) }}});
+ }
+ pass.setBindGroup(groupIndex, group, offsets);
+ }
+ },
+ wgpuRenderPassEncoderSetBlendConstant: (passId, colorPtr) => {
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+ var color = WebGPU.makeColor(colorPtr);
+ pass.setBlendConstant(color);
+ },
+ wgpuRenderPassEncoderSetIndexBuffer: (passId, bufferId, format, offset, size) => {
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+ var buffer = WebGPU.mgrBuffer.get(bufferId);
+ {{{ gpu.convertSentinelToUndefined('size') }}}
+ pass.setIndexBuffer(buffer, WebGPU.IndexFormat[format], offset, size);
+ },
+ wgpuRenderPassEncoderSetPipeline: (passId, pipelineId) => {
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+ var pipeline = WebGPU.mgrRenderPipeline.get(pipelineId);
+ pass.setPipeline(pipeline);
+ },
+ wgpuRenderPassEncoderSetScissorRect: (passId, x, y, w, h) => {
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+ pass.setScissorRect(x, y, w, h);
+ },
+ wgpuRenderPassEncoderSetViewport: (passId, x, y, w, h, minDepth, maxDepth) => {
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+ pass.setViewport(x, y, w, h, minDepth, maxDepth);
+ },
+ wgpuRenderPassEncoderSetStencilReference: (passId, reference) => {
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+ pass.setStencilReference(reference);
+ },
+ wgpuRenderPassEncoderSetVertexBuffer: (passId, slot, bufferId, offset, size) => {
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+ var buffer = WebGPU.mgrBuffer.get(bufferId);
+ {{{ gpu.convertSentinelToUndefined('size') }}}
+ pass.setVertexBuffer(slot, buffer, offset, size);
+ },
+
+ wgpuRenderPassEncoderDraw: (passId, vertexCount, instanceCount, firstVertex, firstInstance) => {
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+ pass.draw(vertexCount, instanceCount, firstVertex, firstInstance);
+ },
+ wgpuRenderPassEncoderDrawIndexed: (passId, indexCount, instanceCount, firstIndex, baseVertex, firstInstance) => {
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+ pass.drawIndexed(indexCount, instanceCount, firstIndex, baseVertex, firstInstance);
+ },
+ wgpuRenderPassEncoderDrawIndirect: (passId, indirectBufferId, indirectOffset) => {
+ var indirectBuffer = WebGPU.mgrBuffer.get(indirectBufferId);
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+ pass.drawIndirect(indirectBuffer, indirectOffset);
+ },
+ wgpuRenderPassEncoderDrawIndexedIndirect: (passId, indirectBufferId, indirectOffset) => {
+ var indirectBuffer = WebGPU.mgrBuffer.get(indirectBufferId);
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+ pass.drawIndexedIndirect(indirectBuffer, indirectOffset);
+ },
+
+ wgpuRenderPassEncoderExecuteBundles: (passId, count, bundlesPtr) => {
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+
+#if ASSERTIONS
+ assert(bundlesPtr % 4 === 0);
+#endif
+
+ var bundles = Array.from({{{ makeHEAPView(`${POINTER_BITS}`, 'bundlesPtr', `bundlesPtr + count * ${POINTER_SIZE}`) }}},
+ (id) => WebGPU.mgrRenderBundle.get(id));
+ pass.executeBundles(bundles);
+ },
+
+ wgpuRenderPassEncoderBeginOcclusionQuery: (passId, queryIndex) => {
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+ pass.beginOcclusionQuery(queryIndex);
+ },
+ wgpuRenderPassEncoderEndOcclusionQuery: (passId) => {
+ var pass = WebGPU.mgrRenderPassEncoder.get(passId);
+ pass.endOcclusionQuery();
+ },
+
+ wgpuRenderPassEncoderWriteTimestamp: (encoderId, querySetId, queryIndex) => {
+ var pass = WebGPU.mgrRenderPassEncoder.get(encoderId);
+ var querySet = WebGPU.mgrQuerySet.get(querySetId);
+ pass.writeTimestamp(querySet, queryIndex);
+ },
+
+ wgpuRenderPassEncoderPushDebugGroup: (encoderId, groupLabelPtr) => {
+ var encoder = WebGPU.mgrRenderPassEncoder.get(encoderId);
+ encoder.pushDebugGroup(UTF8ToString(groupLabelPtr));
+ },
+ wgpuRenderPassEncoderPopDebugGroup: (encoderId) => {
+ var encoder = WebGPU.mgrRenderPassEncoder.get(encoderId);
+ encoder.popDebugGroup();
+ },
+ wgpuRenderPassEncoderInsertDebugMarker: (encoderId, markerLabelPtr) => {
+ var encoder = WebGPU.mgrRenderPassEncoder.get(encoderId);
+ encoder.insertDebugMarker(UTF8ToString(markerLabelPtr));
+ },
+ wgpuRenderPassEncoderEnd: (encoderId) => {
+ var encoder = WebGPU.mgrRenderPassEncoder.get(encoderId);
+ encoder.end();
+ },
+
+ // Render bundle
+
+ wgpuRenderBundleSetLabel: (bundleId, labelPtr) => {
+ var bundle = WebGPU.mgrRenderBundle.get(bundleId);
+ bundle.label = UTF8ToString(labelPtr);
+ },
+
+ // Render bundle encoder
+
+ wgpuRenderBundleEncoderSetLabel: (bundleId, labelPtr) => {
+ var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId);
+ pass.label = UTF8ToString(labelPtr);
+ },
+
+ wgpuRenderBundleEncoderSetBindGroup: (bundleId, groupIndex, groupId, dynamicOffsetCount, dynamicOffsetsPtr) => {
+ var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId);
+ var group = WebGPU.mgrBindGroup.get(groupId);
+ if (dynamicOffsetCount == 0) {
+ pass.setBindGroup(groupIndex, group);
+ } else {
+ var offsets = [];
+ for (var i = 0; i < dynamicOffsetCount; i++, dynamicOffsetsPtr += 4) {
+ offsets.push({{{ gpu.makeGetU32('dynamicOffsetsPtr', 0) }}});
+ }
+ pass.setBindGroup(groupIndex, group, offsets);
+ }
+ },
+ wgpuRenderBundleEncoderSetIndexBuffer: (bundleId, bufferId, format, offset, size) => {
+ var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId);
+ var buffer = WebGPU.mgrBuffer.get(bufferId);
+ {{{ gpu.convertSentinelToUndefined('size') }}}
+ pass.setIndexBuffer(buffer, WebGPU.IndexFormat[format], offset, size);
+ },
+ wgpuRenderBundleEncoderSetPipeline: (bundleId, pipelineId) => {
+ var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId);
+ var pipeline = WebGPU.mgrRenderPipeline.get(pipelineId);
+ pass.setPipeline(pipeline);
+ },
+ wgpuRenderBundleEncoderSetVertexBuffer: (bundleId, slot, bufferId, offset, size) => {
+ var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId);
+ var buffer = WebGPU.mgrBuffer.get(bufferId);
+ {{{ gpu.convertSentinelToUndefined('size') }}}
+ pass.setVertexBuffer(slot, buffer, offset, size);
+ },
+
+ wgpuRenderBundleEncoderDraw: (bundleId, vertexCount, instanceCount, firstVertex, firstInstance) => {
+ var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId);
+ pass.draw(vertexCount, instanceCount, firstVertex, firstInstance);
+ },
+ wgpuRenderBundleEncoderDrawIndexed: (bundleId, indexCount, instanceCount, firstIndex, baseVertex, firstInstance) => {
+ var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId);
+ pass.drawIndexed(indexCount, instanceCount, firstIndex, baseVertex, firstInstance);
+ },
+ wgpuRenderBundleEncoderDrawIndirect: (bundleId, indirectBufferId, indirectOffset) => {
+ var indirectBuffer = WebGPU.mgrBuffer.get(indirectBufferId);
+ var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId);
+ pass.drawIndirect(indirectBuffer, indirectOffset);
+ },
+ wgpuRenderBundleEncoderDrawIndexedIndirect: (bundleId, indirectBufferId, indirectOffset) => {
+ var indirectBuffer = WebGPU.mgrBuffer.get(indirectBufferId);
+ var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId);
+ pass.drawIndexedIndirect(indirectBuffer, indirectOffset);
+ },
+
+ wgpuRenderBundleEncoderPushDebugGroup: (encoderId, groupLabelPtr) => {
+ var encoder = WebGPU.mgrRenderBundleEncoder.get(encoderId);
+ encoder.pushDebugGroup(UTF8ToString(groupLabelPtr));
+ },
+ wgpuRenderBundleEncoderPopDebugGroup: (encoderId) => {
+ var encoder = WebGPU.mgrRenderBundleEncoder.get(encoderId);
+ encoder.popDebugGroup();
+ },
+ wgpuRenderBundleEncoderInsertDebugMarker: (encoderId, markerLabelPtr) => {
+ var encoder = WebGPU.mgrRenderBundleEncoder.get(encoderId);
+ encoder.insertDebugMarker(UTF8ToString(markerLabelPtr));
+ },
+
+ wgpuRenderBundleEncoderFinish: (bundleId, descriptor) => {
+ var desc;
+ if (descriptor) {
+ {{{ gpu.makeCheckDescriptor('descriptor') }}}
+ desc = {};
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPURenderBundleDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+ }
+ var encoder = WebGPU.mgrRenderBundleEncoder.get(bundleId);
+ return WebGPU.mgrRenderBundle.create(encoder.finish(desc));
+ },
+
+ // Instance
+
+ wgpuInstanceCreateSurface__deps: ['$findCanvasEventTarget'],
+ wgpuInstanceCreateSurface: (instanceId, descriptor) => {
+ {{{ gpu.makeCheck('descriptor') }}}
+ {{{ gpu.makeCheck('instanceId === 1, "WGPUInstance must be created by wgpuCreateInstance"') }}}
+ var nextInChainPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUSurfaceDescriptor.nextInChain, '*') }}};
+#if ASSERTIONS
+ assert(nextInChainPtr !== 0);
+ assert({{{ gpu.SType.SurfaceDescriptorFromCanvasHTMLSelector }}} ===
+ {{{ gpu.makeGetU32('nextInChainPtr', C_STRUCTS.WGPUChainedStruct.sType) }}});
+#endif
+ var descriptorFromCanvasHTMLSelector = nextInChainPtr;
+
+ {{{ gpu.makeCheckDescriptor('descriptorFromCanvasHTMLSelector') }}}
+ var selectorPtr = {{{ makeGetValue('descriptorFromCanvasHTMLSelector', C_STRUCTS.WGPUSurfaceDescriptorFromCanvasHTMLSelector.selector, '*') }}};
+ {{{ gpu.makeCheck('selectorPtr') }}}
+ var canvas = findCanvasEventTarget(selectorPtr);
+#if OFFSCREENCANVAS_SUPPORT
+ if (canvas.offscreenCanvas) canvas = canvas.offscreenCanvas;
+#endif
+ var context = canvas.getContext('webgpu');
+#if ASSERTIONS
+ assert(context);
+#endif
+ if (!context) return 0;
+
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUSurfaceDescriptor.label, '*') }}};
+ if (labelPtr) context.surfaceLabelWebGPU = UTF8ToString(labelPtr);
+
+ return WebGPU.mgrSurface.create(context);
+ },
+
+ wgpuInstanceHasWGSLLanguageFeature: (instance, featureEnumValue) => {
+ if (!('wgslLanguageFeatures' in navigator["gpu"])) {
+ return false;
+ }
+ return navigator["gpu"]["wgslLanguageFeatures"].has(WebGPU.WGSLFeatureName[featureEnumValue]);
+ },
+
+ wgpuInstanceProcessEvents: (instance) => {
+ // TODO: This could probably be emulated with ASYNCIFY.
+#if ASSERTIONS
+ abort('wgpuInstanceProcessEvents is unsupported (use requestAnimationFrame via html5.h instead)');
+#endif
+ },
+
+ wgpuInstanceRequestAdapter__deps: ['$callUserCallback', '$stringToUTF8OnStack'],
+ wgpuInstanceRequestAdapter: (instanceId, options, callback, userdata) => {
+ {{{ gpu.makeCheck('instanceId === 1, "WGPUInstance must be created by wgpuCreateInstance"') }}}
+
+ var opts;
+ if (options) {
+ {{{ gpu.makeCheckDescriptor('options') }}}
+ opts = {
+ "powerPreference": WebGPU.PowerPreference[
+ {{{ gpu.makeGetU32('options', C_STRUCTS.WGPURequestAdapterOptions.powerPreference) }}}],
+ "forceFallbackAdapter":
+ {{{ gpu.makeGetBool('options', C_STRUCTS.WGPURequestAdapterOptions.forceFallbackAdapter) }}},
+ };
+ }
+
+ if (!('gpu' in navigator)) {
+ var sp = stackSave();
+ var messagePtr = stringToUTF8OnStack('WebGPU not available on this browser (navigator.gpu is not available)');
+ {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.RequestAdapterStatus.Unavailable }}}, 0, messagePtr, userdata);
+ stackRestore(sp);
+ return;
+ }
+
+ {{{ runtimeKeepalivePush() }}}
+ navigator["gpu"]["requestAdapter"](opts).then((adapter) => {
+ {{{ runtimeKeepalivePop() }}}
+ callUserCallback(() => {
+ if (adapter) {
+ var adapterId = WebGPU.mgrAdapter.create(adapter);
+ {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.RequestAdapterStatus.Success }}}, adapterId, 0, userdata);
+ } else {
+ var sp = stackSave();
+ var messagePtr = stringToUTF8OnStack('WebGPU not available on this system (requestAdapter returned null)');
+ {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.RequestAdapterStatus.Unavailable }}}, 0, messagePtr, userdata);
+ stackRestore(sp);
+ }
+ });
+ }, (ex) => {
+ {{{ runtimeKeepalivePop() }}}
+ callUserCallback(() => {
+ var sp = stackSave();
+ var messagePtr = stringToUTF8OnStack(ex.message);
+ {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.RequestAdapterStatus.Error }}}, 0, messagePtr, userdata);
+ stackRestore(sp);
+ });
+ });
+ },
+
+ // WGPUAdapter
+
+ wgpuAdapterEnumerateFeatures: (adapterId, featuresOutPtr) => {
+ var adapter = WebGPU.mgrAdapter.get(adapterId);
+ if (featuresOutPtr !== 0) {
+ var offset = 0;
+ adapter.features.forEach(feature => {
+ var featureEnumValue = WebGPU.FeatureNameString2Enum[feature];
+ {{{ makeSetValue('featuresOutPtr', 'offset', 'featureEnumValue', 'i32') }}};
+ offset += 4;
+ });
+ }
+ return adapter.features.size;
+ },
+
+ wgpuAdapterGetInfo__deps: ['$stringToNewUTF8'],
+ wgpuAdapterGetInfo: (adapterId, info) => {
+ var adapter = WebGPU.mgrAdapter.get(adapterId);
+ {{{ gpu.makeCheckDescriptor('info') }}}
+
+ var vendorPtr = stringToNewUTF8(adapter.info.vendor);
+ {{{ makeSetValue('info', C_STRUCTS.WGPUAdapterInfo.vendor, 'vendorPtr', '*') }}};
+ var architecturePtr = stringToNewUTF8(adapter.info.architecture);
+ {{{ makeSetValue('info', C_STRUCTS.WGPUAdapterInfo.architecture, 'architecturePtr', '*') }}};
+ var devicePtr = stringToNewUTF8(adapter.info.device);
+ {{{ makeSetValue('info', C_STRUCTS.WGPUAdapterInfo.device, 'devicePtr', '*') }}};
+ var descriptionPtr = stringToNewUTF8(adapter.info.description);
+ {{{ makeSetValue('info', C_STRUCTS.WGPUAdapterInfo.description, 'descriptionPtr', '*') }}};
+ {{{ makeSetValue('info', C_STRUCTS.WGPUAdapterInfo.backendType, gpu.BackendType.WebGPU, 'i32') }}};
+ var adapterType = adapter.isFallbackAdapter ? {{{ gpu.AdapterType.CPU }}} : {{{ gpu.AdapterType.Unknown }}};
+ {{{ makeSetValue('info', C_STRUCTS.WGPUAdapterInfo.adapterType, 'adapterType', 'i32') }}};
+ {{{ makeSetValue('info', C_STRUCTS.WGPUAdapterInfo.vendorID, '0', 'i32') }}};
+ {{{ makeSetValue('info', C_STRUCTS.WGPUAdapterInfo.deviceID, '0', 'i32') }}};
+ },
+
+ wgpuAdapterGetProperties__deps: ['$warnOnce'],
+ wgpuAdapterGetProperties: (adapterId, properties) => {
+ warnOnce('wgpuAdapterGetProperties is deprecated, use wgpuAdapterGetInfo instead');
+
+ {{{ gpu.makeCheckDescriptor('properties') }}}
+ {{{ makeSetValue('properties', C_STRUCTS.WGPUAdapterProperties.vendorID, '0', 'i32') }}};
+ {{{ makeSetValue('properties', C_STRUCTS.WGPUAdapterProperties.vendorName, '0', 'i32') }}};
+ {{{ makeSetValue('properties', C_STRUCTS.WGPUAdapterProperties.architecture, '0', 'i32') }}};
+ {{{ makeSetValue('properties', C_STRUCTS.WGPUAdapterProperties.deviceID, '0', 'i32') }}};
+ {{{ makeSetValue('properties', C_STRUCTS.WGPUAdapterProperties.name, '0', 'i32') }}};
+ {{{ makeSetValue('properties', C_STRUCTS.WGPUAdapterProperties.driverDescription, '0', 'i32') }}};
+ {{{ makeSetValue('properties', C_STRUCTS.WGPUAdapterProperties.adapterType, gpu.AdapterType.Unknown, 'i32') }}};
+ {{{ makeSetValue('properties', C_STRUCTS.WGPUAdapterProperties.backendType, gpu.BackendType.WebGPU, 'i32') }}};
+ {{{ makeSetValue('properties', C_STRUCTS.WGPUAdapterProperties.compatibilityMode, '0', 'i32') }}};
+ },
+
+ wgpuAdapterGetLimits: (adapterId, limitsOutPtr) => {
+ var adapter = WebGPU.mgrAdapter.get(adapterId);
+ WebGPU.fillLimitStruct(adapter.limits, limitsOutPtr);
+ return 1;
+ },
+
+ wgpuAdapterHasFeature: (adapterId, featureEnumValue) => {
+ var adapter = WebGPU.mgrAdapter.get(adapterId);
+ return adapter.features.has(WebGPU.FeatureName[featureEnumValue]);
+ },
+
+ wgpuAdapterRequestDevice__deps: ['$callUserCallback', '$stringToUTF8OnStack'],
+ wgpuAdapterRequestDevice: (adapterId, descriptor, callback, userdata) => {
+ var adapter = WebGPU.mgrAdapter.get(adapterId);
+
+ var desc = {};
+ if (descriptor) {
+ {{{ gpu.makeCheckDescriptor('descriptor') }}}
+ var requiredFeatureCount = {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUDeviceDescriptor.requiredFeatureCount) }}};
+ if (requiredFeatureCount) {
+ var requiredFeaturesPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUDeviceDescriptor.requiredFeatures, '*') }}};
+ desc["requiredFeatures"] = Array.from({{{ makeHEAPView('32', 'requiredFeaturesPtr', `requiredFeaturesPtr + requiredFeatureCount * ${POINTER_SIZE}`) }}},
+ (feature) => WebGPU.FeatureName[feature]);
+ }
+ var requiredLimitsPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUDeviceDescriptor.requiredLimits, '*') }}};
+ if (requiredLimitsPtr) {
+ {{{ gpu.makeCheckDescriptor('requiredLimitsPtr') }}}
+ var limitsPtr = requiredLimitsPtr + {{{ C_STRUCTS.WGPURequiredLimits.limits }}};
+ var requiredLimits = {};
+ function setLimitU32IfDefined(name, limitOffset) {
+ var ptr = limitsPtr + limitOffset;
+ var value = {{{ gpu.makeGetU32('ptr', 0) }}};
+ if (value != {{{ gpu.LIMIT_U32_UNDEFINED }}}) {
+ requiredLimits[name] = value;
+ }
+ }
+ function setLimitU64IfDefined(name, limitOffset) {
+ var ptr = limitsPtr + limitOffset;
+ // Handle WGPU_LIMIT_U64_UNDEFINED.
+ var limitPart1 = {{{ gpu.makeGetU32('ptr', 0) }}};
+ var limitPart2 = {{{ gpu.makeGetU32('ptr', 4) }}};
+ if (limitPart1 != 0xFFFFFFFF || limitPart2 != 0xFFFFFFFF) {
+ requiredLimits[name] = {{{ gpu.makeGetU64('ptr', 0) }}}
+ }
+ }
+
+ setLimitU32IfDefined("maxTextureDimension1D", {{{ C_STRUCTS.WGPULimits.maxTextureDimension1D }}});
+ setLimitU32IfDefined("maxTextureDimension2D", {{{ C_STRUCTS.WGPULimits.maxTextureDimension2D }}});
+ setLimitU32IfDefined("maxTextureDimension3D", {{{ C_STRUCTS.WGPULimits.maxTextureDimension3D }}});
+ setLimitU32IfDefined("maxTextureArrayLayers", {{{ C_STRUCTS.WGPULimits.maxTextureArrayLayers }}});
+ setLimitU32IfDefined("maxBindGroups", {{{ C_STRUCTS.WGPULimits.maxBindGroups }}});
+ setLimitU32IfDefined('maxBindGroupsPlusVertexBuffers', {{{ C_STRUCTS.WGPULimits.maxBindGroupsPlusVertexBuffers }}});
+ setLimitU32IfDefined("maxDynamicUniformBuffersPerPipelineLayout", {{{ C_STRUCTS.WGPULimits.maxDynamicUniformBuffersPerPipelineLayout }}});
+ setLimitU32IfDefined("maxDynamicStorageBuffersPerPipelineLayout", {{{ C_STRUCTS.WGPULimits.maxDynamicStorageBuffersPerPipelineLayout }}});
+ setLimitU32IfDefined("maxSampledTexturesPerShaderStage", {{{ C_STRUCTS.WGPULimits.maxSampledTexturesPerShaderStage }}});
+ setLimitU32IfDefined("maxSamplersPerShaderStage", {{{ C_STRUCTS.WGPULimits.maxSamplersPerShaderStage }}});
+ setLimitU32IfDefined("maxStorageBuffersPerShaderStage", {{{ C_STRUCTS.WGPULimits.maxStorageBuffersPerShaderStage }}});
+ setLimitU32IfDefined("maxStorageTexturesPerShaderStage", {{{ C_STRUCTS.WGPULimits.maxStorageTexturesPerShaderStage }}});
+ setLimitU32IfDefined("maxUniformBuffersPerShaderStage", {{{ C_STRUCTS.WGPULimits.maxUniformBuffersPerShaderStage }}});
+ setLimitU32IfDefined("minUniformBufferOffsetAlignment", {{{ C_STRUCTS.WGPULimits.minUniformBufferOffsetAlignment }}});
+ setLimitU32IfDefined("minStorageBufferOffsetAlignment", {{{ C_STRUCTS.WGPULimits.minStorageBufferOffsetAlignment }}});
+ setLimitU64IfDefined("maxUniformBufferBindingSize", {{{ C_STRUCTS.WGPULimits.maxUniformBufferBindingSize }}});
+ setLimitU64IfDefined("maxStorageBufferBindingSize", {{{ C_STRUCTS.WGPULimits.maxStorageBufferBindingSize }}});
+ setLimitU32IfDefined("maxVertexBuffers", {{{ C_STRUCTS.WGPULimits.maxVertexBuffers }}});
+ setLimitU32IfDefined("maxBufferSize", {{{ C_STRUCTS.WGPULimits.maxBufferSize }}});
+ setLimitU32IfDefined("maxVertexAttributes", {{{ C_STRUCTS.WGPULimits.maxVertexAttributes }}});
+ setLimitU32IfDefined("maxVertexBufferArrayStride", {{{ C_STRUCTS.WGPULimits.maxVertexBufferArrayStride }}});
+ setLimitU32IfDefined("maxInterStageShaderComponents", {{{ C_STRUCTS.WGPULimits.maxInterStageShaderComponents }}});
+ setLimitU32IfDefined("maxInterStageShaderVariables", {{{ C_STRUCTS.WGPULimits.maxInterStageShaderVariables }}});
+ setLimitU32IfDefined("maxColorAttachments", {{{ C_STRUCTS.WGPULimits.maxColorAttachments }}});
+ setLimitU32IfDefined("maxColorAttachmentBytesPerSample", {{{ C_STRUCTS.WGPULimits.maxColorAttachmentBytesPerSample }}});
+ setLimitU32IfDefined("maxComputeWorkgroupStorageSize", {{{ C_STRUCTS.WGPULimits.maxComputeWorkgroupStorageSize }}});
+ setLimitU32IfDefined("maxComputeInvocationsPerWorkgroup", {{{ C_STRUCTS.WGPULimits.maxComputeInvocationsPerWorkgroup }}});
+ setLimitU32IfDefined("maxComputeWorkgroupSizeX", {{{ C_STRUCTS.WGPULimits.maxComputeWorkgroupSizeX }}});
+ setLimitU32IfDefined("maxComputeWorkgroupSizeY", {{{ C_STRUCTS.WGPULimits.maxComputeWorkgroupSizeY }}});
+ setLimitU32IfDefined("maxComputeWorkgroupSizeZ", {{{ C_STRUCTS.WGPULimits.maxComputeWorkgroupSizeZ }}});
+ setLimitU32IfDefined("maxComputeWorkgroupsPerDimension", {{{ C_STRUCTS.WGPULimits.maxComputeWorkgroupsPerDimension }}});
+ desc["requiredLimits"] = requiredLimits;
+ }
+
+ var defaultQueuePtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUDeviceDescriptor.defaultQueue, '*') }}};
+ if (defaultQueuePtr) {
+ var defaultQueueDesc = {};
+ var labelPtr = {{{ makeGetValue('defaultQueuePtr', C_STRUCTS.WGPUQueueDescriptor.label, '*') }}};
+ if (labelPtr) defaultQueueDesc["label"] = UTF8ToString(labelPtr);
+ desc["defaultQueue"] = defaultQueueDesc;
+ }
+
+ var deviceLostCallbackPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUDeviceDescriptor.deviceLostCallback, '*') }}};
+ var deviceLostUserdataPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUDeviceDescriptor.deviceLostUserdata, '*') }}};
+
+ var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUDeviceDescriptor.label, '*') }}};
+ if (labelPtr) desc["label"] = UTF8ToString(labelPtr);
+ }
+
+ {{{ runtimeKeepalivePush() }}}
+ adapter.requestDevice(desc).then((device) => {
+ {{{ runtimeKeepalivePop() }}}
+ callUserCallback(() => {
+ var deviceWrapper = { queueId: WebGPU.mgrQueue.create(device.queue) };
+ var deviceId = WebGPU.mgrDevice.create(device, deviceWrapper);
+ if (deviceLostCallbackPtr) {
+ device.lost.then((info) => {
+ callUserCallback(() => WebGPU.errorCallback(deviceLostCallbackPtr,
+ WebGPU.Int_DeviceLostReason[info.reason], info.message, deviceLostUserdataPtr));
+ });
+ }
+ {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.RequestDeviceStatus.Success }}}, deviceId, 0, userdata);
+ });
+ }, function(ex) {
+ {{{ runtimeKeepalivePop() }}}
+ callUserCallback(() => {
+ var sp = stackSave();
+ var messagePtr = stringToUTF8OnStack(ex.message);
+ {{{ makeDynCall('vippp', 'callback') }}}({{{ gpu.RequestDeviceStatus.Error }}}, 0, messagePtr, userdata);
+ stackRestore(sp);
+ });
+ });
+ },
+
+ // WGPUAdapterProperties
+
+ wgpuAdapterPropertiesFreeMembers: (value) => {
+ // wgpuAdapterGetProperties doesn't currently allocate anything.
+ },
+
+ // WGPUSampler
+
+ wgpuSamplerSetLabel: (samplerId, labelPtr) => {
+ var sampler = WebGPU.mgrSampler.get(samplerId);
+ sampler.label = UTF8ToString(labelPtr);
+ },
+
+ // WGPUSurface
+
+ wgpuSurfaceConfigure: (surfaceId, config) => {
+ {{{ gpu.makeCheckDescriptor('config') }}}
+ var deviceId = {{{ makeGetValue('config', C_STRUCTS.WGPUSurfaceConfiguration.device, '*') }}};
+ var context = WebGPU.mgrSurface.get(surfaceId);
+
+#if ASSERTIONS
+ var viewFormatCount = {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.viewFormatCount) }}};
+ var viewFormats = {{{ makeGetValue('config', C_STRUCTS.WGPUSurfaceConfiguration.viewFormats, '*') }}};
+ assert(viewFormatCount === 0 && viewFormats === 0, "TODO: Support viewFormats.");
+ var alphaMode = {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.alphaMode) }}};
+ assert(alphaMode === {{{ gpu.CompositeAlphaMode.Auto }}} ||
+ alphaMode === {{{ gpu.CompositeAlphaMode.Opaque }}},
+ "TODO: Support WGPUCompositeAlphaMode_Premultiplied.");
+ assert({{{ gpu.PresentMode.Fifo }}} ===
+ {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.presentMode) }}});
+#endif
+
+ var canvasSize = [
+ {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.width) }}},
+ {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.height) }}}
+ ];
+
+ if (canvasSize[0] !== 0) {
+ context["canvas"]["width"] = canvasSize[0];
+ }
+
+ if (canvasSize[1] !== 0) {
+ context["canvas"]["height"] = canvasSize[1];
+ }
+
+ var configuration = {
+ "device": WebGPU.mgrDevice.get(deviceId),
+ "format": WebGPU.TextureFormat[
+ {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.format) }}}],
+ "usage": {{{ gpu.makeGetU32('config', C_STRUCTS.WGPUSurfaceConfiguration.usage) }}},
+ "alphaMode": "opaque",
+ };
+ context.configure(configuration);
+ },
+
+ wgpuSurfaceGetCurrentTexture: (surfaceId, surfaceTexturePtr) => {
+ {{{ gpu.makeCheck('surfaceTexturePtr') }}}
+ var context = WebGPU.mgrSurface.get(surfaceId);
+
+ try {
+ var texture = WebGPU.mgrTexture.create(context.getCurrentTexture());
+ {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.texture, 'texture', '*') }}};
+ {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.suboptimal, '0', 'i32') }}};
+ {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.status,
+ gpu.SurfaceGetCurrentTextureStatus.Success, 'i32') }}};
+ } catch (ex) {
+#if ASSERTIONS
+ err(`wgpuSurfaceGetCurrentTexture() failed: ${ex}`);
+#endif
+ {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.texture, '0', '*') }}};
+ {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.suboptimal, '0', 'i32') }}};
+ // TODO(https://github.com/webgpu-native/webgpu-headers/issues/291): What should the status be here?
+ {{{ makeSetValue('surfaceTexturePtr', C_STRUCTS.WGPUSurfaceTexture.status,
+ gpu.SurfaceGetCurrentTextureStatus.DeviceLost, 'i32') }}};
+ }
+ },
+
+ wgpuSurfaceGetPreferredFormat: (surfaceId, adapterId) => {
+ var format = navigator["gpu"]["getPreferredCanvasFormat"]();
+ return WebGPU.Int_PreferredFormat[format];
+ },
+
+ wgpuSurfacePresent: (surfaceId) => {
+ // TODO: This could probably be emulated with ASYNCIFY.
+ abort('wgpuSurfacePresent is unsupported (use requestAnimationFrame via html5.h instead)');
+ },
+
+ wgpuSurfaceUnconfigure: (surfaceId) => {
+ var context = WebGPU.mgrSurface.get(surfaceId);
+ context.unconfigure();
+ },
+
+ // WGPUSwapChain
+
+ wgpuDeviceCreateSwapChain: (deviceId, surfaceId, descriptor) => {
+ {{{ gpu.makeCheckDescriptor('descriptor') }}}
+ var device = WebGPU.mgrDevice.get(deviceId);
+ var context = WebGPU.mgrSurface.get(surfaceId);
+
+#if ASSERTIONS
+ assert({{{ gpu.PresentMode.Fifo }}} ===
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSwapChainDescriptor.presentMode) }}});
+#endif
+
+ var canvasSize = [
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSwapChainDescriptor.width) }}},
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSwapChainDescriptor.height) }}}
+ ];
+
+ if (canvasSize[0] !== 0) {
+ context["canvas"]["width"] = canvasSize[0];
+ }
+
+ if (canvasSize[1] !== 0) {
+ context["canvas"]["height"] = canvasSize[1];
+ }
+
+ var configuration = {
+ "device": device,
+ "format": WebGPU.TextureFormat[
+ {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSwapChainDescriptor.format) }}}],
+ "usage": {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSwapChainDescriptor.usage) }}},
+ "alphaMode": "opaque",
+ };
+ context.configure(configuration);
+
+ return WebGPU.mgrSwapChain.create(context);
+ },
+
+ wgpuSwapChainGetCurrentTexture: (swapChainId) => {
+ var context = WebGPU.mgrSwapChain.get(swapChainId);
+ return WebGPU.mgrTexture.create(context.getCurrentTexture());
+ },
+ wgpuSwapChainGetCurrentTextureView: (swapChainId) => {
+ var context = WebGPU.mgrSwapChain.get(swapChainId);
+ return WebGPU.mgrTextureView.create(context.getCurrentTexture().createView());
+ },
+ wgpuSwapChainPresent: (swapChainId) => {
+ // TODO: This could probably be emulated with ASYNCIFY.
+ abort('wgpuSwapChainPresent is unsupported (use requestAnimationFrame via html5.h instead)');
+ },
+};
+
+// Inverted index used by EnumerateFeatures/HasFeature
+LibraryWebGPU.$WebGPU.FeatureNameString2Enum = {};
+for (var value in LibraryWebGPU.$WebGPU.FeatureName) {
+ LibraryWebGPU.$WebGPU.FeatureNameString2Enum[LibraryWebGPU.$WebGPU.FeatureName[value]] = value;
+}
+
+for (const key of Object.keys(LibraryWebGPU)) {
+ if (typeof LibraryWebGPU[key] === 'function') {
+ LibraryWebGPU[key + '__i53abi'] = true;
+ }
+}
+
+autoAddDeps(LibraryWebGPU, '$WebGPU');
+addToLibrary(LibraryWebGPU);
diff --git a/third_party/emdawnwebgpu/webgpu.cpp b/third_party/emdawnwebgpu/webgpu.cpp
new file mode 100644
index 0000000..e65fbe2
--- /dev/null
+++ b/third_party/emdawnwebgpu/webgpu.cpp
@@ -0,0 +1,93 @@
+// Copyright 2024 The Emscripten Authors. All rights reserved.
+// Emscripten is available under two separate licenses, the MIT license and the
+// University of Illinois/NCSA Open Source License. Both these licenses can be
+// found in the LICENSE file.
+
+//
+// This file and library_webgpu.js together implement <webgpu/webgpu.h>.
+//
+
+#include <webgpu/webgpu.h>
+
+#include <array>
+#include <cstdlib>
+#include <cassert>
+
+//
+// WebGPU function definitions, with methods organized by "class". Note these
+// don't need to be extern "C" because they are already declared in webgpu.h.
+//
+
+// Standalone (non-method) functions
+
+WGPUInstance wgpuCreateInstance(const WGPUInstanceDescriptor* descriptor) {
+ assert(descriptor == nullptr); // descriptor not implemented yet
+ return reinterpret_cast<WGPUInstance>(1);
+}
+
+// Instance
+
+void wgpuInstanceReference(WGPUInstance) { /* no-op for now */ }
+void wgpuInstanceRelease(WGPUInstance) { /* no-op for now */ }
+
+// WGPUSurface
+
+void wgpuSurfaceGetCapabilities(WGPUSurface surface,
+ WGPUAdapter adapter,
+ WGPUSurfaceCapabilities* capabilities) {
+ assert(capabilities->nextInChain == nullptr); // TODO: Return WGPUStatus_Error
+
+ static constexpr std::array<WGPUTextureFormat, 3> kSurfaceFormatsRGBAFirst = {
+ WGPUTextureFormat_RGBA8Unorm,
+ WGPUTextureFormat_BGRA8Unorm,
+ WGPUTextureFormat_RGBA16Float,
+ };
+ static constexpr std::array<WGPUTextureFormat, 3> kSurfaceFormatsBGRAFirst = {
+ WGPUTextureFormat_BGRA8Unorm,
+ WGPUTextureFormat_RGBA8Unorm,
+ WGPUTextureFormat_RGBA16Float,
+ };
+ WGPUTextureFormat preferredFormat = wgpuSurfaceGetPreferredFormat(surface, adapter);
+ switch (preferredFormat) {
+ case WGPUTextureFormat_RGBA8Unorm:
+ capabilities->formatCount = kSurfaceFormatsRGBAFirst.size();
+ capabilities->formats = kSurfaceFormatsRGBAFirst.data();
+ break;
+ case WGPUTextureFormat_BGRA8Unorm:
+ capabilities->formatCount = kSurfaceFormatsBGRAFirst.size();
+ capabilities->formats = kSurfaceFormatsBGRAFirst.data();
+ break;
+ default:
+ assert(false);
+ }
+
+ {
+ static constexpr WGPUPresentMode kPresentMode = WGPUPresentMode_Fifo;
+ capabilities->presentModeCount = 1;
+ capabilities->presentModes = &kPresentMode;
+ }
+
+ {
+ static constexpr std::array<WGPUCompositeAlphaMode, 2> kAlphaModes = {
+ WGPUCompositeAlphaMode_Opaque,
+ WGPUCompositeAlphaMode_Premultiplied,
+ };
+ capabilities->alphaModeCount = kAlphaModes.size();
+ capabilities->alphaModes = kAlphaModes.data();
+ }
+};
+
+// WGPUSurfaceCapabilities
+
+void wgpuSurfaceCapabilitiesFreeMembers(WGPUSurfaceCapabilities value) {
+ // wgpuSurfaceCapabilities doesn't currently allocate anything.
+}
+
+// WGPUAdapterInfo
+
+void wgpuAdapterInfoFreeMembers(WGPUAdapterInfo value) {
+ free(const_cast<char *>(value.vendor));
+ free(const_cast<char *>(value.architecture));
+ free(const_cast<char *>(value.device));
+ free(const_cast<char *>(value.description));
+}