mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 06:44:14 +00:00
feat(deno): surface support (#3265)
This commit is contained in:
parent
ad4dac87fb
commit
2252b1209a
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -628,6 +628,7 @@ name = "deno_webgpu"
|
||||
version = "0.81.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"raw-window-handle 0.5.0",
|
||||
"serde",
|
||||
"tokio",
|
||||
"wgpu-core",
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
@ -212,7 +215,9 @@
|
||||
prefix,
|
||||
context: "Argument 1",
|
||||
});
|
||||
super(message);
|
||||
super(illegalConstructorKey);
|
||||
this[webidl.brand] = webidl.brand;
|
||||
this[_message] = message;
|
||||
}
|
||||
}
|
||||
const GPUValidationErrorPrototype = GPUValidationError.prototype;
|
||||
@ -226,7 +231,9 @@
|
||||
prefix,
|
||||
context: "Argument 1",
|
||||
});
|
||||
super(message);
|
||||
super(illegalConstructorKey);
|
||||
this[webidl.brand] = webidl.brand;
|
||||
this[_message] = message;
|
||||
}
|
||||
}
|
||||
const GPUOutOfMemoryErrorPrototype = GPUOutOfMemoryError.prototype;
|
||||
@ -347,7 +354,7 @@
|
||||
rid,
|
||||
adapter: this,
|
||||
features: createGPUSupportedFeatures(features),
|
||||
limits: createGPUSupportedFeatures(limits),
|
||||
limits: createGPUSupportedLimits(limits),
|
||||
});
|
||||
return createGPUDevice(
|
||||
descriptor.label,
|
||||
@ -5251,6 +5258,9 @@
|
||||
const GPUQuerySetPrototype = GPUQuerySet.prototype;
|
||||
|
||||
window.__bootstrap.webgpu = {
|
||||
_device,
|
||||
assertDevice,
|
||||
createGPUTexture,
|
||||
gpu: webidl.createBranded(GPU),
|
||||
GPU,
|
||||
GPUAdapter,
|
||||
|
135
deno_webgpu/src/03_surface.js
Normal file
135
deno_webgpu/src/03_surface.js
Normal file
@ -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
deno_webgpu/src/04_surface_idl_types.js
Normal file
77
deno_webgpu/src/04_surface_idl_types.js
Normal file
@ -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);
|
@ -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;
|
||||
@ -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,
|
||||
|
@ -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),
|
||||
}
|
||||
@ -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);
|
||||
@ -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 {
|
||||
|
130
deno_webgpu/src/surface.rs
Normal file
130
deno_webgpu/src/surface.rs
Normal file
@ -0,0 +1,130 @@
|
||||
// Copyright 2018-2022 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()
|
||||
.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,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
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,
|
||||
};
|
||||
|
||||
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(())
|
||||
}
|
@ -374,11 +374,6 @@ interface GPUExternalTexture {
|
||||
};
|
||||
GPUExternalTexture includes GPUObjectBase;
|
||||
|
||||
dictionary GPUExternalTextureDescriptor : GPUObjectDescriptorBase {
|
||||
required HTMLVideoElement source;
|
||||
PredefinedColorSpace colorSpace = "srgb";
|
||||
};
|
||||
|
||||
[Exposed=(Window, DedicatedWorker), SecureContext]
|
||||
interface GPUSampler {
|
||||
};
|
||||
@ -1068,6 +1063,26 @@ enum GPUPipelineStatisticName {
|
||||
"compute-shader-invocations",
|
||||
};
|
||||
|
||||
[Exposed=(Window, DedicatedWorker), SecureContext]
|
||||
interface GPUCanvasContext {
|
||||
undefined configure(GPUCanvasConfiguration configuration);
|
||||
undefined unconfigure();
|
||||
|
||||
GPUTexture getCurrentTexture();
|
||||
};
|
||||
|
||||
enum GPUCanvasAlphaMode {
|
||||
"opaque",
|
||||
"premultiplied"
|
||||
};
|
||||
|
||||
dictionary GPUCanvasConfiguration {
|
||||
required GPUDevice device;
|
||||
required GPUTextureFormat format;
|
||||
GPUTextureUsageFlags usage = 0x10; // GPUTextureUsage.RENDER_ATTACHMENT
|
||||
GPUCanvasAlphaMode alphaMode = "opaque";
|
||||
};
|
||||
|
||||
enum GPUDeviceLostReason {
|
||||
"destroyed"
|
||||
};
|
||||
|
@ -3847,6 +3847,7 @@ pub enum PresentMode {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "trace", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
|
||||
pub enum CompositeAlphaMode {
|
||||
/// Chooses either `Opaque` or `Inherit` automatically,depending on the
|
||||
/// `alpha_mode` that the current surface can support.
|
||||
|
Loading…
Reference in New Issue
Block a user