diff options
author | Leo Kettmeir <crowlkats@toaxl.com> | 2023-01-30 15:14:16 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-30 15:14:16 +0100 |
commit | 3035dee9f14402f57d42ff0b362152140b4dca13 (patch) | |
tree | b9a3d3d36e368b3585970ffe00127c90e16b7a09 /ext/webgpu/src | |
parent | 266915d5ce354fde12b20f8f5ceb5ffdfacb7983 (diff) |
chore: update webgpu (#17534)
Diffstat (limited to 'ext/webgpu/src')
-rw-r--r-- | ext/webgpu/src/01_webgpu.js | 352 | ||||
-rw-r--r-- | ext/webgpu/src/02_idl_types.js | 29 | ||||
-rw-r--r-- | ext/webgpu/src/03_surface.js | 148 | ||||
-rw-r--r-- | ext/webgpu/src/04_surface_idl_types.js | 86 | ||||
-rw-r--r-- | ext/webgpu/src/binding.rs | 6 | ||||
-rw-r--r-- | ext/webgpu/src/buffer.rs | 15 | ||||
-rw-r--r-- | ext/webgpu/src/bundle.rs | 24 | ||||
-rw-r--r-- | ext/webgpu/src/command_encoder.rs | 3 | ||||
-rw-r--r-- | ext/webgpu/src/compute_pass.rs | 4 | ||||
-rw-r--r-- | ext/webgpu/src/error.rs | 14 | ||||
-rw-r--r-- | ext/webgpu/src/lib.rs | 44 | ||||
-rw-r--r-- | ext/webgpu/src/pipeline.rs | 16 | ||||
-rw-r--r-- | ext/webgpu/src/render_pass.rs | 4 | ||||
-rw-r--r-- | ext/webgpu/src/sampler.rs | 2 | ||||
-rw-r--r-- | ext/webgpu/src/shader.rs | 3 | ||||
-rw-r--r-- | ext/webgpu/src/surface.rs | 137 | ||||
-rw-r--r-- | ext/webgpu/src/texture.rs | 6 |
17 files changed, 685 insertions, 208 deletions
diff --git a/ext/webgpu/src/01_webgpu.js b/ext/webgpu/src/01_webgpu.js index eb239bab8..23e8b24f0 100644 --- a/ext/webgpu/src/01_webgpu.js +++ b/ext/webgpu/src/01_webgpu.js @@ -57,7 +57,6 @@ const _architecture = Symbol("[[architecture]]"); const _description = Symbol("[[description]]"); const _limits = Symbol("[[limits]]"); - const _features = Symbol("[[features]]"); const _reason = Symbol("[[reason]]"); const _message = Symbol("[[message]]"); const _label = Symbol("[[label]]"); @@ -68,6 +67,15 @@ const _encoders = Symbol("[[encoders]]"); const _encoder = Symbol("[[encoder]]"); const _descriptor = Symbol("[[descriptor]]"); + const _width = Symbol("[[width]]"); + const _height = Symbol("[[height]]"); + const _depthOrArrayLayers = Symbol("[[depthOrArrayLayers]]"); + const _mipLevelCount = Symbol("[[mipLevelCount]]"); + const _sampleCount = Symbol("[[sampleCount]]"); + const _dimension = Symbol("[[dimension]]"); + const _format = Symbol("[[format]]"); + const _type = Symbol("[[type]]"); + const _count = Symbol("[[count]]"); /** * @param {any} self @@ -175,10 +183,13 @@ } } + const illegalConstructorKey = Symbol("illegalConstructorKey"); class GPUError extends Error { - constructor() { + constructor(key = null) { super(); - webidl.illegalConstructor(); + if (key !== illegalConstructorKey) { + webidl.illegalConstructor(); + } } [_message]; @@ -189,34 +200,38 @@ } const GPUErrorPrototype = GPUError.prototype; - class GPUOutOfMemoryError extends GPUError { - name = "GPUOutOfMemoryError"; + class GPUValidationError extends GPUError { + name = "GPUValidationError"; + /** @param {string} message */ constructor(message) { - const prefix = "Failed to construct 'GPUOutOfMemoryError'"; + const prefix = "Failed to construct 'GPUValidationError'"; webidl.requiredArguments(arguments.length, 1, { prefix }); message = webidl.converters.DOMString(message, { prefix, context: "Argument 1", }); - super(message); + super(illegalConstructorKey); + this[webidl.brand] = webidl.brand; + this[_message] = message; } } - const GPUOutOfMemoryErrorPrototype = GPUOutOfMemoryError.prototype; + const GPUValidationErrorPrototype = GPUValidationError.prototype; - class GPUValidationError extends GPUError { - name = "GPUValidationError"; - /** @param {string} message */ + class GPUOutOfMemoryError extends GPUError { + name = "GPUOutOfMemoryError"; constructor(message) { - const prefix = "Failed to construct 'GPUValidationError'"; + const prefix = "Failed to construct 'GPUOutOfMemoryError'"; webidl.requiredArguments(arguments.length, 1, { prefix }); message = webidl.converters.DOMString(message, { prefix, context: "Argument 1", }); - super(message); + super(illegalConstructorKey); + this[webidl.brand] = webidl.brand; + this[_message] = message; } } - const GPUValidationErrorPrototype = GPUValidationError.prototype; + const GPUOutOfMemoryErrorPrototype = GPUOutOfMemoryError.prototype; class GPU { [webidl.brand] = webidl.brand; @@ -314,27 +329,24 @@ const requiredFeatures = descriptor.requiredFeatures ?? []; for (let i = 0; i < requiredFeatures.length; ++i) { const feature = requiredFeatures[i]; - if (!SetPrototypeHas(this[_adapter].features[_features], feature)) { + if ( + !SetPrototypeHas( + this[_adapter].features[webidl.setlikeInner], + feature, + ) + ) { throw new TypeError( - `${prefix}: nonGuaranteedFeatures must be a subset of the adapter features.`, + `${prefix}: requiredFeatures must be a subset of the adapter features.`, ); } } - let requiredLimits = descriptor.requiredLimits; - if (requiredLimits) { - requiredLimits = { - ...this[_adapter].limits[_limits], - ...requiredLimits, - }; - } - // TODO(lucacasonato): validate requiredLimits const { rid, features, limits } = await core.opAsync( "op_webgpu_request_device", this[_adapter].rid, descriptor.label, requiredFeatures, - requiredLimits, + descriptor.requiredLimits, ); const inner = new InnerGPUDevice({ @@ -344,9 +356,9 @@ limits: createGPUSupportedLimits(limits), }); return createGPUDevice( - descriptor.label ?? null, + descriptor.label, inner, - createGPUQueue(descriptor.label ?? null, inner), + createGPUQueue(descriptor.label, inner), ); } @@ -441,10 +453,10 @@ } const GPUAdapterInfoPrototype = GPUAdapterInfo.prototype; - function createGPUSupportedLimits(features) { + function createGPUSupportedLimits(limits) { /** @type {GPUSupportedLimits} */ const adapterFeatures = webidl.createBranded(GPUSupportedLimits); - adapterFeatures[_limits] = features; + adapterFeatures[_limits] = limits; return adapterFeatures; } @@ -505,6 +517,14 @@ webidl.assertBranded(this, GPUSupportedLimitsPrototype); return this[_limits].maxBindGroups; } + get maxBindingsPerBindGroup() { + webidl.assertBranded(this, GPUSupportedLimitsPrototype); + return this[_limits].maxBindingsPerBindGroup; + } + get maxBufferSize() { + webidl.assertBranded(this, GPUSupportedLimitsPrototype); + return this[_limits].maxBufferSize; + } get maxDynamicUniformBuffersPerPipelineLayout() { webidl.assertBranded(this, GPUSupportedLimitsPrototype); return this[_limits].maxDynamicUniformBuffersPerPipelineLayout; @@ -611,7 +631,6 @@ constructor() { webidl.illegalConstructor(); } - [SymbolFor("Deno.privateCustomInspect")](inspect) { return `${this.constructor.name} ${ inspect([...new SafeArrayIterator(this.values())]) @@ -923,7 +942,7 @@ }; } const buffer = createGPUBuffer( - descriptor.label ?? null, + descriptor.label, device, rid, descriptor.size, @@ -955,7 +974,7 @@ device.pushError(err); const texture = createGPUTexture( - descriptor.label ?? null, + descriptor, device, rid, ); @@ -975,14 +994,14 @@ context: "Argument 1", }); const device = assertDevice(this, { prefix, context: "this" }); - const { rid, err } = ops.op_webgpu_create_sampler({ + const { rid, err } = ops.op_webgpu_create_texture({ deviceRid: device.rid, ...descriptor, }); device.pushError(err); const sampler = createGPUSampler( - descriptor.label ?? null, + descriptor.label, device, rid, ); @@ -1006,13 +1025,13 @@ for (let i = 0; i < descriptor.entries.length; ++i) { const entry = descriptor.entries[i]; - let count = 0; - if (entry.buffer) count++; - if (entry.sampler) count++; - if (entry.texture) count++; - if (entry.storageTexture) count++; + let j = 0; + if (entry.buffer) j++; + if (entry.sampler) j++; + if (entry.texture) j++; + if (entry.storageTexture) j++; - if (count !== 1) { + if (j !== 1) { throw new Error(); // TODO(@crowlKats): correct error } } @@ -1025,7 +1044,7 @@ device.pushError(err); const bindGroupLayout = createGPUBindGroupLayout( - descriptor.label ?? null, + descriptor.label, device, rid, ); @@ -1067,7 +1086,7 @@ device.pushError(err); const pipelineLayout = createGPUPipelineLayout( - descriptor.label ?? null, + descriptor.label, device, rid, ); @@ -1162,7 +1181,7 @@ device.pushError(err); const bindGroup = createGPUBindGroup( - descriptor.label ?? null, + descriptor.label, device, rid, ); @@ -1186,12 +1205,11 @@ device.rid, descriptor.label, descriptor.code, - descriptor.sourceMap, ); device.pushError(err); const shaderModule = createGPUShaderModule( - descriptor.label ?? null, + descriptor.label, device, rid, ); @@ -1245,7 +1263,7 @@ device.pushError(err); const computePipeline = createGPUComputePipeline( - descriptor.label ?? null, + descriptor.label, device, rid, ); @@ -1320,7 +1338,7 @@ device.pushError(err); const renderPipeline = createGPURenderPipeline( - descriptor.label ?? null, + descriptor.label, device, rid, ); @@ -1357,7 +1375,7 @@ device.pushError(err); const commandEncoder = createGPUCommandEncoder( - descriptor.label ?? null, + descriptor.label, device, rid, ); @@ -1382,16 +1400,14 @@ }, ); const device = assertDevice(this, { prefix, context: "this" }); - const { rid, err } = ops.op_webgpu_create_render_bundle_encoder( - { - deviceRid: device.rid, - ...descriptor, - }, - ); + const { rid, err } = ops.op_webgpu_create_render_bundle_encoder({ + deviceRid: device.rid, + ...descriptor, + }); device.pushError(err); const renderBundleEncoder = createGPURenderBundleEncoder( - descriptor.label ?? null, + descriptor.label, device, rid, ); @@ -1422,7 +1438,7 @@ device.pushError(err); const querySet = createGPUQuerySet( - descriptor.label ?? null, + descriptor.label, device, rid, descriptor, @@ -1523,7 +1539,7 @@ * @param {GPUCommandBuffer[]} commandBuffers */ submit(commandBuffers) { - webidl.assertBranded(this, GPUQueue.prototype); + webidl.assertBranded(this, GPUQueuePrototype); const prefix = "Failed to execute 'submit' on 'GPUQueue'"; webidl.requiredArguments(arguments.length, 1, { prefix, @@ -1546,10 +1562,7 @@ return rid; }, ); - const { err } = ops.op_webgpu_queue_submit( - device.rid, - commandBufferRids, - ); + const { err } = ops.op_webgpu_queue_submit(device.rid, commandBufferRids); for (let i = 0; i < commandBuffers.length; ++i) { commandBuffers[i][_rid] = undefined; } @@ -1557,7 +1570,7 @@ } onSubmittedWorkDone() { - webidl.assertBranded(this, GPUQueue.prototype); + webidl.assertBranded(this, GPUQueuePrototype); return PromiseResolve(); } @@ -1569,7 +1582,7 @@ * @param {number} [size] */ writeBuffer(buffer, bufferOffset, data, dataOffset = 0, size) { - webidl.assertBranded(this, GPUQueue.prototype); + webidl.assertBranded(this, GPUQueuePrototype); const prefix = "Failed to execute 'writeBuffer' on 'GPUQueue'"; webidl.requiredArguments(arguments.length, 3, { prefix }); buffer = webidl.converters["GPUBuffer"](buffer, { @@ -1622,7 +1635,7 @@ * @param {GPUExtent3D} size */ writeTexture(destination, data, dataLayout, size) { - webidl.assertBranded(this, GPUQueue.prototype); + webidl.assertBranded(this, GPUQueuePrototype); const prefix = "Failed to execute 'writeTexture' on 'GPUQueue'"; webidl.requiredArguments(arguments.length, 4, { prefix }); destination = webidl.converters.GPUImageCopyTexture(destination, { @@ -1681,6 +1694,7 @@ } } GPUObjectBaseMixin("GPUQueue", GPUQueue); + const GPUQueuePrototype = GPUQueue.prototype; /** * @typedef CreateGPUBufferOptions @@ -1716,25 +1730,18 @@ class GPUBuffer { /** @type {InnerGPUDevice} */ [_device]; - /** @type {number} */ [_rid]; - /** @type {number} */ [_size]; - /** @type {number} */ [_usage]; - - /** @type {"mapped" | "mapped at creation" | "mapped pending" | "unmapped" | "destroy"} */ + /** @type {"mapped" | "mapped at creation" | "pending" | "unmapped" | "destroy"} */ [_state]; - /** @type {[number, number] | null} */ [_mappingRange]; - /** @type {[ArrayBuffer, number, number][] | null} */ [_mappedRanges]; - /** @type {number} */ [_mapMode]; @@ -1761,13 +1768,33 @@ webidl.illegalConstructor(); } + get size() { + webidl.assertBranded(this, GPUBufferPrototype); + return this[_size]; + } + + get usage() { + webidl.assertBranded(this, GPUBufferPrototype); + return this[_usage]; + } + + get mapState() { + webidl.assertBranded(this, GPUBufferPrototype); + const state = this[_state]; + if (state === "mapped at creation") { + return "mapped"; + } else { + return state; + } + } + /** * @param {number} mode * @param {number} offset * @param {number} [size] */ async mapAsync(mode, offset = 0, size) { - webidl.assertBranded(this, GPUBuffer.prototype); + webidl.assertBranded(this, GPUBufferPrototype); const prefix = "Failed to execute 'mapAsync' on 'GPUBuffer'"; webidl.requiredArguments(arguments.length, 1, { prefix }); mode = webidl.converters.GPUMapModeFlags(mode, { @@ -1839,7 +1866,7 @@ } this[_mapMode] = mode; - this[_state] = "mapping pending"; + this[_state] = "pending"; const promise = PromisePrototypeThen( core.opAsync( "op_webgpu_buffer_get_map_async", @@ -1867,7 +1894,7 @@ * @param {number} size */ getMappedRange(offset = 0, size) { - webidl.assertBranded(this, GPUBuffer.prototype); + webidl.assertBranded(this, GPUBufferPrototype); const prefix = "Failed to execute 'getMappedRange' on 'GPUBuffer'"; offset = webidl.converters.GPUSize64(offset, { prefix, @@ -1922,7 +1949,7 @@ } unmap() { - webidl.assertBranded(this, GPUBuffer.prototype); + webidl.assertBranded(this, GPUBufferPrototype); const prefix = "Failed to execute 'unmap' on 'GPUBuffer'"; const device = assertDevice(this, { prefix, context: "this" }); const bufferRid = assertResource(this, { prefix, context: "this" }); @@ -1932,7 +1959,7 @@ "OperationError", ); } - if (this[_state] === "mapping pending") { + if (this[_state] === "pending") { // TODO(lucacasonato): this is not spec compliant. throw new DOMException( `${prefix}: can not unmap while mapping. This is a Deno limitation.`, @@ -1980,7 +2007,7 @@ } destroy() { - webidl.assertBranded(this, GPUBuffer.prototype); + webidl.assertBranded(this, GPUBufferPrototype); this[_cleanup](); } @@ -1993,6 +2020,7 @@ } } GPUObjectBaseMixin("GPUBuffer", GPUBuffer); + const GPUBufferPrototype = GPUBuffer.prototype; class GPUBufferUsage { constructor() { @@ -2045,18 +2073,26 @@ } /** - * @param {string | null} label + * @param {GPUTextureDescriptor} descriptor * @param {InnerGPUDevice} device * @param {number} rid * @returns {GPUTexture} */ - function createGPUTexture(label, device, rid) { + function createGPUTexture(descriptor, device, rid) { /** @type {GPUTexture} */ const texture = webidl.createBranded(GPUTexture); - texture[_label] = label; + texture[_label] = descriptor.label; texture[_device] = device; texture[_rid] = rid; texture[_views] = []; + texture[_width] = descriptor.size.width; + texture[_height] = descriptor.size.height; + texture[_depthOrArrayLayers] = descriptor.size.depthOrArrayLayers; + texture[_mipLevelCount] = descriptor.mipLevelCount; + texture[_sampleCount] = descriptor.sampleCount; + texture[_dimension] = descriptor.dimension; + texture[_format] = descriptor.format; + texture[_usage] = descriptor.usage; return texture; } @@ -2068,6 +2104,23 @@ /** @type {WeakRef<GPUTextureView>[]} */ [_views]; + /** @type {number} */ + [_width]; + /** @type {number} */ + [_height]; + /** @type {number} */ + [_depthOrArrayLayers]; + /** @type {number} */ + [_mipLevelCount]; + /** @type {number} */ + [_sampleCount]; + /** @type {GPUTextureDimension} */ + [_dimension]; + /** @type {GPUTextureFormat} */ + [_format]; + /** @type {number} */ + [_usage]; + [_cleanup]() { const views = this[_views]; while (views.length > 0) { @@ -2092,7 +2145,7 @@ * @param {GPUTextureViewDescriptor} descriptor */ createView(descriptor = {}) { - webidl.assertBranded(this, GPUTexture.prototype); + webidl.assertBranded(this, GPUTexturePrototype); const prefix = "Failed to execute 'createView' on 'GPUTexture'"; webidl.requiredArguments(arguments.length, 0, { prefix }); descriptor = webidl.converters.GPUTextureViewDescriptor(descriptor, { @@ -2108,7 +2161,7 @@ device.pushError(err); const textureView = createGPUTextureView( - descriptor.label ?? null, + descriptor.label, this, rid, ); @@ -2117,10 +2170,50 @@ } destroy() { - webidl.assertBranded(this, GPUTexture.prototype); + webidl.assertBranded(this, GPUTexturePrototype); this[_cleanup](); } + get width() { + webidl.assertBranded(this, GPUTexturePrototype); + return this[_width]; + } + + get height() { + webidl.assertBranded(this, GPUTexturePrototype); + return this[_height]; + } + + get depthOrArrayLayers() { + webidl.assertBranded(this, GPUTexturePrototype); + return this[_depthOrArrayLayers]; + } + + get mipLevelCount() { + webidl.assertBranded(this, GPUTexturePrototype); + return this[_mipLevelCount]; + } + + get sampleCount() { + webidl.assertBranded(this, GPUTexturePrototype); + return this[_sampleCount]; + } + + get dimension() { + webidl.assertBranded(this, GPUTexturePrototype); + return this[_dimension]; + } + + get format() { + webidl.assertBranded(this, GPUTexturePrototype); + return this[_format]; + } + + get usage() { + webidl.assertBranded(this, GPUTexturePrototype); + return this[_usage]; + } + [SymbolFor("Deno.privateCustomInspect")](inspect) { return `${this.constructor.name} ${ inspect({ @@ -2130,6 +2223,7 @@ } } GPUObjectBaseMixin("GPUTexture", GPUTexture); + const GPUTexturePrototype = GPUTexture.prototype; class GPUTextureUsage { constructor() { @@ -2763,7 +2857,7 @@ ); const renderPassEncoder = createGPURenderPassEncoder( - descriptor.label ?? null, + descriptor.label, this, rid, ); @@ -2795,7 +2889,7 @@ ); const computePassEncoder = createGPUComputePassEncoder( - descriptor.label ?? null, + descriptor.label, this, rid, ); @@ -3310,7 +3404,7 @@ this[_rid] = undefined; const commandBuffer = createGPUCommandBuffer( - descriptor.label ?? null, + descriptor.label, device, rid, ); @@ -3573,9 +3667,7 @@ context: "encoder referenced by this", }); const renderPassRid = assertResource(this, { prefix, context: "this" }); - ops.op_webgpu_render_pass_end_pipeline_statistics_query( - renderPassRid, - ); + ops.op_webgpu_render_pass_end_pipeline_statistics_query(renderPassRid); } /** @@ -3651,10 +3743,7 @@ }); return rid; }); - ops.op_webgpu_render_pass_execute_bundles( - renderPassRid, - bundleRids, - ); + ops.op_webgpu_render_pass_execute_bundles(renderPassRid, bundleRids); } end() { @@ -3747,10 +3836,7 @@ context: "encoder referenced by this", }); const renderPassRid = assertResource(this, { prefix, context: "this" }); - ops.op_webgpu_render_pass_push_debug_group( - renderPassRid, - groupLabel, - ); + ops.op_webgpu_render_pass_push_debug_group(renderPassRid, groupLabel); } popDebugGroup() { @@ -3790,10 +3876,7 @@ context: "encoder referenced by this", }); const renderPassRid = assertResource(this, { prefix, context: "this" }); - ops.op_webgpu_render_pass_insert_debug_marker( - renderPassRid, - markerLabel, - ); + ops.op_webgpu_render_pass_insert_debug_marker(renderPassRid, markerLabel); } /** @@ -3826,10 +3909,7 @@ resourceContext: "Argument 1", selfContext: "this", }); - ops.op_webgpu_render_pass_set_pipeline( - renderPassRid, - pipelineRid, - ); + ops.op_webgpu_render_pass_set_pipeline(renderPassRid, pipelineRid); } /** @@ -4205,10 +4285,7 @@ resourceContext: "Argument 1", selfContext: "this", }); - ops.op_webgpu_compute_pass_set_pipeline( - computePassRid, - pipelineRid, - ); + ops.op_webgpu_compute_pass_set_pipeline(computePassRid, pipelineRid); } /** @@ -4351,9 +4428,7 @@ context: "encoder referenced by this", }); const computePassRid = assertResource(this, { prefix, context: "this" }); - ops.op_webgpu_compute_pass_end_pipeline_statistics_query( - computePassRid, - ); + ops.op_webgpu_compute_pass_end_pipeline_statistics_query(computePassRid); } /** @@ -4488,10 +4563,7 @@ context: "encoder referenced by this", }); const computePassRid = assertResource(this, { prefix, context: "this" }); - ops.op_webgpu_compute_pass_push_debug_group( - computePassRid, - groupLabel, - ); + ops.op_webgpu_compute_pass_push_debug_group(computePassRid, groupLabel); } popDebugGroup() { @@ -4630,7 +4702,7 @@ * @param {GPURenderBundleDescriptor} descriptor */ finish(descriptor = {}) { - webidl.assertBranded(this, GPURenderBundleEncoder.prototype); + webidl.assertBranded(this, GPURenderBundleEncoderPrototype); const prefix = "Failed to execute 'finish' on 'GPURenderBundleEncoder'"; descriptor = webidl.converters.GPURenderBundleDescriptor(descriptor, { prefix, @@ -4649,7 +4721,7 @@ this[_rid] = undefined; const renderBundle = createGPURenderBundle( - descriptor.label ?? null, + descriptor.label, device, rid, ); @@ -4665,7 +4737,7 @@ dynamicOffsetsDataStart, dynamicOffsetsDataLength, ) { - webidl.assertBranded(this, GPURenderBundleEncoder.prototype); + webidl.assertBranded(this, GPURenderBundleEncoderPrototype); const prefix = "Failed to execute 'setBindGroup' on 'GPURenderBundleEncoder'"; const device = assertDevice(this, { prefix, context: "this" }); @@ -4706,7 +4778,7 @@ * @param {string} groupLabel */ pushDebugGroup(groupLabel) { - webidl.assertBranded(this, GPURenderBundleEncoder.prototype); + webidl.assertBranded(this, GPURenderBundleEncoderPrototype); const prefix = "Failed to execute 'pushDebugGroup' on 'GPURenderBundleEncoder'"; webidl.requiredArguments(arguments.length, 1, { prefix }); @@ -4726,7 +4798,7 @@ } popDebugGroup() { - webidl.assertBranded(this, GPURenderBundleEncoder.prototype); + webidl.assertBranded(this, GPURenderBundleEncoderPrototype); const prefix = "Failed to execute 'popDebugGroup' on 'GPURenderBundleEncoder'"; assertDevice(this, { prefix, context: "this" }); @@ -4743,7 +4815,7 @@ * @param {string} markerLabel */ insertDebugMarker(markerLabel) { - webidl.assertBranded(this, GPURenderBundleEncoder.prototype); + webidl.assertBranded(this, GPURenderBundleEncoderPrototype); const prefix = "Failed to execute 'insertDebugMarker' on 'GPURenderBundleEncoder'"; webidl.requiredArguments(arguments.length, 1, { prefix }); @@ -4766,7 +4838,7 @@ * @param {GPURenderPipeline} pipeline */ setPipeline(pipeline) { - webidl.assertBranded(this, GPURenderBundleEncoder.prototype); + webidl.assertBranded(this, GPURenderBundleEncoderPrototype); const prefix = "Failed to execute 'setPipeline' on 'GPURenderBundleEncoder'"; webidl.requiredArguments(arguments.length, 1, { prefix }); @@ -4801,7 +4873,7 @@ * @param {number} size */ setIndexBuffer(buffer, indexFormat, offset = 0, size = 0) { - webidl.assertBranded(this, GPURenderBundleEncoder.prototype); + webidl.assertBranded(this, GPURenderBundleEncoderPrototype); const prefix = "Failed to execute 'setIndexBuffer' on 'GPURenderBundleEncoder'"; webidl.requiredArguments(arguments.length, 2, { prefix }); @@ -4851,7 +4923,7 @@ * @param {number} size */ setVertexBuffer(slot, buffer, offset = 0, size = 0) { - webidl.assertBranded(this, GPURenderBundleEncoder.prototype); + webidl.assertBranded(this, GPURenderBundleEncoderPrototype); const prefix = "Failed to execute 'setVertexBuffer' on 'GPURenderBundleEncoder'"; webidl.requiredArguments(arguments.length, 2, { prefix }); @@ -4901,7 +4973,7 @@ * @param {number} firstInstance */ draw(vertexCount, instanceCount = 1, firstVertex = 0, firstInstance = 0) { - webidl.assertBranded(this, GPURenderBundleEncoder.prototype); + webidl.assertBranded(this, GPURenderBundleEncoderPrototype); const prefix = "Failed to execute 'draw' on 'GPURenderBundleEncoder'"; webidl.requiredArguments(arguments.length, 1, { prefix }); vertexCount = webidl.converters.GPUSize32(vertexCount, { @@ -4948,7 +5020,7 @@ baseVertex = 0, firstInstance = 0, ) { - webidl.assertBranded(this, GPURenderBundleEncoder.prototype); + webidl.assertBranded(this, GPURenderBundleEncoderPrototype); const prefix = "Failed to execute 'drawIndexed' on 'GPURenderBundleEncoder'"; webidl.requiredArguments(arguments.length, 1, { prefix }); @@ -4992,7 +5064,7 @@ * @param {number} indirectOffset */ drawIndirect(indirectBuffer, indirectOffset) { - webidl.assertBranded(this, GPURenderBundleEncoder.prototype); + webidl.assertBranded(this, GPURenderBundleEncoderPrototype); const prefix = "Failed to execute 'drawIndirect' on 'GPURenderBundleEncoder'"; webidl.requiredArguments(arguments.length, 2, { prefix }); @@ -5038,6 +5110,7 @@ } } GPUObjectBaseMixin("GPURenderBundleEncoder", GPURenderBundleEncoder); + const GPURenderBundleEncoderPrototype = GPURenderBundleEncoder.prototype; /** * @param {string | null} label @@ -5106,6 +5179,10 @@ [_rid]; /** @type {GPUQuerySetDescriptor} */ [_descriptor]; + /** @type {GPUQueryType} */ + [_type]; + /** @type {number} */ + [_count]; [_cleanup]() { const rid = this[_rid]; @@ -5125,6 +5202,16 @@ this[_cleanup](); } + get type() { + webidl.assertBranded(this, GPUQuerySetPrototype); + return this[_type](); + } + + get count() { + webidl.assertBranded(this, GPUQuerySetPrototype); + return this[_count](); + } + [SymbolFor("Deno.privateCustomInspect")](inspect) { return `${this.constructor.name} ${ inspect({ @@ -5137,12 +5224,17 @@ const GPUQuerySetPrototype = GPUQuerySet.prototype; window.__bootstrap.webgpu = { + _device, + assertDevice, + createGPUTexture, gpu: webidl.createBranded(GPU), GPU, GPUAdapter, + GPUAdapterInfo, GPUSupportedLimits, GPUSupportedFeatures, GPUDevice, + GPUDeviceLostInfo, GPUQueue, GPUBuffer, GPUBufferUsage, @@ -5167,7 +5259,7 @@ GPURenderBundle, GPUQuerySet, GPUError, - GPUOutOfMemoryError, GPUValidationError, + GPUOutOfMemoryError, }; })(this); diff --git a/ext/webgpu/src/02_idl_types.js b/ext/webgpu/src/02_idl_types.js index 42986d4fd..c927f10a5 100644 --- a/ext/webgpu/src/02_idl_types.js +++ b/ext/webgpu/src/02_idl_types.js @@ -65,12 +65,6 @@ GPUSupportedFeatures.prototype, ); - // ENUM: GPUPredefinedColorSpace - webidl.converters.GPUPredefinedColorSpace = webidl.createEnumConverter( - "GPUPredefinedColorSpace", - ["srgb"], - ); - // INTERFACE: GPU webidl.converters.GPU = webidl.createInterfaceConverter("GPU", GPU.prototype); @@ -112,7 +106,6 @@ "GPUFeatureName", [ "depth-clip-control", - "depth24unorm-stencil8", "depth32float-stencil8", "pipeline-statistics-query", "texture-compression-bc", @@ -148,6 +141,10 @@ webidl.converters["GPUSize32"] = (V, opts) => webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }); + // TYPEDEF: GPUSize64 + webidl.converters["GPUSize64"] = (V, opts) => + webidl.converters["unsigned long long"](V, { ...opts, enforceRange: true }); + // DICTIONARY: GPUDeviceDescriptor const dictMembersGPUDeviceDescriptor = [ { @@ -163,7 +160,7 @@ key: "requiredLimits", converter: webidl.createRecordConverter( webidl.converters["DOMString"], - webidl.converters["GPUSize32"], + webidl.converters["GPUSize64"], ), }, ]; @@ -185,10 +182,6 @@ GPUBuffer.prototype, ); - // TYPEDEF: GPUSize64 - webidl.converters["GPUSize64"] = (V, opts) => - webidl.converters["unsigned long long"](V, { ...opts, enforceRange: true }); - // TYPEDEF: GPUBufferUsageFlags webidl.converters["GPUBufferUsageFlags"] = (V, opts) => webidl.converters["unsigned long"](V, { ...opts, enforceRange: true }); @@ -339,7 +332,6 @@ "depth24plus", "depth24plus-stencil8", "depth32float", - "depth24unorm-stencil8", "depth32float-stencil8", "bc1-rgba-unorm", "bc1-rgba-unorm-srgb", @@ -432,6 +424,15 @@ converter: webidl.converters["GPUTextureUsageFlags"], required: true, }, + { + key: "viewFormats", + converter: webidl.createSequenceConverter( + webidl.converters["GPUTextureFormat"], + ), + get defaultValue() { + return []; + }, + }, ]; webidl.converters["GPUTextureDescriptor"] = webidl.createDictionaryConverter( "GPUTextureDescriptor", @@ -911,7 +912,6 @@ converter: webidl.converters["DOMString"], required: true, }, - { key: "sourceMap", converter: webidl.converters["object"] }, ]; webidl.converters["GPUShaderModuleDescriptor"] = webidl .createDictionaryConverter( @@ -1842,7 +1842,6 @@ key: "depthStencilAttachment", converter: webidl.converters["GPURenderPassDepthStencilAttachment"], }, - { key: "occlusionQuerySet", converter: webidl.converters["GPUQuerySet"] }, ]; webidl.converters["GPURenderPassDescriptor"] = webidl .createDictionaryConverter( diff --git a/ext/webgpu/src/03_surface.js b/ext/webgpu/src/03_surface.js new file mode 100644 index 000000000..0152098ea --- /dev/null +++ b/ext/webgpu/src/03_surface.js @@ -0,0 +1,148 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +// @ts-check +/// <reference path="../../core/lib.deno_core.d.ts" /> +/// <reference path="../web/internal.d.ts" /> +/// <reference path="../web/lib.deno_web.d.ts" /> +/// <reference path="./lib.deno_webgpu.d.ts" /> + +"use strict"; + +((window) => { + const core = window.Deno.core; + const ops = core.ops; + const webidl = window.__bootstrap.webidl; + const { Symbol } = window.__bootstrap.primordials; + const { _device, assertDevice, createGPUTexture } = window.__bootstrap.webgpu; + + const _surfaceRid = Symbol("[[surfaceRid]]"); + const _configuration = Symbol("[[configuration]]"); + const _canvas = Symbol("[[canvas]]"); + const _currentTexture = Symbol("[[currentTexture]]"); + class GPUCanvasContext { + /** @type {number} */ + [_surfaceRid]; + /** @type {InnerGPUDevice} */ + [_device]; + [_configuration]; + [_canvas]; + /** @type {GPUTexture | undefined} */ + [_currentTexture]; + + get canvas() { + webidl.assertBranded(this, GPUCanvasContextPrototype); + return this[_canvas]; + } + + constructor() { + webidl.illegalConstructor(); + } + + configure(configuration) { + webidl.assertBranded(this, GPUCanvasContextPrototype); + const prefix = "Failed to execute 'configure' on 'GPUCanvasContext'"; + webidl.requiredArguments(arguments.length, 1, { prefix }); + configuration = webidl.converters.GPUCanvasConfiguration(configuration, { + prefix, + context: "Argument 1", + }); + + this[_device] = configuration.device[_device]; + this[_configuration] = configuration; + const device = assertDevice(this, { + prefix, + context: "configuration.device", + }); + + const { err } = ops.op_webgpu_surface_configure({ + surfaceRid: this[_surfaceRid], + deviceRid: device.rid, + format: configuration.format, + usage: configuration.usage, + width: configuration.width, + height: configuration.height, + alphaMode: configuration.alphaMode, + }); + + device.pushError(err); + } + + unconfigure() { + webidl.assertBranded(this, GPUCanvasContextPrototype); + + this[_configuration] = null; + this[_device] = null; + } + + getCurrentTexture() { + webidl.assertBranded(this, GPUCanvasContextPrototype); + const prefix = + "Failed to execute 'getCurrentTexture' on 'GPUCanvasContext'"; + + if (this[_configuration] === null) { + throw new DOMException( + "context is not configured.", + "InvalidStateError", + ); + } + + const device = assertDevice(this, { prefix, context: "this" }); + + if (this[_currentTexture]) { + return this[_currentTexture]; + } + + const { rid } = ops.op_webgpu_surface_get_current_texture( + device.rid, + this[_surfaceRid], + ); + + const texture = createGPUTexture( + { + size: { + width: this[_configuration].width, + height: this[_configuration].height, + depthOrArrayLayers: 1, + }, + mipLevelCount: 1, + sampleCount: 1, + dimension: "2d", + format: this[_configuration].format, + usage: this[_configuration].usage, + }, + device, + rid, + ); + device.trackResource(texture); + this[_currentTexture] = texture; + return texture; + } + + // Extended from spec. Required to present the texture; browser don't need this. + present() { + webidl.assertBranded(this, GPUCanvasContextPrototype); + const prefix = "Failed to execute 'present' on 'GPUCanvasContext'"; + const device = assertDevice(this[_currentTexture], { + prefix, + context: "this", + }); + ops.op_webgpu_surface_present(device.rid, this[_surfaceRid]); + this[_currentTexture].destroy(); + this[_currentTexture] = undefined; + } + } + const GPUCanvasContextPrototype = GPUCanvasContext.prototype; + + function createCanvasContext(options) { + const canvasContext = webidl.createBranded(GPUCanvasContext); + canvasContext[_surfaceRid] = options.surfaceRid; + canvasContext[_canvas] = options.canvas; + return canvasContext; + } + + window.__bootstrap.webgpu = { + ...window.__bootstrap.webgpu, + GPUCanvasContext, + createCanvasContext, + }; +})(this); diff --git a/ext/webgpu/src/04_surface_idl_types.js b/ext/webgpu/src/04_surface_idl_types.js new file mode 100644 index 000000000..9dcfa767e --- /dev/null +++ b/ext/webgpu/src/04_surface_idl_types.js @@ -0,0 +1,86 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +// @ts-check +/// <reference path="../../core/lib.deno_core.d.ts" /> +/// <reference path="../web/internal.d.ts" /> +/// <reference path="../web/lib.deno_web.d.ts" /> +/// <reference path="./lib.deno_webgpu.d.ts" /> + +"use strict"; + +((window) => { + const webidl = window.__bootstrap.webidl; + const { GPUTextureUsage } = window.__bootstrap.webgpu; + + // ENUM: GPUCanvasAlphaMode + webidl.converters["GPUCanvasAlphaMode"] = webidl.createEnumConverter( + "GPUCanvasAlphaMode", + [ + "opaque", + "premultiplied", + ], + ); + + // NON-SPEC: ENUM: GPUPresentMode + webidl.converters["GPUPresentMode"] = webidl.createEnumConverter( + "GPUPresentMode", + [ + "autoVsync", + "autoNoVsync", + "fifo", + "fifoRelaxed", + "immediate", + "mailbox", + ], + ); + + // DICT: GPUCanvasConfiguration + const dictMembersGPUCanvasConfiguration = [ + { key: "device", converter: webidl.converters.GPUDevice, required: true }, + { + key: "format", + converter: webidl.converters.GPUTextureFormat, + required: true, + }, + { + key: "usage", + converter: webidl.converters["GPUTextureUsageFlags"], + defaultValue: GPUTextureUsage.RENDER_ATTACHMENT, + }, + { + key: "alphaMode", + converter: webidl.converters["GPUCanvasAlphaMode"], + defaultValue: "opaque", + }, + + // Extended from spec + { + key: "presentMode", + converter: webidl.converters["GPUPresentMode"], + }, + { + key: "width", + converter: webidl.converters["long"], + required: true, + }, + { + key: "height", + converter: webidl.converters["long"], + required: true, + }, + { + key: "viewFormats", + converter: webidl.createSequenceConverter( + webidl.converters["GPUTextureFormat"], + ), + get defaultValue() { + return []; + }, + }, + ]; + webidl.converters["GPUCanvasConfiguration"] = webidl + .createDictionaryConverter( + "GPUCanvasConfiguration", + dictMembersGPUCanvasConfiguration, + ); +})(this); diff --git a/ext/webgpu/src/binding.rs b/ext/webgpu/src/binding.rs index 7a35db503..4c4a864fd 100644 --- a/ext/webgpu/src/binding.rs +++ b/ext/webgpu/src/binding.rs @@ -199,7 +199,7 @@ pub fn op_webgpu_create_bind_group_layout( gfx_put!(device => instance.device_create_bind_group_layout( device, &descriptor, - std::marker::PhantomData + () ) => state, WebGpuBindGroupLayout) } @@ -234,7 +234,7 @@ pub fn op_webgpu_create_pipeline_layout( gfx_put!(device => instance.device_create_pipeline_layout( device, &descriptor, - std::marker::PhantomData + () ) => state, super::pipeline::WebGpuPipelineLayout) } @@ -317,6 +317,6 @@ pub fn op_webgpu_create_bind_group( gfx_put!(device => instance.device_create_bind_group( device, &descriptor, - std::marker::PhantomData + () ) => state, WebGpuBindGroup) } diff --git a/ext/webgpu/src/buffer.rs b/ext/webgpu/src/buffer.rs index a10642f33..58348129e 100644 --- a/ext/webgpu/src/buffer.rs +++ b/ext/webgpu/src/buffer.rs @@ -13,6 +13,7 @@ use std::cell::RefCell; use std::convert::TryFrom; use std::rc::Rc; use std::time::Duration; +use wgpu_core::resource::BufferAccessResult; use super::error::DomExceptionOperationError; use super::error::WebGpuResult; @@ -57,7 +58,7 @@ pub fn op_webgpu_create_buffer( gfx_put!(device => instance.device_create_buffer( device, &descriptor, - std::marker::PhantomData + () ) => state, WebGpuBuffer) } @@ -70,7 +71,7 @@ pub async fn op_webgpu_buffer_get_map_async( offset: u64, size: u64, ) -> Result<WebGpuResult, AnyError> { - let (sender, receiver) = oneshot::channel::<Result<(), AnyError>>(); + let (sender, receiver) = oneshot::channel::<BufferAccessResult>(); let device; { @@ -85,12 +86,7 @@ pub async fn op_webgpu_buffer_get_map_async( device = device_resource.0; let callback = Box::new(move |status| { - sender - .send(match status { - wgpu_core::resource::BufferMapAsyncStatus::Success => Ok(()), - _ => unreachable!(), // TODO - }) - .unwrap(); + sender.send(status).unwrap(); }); // TODO(lucacasonato): error handling @@ -120,7 +116,8 @@ pub async fn op_webgpu_buffer_get_map_async( { let state = state.borrow(); let instance = state.borrow::<super::Instance>(); - gfx_select!(device => instance.device_poll(device, wgpu_types::Maintain::Wait)).unwrap(); + gfx_select!(device => instance.device_poll(device, wgpu_types::Maintain::Wait)) + .unwrap(); } tokio::time::sleep(Duration::from_millis(10)).await; } diff --git a/ext/webgpu/src/bundle.rs b/ext/webgpu/src/bundle.rs index 13b0d0cc7..3d0f11d89 100644 --- a/ext/webgpu/src/bundle.rs +++ b/ext/webgpu/src/bundle.rs @@ -1,5 +1,6 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +use deno_core::error::type_error; use deno_core::error::AnyError; use deno_core::op; use deno_core::OpState; @@ -108,7 +109,7 @@ pub fn op_webgpu_render_bundle_encoder_finish( &wgpu_core::command::RenderBundleDescriptor { label: label.map(Cow::from), }, - std::marker::PhantomData + () ) => state, WebGpuRenderBundle) } @@ -134,8 +135,8 @@ pub fn op_webgpu_render_bundle_encoder_set_bind_group( // Align the data assert!(dynamic_offsets_data.len() % std::mem::size_of::<u32>() == 0); let (prefix, dynamic_offsets_data, suffix) = - // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a - // multiple of 4. + // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a + // multiple of 4. unsafe { dynamic_offsets_data.align_to::<u32>() }; assert!(prefix.is_empty()); assert!(suffix.is_empty()); @@ -268,16 +269,15 @@ pub fn op_webgpu_render_bundle_encoder_set_index_buffer( state .resource_table .get::<WebGpuRenderBundleEncoder>(render_bundle_encoder_rid)?; + let size = Some( + std::num::NonZeroU64::new(size) + .ok_or_else(|| type_error("size must be larger than 0"))?, + ); render_bundle_encoder_resource .0 .borrow_mut() - .set_index_buffer( - buffer_resource.0, - index_format, - offset, - std::num::NonZeroU64::new(size), - ); + .set_index_buffer(buffer_resource.0, index_format, offset, size); Ok(WebGpuResult::empty()) } @@ -298,13 +298,17 @@ pub fn op_webgpu_render_bundle_encoder_set_vertex_buffer( state .resource_table .get::<WebGpuRenderBundleEncoder>(render_bundle_encoder_rid)?; + let size = Some( + std::num::NonZeroU64::new(size) + .ok_or_else(|| type_error("size must be larger than 0"))?, + ); wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_vertex_buffer( &mut render_bundle_encoder_resource.0.borrow_mut(), slot, buffer_resource.0, offset, - std::num::NonZeroU64::new(size), + size, ); Ok(WebGpuResult::empty()) diff --git a/ext/webgpu/src/command_encoder.rs b/ext/webgpu/src/command_encoder.rs index e552a14e0..eb534f6bc 100644 --- a/ext/webgpu/src/command_encoder.rs +++ b/ext/webgpu/src/command_encoder.rs @@ -49,7 +49,7 @@ pub fn op_webgpu_create_command_encoder( gfx_put!(device => instance.device_create_command_encoder( device, &descriptor, - std::marker::PhantomData + () ) => state, WebGpuCommandEncoder) } @@ -84,7 +84,6 @@ pub fn op_webgpu_command_encoder_begin_render_pass( label: Option<String>, color_attachments: Vec<Option<GpuRenderPassColorAttachment>>, depth_stencil_attachment: Option<GpuRenderPassDepthStencilAttachment>, - _occlusion_query_set: Option<u32>, // not yet implemented ) -> Result<WebGpuResult, AnyError> { let command_encoder_resource = state .resource_table diff --git a/ext/webgpu/src/compute_pass.rs b/ext/webgpu/src/compute_pass.rs index 71f9dfe3b..8132b450c 100644 --- a/ext/webgpu/src/compute_pass.rs +++ b/ext/webgpu/src/compute_pass.rs @@ -194,8 +194,8 @@ pub fn op_webgpu_compute_pass_set_bind_group( // Align the data assert!(dynamic_offsets_data_start % std::mem::size_of::<u32>() == 0); let (prefix, dynamic_offsets_data, suffix) = - // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a - // multiple of 4. + // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a + // multiple of 4. unsafe { dynamic_offsets_data.align_to::<u32>() }; assert!(prefix.is_empty()); assert!(suffix.is_empty()); diff --git a/ext/webgpu/src/error.rs b/ext/webgpu/src/error.rs index 55ef223a1..41d7d6cf3 100644 --- a/ext/webgpu/src/error.rs +++ b/ext/webgpu/src/error.rs @@ -5,7 +5,6 @@ use serde::Serialize; use std::convert::From; use std::error::Error; use std::fmt; -use std::fmt::Write; use wgpu_core::binding_model::CreateBindGroupError; use wgpu_core::binding_model::CreateBindGroupLayoutError; use wgpu_core::binding_model::CreatePipelineLayoutError; @@ -24,6 +23,8 @@ use wgpu_core::device::DeviceError; use wgpu_core::pipeline::CreateComputePipelineError; use wgpu_core::pipeline::CreateRenderPipelineError; use wgpu_core::pipeline::CreateShaderModuleError; +#[cfg(feature = "surface")] +use wgpu_core::present::ConfigureSurfaceError; use wgpu_core::resource::BufferAccessError; use wgpu_core::resource::CreateBufferError; use wgpu_core::resource::CreateQuerySetError; @@ -36,9 +37,7 @@ fn fmt_err(err: &(dyn Error + 'static)) -> String { let mut e = err.source(); while let Some(source) = e { - // No error possible, unwrap is fine here. - // https://github.com/rust-lang/rust/blob/1.47.0/library/alloc/src/string.rs#L2414-L2427 - write!(output, ": {source}").unwrap(); + output.push_str(&format!(": {source}")); e = source.source(); } @@ -281,6 +280,13 @@ impl From<ClearError> for WebGpuError { } } +#[cfg(feature = "surface")] +impl From<ConfigureSurfaceError> for WebGpuError { + fn from(err: ConfigureSurfaceError) -> Self { + WebGpuError::Validation(fmt_err(&err)) + } +} + #[derive(Debug)] pub struct DomExceptionOperationError { pub msg: String, diff --git a/ext/webgpu/src/lib.rs b/ext/webgpu/src/lib.rs index d1fb55dbf..d4fd5660a 100644 --- a/ext/webgpu/src/lib.rs +++ b/ext/webgpu/src/lib.rs @@ -1,5 +1,7 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +#![warn(unsafe_op_in_unsafe_fn)] + use deno_core::error::AnyError; use deno_core::include_js_files; use deno_core::op; @@ -25,13 +27,22 @@ mod macros { macro_rules! gfx_select { ($id:expr => $global:ident.$method:ident( $($param:expr),* )) => { match $id.backend() { - #[cfg(not(target_os = "macos"))] + #[cfg(any( + all(not(target_arch = "wasm32"), not(target_os = "ios"), not(target_os = "macos")), + feature = "vulkan-portability" + ))] wgpu_types::Backend::Vulkan => $global.$method::<wgpu_core::api::Vulkan>( $($param),* ), - #[cfg(target_os = "macos")] + #[cfg(all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos")))] wgpu_types::Backend::Metal => $global.$method::<wgpu_core::api::Metal>( $($param),* ), - #[cfg(windows)] + #[cfg(all(not(target_arch = "wasm32"), windows))] wgpu_types::Backend::Dx12 => $global.$method::<wgpu_core::api::Dx12>( $($param),* ), - #[cfg(all(unix, not(target_os = "macos")))] + #[cfg(all(not(target_arch = "wasm32"), windows))] + wgpu_types::Backend::Dx11 => $global.$method::<wgpu_core::api::Dx11>( $($param),* ), + #[cfg(any( + all(unix, not(target_os = "macos"), not(target_os = "ios")), + feature = "angle", + target_arch = "wasm32" + ))] wgpu_types::Backend::Gl => $global.$method::<wgpu_core::api::Gles>( $($param),+ ), other => panic!("Unexpected backend {:?}", other), } @@ -65,6 +76,8 @@ pub mod queue; pub mod render_pass; pub mod sampler; pub mod shader; +#[cfg(feature = "surface")] +pub mod surface; pub mod texture; pub struct Unstable(pub bool); @@ -79,7 +92,8 @@ fn check_unstable(state: &OpState, api_name: &str) { } } -type Instance = wgpu_core::hub::Global<wgpu_core::hub::IdentityManagerFactory>; +pub type Instance = + wgpu_core::hub::Global<wgpu_core::hub::IdentityManagerFactory>; struct WebGpuAdapter(wgpu_core::id::AdapterId); impl Resource for WebGpuAdapter { @@ -128,9 +142,6 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> { if features.contains(wgpu_types::Features::DEPTH_CLIP_CONTROL) { return_features.push("depth-clip-control"); } - if features.contains(wgpu_types::Features::DEPTH24UNORM_STENCIL8) { - return_features.push("depth24unorm-stencil8"); - } if features.contains(wgpu_types::Features::DEPTH32FLOAT_STENCIL8) { return_features.push("depth32float-stencil8"); } @@ -243,7 +254,10 @@ pub async fn op_webgpu_request_adapter( state.put(wgpu_core::hub::Global::new( "webgpu", wgpu_core::hub::IdentityManagerFactory, - backends, + wgpu_types::InstanceDescriptor { + backends, + dx12_shader_compiler: wgpu_types::Dx12Compiler::Fxc, + }, )); state.borrow::<Instance>() }; @@ -255,9 +269,7 @@ pub async fn op_webgpu_request_adapter( }; let res = instance.request_adapter( &descriptor, - wgpu_core::instance::AdapterInputs::Mask(backends, |_| { - std::marker::PhantomData - }), + wgpu_core::instance::AdapterInputs::Mask(backends, |_| ()), ); let adapter = match res { @@ -295,10 +307,6 @@ impl From<GpuRequiredFeatures> for wgpu_types::Features { required_features.0.contains("depth-clip-control"), ); features.set( - wgpu_types::Features::DEPTH24UNORM_STENCIL8, - required_features.0.contains("depth24unorm-stencil8"), - ); - features.set( wgpu_types::Features::DEPTH32FLOAT_STENCIL8, required_features.0.contains("depth32float-stencil8"), ); @@ -427,7 +435,7 @@ pub async fn op_webgpu_request_device( adapter, &descriptor, std::env::var("DENO_WEBGPU_TRACE").ok().as_ref().map(std::path::Path::new), - std::marker::PhantomData + () )); if let Some(err) = maybe_err { return Err(DomExceptionOperationError::new(&err.to_string()).into()); @@ -553,7 +561,7 @@ pub fn op_webgpu_create_query_set( gfx_put!(device => instance.device_create_query_set( device, &descriptor, - std::marker::PhantomData + () ) => state, WebGpuQuerySet) } diff --git a/ext/webgpu/src/pipeline.rs b/ext/webgpu/src/pipeline.rs index ba90eedf0..2e728d8d9 100644 --- a/ext/webgpu/src/pipeline.rs +++ b/ext/webgpu/src/pipeline.rs @@ -102,8 +102,8 @@ pub fn op_webgpu_create_compute_pipeline( GPUPipelineLayoutOrGPUAutoLayoutMode::Layout(_) => None, GPUPipelineLayoutOrGPUAutoLayoutMode::Auto(GPUAutoLayoutMode::Auto) => { Some(wgpu_core::device::ImplicitPipelineIds { - root_id: std::marker::PhantomData, - group_ids: &[std::marker::PhantomData; MAX_BIND_GROUPS], + root_id: (), + group_ids: &[(); MAX_BIND_GROUPS], }) } }; @@ -111,7 +111,7 @@ pub fn op_webgpu_create_compute_pipeline( let (compute_pipeline, maybe_err) = gfx_select!(device => instance.device_create_compute_pipeline( device, &descriptor, - std::marker::PhantomData, + (), implicit_pipelines )); @@ -142,7 +142,7 @@ pub fn op_webgpu_compute_pipeline_get_bind_group_layout( .get::<WebGpuComputePipeline>(compute_pipeline_rid)?; let compute_pipeline = compute_pipeline_resource.0; - let (bind_group_layout, maybe_err) = gfx_select!(compute_pipeline => instance.compute_pipeline_get_bind_group_layout(compute_pipeline, index, std::marker::PhantomData)); + let (bind_group_layout, maybe_err) = gfx_select!(compute_pipeline => instance.compute_pipeline_get_bind_group_layout(compute_pipeline, index, ())); let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout)); @@ -376,8 +376,8 @@ pub fn op_webgpu_create_render_pipeline( GPUPipelineLayoutOrGPUAutoLayoutMode::Layout(_) => None, GPUPipelineLayoutOrGPUAutoLayoutMode::Auto(GPUAutoLayoutMode::Auto) => { Some(wgpu_core::device::ImplicitPipelineIds { - root_id: std::marker::PhantomData, - group_ids: &[std::marker::PhantomData; MAX_BIND_GROUPS], + root_id: (), + group_ids: &[(); MAX_BIND_GROUPS], }) } }; @@ -385,7 +385,7 @@ pub fn op_webgpu_create_render_pipeline( let (render_pipeline, maybe_err) = gfx_select!(device => instance.device_create_render_pipeline( device, &descriptor, - std::marker::PhantomData, + (), implicit_pipelines )); @@ -408,7 +408,7 @@ pub fn op_webgpu_render_pipeline_get_bind_group_layout( .get::<WebGpuRenderPipeline>(render_pipeline_rid)?; let render_pipeline = render_pipeline_resource.0; - let (bind_group_layout, maybe_err) = gfx_select!(render_pipeline => instance.render_pipeline_get_bind_group_layout(render_pipeline, index, std::marker::PhantomData)); + let (bind_group_layout, maybe_err) = gfx_select!(render_pipeline => instance.render_pipeline_get_bind_group_layout(render_pipeline, index, ())); let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout)); diff --git a/ext/webgpu/src/render_pass.rs b/ext/webgpu/src/render_pass.rs index 85440b18d..ee38091bc 100644 --- a/ext/webgpu/src/render_pass.rs +++ b/ext/webgpu/src/render_pass.rs @@ -254,8 +254,8 @@ pub fn op_webgpu_render_pass_set_bind_group( // Align the data assert_eq!(dynamic_offsets_data_start % std::mem::size_of::<u32>(), 0); let (prefix, dynamic_offsets_data, suffix) = - // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a - // multiple of 4. + // SAFETY: A u8 to u32 cast is safe because we asserted that the length is a + // multiple of 4. unsafe { dynamic_offsets_data.align_to::<u32>() }; assert!(prefix.is_empty()); assert!(suffix.is_empty()); diff --git a/ext/webgpu/src/sampler.rs b/ext/webgpu/src/sampler.rs index f2f1037f1..b377f6835 100644 --- a/ext/webgpu/src/sampler.rs +++ b/ext/webgpu/src/sampler.rs @@ -65,6 +65,6 @@ pub fn op_webgpu_create_sampler( gfx_put!(device => instance.device_create_sampler( device, &descriptor, - std::marker::PhantomData + () ) => state, WebGpuSampler) } diff --git a/ext/webgpu/src/shader.rs b/ext/webgpu/src/shader.rs index f45ab4400..242cb85ba 100644 --- a/ext/webgpu/src/shader.rs +++ b/ext/webgpu/src/shader.rs @@ -22,7 +22,6 @@ pub fn op_webgpu_create_shader_module( device_rid: ResourceId, label: Option<String>, code: String, - _source_map: Option<()>, // not yet implemented ) -> Result<WebGpuResult, AnyError> { let instance = state.borrow::<super::Instance>(); let device_resource = state @@ -41,6 +40,6 @@ pub fn op_webgpu_create_shader_module( device, &descriptor, source, - std::marker::PhantomData + () ) => state, WebGpuShaderModule) } diff --git a/ext/webgpu/src/surface.rs b/ext/webgpu/src/surface.rs new file mode 100644 index 000000000..1adebb53a --- /dev/null +++ b/ext/webgpu/src/surface.rs @@ -0,0 +1,137 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +use super::WebGpuResult; +use deno_core::error::AnyError; +use deno_core::include_js_files; +use deno_core::op; +use deno_core::Extension; +use deno_core::OpState; +use deno_core::Resource; +use deno_core::ResourceId; +use serde::Deserialize; +use std::borrow::Cow; +use wgpu_types::SurfaceStatus; + +pub fn init_surface(unstable: bool) -> Extension { + Extension::builder("deno_webgpu_surface") + .dependencies(vec!["deno_webidl", "deno_web", "deno_webgpu"]) + .js(include_js_files!( + prefix "deno:deno_webgpu", + "03_surface.js", + "04_surface_idl_types.js", + )) + .ops(vec![ + op_webgpu_surface_configure::decl(), + op_webgpu_surface_get_current_texture::decl(), + op_webgpu_surface_present::decl(), + ]) + .state(move |state| { + // TODO: check & possibly streamline this + // Unstable might be able to be OpMiddleware + // let unstable_checker = state.borrow::<super::UnstableChecker>(); + // let unstable = unstable_checker.unstable; + state.put(super::Unstable(unstable)); + Ok(()) + }) + .build() +} + +pub struct WebGpuSurface(pub wgpu_core::id::SurfaceId); +impl Resource for WebGpuSurface { + fn name(&self) -> Cow<str> { + "webGPUSurface".into() + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SurfaceConfigureArgs { + surface_rid: ResourceId, + device_rid: ResourceId, + format: wgpu_types::TextureFormat, + usage: u32, + width: u32, + height: u32, + present_mode: Option<wgpu_types::PresentMode>, + alpha_mode: wgpu_types::CompositeAlphaMode, + view_formats: Vec<wgpu_types::TextureFormat>, +} + +#[op] +pub fn op_webgpu_surface_configure( + state: &mut OpState, + args: SurfaceConfigureArgs, +) -> Result<WebGpuResult, AnyError> { + let instance = state.borrow::<super::Instance>(); + let device_resource = state + .resource_table + .get::<super::WebGpuDevice>(args.device_rid)?; + let device = device_resource.0; + let surface_resource = state + .resource_table + .get::<WebGpuSurface>(args.surface_rid)?; + let surface = surface_resource.0; + + let conf = wgpu_types::SurfaceConfiguration::<Vec<wgpu_types::TextureFormat>> { + usage: wgpu_types::TextureUsages::from_bits_truncate(args.usage), + format: args.format, + width: args.width, + height: args.height, + present_mode: args.present_mode.unwrap_or_default(), + alpha_mode: args.alpha_mode, + view_formats: args.view_formats, + }; + + let err = + gfx_select!(device => instance.surface_configure(surface, device, &conf)); + + Ok(WebGpuResult::maybe_err(err)) +} + +#[op] +pub fn op_webgpu_surface_get_current_texture( + state: &mut OpState, + device_rid: ResourceId, + surface_rid: ResourceId, +) -> Result<WebGpuResult, AnyError> { + let instance = state.borrow::<super::Instance>(); + let device_resource = state + .resource_table + .get::<super::WebGpuDevice>(device_rid)?; + let device = device_resource.0; + let surface_resource = + state.resource_table.get::<WebGpuSurface>(surface_rid)?; + let surface = surface_resource.0; + + let output = + gfx_select!(device => instance.surface_get_current_texture(surface, ()))?; + + match output.status { + SurfaceStatus::Good | SurfaceStatus::Suboptimal => { + let id = output.texture_id.unwrap(); + let rid = state.resource_table.add(crate::texture::WebGpuTexture(id)); + Ok(WebGpuResult::rid(rid)) + } + _ => Err(AnyError::msg("Invalid Surface Status")), + } +} + +#[op] +pub fn op_webgpu_surface_present( + state: &mut OpState, + device_rid: ResourceId, + surface_rid: ResourceId, +) -> Result<(), AnyError> { + let instance = state.borrow::<super::Instance>(); + let device_resource = state + .resource_table + .get::<super::WebGpuDevice>(device_rid)?; + let device = device_resource.0; + let surface_resource = + state.resource_table.get::<WebGpuSurface>(surface_rid)?; + let surface = surface_resource.0; + + let _ = gfx_select!(device => instance.surface_present(surface))?; + + Ok(()) +} diff --git a/ext/webgpu/src/texture.rs b/ext/webgpu/src/texture.rs index 9a6a1e939..c4b36c288 100644 --- a/ext/webgpu/src/texture.rs +++ b/ext/webgpu/src/texture.rs @@ -34,6 +34,7 @@ pub struct CreateTextureArgs { dimension: wgpu_types::TextureDimension, format: wgpu_types::TextureFormat, usage: u32, + view_formats: Vec<wgpu_types::TextureFormat>, } #[op] @@ -55,12 +56,13 @@ pub fn op_webgpu_create_texture( dimension: args.dimension, format: args.format, usage: wgpu_types::TextureUsages::from_bits_truncate(args.usage), + view_formats: args.view_formats, }; gfx_put!(device => instance.device_create_texture( device, &descriptor, - std::marker::PhantomData + () ) => state, WebGpuTexture) } @@ -109,6 +111,6 @@ pub fn op_webgpu_create_texture_view( gfx_put!(texture => instance.texture_create_view( texture, &descriptor, - std::marker::PhantomData + () ) => state, WebGpuTextureView) } |