chore(ext/webgpu): include GPUCanvasContext in snapshot (#21773)

Part 1 of #21713 

Changes:

- Remove `.present()` and add a `presentGPUCanvasContext` (not exposed
yet to users)
- Move lazy load logic to `00_init.js`. This can be used to use webgpu
on-demand from future code (OffScreenCanvas)
This commit is contained in:
Divy Srivastava 2024-01-05 19:55:01 +05:30 committed by GitHub
parent 611993fbe0
commit 9f86705fa6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 141 additions and 139 deletions

View File

@ -172,7 +172,7 @@ hkdf = "0.12.3"
# webgpu
raw-window-handle = "0.5.0"
wgpu-core = "=0.18"
wgpu-core = { version = "=0.18", features = ["raw-window-handle"] }
wgpu-types = "=0.18"
wgpu-hal = "=0.18"

39
ext/webgpu/00_init.js Normal file
View File

@ -0,0 +1,39 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { core } from "ext:core/mod.js";
const ops = core.ops;
let webgpu;
function webGPUNonEnumerable(getter) {
let valueIsSet = false;
let value;
return {
get() {
loadWebGPU();
if (valueIsSet) {
return value;
} else {
return getter();
}
},
set(v) {
loadWebGPU();
valueIsSet = true;
value = v;
},
enumerable: false,
configurable: true,
};
}
function loadWebGPU() {
if (!webgpu) {
webgpu = ops.op_lazy_load_esm("ext:deno_webgpu/01_webgpu.js");
}
}
export { loadWebGPU, webgpu, webGPUNonEnumerable };

View File

@ -7036,6 +7036,78 @@ webidl.converters["GPUSignedOffset32"] = (V, opts) =>
// TYPEDEF: GPUFlagsConstant
webidl.converters["GPUFlagsConstant"] = webidl.converters["unsigned long"];
// 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,
);
const gpu = webidl.createBranded(GPU);
export {
_device,

View File

@ -11,22 +11,16 @@ const ops = core.ops;
import * as webidl from "ext:deno_webidl/00_webidl.js";
import { createFilteredInspectProxy } from "ext:deno_console/01_console.js";
const { Symbol, SymbolFor, ObjectPrototypeIsPrototypeOf } = primordials;
import {
_device,
assertDevice,
createGPUTexture,
GPUTextureUsage,
} from "ext:deno_webgpu/01_webgpu.js";
import { loadWebGPU, webgpu } from "ext:deno_webgpu/00_init.js";
const _surfaceRid = Symbol("[[surfaceRid]]");
const _configuration = Symbol("[[configuration]]");
const _canvas = Symbol("[[canvas]]");
const _currentTexture = Symbol("[[currentTexture]]");
const _present = Symbol("[[present]]");
class GPUCanvasContext {
/** @type {number} */
[_surfaceRid];
/** @type {InnerGPUDevice} */
[_device];
[_configuration];
[_canvas];
/** @type {GPUTexture | undefined} */
@ -50,6 +44,7 @@ class GPUCanvasContext {
context: "Argument 1",
});
const { _device, assertDevice } = webgpu;
this[_device] = configuration.device[_device];
this[_configuration] = configuration;
const device = assertDevice(this, {
@ -72,6 +67,8 @@ class GPUCanvasContext {
}
unconfigure() {
const { _device } = webgpu;
webidl.assertBranded(this, GPUCanvasContextPrototype);
this[_configuration] = null;
@ -86,6 +83,7 @@ class GPUCanvasContext {
if (this[_configuration] === null) {
throw new DOMException("context is not configured.", "InvalidStateError");
}
const { createGPUTexture, assertDevice } = webgpu;
const device = assertDevice(this, { prefix, context: "this" });
@ -119,8 +117,10 @@ class GPUCanvasContext {
return texture;
}
// Extended from spec. Required to present the texture; browser don't need this.
present() {
// Required to present the texture; browser don't need this.
[_present]() {
const { assertDevice } = webgpu;
webidl.assertBranded(this, GPUCanvasContextPrototype);
const prefix = "Failed to execute 'present' on 'GPUCanvasContext'";
const device = assertDevice(this[_currentTexture], {
@ -148,88 +148,17 @@ class GPUCanvasContext {
const GPUCanvasContextPrototype = GPUCanvasContext.prototype;
function createCanvasContext(options) {
// lazy load webgpu if needed
loadWebGPU();
const canvasContext = webidl.createBranded(GPUCanvasContext);
canvasContext[_surfaceRid] = options.surfaceRid;
canvasContext[_canvas] = options.canvas;
return canvasContext;
}
// Converters
function presentGPUCanvasContext(ctx) {
ctx[_present]();
}
// 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,
);
window.__bootstrap.webgpu = {
...window.__bootstrap.webgpu,
GPUCanvasContext,
createCanvasContext,
};
export { createCanvasContext, GPUCanvasContext, presentGPUCanvasContext };

View File

@ -13,9 +13,6 @@ description = "WebGPU implementation for Deno"
[lib]
path = "lib.rs"
[features]
surface = ["wgpu-core/raw-window-handle", "dep:raw-window-handle"]
# We make all dependencies conditional on not being wasm,
# so the whole workspace can built as wasm.
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]

View File

@ -23,7 +23,6 @@ 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;
@ -282,7 +281,6 @@ impl From<ClearError> for WebGpuError {
}
}
#[cfg(feature = "surface")]
impl From<ConfigureSurfaceError> for WebGpuError {
fn from(err: ConfigureSurfaceError) -> Self {
WebGpuError::Validation(fmt_err(&err))

View File

@ -75,7 +75,6 @@ pub mod queue;
pub mod render_pass;
pub mod sampler;
pub mod shader;
#[cfg(feature = "surface")]
pub mod surface;
pub mod texture;
@ -212,7 +211,12 @@ deno_core::extension!(
queue::op_webgpu_write_texture,
// shader
shader::op_webgpu_create_shader_module,
// surface
surface::op_webgpu_surface_configure,
surface::op_webgpu_surface_get_current_texture,
surface::op_webgpu_surface_present
],
esm = ["00_init.js", "02_surface.js"],
lazy_loaded_esm = ["01_webgpu.js"],
);

View File

@ -11,17 +11,6 @@ use std::borrow::Cow;
use std::rc::Rc;
use wgpu_types::SurfaceStatus;
deno_core::extension!(
deno_webgpu_surface,
deps = [deno_webidl, deno_web, deno_webgpu],
ops = [
op_webgpu_surface_configure,
op_webgpu_surface_get_current_texture,
op_webgpu_surface_present,
],
esm = ["02_surface.js"],
);
pub struct WebGpuSurface(pub crate::Instance, pub wgpu_core::id::SurfaceId);
impl Resource for WebGpuSurface {
fn name(&self) -> Cow<str> {

View File

@ -42,6 +42,12 @@ import * as globalInterfaces from "ext:deno_web/04_global_interfaces.js";
import * as webStorage from "ext:deno_webstorage/01_webstorage.js";
import * as prompt from "ext:runtime/41_prompt.js";
import * as imageData from "ext:deno_web/16_image_data.js";
import {
loadWebGPU,
webgpu,
webGPUNonEnumerable,
} from "ext:deno_webgpu/00_init.js";
import * as webgpuSurface from "ext:deno_webgpu/02_surface.js";
import { unstableIds } from "ext:runtime/90_deno_ns.js";
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope
@ -189,6 +195,7 @@ unstableForWindowOrWorkerGlobalScope[unstableIds.webgpu] = {
GPUError: webGPUNonEnumerable(() => webgpu.GPUError),
GPUValidationError: webGPUNonEnumerable(() => webgpu.GPUValidationError),
GPUOutOfMemoryError: webGPUNonEnumerable(() => webgpu.GPUOutOfMemoryError),
GPUCanvasContext: webGPUNonEnumerable(() => webgpuSurface.GPUCanvasContext),
};
class Navigator {
@ -229,39 +236,6 @@ const numCpus = memoizeLazy(() => ops.op_bootstrap_numcpus());
const userAgent = memoizeLazy(() => ops.op_bootstrap_user_agent());
const language = memoizeLazy(() => ops.op_bootstrap_language());
let webgpu;
function webGPUNonEnumerable(getter) {
let valueIsSet = false;
let value;
return {
get() {
loadWebGPU();
if (valueIsSet) {
return value;
} else {
return getter();
}
},
set(v) {
loadWebGPU();
valueIsSet = true;
value = v;
},
enumerable: false,
configurable: true,
};
}
function loadWebGPU() {
if (!webgpu) {
webgpu = ops.op_lazy_load_esm("ext:deno_webgpu/01_webgpu.js");
}
}
ObjectDefineProperties(Navigator.prototype, {
gpu: {
configurable: true,