Skip to content

Commit

Permalink
feat(deno): surface support (#3265)
Browse files Browse the repository at this point in the history
  • Loading branch information
crowlKats authored Jan 9, 2023
1 parent ad4dac8 commit 2252b12
Show file tree
Hide file tree
Showing 10 changed files with 408 additions and 15 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions deno_webgpu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ readme = "README.md"
repository.workspace = true
description = "WebGPU implementation for Deno"

[features]
surface = ["wgpu-core/raw-window-handle", "dep:raw-window-handle"]

[dependencies]
deno_core.workspace = true
serde = { workspace = true, features = ["derive"] }
tokio = { workspace = true, features = ["full"] }
wgpu-types = { workspace = true, features = ["trace", "replay", "serde"] }
raw-window-handle = { workspace = true, optional = true }

[dependencies.wgpu-core]
workspace = true
Expand Down
20 changes: 15 additions & 5 deletions deno_webgpu/src/01_webgpu.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,13 @@
}
}

const illegalConstructorKey = Symbol("illegalConstructorKey");
class GPUError extends Error {
constructor() {
constructor(key = null) {
super();
webidl.illegalConstructor();
if (key !== illegalConstructorKey) {
webidl.illegalConstructor();
}
}

[_message];
Expand All @@ -212,7 +215,9 @@
prefix,
context: "Argument 1",
});
super(message);
super(illegalConstructorKey);
this[webidl.brand] = webidl.brand;
this[_message] = message;
}
}
const GPUValidationErrorPrototype = GPUValidationError.prototype;
Expand All @@ -226,7 +231,9 @@
prefix,
context: "Argument 1",
});
super(message);
super(illegalConstructorKey);
this[webidl.brand] = webidl.brand;
this[_message] = message;
}
}
const GPUOutOfMemoryErrorPrototype = GPUOutOfMemoryError.prototype;
Expand Down Expand Up @@ -347,7 +354,7 @@
rid,
adapter: this,
features: createGPUSupportedFeatures(features),
limits: createGPUSupportedFeatures(limits),
limits: createGPUSupportedLimits(limits),
});
return createGPUDevice(
descriptor.label,
Expand Down Expand Up @@ -5251,6 +5258,9 @@
const GPUQuerySetPrototype = GPUQuerySet.prototype;

window.__bootstrap.webgpu = {
_device,
assertDevice,
createGPUTexture,
gpu: webidl.createBranded(GPU),
GPU,
GPUAdapter,
Expand Down
135 changes: 135 additions & 0 deletions deno_webgpu/src/03_surface.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Copyright 2018-2022 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);
77 changes: 77 additions & 0 deletions deno_webgpu/src/04_surface_idl_types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright 2018-2022 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,
},
];
webidl.converters["GPUCanvasConfiguration"] = webidl
.createDictionaryConverter(
"GPUCanvasConfiguration",
dictMembersGPUCanvasConfiguration,
);
})(this);
9 changes: 9 additions & 0 deletions deno_webgpu/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,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;
Expand Down Expand Up @@ -275,6 +277,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,
Expand Down
21 changes: 16 additions & 5 deletions deno_webgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,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),
}
Expand Down Expand Up @@ -67,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);
Expand All @@ -82,7 +93,7 @@ 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 {
Expand Down
Loading

0 comments on commit 2252b12

Please sign in to comment.