| /** |
| * @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: |
| * - tests/runner.py other.test_webgpu_compiletest |
| * - EMTEST_BROWSERS="/path/to/chrome --user-data-dir=chromeuserdata --enable-unsafe-webgpu" \ |
| * tests/runner.py browser.test_webgpu_basic_rendering |
| * (requires WebGPU to be available - otherwise the test will skip itself and pass) |
| */ |
| |
| {{{ (function() { |
| // Helper functions for code generation |
| global.gpu = { |
| makeInitManager: function(type) { |
| var mgr = 'WebGPU.mgr' + type |
| return mgr + ' = ' + mgr + ' || new Manager();'; |
| }, |
| |
| makeReferenceRelease: function(type) { |
| var s = ''; |
| s += 'wgpu' + type + 'Reference: function(id) {\n'; |
| s += ' WebGPU.mgr' + type + '.reference(id);\n' |
| s += '},\n'; |
| s += 'wgpu' + type + 'Release: function(id) {\n'; |
| s += ' WebGPU.mgr' + type + '.release(id);\n' |
| s += '},'; |
| return s; |
| }, |
| |
| makeU64ToNumber: function(lowName, highName) { |
| var ret = '('; |
| if (ASSERTIONS) { |
| ret += `assert(${highName} < 0x200000), `; |
| } |
| ret += `${highName} * 0x100000000 + ${lowName})\n`; |
| return ret; |
| }, |
| |
| makeU64ToNumberWithSentinelAsUndefined: function(lowName, highName) { |
| var ret = `((${highName} === -1 && ${lowName} === -1) ? undefined : \ |
| ${this.makeU64ToNumber(lowName, highName)})`; |
| return ret; |
| }, |
| |
| makeGetBool: function(struct, offset) { |
| // In an actual build, bool seems to be i8. But on the off-chance it's i32, on little-endian |
| // this will still work as long as the value of 'true' isn't zero in the lowest byte. |
| return '(' + makeGetValue(struct, offset, 'i8') + ' !== 0)'; |
| }, |
| 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'); |
| }, |
| |
| // Must be in sync with webgpu.h. |
| COPY_STRIDE_UNDEFINED: 0xFFFFFFFF, |
| LIMIT_U32_UNDEFINED: 0xFFFFFFFF, |
| WHOLE_MAP_SIZE: 0xFFFFFFFF, // use 32-bit uint max |
| MIP_LEVEL_COUNT_UNDEFINED: 0xFFFFFFFF, |
| ARRAY_LAYER_COUNT_UNDEFINED: 0xFFFFFFFF, |
| AdapterType: { |
| Unknown: 3, |
| }, |
| BackendType: { |
| WebGPU: 1, |
| }, |
| BufferMapAsyncStatus: { |
| Success: 0, |
| Error: 1, |
| }, |
| ErrorType: { |
| NoError: 0, |
| Validation: 1, |
| OutOfMemory: 2, |
| Unknown: 3, |
| }, |
| PresentMode: { |
| Fifo: 2, |
| }, |
| 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, |
| }, |
| RequestDeviceStatus: { |
| Success: 0, |
| Error: 1, |
| }, |
| SType: { |
| SurfaceDescriptorFromCanvasHTMLSelector: 4, |
| ShaderModuleSPIRVDescriptor: 5, |
| ShaderModuleWGSLDescriptor: 6, |
| }, |
| QueueWorkDoneStatus: { |
| Success: 0, |
| Error: 1, |
| }, |
| TextureFormat: { |
| Undefined: 0, |
| }, |
| }; |
| return null; |
| })(); }}} |
| |
| var LibraryWebGPU = { |
| $WebGPU__postset: 'WebGPU.initManagers();', |
| $WebGPU: { |
| initManagers: function() { |
| if (WebGPU.mgrDevice) return; |
| |
| /** @constructor */ |
| function Manager() { |
| this.objects = {}; |
| this.nextId = 1; |
| this.create = function(object, wrapper /* = {} */) { |
| wrapper = 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: function(ptr) { |
| return { |
| "r": {{{ makeGetValue('ptr', 0, 'double') }}}, |
| "g": {{{ makeGetValue('ptr', 8, 'double') }}}, |
| "b": {{{ makeGetValue('ptr', 16, 'double') }}}, |
| "a": {{{ makeGetValue('ptr', 24, 'double') }}}, |
| }; |
| }, |
| |
| makeExtent3D: function(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: function(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: function(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: function(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: function(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: function(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; |
| }, |
| |
| makeProgrammableStageDescriptor: function(ptr) { |
| if (!ptr) return undefined; |
| {{{ gpu.makeCheckDescriptor('ptr') }}} |
| return { |
| "module": WebGPU.mgrShaderModule.get( |
| {{{ makeGetValue('ptr', C_STRUCTS.WGPUProgrammableStageDescriptor.module, '*') }}}), |
| "entryPoint": UTF8ToString( |
| {{{ makeGetValue('ptr', C_STRUCTS.WGPUProgrammableStageDescriptor.entryPoint, '*') }}}), |
| "constants": WebGPU.makePipelineConstants( |
| {{{ gpu.makeGetU32('ptr', C_STRUCTS.WGPUProgrammableStageDescriptor.constantCount) }}}, |
| {{{ makeGetValue('ptr', C_STRUCTS.WGPUProgrammableStageDescriptor.constants, '*') }}}), |
| }; |
| }, |
| |
| // Map from enum string back to enum number, for callbacks. |
| DeviceLostReason: { |
| 'undefined': 0, |
| 'destroyed': 1, |
| }, |
| PreferredFormat: { |
| 'rgba8unorm': 0x12, |
| 'bgra8unorm': 0x17, |
| }, |
| |
| // This section is auto-generated. See system/include/webgpu/README.md for details. |
| AddressMode: [ |
| 'repeat', |
| 'mirror-repeat', |
| 'clamp-to-edge', |
| ], |
| BlendFactor: [ |
| '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: [ |
| 'add', |
| 'subtract', |
| 'reverse-subtract', |
| 'min', |
| 'max', |
| ], |
| BufferBindingType: [ |
| undefined, |
| 'uniform', |
| 'storage', |
| 'read-only-storage', |
| ], |
| CompareFunction: [ |
| undefined, |
| 'never', |
| 'less', |
| 'less-equal', |
| 'greater', |
| 'greater-equal', |
| 'equal', |
| 'not-equal', |
| 'always', |
| ], |
| CompilationInfoRequestStatus: [ |
| 'success', |
| 'error', |
| 'device-lost', |
| 'unknown', |
| ], |
| ComputePassTimestampLocation: [ |
| 'beginning', |
| 'end', |
| ], |
| CullMode: [ |
| 'none', |
| 'front', |
| 'back', |
| ], |
| ErrorFilter: [ |
| 'validation', |
| 'out-of-memory', |
| ], |
| FeatureName: { |
| 0: undefined, |
| 1: 'depth-clip-control', |
| 2: 'depth24unorm-stencil8', |
| 3: 'depth32float-stencil8', |
| 4: 'timestamp-query', |
| 5: 'pipeline-statistics-query', |
| 6: 'texture-compression-bc', |
| 7: 'texture-compression-etc2', |
| 8: 'texture-compression-astc', |
| 9: 'indirect-first-instance', |
| 1000: 'depth-clamping', |
| }, |
| FilterMode: [ |
| 'nearest', |
| 'linear', |
| ], |
| FrontFace: [ |
| 'ccw', |
| 'cw', |
| ], |
| IndexFormat: [ |
| undefined, |
| 'uint16', |
| 'uint32', |
| ], |
| LoadOp: [ |
| undefined, |
| 'clear', |
| 'load', |
| ], |
| PipelineStatisticName: [ |
| 'vertex-shader-invocations', |
| 'clipper-invocations', |
| 'clipper-primitives-out', |
| 'fragment-shader-invocations', |
| 'compute-shader-invocations', |
| ], |
| PowerPreference: [ |
| undefined, |
| 'low-power', |
| 'high-performance', |
| ], |
| PredefinedColorSpace: [ |
| undefined, |
| 'srgb', |
| ], |
| PrimitiveTopology: [ |
| 'point-list', |
| 'line-list', |
| 'line-strip', |
| 'triangle-list', |
| 'triangle-strip', |
| ], |
| QueryType: [ |
| 'occlusion', |
| 'pipeline-statistics', |
| 'timestamp', |
| ], |
| RenderPassTimestampLocation: [ |
| 'beginning', |
| 'end', |
| ], |
| SamplerBindingType: [ |
| undefined, |
| 'filtering', |
| 'non-filtering', |
| 'comparison', |
| ], |
| StencilOperation: [ |
| 'keep', |
| 'zero', |
| 'replace', |
| 'invert', |
| 'increment-clamp', |
| 'decrement-clamp', |
| 'increment-wrap', |
| 'decrement-wrap', |
| ], |
| StorageTextureAccess: [ |
| undefined, |
| 'write-only', |
| ], |
| StoreOp: [ |
| undefined, |
| 'store', |
| 'discard', |
| ], |
| TextureAspect: [ |
| 'all', |
| 'stencil-only', |
| 'depth-only', |
| ], |
| TextureComponentType: [ |
| 'float', |
| 'sint', |
| 'uint', |
| 'depth-comparison', |
| ], |
| TextureDimension: [ |
| '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', |
| 'rgb10a2unorm', |
| 'rg11b10ufloat', |
| 'rgb9e5ufloat', |
| 'rg32float', |
| 'rg32uint', |
| 'rg32sint', |
| 'rgba16uint', |
| 'rgba16sint', |
| 'rgba16float', |
| 'rgba32float', |
| 'rgba32uint', |
| 'rgba32sint', |
| 'stencil8', |
| 'depth16unorm', |
| 'depth24plus', |
| 'depth24plus-stencil8', |
| 'depth24unorm-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', |
| ], |
| VertexStepMode: [ |
| 'vertex', |
| 'instance', |
| ], |
| }, |
| |
| // *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: function(bufferId) { WebGPU.mgrBuffer.get(bufferId)["destroy"](); }, |
| wgpuTextureDestroy: function(textureId) { WebGPU.mgrTexture.get(textureId)["destroy"](); }, |
| wgpuQuerySetDestroy: function(querySetId) { WebGPU.mgrQuerySet.get(querySetId)["destroy"](); }, |
| |
| // wgpuDevice |
| |
| wgpuDeviceEnumerateFeatures: function(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: function(deviceId) { WebGPU.mgrDevice.get(deviceId)["destroy"](); }, |
| |
| wgpuDeviceGetLimits: function(deviceId, limitsOutPtr) { |
| var device = WebGPU.mgrDevice.objects[deviceId].object; |
| var limitsPtr = {{{ C_STRUCTS.WGPUSupportedLimits.limits }}}; |
| function setLimitValueU32(name, limitOffset) { |
| var limitValue = device.limits[name]; |
| {{{ makeSetValue('limitsOutPtr', 'limitsPtr + limitOffset', 'limitValue', 'i32') }}}; |
| } |
| function setLimitValueU64(name, limitOffset) { |
| var limitValue = device.limits[name]; |
| {{{ makeSetValue('limitsOutPtr', 'limitsPtr + 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('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('maxVertexAttributes', {{{ C_STRUCTS.WGPULimits.maxVertexAttributes }}}); |
| setLimitValueU32('maxVertexBufferArrayStride', {{{ C_STRUCTS.WGPULimits.maxVertexBufferArrayStride }}}); |
| setLimitValueU32('maxInterStageShaderComponents', {{{ C_STRUCTS.WGPULimits.maxInterStageShaderComponents }}}); |
| 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 }}}); |
| }, |
| |
| wgpuDeviceGetQueue: function(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: function(deviceId, featureEnumValue) { |
| var device = WebGPU.mgrDevice.get(deviceId); |
| return device.features.has(WebGPU.FeatureName[featureEnumValue]); |
| }, |
| |
| wgpuDevicePushErrorScope: function(deviceId, filter) { |
| var device = WebGPU.mgrDevice.get(deviceId); |
| device["pushErrorScope"](WebGPU.ErrorFilter[filter]); |
| }, |
| |
| wgpuDevicePopErrorScope__deps: ['$callUserCallback', '$allocateUTF8'], |
| wgpuDevicePopErrorScope: function(deviceId, callback, userdata) { |
| var device = WebGPU.mgrDevice.get(deviceId); |
| {{{ runtimeKeepalivePush() }}} |
| device["popErrorScope"]().then(function(gpuError) { |
| {{{ runtimeKeepalivePop() }}} |
| callUserCallback(function() { |
| if (!gpuError) { |
| {{{ makeDynCall('viii', 'callback') }}}( |
| {{{ gpu.ErrorType.NoError }}}, 0, userdata); |
| } else if (gpuError instanceof GPUOutOfMemoryError) { |
| {{{ makeDynCall('viii', 'callback') }}}( |
| {{{ gpu.ErrorType.OutOfMemory }}}, 0, userdata); |
| } else { |
| #if ASSERTIONS |
| assert(gpuError instanceof GPUValidationError); |
| #endif |
| var messagePtr = allocateUTF8(gpuError.message); |
| {{{ makeDynCall('viii', 'callback') }}}({{{ gpu.ErrorType.Validation }}}, messagePtr, userdata); |
| _free(messagePtr); |
| } |
| }); |
| }, function(ex) { |
| {{{ runtimeKeepalivePop() }}} |
| callUserCallback(function() { |
| var messagePtr = allocateUTF8(ex.message); |
| // 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.) |
| {{{ makeDynCall('viii', 'callback') }}}({{{ gpu.ErrorType.Unknown }}}, messagePtr, userdata); |
| _free(messagePtr); |
| }); |
| }); |
| }, |
| |
| wgpuDeviceSetLabel: function(deviceId, labelPtr) { |
| var device = WebGPU.mgrDevice.get(deviceId); |
| device.label = UTF8ToString(labelPtr); |
| }, |
| |
| wgpuDeviceSetDeviceLostCallback__deps: ['$callUserCallback', '$allocateUTF8'], |
| wgpuDeviceSetDeviceLostCallback: function(deviceId, callback, userdata) { |
| var deviceWrapper = WebGPU.mgrDevice.objects[deviceId]; |
| {{{ gpu.makeCheckDefined('deviceWrapper') }}} |
| if (!deviceWrapper.lostCallback) { |
| // device.lost hasn't been registered yet - register it. |
| deviceWrapper.object["lost"].then(function(info) { |
| deviceWrapper.lostCallback(info); |
| }); |
| } |
| deviceWrapper.lostCallback = function(info) { |
| // This will skip the callback if the runtime is no longer alive. |
| callUserCallback(function() { |
| var messagePtr = allocateUTF8(info.message); |
| {{{ makeDynCall('viii', 'callback') }}}(WebGPU.DeviceLostReason[info.reason], messagePtr, userdata); |
| _free(messagePtr); |
| }); |
| }; |
| }, |
| |
| wgpuDeviceSetUncapturedErrorCallback__deps: ['$callUserCallback', '$allocateUTF8'], |
| wgpuDeviceSetUncapturedErrorCallback: function(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(function() { |
| // 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; |
| |
| var messagePtr = allocateUTF8(ev.error.message); |
| {{{ makeDynCall('viii', 'callback') }}}(type, messagePtr, userdata); |
| _free(messagePtr); |
| }); |
| }; |
| }, |
| |
| // wgpuDeviceCreate* |
| |
| wgpuDeviceCreateCommandEncoder: function(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: function(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: function(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, '*') }}}; |
| desc["viewFormats"] = Array.from(HEAP32.subarray(viewFormatsPtr >> 2, (viewFormatsPtr >> 2) + viewFormatCount), |
| function(format) { return WebGPU.TextureFormat[format]; }); |
| } |
| |
| var device = WebGPU.mgrDevice.get(deviceId); |
| return WebGPU.mgrTexture.create(device["createTexture"](desc)); |
| }, |
| |
| wgpuDeviceCreateSampler: function(deviceId, descriptor) { |
| {{{ gpu.makeCheckDescriptor('descriptor') }}} |
| |
| var 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.FilterMode[ |
| {{{ 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: function(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: function(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_low = {{{ gpu.makeGetU32('entryPtr', C_STRUCTS.WGPUBindGroupEntry.size) }}}; |
| var size_high = {{{ gpu.makeGetU32('entryPtr', C_STRUCTS.WGPUBindGroupEntry.size + 4) }}}; |
| var size = {{{ gpu.makeU64ToNumberWithSentinelAsUndefined('size_low', 'size_high') }}}; |
| |
| 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: function(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', '4 * 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: function(deviceId, descriptor) { |
| {{{ gpu.makeCheckDescriptor('descriptor') }}} |
| |
| var pipelineStatistics; |
| var pipelineStatisticsCount = |
| {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUQuerySetDescriptor.pipelineStatisticsCount) }}}; |
| if (pipelineStatisticsCount) { |
| var pipelineStatisticsPtr = |
| {{{ makeGetValue('descriptor', C_STRUCTS.WGPUQuerySetDescriptor.pipelineStatistics, '*') }}}; |
| pipelineStatistics = []; |
| for (var i = 0; i < pipelineStatisticsCount; ++i) { |
| pipelineStatistics.push(WebGPU.PipelineStatisticName[ |
| {{{ gpu.makeGetU32('pipelineStatisticsPtr', '4 * i') }}}]); |
| } |
| } |
| |
| var desc = { |
| "type": WebGPU.QueryType[ |
| {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUQuerySetDescriptor.type) }}}], |
| "count": {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUQuerySetDescriptor.count) }}}, |
| "pipelineStatistics": pipelineStatistics, |
| }; |
| |
| var device = WebGPU.mgrDevice.get(deviceId); |
| return WebGPU.mgrQuerySet.create(device["createQuerySet"](desc)); |
| }, |
| |
| wgpuDeviceCreateRenderBundleEncoder: function(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.colorFormatsCount) }}}, |
| {{{ 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)); |
| }, |
| |
| wgpuDeviceCreateComputePipeline: function(deviceId, descriptor) { |
| {{{ gpu.makeCheckDescriptor('descriptor') }}} |
| |
| var desc = { |
| "label": undefined, |
| "layout": WebGPU.mgrPipelineLayout.get( |
| {{{ 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); |
| |
| var device = WebGPU.mgrDevice.get(deviceId); |
| return WebGPU.mgrComputePipeline.create(device["createComputePipeline"](desc)); |
| }, |
| |
| wgpuDeviceCreateComputePipelineAsync: function(deviceId, descriptor, callback, userdata) { |
| abort('TODO: wgpuDeviceCreateComputePipelineAsync unimplemented'); |
| }, |
| |
| wgpuDeviceCreateRenderPipeline: function(deviceId, descriptor) { |
| {{{ gpu.makeCheckDescriptor('descriptor') }}} |
| |
| function makePrimitiveState(rsPtr) { |
| if (!rsPtr) return undefined; |
| {{{ gpu.makeCheckDescriptor('rsPtr') }}} |
| 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) }}}], |
| }; |
| } |
| |
| 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; |
| {{{ gpu.makeCheckDescriptor('bsPtr') }}} |
| 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, '*') }}}, |
| "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; |
| |
| return { |
| "arrayStride": {{{ gpu.makeGetU64('vbPtr', C_STRUCTS.WGPUVertexBufferLayout.arrayStride) }}}, |
| "stepMode": WebGPU.VertexStepMode[ |
| {{{ gpu.makeGetU32('vbPtr', C_STRUCTS.WGPUVertexBufferLayout.stepMode) }}}], |
| "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') }}} |
| return { |
| "module": WebGPU.mgrShaderModule.get( |
| {{{ makeGetValue('viPtr', C_STRUCTS.WGPUVertexState.module, '*') }}}), |
| "entryPoint": UTF8ToString( |
| {{{ makeGetValue('viPtr', C_STRUCTS.WGPUVertexState.entryPoint, '*') }}}), |
| "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, '*') }}}), |
| }; |
| } |
| |
| 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') }}} |
| return { |
| "module": WebGPU.mgrShaderModule.get( |
| {{{ makeGetValue('fsPtr', C_STRUCTS.WGPUFragmentState.module, '*') }}}), |
| "entryPoint": UTF8ToString( |
| {{{ makeGetValue('fsPtr', C_STRUCTS.WGPUFragmentState.entryPoint, '*') }}}), |
| "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 desc = { |
| "label": undefined, |
| "layout": WebGPU.mgrPipelineLayout.get( |
| {{{ 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); |
| |
| var device = WebGPU.mgrDevice.get(deviceId); |
| return WebGPU.mgrRenderPipeline.create(device["createRenderPipeline"](desc)); |
| }, |
| |
| wgpuDeviceCreateRenderPipelineAsync: function(deviceId, descriptor, callback, userdata) { |
| abort('TODO: wgpuDeviceCreateRenderPipelineAsync unimplemented'); |
| }, |
| |
| wgpuDeviceCreateShaderModule: function(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, '*') }}}; |
| #if USE_PTHREADS |
| // Chrome can't currently handle a SharedArrayBuffer view here, so make a copy. |
| desc["code"] = HEAPU32.slice(start >> 2, (start >> 2) + count); |
| #else |
| desc["code"] = HEAPU32.subarray(start >> 2, (start >> 2) + count); |
| #endif |
| break; |
| } |
| case {{{ gpu.SType.ShaderModuleWGSLDescriptor }}}: { |
| var sourcePtr = {{{ makeGetValue('nextInChainPtr', C_STRUCTS.WGPUShaderModuleWGSLDescriptor.source, '*') }}}; |
| 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 |
| |
| wgpuQuerySetSetLabel: function(querySetId, labelPtr) { |
| var querySet = WebGPU.mgrQuerySet.get(querySetId); |
| querySet.label = UTF8ToString(labelPtr); |
| }, |
| |
| // wgpuQueue |
| |
| wgpuQueueSetLabel: function(queueId, labelPtr) { |
| var queue = WebGPU.mgrQueue.get(queueId); |
| queue.label = UTF8ToString(labelPtr); |
| }, |
| |
| wgpuQueueSubmit: function(queueId, commandCount, commands) { |
| #if ASSERTIONS |
| assert(commands % 4 === 0); |
| #endif |
| var queue = WebGPU.mgrQueue.get(queueId); |
| var cmds = Array.from(HEAP32.subarray(commands >> 2, (commands >> 2) + commandCount), |
| function(id) { return WebGPU.mgrCommandBuffer.get(id); }); |
| queue["submit"](cmds); |
| }, |
| |
| wgpuQueueOnSubmittedWorkDone__deps: ['$callUserCallback'], |
| wgpuQueueOnSubmittedWorkDone: function(queueId, {{{ defineI64Param('signalValue') }}}, callback, userdata) { |
| var queue = WebGPU.mgrQueue.get(queueId); |
| #if ASSERTIONS |
| assert(signalValue_low === 0 && signalValue_high === 0, 'signalValue not supported, must be 0'); |
| #endif |
| |
| {{{ runtimeKeepalivePush() }}} |
| queue["onSubmittedWorkDone"]().then(function() { |
| {{{ runtimeKeepalivePop() }}} |
| callUserCallback(function() { |
| {{{ makeDynCall('vii', 'callback') }}}({{{ gpu.QueueWorkDoneStatus.Success }}}, userdata); |
| }); |
| }, function() { |
| {{{ runtimeKeepalivePop() }}} |
| callUserCallback(function() { |
| {{{ makeDynCall('vii', 'callback') }}}({{{ gpu.QueueWorkDoneStatus.Error }}}, userdata); |
| }); |
| }); |
| }, |
| |
| wgpuQueueWriteBuffer: function(queueId, |
| bufferId, {{{ defineI64Param('bufferOffset') }}}, data, size) { |
| {{{ receiveI64ParamAsI32s('bufferOffset') }}} |
| |
| var queue = WebGPU.mgrQueue.get(queueId); |
| var buffer = WebGPU.mgrBuffer.get(bufferId); |
| var bufferOffset = {{{ gpu.makeU64ToNumber('bufferOffset_low', 'bufferOffset_high') }}}; |
| // 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: function(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: function(encoderId, descriptor) { |
| var desc; |
| |
| function makeComputePassTimestampWrite(twPtr) { |
| return { |
| "querySet": WebGPU.mgrQuerySet.get( |
| {{{ makeGetValue('twPtr', C_STRUCTS.WGPUComputePassTimestampWrite.querySet, '*') }}}), |
| "queryIndex": {{{ gpu.makeGetU32('twPtr', C_STRUCTS.WGPUComputePassTimestampWrite.queryIndex) }}}, |
| "location": WebGPU.ComputePassTimestampLocation[ |
| {{{ gpu.makeGetU32('twPtr', C_STRUCTS.WGPUComputePassTimestampWrite.location) }}}], |
| }; |
| } |
| |
| function makeComputePassTimestampWrites(count, twPtr) { |
| var timestampWrites = []; |
| for (var i = 0; i < count; ++i) { |
| timestampWrites.push(makeComputePassTimestampWrite(twPtr + {{{ C_STRUCTS.WGPUComputePassTimestampWrite.__size__ }}} * i)); |
| } |
| return timestampWrites; |
| } |
| |
| if (descriptor) { |
| {{{ gpu.makeCheckDescriptor('descriptor') }}} |
| desc = {}; |
| var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUComputePassDescriptor.label, '*') }}}; |
| if (labelPtr) desc["label"] = UTF8ToString(labelPtr); |
| |
| var timestampWriteCount = {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUComputePassDescriptor.timestampWriteCount) }}}; |
| if (timestampWriteCount) { |
| desc["timestampWrites"] = makeComputePassTimestampWrites( |
| timestampWriteCount, |
| {{{ makeGetValue('descriptor', C_STRUCTS.WGPUComputePassDescriptor.timestampWrites, '*') }}}); |
| } |
| } |
| var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId); |
| return WebGPU.mgrComputePassEncoder.create(commandEncoder["beginComputePass"](desc)); |
| }, |
| |
| wgpuCommandEncoderBeginRenderPass: function(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 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), |
| "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 makeRenderPassTimestampWrite(twPtr) { |
| return { |
| "querySet": WebGPU.mgrQuerySet.get( |
| {{{ makeGetValue('twPtr', C_STRUCTS.WGPURenderPassTimestampWrite.querySet, '*') }}}), |
| "queryIndex": {{{ gpu.makeGetU32('twPtr', C_STRUCTS.WGPURenderPassTimestampWrite.queryIndex) }}}, |
| "location": WebGPU.RenderPassTimestampLocation[ |
| {{{ gpu.makeGetU32('twPtr', C_STRUCTS.WGPURenderPassTimestampWrite.location) }}}], |
| }; |
| } |
| |
| function makeRenderPassTimestampWrites(count, twPtr) { |
| var timestampWrites = []; |
| for (var i = 0; i < count; ++i) { |
| timestampWrites.push(makeRenderPassTimestampWrite(twPtr + {{{ C_STRUCTS.WGPURenderPassTimestampWrite.__size__ }}} * i)); |
| } |
| return timestampWrites; |
| } |
| |
| function makeRenderPassDescriptor(descriptor) { |
| {{{ gpu.makeCheckDescriptor('descriptor') }}} |
| 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, '*') }}}), |
| }; |
| var labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPURenderPassDescriptor.label, '*') }}}; |
| if (labelPtr) desc["label"] = UTF8ToString(labelPtr); |
| |
| var timestampWriteCount = {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPURenderPassDescriptor.timestampWriteCount) }}}; |
| if (timestampWriteCount) { |
| desc["timestampWrites"] = makeRenderPassTimestampWrites( |
| timestampWriteCount, |
| {{{ makeGetValue('descriptor', C_STRUCTS.WGPURenderPassDescriptor.timestampWrites, '*') }}}); |
| } |
| return desc; |
| } |
| |
| var desc = makeRenderPassDescriptor(descriptor); |
| |
| var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId); |
| return WebGPU.mgrRenderPassEncoder.create(commandEncoder["beginRenderPass"](desc)); |
| }, |
| |
| wgpuCommandEncoderClearBuffer: function(encoderId, bufferId, {{{ defineI64Param('offset') }}}, {{{ defineI64Param('size') }}}) { |
| var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId); |
| {{{ receiveI64ParamAsI32s('offset') }}} |
| {{{ receiveI64ParamAsI32s('size') }}} |
| |
| var buffer = WebGPU.mgrBuffer.get(bufferId); |
| commandEncoder["clearBuffer"]( |
| buffer, |
| {{{ gpu.makeU64ToNumber('offset_low', 'offset_high') }}}, |
| {{{ gpu.makeU64ToNumber('size_low', 'size_high') }}} |
| ); |
| }, |
| |
| wgpuCommandEncoderCopyBufferToBuffer: function(encoderId, srcId, {{{ defineI64Param('srcOffset') }}}, dstId, {{{ defineI64Param('dstOffset') }}}, {{{ defineI64Param('size') }}}) { |
| {{{ receiveI64ParamAsI32s('srcOffset') }}} |
| {{{ receiveI64ParamAsI32s('dstOffset') }}} |
| {{{ receiveI64ParamAsI32s('size') }}} |
| var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId); |
| var src = WebGPU.mgrBuffer.get(srcId); |
| var dst = WebGPU.mgrBuffer.get(dstId); |
| commandEncoder["copyBufferToBuffer"]( |
| src, {{{ gpu.makeU64ToNumber('srcOffset_low', 'srcOffset_high') }}}, |
| dst, {{{ gpu.makeU64ToNumber('dstOffset_low', 'dstOffset_high') }}}, |
| {{{ gpu.makeU64ToNumber('size_low', 'size_high') }}}); |
| }, |
| |
| wgpuCommandEncoderCopyBufferToTexture: function(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: function(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: function(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: function(encoderId, querySetId, firstQuery, queryCount, |
| destinationId, {{{ defineI64Param('destinationOffset') }}}) { |
| {{{ receiveI64ParamAsI32s('destinationOffset') }}} |
| var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId); |
| var querySet = WebGPU.mgrQuerySet.get(querySetId); |
| var destination = WebGPU.mgrBuffer.get(destinationId); |
| var destinationOffset = {{{ gpu.makeU64ToNumber('destinationOffset_low', 'destinationOffset_high') }}}; |
| |
| commandEncoder["resolveQuerySet"](querySet, firstQuery, queryCount, destination, destinationOffset); |
| }, |
| |
| wgpuCommandEncoderWriteTimestamp: function(encoderId, querySetId, queryIndex) { |
| var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId); |
| var querySet = WebGPU.mgrQuerySet.get(querySetId); |
| commandEncoder["writeTimestamp"](querySet, queryIndex); |
| }, |
| |
| wgpuCommandEncoderPushDebugGroup: function(encoderId, groupLabelPtr) { |
| var encoder = WebGPU.mgrCommandEncoder.get(encoderId); |
| encoder["pushDebugGroup"](UTF8ToString(groupLabelPtr)); |
| }, |
| wgpuCommandEncoderPopDebugGroup: function(encoderId) { |
| var encoder = WebGPU.mgrCommandEncoder.get(encoderId); |
| encoder["popDebugGroup"](); |
| }, |
| wgpuCommandEncoderInsertDebugMarker: function(encoderId, markerLabelPtr) { |
| var encoder = WebGPU.mgrCommandEncoder.get(encoderId); |
| encoder["insertDebugMarker"](UTF8ToString(markerLabelPtr)); |
| }, |
| |
| wgpuCommandEncoderFinish: function(encoderId) { |
| var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId); |
| return WebGPU.mgrCommandBuffer.create(commandEncoder["finish"]()); |
| }, |
| |
| wgpuCommandEncoderSetLabel: function(encoderId, labelPtr) { |
| var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId); |
| commandEncoder.label = UTF8ToString(labelPtr); |
| }, |
| |
| // wgpuCommandBuffer |
| |
| wgpuCommandBufferSetLabel: function(commandBufferId, labelPtr) { |
| var commandBuffer = WebGPU.mgrCommandBuffer.get(commandBufferId); |
| commandBuffer.label = UTF8ToString(labelPtr); |
| }, |
| |
| // wgpuPipelineLayout |
| |
| wgpuPipelineLayoutSetLabel: function(pipelineLayoutId, labelPtr) { |
| var pipelineLayout = WebGPU.mgrPipelineLayout.get(pipelineLayoutId); |
| pipelineLayout.label = UTF8ToString(labelPtr); |
| }, |
| |
| // wgpuShaderModule |
| |
| wgpuShaderModuleGetCompilationInfo: function(shaderModuleId, callback, userdata) { |
| var shaderModule = WebGPU.mgrShaderModule.get(shaderModuleId); |
| abort('TODO: wgpuShaderModuleGetCompilationInfo unimplemented'); |
| }, |
| wgpuShaderModuleSetLabel: function(shaderModuleId, labelPtr) { |
| var shaderModule = WebGPU.mgrShaderModule.get(shaderModuleId); |
| shaderModule.label = UTF8ToString(labelPtr); |
| }, |
| |
| // wgpuComputePipeline |
| |
| wgpuComputePipelineGetBindGroupLayout: function(pipelineId, groupIndex) { |
| var pipeline = WebGPU.mgrComputePipeline.get(pipelineId); |
| return WebGPU.mgrBindGroupLayout.create(pipeline["getBindGroupLayout"](groupIndex)); |
| }, |
| wgpuComputePipelineSetLabel: function(pipelineId, labelPtr) { |
| var pipeline = WebGPU.mgrComputePipeline.get(pipelineId); |
| pipeline.label = UTF8ToString(labelPtr); |
| }, |
| |
| // wgpuRenderPipeline |
| |
| wgpuRenderPipelineGetBindGroupLayout: function(pipelineId, groupIndex) { |
| var pipeline = WebGPU.mgrRenderPipeline.get(pipelineId); |
| return WebGPU.mgrBindGroupLayout.create(pipeline["getBindGroupLayout"](groupIndex)); |
| }, |
| wgpuRenderPipelineSetLabel: function(pipelineId, labelPtr) { |
| var pipeline = WebGPU.mgrRenderPipeline.get(pipelineId); |
| pipeline.label = UTF8ToString(labelPtr); |
| }, |
| |
| // wgpuBindGroup |
| |
| wgpuBindGroupSetLabel: function(bindGroupId, labelPtr) { |
| var bindGroup = WebGPU.mgrBindGroup.get(bindGroupId); |
| bindGroup.label = UTF8ToString(labelPtr); |
| }, |
| |
| // wgpuBindGroupLayout |
| |
| wgpuBindGroupLayoutSetLabel: function(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: function(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'); |
| |
| size = size >>> 0; |
| if (size === {{{ gpu.WHOLE_MAP_SIZE }}}) size = undefined; |
| |
| 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 = _malloc(mapped.byteLength); |
| HEAPU8.set(new Uint8Array(mapped), data); |
| bufferWrapper.onUnmap.push(function() { |
| _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. |
| wgpuBufferGetMappedRange: function(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'); |
| |
| size = size >>> 0; |
| if (size === {{{ gpu.WHOLE_MAP_SIZE }}}) size = undefined; |
| |
| 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 = _malloc(mapped.byteLength); |
| HEAPU8.fill(0, data, mapped.byteLength); |
| bufferWrapper.onUnmap.push(function() { |
| 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: function(bufferId, mode, offset, size, callback, userdata) { |
| var bufferWrapper = WebGPU.mgrBuffer.objects[bufferId]; |
| {{{ gpu.makeCheckDefined('bufferWrapper') }}} |
| bufferWrapper.mapMode = mode; |
| bufferWrapper.onUnmap = []; |
| var buffer = bufferWrapper.object; |
| |
| size = size >>> 0; |
| if (size === {{{ gpu.WHOLE_MAP_SIZE }}}) size = undefined; |
| |
| // `callback` takes (WGPUBufferMapAsyncStatus status, void * userdata) |
| |
| {{{ runtimeKeepalivePush() }}} |
| buffer["mapAsync"](mode, offset, size).then(function() { |
| {{{ runtimeKeepalivePop() }}} |
| callUserCallback(function() { |
| {{{ makeDynCall('vii', 'callback') }}}({{{ gpu.BufferMapAsyncStatus.Success }}}, userdata); |
| }); |
| }, function() { |
| {{{ runtimeKeepalivePop() }}} |
| callUserCallback(function() { |
| // TODO(kainino0x): Figure out how to pick other error status values. |
| {{{ makeDynCall('vii', 'callback') }}}({{{ gpu.BufferMapAsyncStatus.Error }}}, userdata); |
| }); |
| }); |
| }, |
| |
| wgpuBufferSetLabel: function(bufferId, labelPtr) { |
| var buffer = WebGPU.mgrBuffer.get(bufferId); |
| buffer.label = UTF8ToString(labelPtr); |
| }, |
| |
| wgpuBufferUnmap: function(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 |
| |
| wgpuTextureSetLabel: function(textureId, labelPtr) { |
| var texture = WebGPU.mgrTexture.get(textureId); |
| texture.label = UTF8ToString(labelPtr); |
| }, |
| |
| wgpuTextureCreateView: function(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: function(textureViewId, labelPtr) { |
| var textureView = WebGPU.mgrTextureView.get(textureViewId); |
| textureView.label = UTF8ToString(labelPtr); |
| }, |
| |
| // wgpuComputePass |
| |
| wgpuComputePassEncoderSetBindGroup: function(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: function(passId, labelPtr) { |
| var pass = WebGPU.mgrComputePassEncoder.get(passId); |
| pass.label = UTF8ToString(labelPtr); |
| }, |
| wgpuComputePassEncoderSetPipeline: function(passId, pipelineId) { |
| var pass = WebGPU.mgrComputePassEncoder.get(passId); |
| var pipeline = WebGPU.mgrComputePipeline.get(pipelineId); |
| pass["setPipeline"](pipeline); |
| }, |
| |
| wgpuComputePassEncoderDispatchWorkgroups: function(passId, x, y, z) { |
| var pass = WebGPU.mgrComputePassEncoder.get(passId); |
| // TODO(shrekshao): Remove deprecated dispatch path |
| if (pass["dispatchWorkgroups"]) { |
| pass["dispatchWorkgroups"](x, y, z); |
| } else { |
| pass["dispatch"](x, y, z); |
| } |
| }, |
| wgpuComputePassEncoderDispatchWorkgroupsIndirect: function(passId, indirectBufferId, {{{ defineI64Param('indirectOffset') }}}) { |
| {{{ receiveI64ParamAsI32s('indirectOffset') }}} |
| var indirectBuffer = WebGPU.mgrBuffer.get(indirectBufferId); |
| var indirectOffset = {{{ gpu.makeU64ToNumber('indirectOffset_low', 'indirectOffset_high') }}}; |
| var pass = WebGPU.mgrComputePassEncoder.get(passId); |
| // TODO(shrekshao): Remove deprecated dispatchIndirect path |
| if (pass["dispatchWorkgroupsIndirect"]) { |
| pass["dispatchWorkgroupsIndirect"](indirectBuffer, indirectOffset); |
| } else { |
| pass["dispatchIndirect"](indirectBuffer, indirectOffset); |
| } |
| }, |
| |
| wgpuComputePassEncoderBeginPipelineStatisticsQuery: function(passId, querySetId, queryIndex) { |
| var pass = WebGPU.mgrComputePassEncoder.get(passId); |
| var querySet = WebGPU.mgrQuerySet.get(querySetId); |
| pass["beginPipelineStatisticsQuery"](querySet, queryIndex); |
| }, |
| wgpuComputePassEncoderEndPipelineStatisticsQuery: function(passId) { |
| var pass = WebGPU.mgrComputePassEncoder.get(passId); |
| pass["endPipelineStatisticsQuery"](); |
| }, |
| |
| wgpuComputePassEncoderWriteTimestamp: function(encoderId, querySetId, queryIndex) { |
| var pass = WebGPU.mgrComputePassEncoder.get(encoderId); |
| var querySet = WebGPU.mgrQuerySet.get(querySetId); |
| pass["writeTimestamp"](querySet, queryIndex); |
| }, |
| |
| wgpuComputePassEncoderPushDebugGroup: function(encoderId, groupLabelPtr) { |
| var encoder = WebGPU.mgrComputePassEncoder.get(encoderId); |
| encoder["pushDebugGroup"](UTF8ToString(groupLabelPtr)); |
| }, |
| wgpuComputePassEncoderPopDebugGroup: function(encoderId) { |
| var encoder = WebGPU.mgrComputePassEncoder.get(encoderId); |
| encoder["popDebugGroup"](); |
| }, |
| wgpuComputePassEncoderInsertDebugMarker: function(encoderId, markerLabelPtr) { |
| var encoder = WebGPU.mgrComputePassEncoder.get(encoderId); |
| encoder["insertDebugMarker"](UTF8ToString(markerLabelPtr)); |
| }, |
| |
| wgpuComputePassEncoderEnd: function(passId) { |
| var pass = WebGPU.mgrComputePassEncoder.get(passId); |
| pass["end"](); |
| }, |
| |
| // wgpuRenderPass |
| |
| wgpuRenderPassEncoderSetLabel: function(passId, labelPtr) { |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| pass.label = UTF8ToString(labelPtr); |
| }, |
| |
| wgpuRenderPassEncoderSetBindGroup: function(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: function(passId, colorPtr) { |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| var color = WebGPU.makeColor(colorPtr); |
| pass["setBlendConstant"](color); |
| }, |
| wgpuRenderPassEncoderSetIndexBuffer: function(passId, bufferId, format, {{{ defineI64Param('offset') }}}, {{{ defineI64Param('size') }}}) { |
| {{{ receiveI64ParamAsI32s('offset') }}} |
| {{{ receiveI64ParamAsI32s('size') }}} |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| var buffer = WebGPU.mgrBuffer.get(bufferId); |
| var offset = {{{ gpu.makeU64ToNumber('offset_low', 'offset_high') }}}; |
| var size = {{{ gpu.makeU64ToNumberWithSentinelAsUndefined('size_low', 'size_high') }}}; |
| pass["setIndexBuffer"](buffer, WebGPU.IndexFormat[format], offset, size); |
| }, |
| wgpuRenderPassEncoderSetPipeline: function(passId, pipelineId) { |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| var pipeline = WebGPU.mgrRenderPipeline.get(pipelineId); |
| pass["setPipeline"](pipeline); |
| }, |
| wgpuRenderPassEncoderSetScissorRect: function(passId, x, y, w, h) { |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| pass["setScissorRect"](x, y, w, h); |
| }, |
| wgpuRenderPassEncoderSetViewport: function(passId, x, y, w, h, minDepth, maxDepth) { |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| pass["setViewport"](x, y, w, h, minDepth, maxDepth); |
| }, |
| wgpuRenderPassEncoderSetStencilReference: function(passId, reference) { |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| pass["setStencilReference"](reference); |
| }, |
| wgpuRenderPassEncoderSetVertexBuffer: function(passId, slot, bufferId, {{{ defineI64Param('offset') }}}, {{{ defineI64Param('size') }}}) { |
| {{{ receiveI64ParamAsI32s('offset') }}} |
| {{{ receiveI64ParamAsI32s('size') }}} |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| var buffer = WebGPU.mgrBuffer.get(bufferId); |
| var offset = {{{ gpu.makeU64ToNumber('offset_low', 'offset_high') }}}; |
| var size = {{{ gpu.makeU64ToNumberWithSentinelAsUndefined('size_low', 'size_high') }}}; |
| pass["setVertexBuffer"](slot, buffer, offset, size); |
| }, |
| |
| wgpuRenderPassEncoderDraw: function(passId, vertexCount, instanceCount, firstVertex, firstInstance) { |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| pass["draw"](vertexCount, instanceCount, firstVertex, firstInstance); |
| }, |
| wgpuRenderPassEncoderDrawIndexed: function(passId, indexCount, instanceCount, firstIndex, baseVertex, firstInstance) { |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| pass["drawIndexed"](indexCount, instanceCount, firstIndex, baseVertex, firstInstance); |
| }, |
| wgpuRenderPassEncoderDrawIndirect: function(passId, indirectBufferId, {{{ defineI64Param('indirectOffset') }}}) { |
| {{{ receiveI64ParamAsI32s('indirectOffset') }}} |
| var indirectBuffer = WebGPU.mgrBuffer.get(indirectBufferId); |
| var indirectOffset = {{{ gpu.makeU64ToNumber('indirectOffset_low', 'indirectOffset_high') }}}; |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| pass["drawIndirect"](indirectBuffer, indirectOffset); |
| }, |
| wgpuRenderPassEncoderDrawIndexedIndirect: function(passId, indirectBufferId, {{{ defineI64Param('indirectOffset') }}}) { |
| {{{ receiveI64ParamAsI32s('indirectOffset') }}} |
| var indirectBuffer = WebGPU.mgrBuffer.get(indirectBufferId); |
| var indirectOffset = {{{ gpu.makeU64ToNumber('indirectOffset_low', 'indirectOffset_high') }}}; |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| pass["drawIndexedIndirect"](indirectBuffer, indirectOffset); |
| }, |
| |
| wgpuRenderPassEncoderExecuteBundles: function(passId, count, bundlesPtr) { |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| |
| #if ASSERTIONS |
| assert(bundlesPtr % 4 === 0); |
| #endif |
| |
| var bundles = Array.from(HEAP32.subarray(bundlesPtr >> 2, (bundlesPtr >> 2) + count), |
| function(id) { return WebGPU.mgrRenderBundle.get(id); }); |
| pass["executeBundles"](bundles); |
| }, |
| |
| wgpuRenderPassEncoderBeginOcclusionQuery: function(passId, queryIndex) { |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| pass["beginOcclusionQuery"](queryIndex); |
| }, |
| wgpuRenderPassEncoderEndOcclusionQuery: function(passId) { |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| pass["endOcclusionQuery"](); |
| }, |
| |
| wgpuRenderPassEncoderBeginPipelineStatisticsQuery: function(passId, querySetId, queryIndex) { |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| var querySet = WebGPU.mgrQuerySet.get(querySetId); |
| pass["beginPipelineStatisticsQuery"](querySet, queryIndex); |
| }, |
| wgpuRenderPassEncoderEndPipelineStatisticsQuery: function(passId) { |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| pass["endPipelineStatisticsQuery"](); |
| }, |
| |
| wgpuRenderPassEncoderWriteTimestamp: function(encoderId, querySetId, queryIndex) { |
| var pass = WebGPU.mgrRenderPassEncoder.get(encoderId); |
| var querySet = WebGPU.mgrQuerySet.get(querySetId); |
| pass["writeTimestamp"](querySet, queryIndex); |
| }, |
| |
| wgpuRenderPassEncoderPushDebugGroup: function(encoderId, groupLabelPtr) { |
| var encoder = WebGPU.mgrRenderPassEncoder.get(encoderId); |
| encoder["pushDebugGroup"](UTF8ToString(groupLabelPtr)); |
| }, |
| wgpuRenderPassEncoderPopDebugGroup: function(encoderId) { |
| var encoder = WebGPU.mgrRenderPassEncoder.get(encoderId); |
| encoder["popDebugGroup"](); |
| }, |
| wgpuRenderPassEncoderInsertDebugMarker: function(encoderId, markerLabelPtr) { |
| var encoder = WebGPU.mgrRenderPassEncoder.get(encoderId); |
| encoder["insertDebugMarker"](UTF8ToString(markerLabelPtr)); |
| }, |
| |
| wgpuRenderPassEncoderEnd: function(passId) { |
| var pass = WebGPU.mgrRenderPassEncoder.get(passId); |
| pass["end"](); |
| }, |
| |
| // Render bundle encoder |
| |
| wgpuRenderBundleEncoderSetLabel: function(bundleId, labelPtr) { |
| var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId); |
| pass.label = UTF8ToString(labelPtr); |
| }, |
| |
| wgpuRenderBundleEncoderSetBindGroup: function(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: function(bundleId, bufferId, format, {{{ defineI64Param('offset') }}}, {{{ defineI64Param('size') }}}) { |
| {{{ receiveI64ParamAsI32s('offset') }}} |
| {{{ receiveI64ParamAsI32s('size') }}} |
| var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId); |
| var buffer = WebGPU.mgrBuffer.get(bufferId); |
| var offset = {{{ gpu.makeU64ToNumber('offset_low', 'offset_high') }}}; |
| var size = {{{ gpu.makeU64ToNumberWithSentinelAsUndefined('size_low', 'size_high') }}}; |
| pass["setIndexBuffer"](buffer, WebGPU.IndexFormat[format], offset, size); |
| }, |
| wgpuRenderBundleEncoderSetPipeline: function(bundleId, pipelineId) { |
| var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId); |
| var pipeline = WebGPU.mgrRenderPipeline.get(pipelineId); |
| pass["setPipeline"](pipeline); |
| }, |
| wgpuRenderBundleEncoderSetVertexBuffer: function(bundleId, slot, bufferId, {{{ defineI64Param('offset') }}}, {{{ defineI64Param('size') }}}) { |
| {{{ receiveI64ParamAsI32s('offset') }}} |
| {{{ receiveI64ParamAsI32s('size') }}} |
| var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId); |
| var buffer = WebGPU.mgrBuffer.get(bufferId); |
| var offset = {{{ gpu.makeU64ToNumber('offset_low', 'offset_high') }}}; |
| var size = {{{ gpu.makeU64ToNumberWithSentinelAsUndefined('size_low', 'size_high') }}}; |
| pass["setVertexBuffer"](slot, buffer, offset, size); |
| }, |
| |
| wgpuRenderBundleEncoderDraw: function(bundleId, vertexCount, instanceCount, firstVertex, firstInstance) { |
| var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId); |
| pass["draw"](vertexCount, instanceCount, firstVertex, firstInstance); |
| }, |
| wgpuRenderBundleEncoderDrawIndexed: function(bundleId, indexCount, instanceCount, firstIndex, baseVertex, firstInstance) { |
| var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId); |
| pass["drawIndexed"](indexCount, instanceCount, firstIndex, baseVertex, firstInstance); |
| }, |
| wgpuRenderBundleEncoderDrawIndirect: function(bundleId, indirectBufferId, {{{ defineI64Param('indirectOffset') }}}) { |
| {{{ receiveI64ParamAsI32s('indirectOffset') }}} |
| var indirectBuffer = WebGPU.mgrBuffer.get(indirectBufferId); |
| var indirectOffset = {{{ gpu.makeU64ToNumber('indirectOffset_low', 'indirectOffset_high') }}}; |
| var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId); |
| pass["drawIndirect"](indirectBuffer, indirectOffset); |
| }, |
| wgpuRenderBundleEncoderDrawIndexedIndirect: function(bundleId, indirectBufferId, {{{ defineI64Param('indirectOffset') }}}) { |
| {{{ receiveI64ParamAsI32s('indirectOffset') }}} |
| var indirectBuffer = WebGPU.mgrBuffer.get(indirectBufferId); |
| var indirectOffset = {{{ gpu.makeU64ToNumber('indirectOffset_low', 'indirectOffset_high') }}}; |
| var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId); |
| pass["drawIndexedIndirect"](indirectBuffer, indirectOffset); |
| }, |
| |
| wgpuRenderBundleEncoderPushDebugGroup: function(encoderId, groupLabelPtr) { |
| var encoder = WebGPU.mgrRenderBundleEncoder.get(encoderId); |
| encoder["pushDebugGroup"](UTF8ToString(groupLabelPtr)); |
| }, |
| wgpuRenderBundleEncoderPopDebugGroup: function(encoderId) { |
| var encoder = WebGPU.mgrRenderBundleEncoder.get(encoderId); |
| encoder["popDebugGroup"](); |
| }, |
| wgpuRenderBundleEncoderInsertDebugMarker: function(encoderId, markerLabelPtr) { |
| var encoder = WebGPU.mgrRenderBundleEncoder.get(encoderId); |
| encoder["insertDebugMarker"](UTF8ToString(markerLabelPtr)); |
| }, |
| |
| wgpuRenderBundleEncoderFinish: function(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 |
| |
| wgpuCreateInstance: function() { |
| #if ASSERTIONS |
| // Once implemented, Instance should create and own the object management tables. |
| abort('TODO: wgpuCreateInstance unimplemented'); |
| #endif |
| }, |
| |
| wgpuInstanceReference: function() { |
| #if ASSERTIONS |
| abort('TODO: no WGPUInstance object should exist'); |
| #endif |
| }, |
| wgpuInstanceRelease: function() { |
| #if ASSERTIONS |
| abort('TODO: no WGPUInstance object should exist'); |
| #endif |
| }, |
| |
| wgpuInstanceCreateSurface__deps: ['$findCanvasEventTarget'], |
| wgpuInstanceCreateSurface: function(instanceId, descriptor) { |
| {{{ gpu.makeCheck('descriptor') }}} |
| {{{ gpu.makeCheck('instanceId === 0, "WGPUInstance is ignored"') }}} |
| 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 ASSERTIONS |
| assert(canvas instanceof HTMLCanvasElement); |
| #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); |
| }, |
| |
| wgpuInstanceProcessEvents: function() { |
| // TODO: This could probably be emulated with ASYNCIFY. |
| #if ASSERTIONS |
| abort('wgpuInstanceProcessEvents is unsupported (use requestAnimationFrame via html5.h instead)'); |
| #endif |
| }, |
| |
| wgpuInstanceRequestAdapter__deps: ['$callUserCallback', '$allocateUTF8'], |
| wgpuInstanceRequestAdapter: function(instanceId, options, callback, userdata) { |
| {{{ gpu.makeCheck('instanceId === 0, "WGPUInstance is ignored"') }}} |
| |
| 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 messagePtr = allocateUTF8('WebGPU not available on this browser (navigator.gpu is not available)'); |
| {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestAdapterStatus.Unavailable }}}, 0, messagePtr, userdata); |
| _free(messagePtr); |
| return; |
| } |
| |
| {{{ runtimeKeepalivePush() }}} |
| navigator["gpu"]["requestAdapter"](opts).then(function(adapter) { |
| {{{ runtimeKeepalivePop() }}} |
| callUserCallback(function() { |
| if (adapter) { |
| var adapterId = WebGPU.mgrAdapter.create(adapter); |
| {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestAdapterStatus.Success }}}, adapterId, 0, userdata); |
| } else { |
| var messagePtr = allocateUTF8('WebGPU not available on this system (requestAdapter returned null)'); |
| {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestAdapterStatus.Unavailable }}}, 0, messagePtr, userdata); |
| _free(messagePtr); |
| } |
| }); |
| }, function(ex) { |
| {{{ runtimeKeepalivePop() }}} |
| callUserCallback(function() { |
| var messagePtr = allocateUTF8(ex.message); |
| {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestAdapterStatus.Error }}}, 0, messagePtr, userdata); |
| _free(messagePtr); |
| }); |
| }); |
| }, |
| |
| // WGPUAdapter |
| |
| wgpuAdapterEnumerateFeatures: function(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; |
| }, |
| |
| wgpuAdapterGetProperties: function(adapterId, properties) { |
| {{{ gpu.makeCheckDescriptor('properties') }}} |
| {{{ makeSetValue('properties', C_STRUCTS.WGPUAdapterProperties.vendorID, '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') }}}; |
| }, |
| |
| wgpuAdapterGetLimits: function(adapterId, limitsOutPtr) { |
| abort('TODO: wgpuAdapterGetLimits unimplemented'); |
| }, |
| |
| wgpuAdapterHasFeature: function(adapterId, featureEnumValue) { |
| var adapter = WebGPU.mgrAdapter.get(adapterId); |
| return adapter.features.has(WebGPU.FeatureName[featureEnumValue]); |
| }, |
| |
| wgpuAdapterRequestDevice__deps: ['$callUserCallback', '$allocateUTF8'], |
| wgpuAdapterRequestDevice: function(adapterId, descriptor, callback, userdata) { |
| var adapter = WebGPU.mgrAdapter.get(adapterId); |
| |
| var desc = {}; |
| if (descriptor) { |
| {{{ gpu.makeCheckDescriptor('descriptor') }}} |
| var requiredFeaturesCount = {{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUDeviceDescriptor.requiredFeaturesCount) }}}; |
| if (requiredFeaturesCount) { |
| var requiredFeaturesPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUDeviceDescriptor.requiredFeatures, '*') }}}; |
| desc["requiredFeatures"] = Array.from(HEAP32.subarray(requiredFeaturesPtr >> 2, (requiredFeaturesPtr >> 2) + requiredFeaturesCount), |
| function(feature) { return 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("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("maxVertexAttributes", {{{ C_STRUCTS.WGPULimits.maxVertexAttributes }}}); |
| setLimitU32IfDefined("maxVertexBufferArrayStride", {{{ C_STRUCTS.WGPULimits.maxVertexBufferArrayStride }}}); |
| setLimitU32IfDefined("maxInterStageShaderComponents", {{{ C_STRUCTS.WGPULimits.maxInterStageShaderComponents }}}); |
| 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 labelPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUDeviceDescriptor.label, '*') }}}; |
| if (labelPtr) desc["label"] = UTF8ToString(labelPtr); |
| } |
| |
| {{{ runtimeKeepalivePush() }}} |
| adapter["requestDevice"](desc).then(function(device) { |
| {{{ runtimeKeepalivePop() }}} |
| callUserCallback(function() { |
| var deviceWrapper = { queueId: WebGPU.mgrQueue.create(device["queue"]) }; |
| var deviceId = WebGPU.mgrDevice.create(device, deviceWrapper); |
| {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestDeviceStatus.Success }}}, deviceId, 0, userdata); |
| }); |
| }, function(ex) { |
| {{{ runtimeKeepalivePop() }}} |
| callUserCallback(function() { |
| var messagePtr = allocateUTF8(ex.message); |
| {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestDeviceStatus.Error }}}, 0, messagePtr, userdata); |
| _free(messagePtr); |
| }); |
| }); |
| }, |
| |
| // WGPUSampler |
| |
| wgpuSamplerSetLabel: function(samplerId, labelPtr) { |
| var sampler = WebGPU.mgrSampler.get(samplerId); |
| sampler.label = UTF8ToString(labelPtr); |
| }, |
| |
| // WGPUSurface |
| |
| wgpuSurfaceGetPreferredFormat: function(surfaceId, adapterId) { |
| var context = WebGPU.mgrSurface.get(surfaceId); |
| var adapter = WebGPU.mgrAdapter.get(adapterId); |
| var format = context["getPreferredFormat"](adapter); |
| return WebGPU.PreferredFormat[format]; |
| }, |
| |
| // WGPUSwapChain |
| |
| wgpuDeviceCreateSwapChain: function(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); |
| }, |
| |
| wgpuSwapChainGetCurrentTextureView: function(swapChainId) { |
| var context = WebGPU.mgrSwapChain.get(swapChainId); |
| return WebGPU.mgrTextureView.create(context["getCurrentTexture"]()["createView"]()); |
| }, |
| wgpuSwapChainPresent: function() { |
| // TODO: This could probably be emulated with ASYNCIFY. |
| #if ASSERTIONS |
| abort('wgpuSwapChainPresent is unsupported (use requestAnimationFrame via html5.h instead)'); |
| #endif |
| }, |
| |
| // wgpuGetProcAddress |
| |
| wgpuGetProcAddress: function() { |
| #if ASSERTIONS |
| abort('TODO(#11526): wgpuGetProcAddress unimplemented'); |
| #endif |
| return 0; |
| }, |
| }; |
| |
| // Inverted index used by EnumerateFeatures/HasFeature |
| LibraryWebGPU.$WebGPU.FeatureNameString2Enum = {}; |
| for (var value in LibraryWebGPU.$WebGPU.FeatureName) { |
| LibraryWebGPU.$WebGPU.FeatureNameString2Enum[LibraryWebGPU.$WebGPU.FeatureName[value]] = value; |
| } |
| |
| autoAddDeps(LibraryWebGPU, '$WebGPU'); |
| mergeInto(LibraryManager.library, LibraryWebGPU); |