0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 09:31:22 -05:00

experiment: wgpu sync (#13402)

This commit is contained in:
Aaron O'Mullan 2022-01-19 13:38:51 +01:00 committed by GitHub
parent 1259a3f48c
commit 2ab21dafa7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 1348 additions and 1917 deletions

94
Cargo.lock generated
View file

@ -136,9 +136,9 @@ dependencies = [
[[package]]
name = "ash"
version = "0.33.3+1.2.191"
version = "0.35.0+1.2.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc4f1d82f164f838ae413296d1131aa6fa79b917d25bebaa7033d25620c09219"
checksum = "5a7638ce84f8c84d6fd6faa63aa267574d345181ba591c0eeb5550d4c30cd600"
dependencies = [
"libloading",
]
@ -283,6 +283,16 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "bitflags_serde_shim"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25c3d626f0280ec39b33a6fc5c6c1067432b4c41e94aee40ded197a6649bf025"
dependencies = [
"bitflags",
"serde",
]
[[package]]
name = "block"
version = "0.1.6"
@ -1428,12 +1438,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
[[package]]
name = "fixedbitset"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e"
[[package]]
name = "flaky_test"
version = "0.1.0"
@ -1797,6 +1801,12 @@ dependencies = [
"libc",
]
[[package]]
name = "hexf-parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
[[package]]
name = "hmac"
version = "0.11.0"
@ -2307,8 +2317,7 @@ dependencies = [
[[package]]
name = "metal"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0514f491f4cc03632ab399ee01e2c1c1b12d3e1cf2d667c1ff5f87d6dcd2084"
source = "git+https://github.com/gfx-rs/metal-rs?rev=140c8f4#140c8f4e39001ae154f153ffc767da6c0c9d7f06"
dependencies = [
"bitflags",
"block",
@ -2358,17 +2367,17 @@ dependencies = [
[[package]]
name = "naga"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c5859e55c51da10b98e7a73068e0a0c5da7bbcae4fc38f86043d0c6d1b917cf"
version = "0.8.0"
source = "git+https://github.com/gfx-rs/naga?rev=a1840be#a1840beb1a96c9a49980fe3efa8e2f3dcd88abe6"
dependencies = [
"bit-set",
"bitflags",
"codespan-reporting",
"fxhash",
"hexf-parse",
"indexmap",
"log",
"num-traits",
"petgraph 0.6.0",
"rustc-hash",
"serde",
"spirv",
"thiserror",
@ -2660,17 +2669,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
dependencies = [
"fixedbitset 0.2.0",
"indexmap",
]
[[package]]
name = "petgraph"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f"
dependencies = [
"fixedbitset 0.4.1",
"fixedbitset",
"indexmap",
]
@ -3038,16 +3037,6 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6"
[[package]]
name = "raw-window-handle"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28f55143d0548dad60bb4fbdc835a3d7ac6acc3324506450c5fdd6e42903a76"
dependencies = [
"libc",
"raw-window-handle 0.4.2",
]
[[package]]
name = "raw-window-handle"
version = "0.4.2"
@ -3183,9 +3172,9 @@ dependencies = [
[[package]]
name = "ron"
version = "0.6.6"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86018df177b1beef6c7c8ef949969c4f7cb9a9344181b92486b23c79995bdaa4"
checksum = "1b861ecaade43ac97886a512b360d01d66be9f41f3c61088b42cedf92e03d678"
dependencies = [
"base64 0.13.0",
"bitflags",
@ -3730,7 +3719,7 @@ dependencies = [
"is-macro",
"once_cell",
"parking_lot",
"petgraph 0.5.1",
"petgraph",
"radix_fmt",
"relative-path",
"retain_mut",
@ -4081,7 +4070,7 @@ checksum = "1d53bbcbb4b055c547f283af1f84211f425b95ac59e02d8b70c94b8a63a4704f"
dependencies = [
"ahash",
"indexmap",
"petgraph 0.5.1",
"petgraph",
"swc_common",
]
@ -4093,7 +4082,7 @@ checksum = "83b42a8b13068dd90dec954ec44576d5922914687bc34277f3b0f8d0bbeb4e83"
dependencies = [
"ahash",
"auto_impl",
"petgraph 0.5.1",
"petgraph",
"swc_fast_graph",
"tracing",
]
@ -4903,13 +4892,13 @@ dependencies = [
[[package]]
name = "wgpu-core"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f963c62473a36e3cef6c58181f2ed6d0d38d2043d970dbed46cb197190090c99"
version = "0.12.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=cdd480a89c9e3b681d9d174e65082d2bdbc903ef#cdd480a89c9e3b681d9d174e65082d2bdbc903ef"
dependencies = [
"arrayvec 0.7.2",
"bitflags",
"cfg_aliases",
"codespan-reporting",
"copyless",
"fxhash",
"log",
@ -4926,9 +4915,8 @@ dependencies = [
[[package]]
name = "wgpu-hal"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27cd894b17bff1958ee93da1cc991fd64bf99667746d4bd2a7403855f4d37fe2"
version = "0.12.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=cdd480a89c9e3b681d9d174e65082d2bdbc903ef#cdd480a89c9e3b681d9d174e65082d2bdbc903ef"
dependencies = [
"arrayvec 0.7.2",
"ash",
@ -4943,6 +4931,7 @@ dependencies = [
"gpu-alloc",
"gpu-descriptor",
"inplace_it",
"js-sys",
"khronos-egl",
"libloading",
"log",
@ -4950,21 +4939,24 @@ dependencies = [
"naga",
"objc",
"parking_lot",
"profiling",
"range-alloc",
"raw-window-handle 0.3.4",
"raw-window-handle",
"renderdoc-sys",
"thiserror",
"wasm-bindgen",
"web-sys",
"wgpu-types",
"winapi 0.3.9",
]
[[package]]
name = "wgpu-types"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25feb2fbf24ab3219a9f10890ceb8e1ef02b13314ed89d64a9ae99dcad883e18"
version = "0.12.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=cdd480a89c9e3b681d9d174e65082d2bdbc903ef#cdd480a89c9e3b681d9d174e65082d2bdbc903ef"
dependencies = [
"bitflags",
"bitflags_serde_shim",
"serde",
]

View file

@ -82,7 +82,7 @@ fn create_compiler_snapshot(
op_crate_libs.insert("deno.url", deno_url::get_declaration());
op_crate_libs.insert("deno.web", deno_web::get_declaration());
op_crate_libs.insert("deno.fetch", deno_fetch::get_declaration());
op_crate_libs.insert("deno.webgpu", deno_webgpu::get_declaration());
op_crate_libs.insert("deno.webgpu", deno_webgpu_get_declaration());
op_crate_libs.insert("deno.websocket", deno_websocket::get_declaration());
op_crate_libs.insert("deno.webstorage", deno_webstorage::get_declaration());
op_crate_libs.insert("deno.crypto", deno_crypto::get_declaration());
@ -322,7 +322,7 @@ fn main() {
);
println!(
"cargo:rustc-env=DENO_WEBGPU_LIB_PATH={}",
deno_webgpu::get_declaration().display()
deno_webgpu_get_declaration().display()
);
println!(
"cargo:rustc-env=DENO_WEBSOCKET_LIB_PATH={}",
@ -369,6 +369,11 @@ fn main() {
}
}
fn deno_webgpu_get_declaration() -> PathBuf {
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
manifest_dir.join("dts").join("lib.deno_webgpu.d.ts")
}
fn get_js_files(d: &str) -> Vec<PathBuf> {
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let mut js_files = std::fs::read_dir(d)

View file

@ -92,12 +92,15 @@ declare interface GPUDeviceDescriptor extends GPUObjectDescriptorBase {
}
declare type GPUFeatureName =
| "depth-clamping"
| "depth-clip-control"
| "depth24unorm-stencil8"
| "depth32float-stencil8"
| "pipeline-statistics-query"
| "texture-compression-bc"
| "texture-compression-etc2"
| "texture-compression-astc"
| "timestamp-query"
| "indirect-first-instance"
// extended from spec
| "mappable-primary-buffers"
| "sampled-texture-binding-array"
@ -108,9 +111,6 @@ declare type GPUFeatureName =
| "multi-draw-indirect-count"
| "push-constants"
| "address-mode-clamp-to-border"
| "non-fill-polygon-mode"
| "texture-compression-etc2"
| "texture-compression-astc-ldr"
| "texture-adapter-specific-format-features"
| "shader-float64"
| "vertex-attribute-64bit";
@ -314,6 +314,44 @@ declare type GPUTextureFormat =
| "bc6h-rgb-float"
| "bc7-rgba-unorm"
| "bc7-rgba-unorm-srgb"
| "etc2-rgb8unorm"
| "etc2-rgb8unorm-srgb"
| "etc2-rgb8a1unorm"
| "etc2-rgb8a1unorm-srgb"
| "etc2-rgba8unorm"
| "etc2-rgba8unorm-srgb"
| "eac-r11unorm"
| "eac-r11snorm"
| "eac-rg11unorm"
| "eac-rg11snorm"
| "astc-4x4-unorm"
| "astc-4x4-unorm-srgb"
| "astc-5x4-unorm"
| "astc-5x4-unorm-srgb"
| "astc-5x5-unorm"
| "astc-5x5-unorm-srgb"
| "astc-6x5-unorm"
| "astc-6x5-unorm-srgb"
| "astc-6x6-unorm"
| "astc-6x6-unorm-srgb"
| "astc-8x5-unorm"
| "astc-8x5-unorm-srgb"
| "astc-8x6-unorm"
| "astc-8x6-unorm-srgb"
| "astc-8x8-unorm"
| "astc-8x8-unorm-srgb"
| "astc-10x5-unorm"
| "astc-10x5-unorm-srgb"
| "astc-10x6-unorm"
| "astc-10x6-unorm-srgb"
| "astc-10x8-unorm"
| "astc-10x8-unorm-srgb"
| "astc-10x10-unorm"
| "astc-10x10-unorm-srgb"
| "astc-12x10-unorm"
| "astc-12x10-unorm-srgb"
| "astc-12x12-unorm"
| "astc-12x12-unorm-srgb"
| "depth24unorm-stencil8"
| "depth32float-stencil8";
@ -519,7 +557,7 @@ declare interface GPUPrimitiveState {
stripIndexFormat?: GPUIndexFormat;
frontFace?: GPUFrontFace;
cullMode?: GPUCullMode;
clampDepth?: boolean;
unclippedDepth?: boolean;
}
declare type GPUFrontFace = "ccw" | "cw";
@ -558,9 +596,9 @@ declare class GPUColorWrite {
}
declare interface GPUBlendComponent {
operation: GPUBlendOperation;
srcFactor: GPUBlendFactor;
dstFactor: GPUBlendFactor;
operation: GPUBlendOperation;
}
declare type GPUBlendFactor =
@ -673,8 +711,6 @@ declare interface GPUVertexAttribute {
declare class GPUCommandBuffer implements GPUObjectBase {
label: string | null;
readonly executionTime: Promise<number>;
}
declare interface GPUCommandBufferDescriptor extends GPUObjectDescriptorBase {}
@ -713,6 +749,12 @@ declare class GPUCommandEncoder implements GPUObjectBase {
copySize: GPUExtent3D,
): undefined;
clearBuffer(
destination: GPUBuffer,
destinationOffset: number,
size: number,
): undefined;
pushDebugGroup(groupLabel: string): undefined;
popDebugGroup(): undefined;
insertDebugMarker(markerLabel: string): undefined;
@ -730,9 +772,7 @@ declare class GPUCommandEncoder implements GPUObjectBase {
finish(descriptor?: GPUCommandBufferDescriptor): GPUCommandBuffer;
}
declare interface GPUCommandEncoderDescriptor extends GPUObjectDescriptorBase {
measureExecutionTime?: boolean;
}
declare interface GPUCommandEncoderDescriptor extends GPUObjectDescriptorBase {}
declare interface GPUImageDataLayout {
offset?: number;

View file

@ -1,9 +1,10 @@
[[block]]
struct PrimeIndices {
data: [[stride(4)]] array<u32>;
}; // this is used as both input and output for convenience
[[group(0), binding(0)]]
var<storage, read_write> v_indices: PrimeIndices;
// The Collatz Conjecture states that for any integer n:
// If n is even, n = n/2
// If n is odd, n = 3n+1
@ -25,12 +26,14 @@ fn collatz_iterations(n_base: u32) -> u32{
if (n >= 1431655765u) { // 0x55555555u
return 4294967295u; // 0xffffffffu
}
n = 3u * n + 1u;
}
i = i + 1u;
}
return i;
}
[[stage(compute), workgroup_size(1)]]
fn main([[builtin(global_invocation_id)]] global_id: vec3<u32>) {
v_indices.data[global_id.x] = collatz_iterations(v_indices.data[global_id.x]);

View file

@ -33,13 +33,14 @@ Deno.test({
const stagingBuffer = device.createBuffer({
size: size,
usage: 1 | 8,
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
});
const storageBuffer = device.createBuffer({
label: "Storage Buffer",
size: size,
usage: 0x80 | 8 | 4,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST |
GPUBufferUsage.COPY_SRC,
mappedAtCreation: true,
});

View file

@ -1,4 +1,4 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
// @ts-check
/// <reference path="../../core/lib.deno_core.d.ts" />
@ -3060,6 +3060,48 @@
device.pushError(err);
}
/**
* @param {GPUBuffer} destination
* @param {GPUSize64} destinationOffset
* @param {GPUSize64} size
*/
clearBuffer(destination, destinationOffset, size) {
webidl.assertBranded(this, GPUCommandEncoder);
const prefix = "Failed to execute 'clearBuffer' on 'GPUCommandEncoder'";
webidl.requiredArguments(arguments.length, 3, { prefix });
destination = webidl.converters.GPUBuffer(destination, {
prefix,
context: "Argument 1",
});
destinationOffset = webidl.converters.GPUSize64(destinationOffset, {
prefix,
context: "Argument 2",
});
size = webidl.converters.GPUSize64(size, {
prefix,
context: "Argument 3",
});
const device = assertDevice(this, { prefix, context: "this" });
const commandEncoderRid = assertResource(this, {
prefix,
context: "this",
});
const destinationRid = assertResource(destination, {
prefix,
context: "Argument 1",
});
const { err } = core.opSync(
"op_webgpu_command_encoder_clear_buffer",
{
commandEncoderRid,
destinationRid,
destinationOffset,
size,
},
);
device.pushError(err);
}
/**
* @param {string} groupLabel
*/
@ -3203,7 +3245,7 @@
prefix,
context: "Argument 3",
});
destination = webidl.converters.GPUQuerySet(destination, {
destination = webidl.converters.GPUBuffer(destination, {
prefix,
context: "Argument 4",
});
@ -4527,15 +4569,10 @@
webidl.illegalConstructor();
}
get executionTime() {
throw new Error("Not yet implemented");
}
[SymbolFor("Deno.privateCustomInspect")](inspect) {
return `${this.constructor.name} ${
inspect({
label: this.label,
// TODO(crowlKats): executionTime
})
}`;
}

View file

@ -1,4 +1,4 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
// @ts-check
/// <reference path="../web/internal.d.ts" />
@ -111,28 +111,35 @@
webidl.converters["GPUFeatureName"] = webidl.createEnumConverter(
"GPUFeatureName",
[
"depth-clamping",
"depth-clip-control",
"depth24unorm-stencil8",
"depth32float-stencil8",
"pipeline-statistics-query",
"texture-compression-bc",
"texture-compression-etc2",
"texture-compression-astc",
"timestamp-query",
"indirect-first-instance",
// extended from spec
"mappable-primary-buffers",
"sampled-texture-binding-array",
"sampled-texture-array-dynamic-indexing",
"sampled-texture-array-non-uniform-indexing",
"texture-binding-array",
"buffer-binding-array",
"storage-resource-binding-array",
"sampled-texture-and-storage-buffer-array-non-uniform-indexing",
"uniform-buffer-and-storage-buffer-texture-non-uniform-indexing",
"unsized-binding-array",
"multi-draw-indirect",
"multi-draw-indirect-count",
"push-constants",
"address-mode-clamp-to-border",
"non-fill-polygon-mode",
"texture-compression-etc2",
"texture-compression-astc-ldr",
"texture-adapter-specific-format-features",
"shader-float64",
"vertex-attribute-64bit",
"conservative-rasterization",
"vertex-writable-storage",
"clear-commands",
"spirv-shader-passthrough",
"shader-primitive-index",
],
);
@ -348,6 +355,44 @@
"bc6h-rgb-float",
"bc7-rgba-unorm",
"bc7-rgba-unorm-srgb",
"etc2-rgb8unorm",
"etc2-rgb8unorm-srgb",
"etc2-rgb8a1unorm",
"etc2-rgb8a1unorm-srgb",
"etc2-rgba8unorm",
"etc2-rgba8unorm-srgb",
"eac-r11unorm",
"eac-r11snorm",
"eac-rg11unorm",
"eac-rg11snorm",
"astc-4x4-unorm",
"astc-4x4-unorm-srgb",
"astc-5x4-unorm",
"astc-5x4-unorm-srgb",
"astc-5x5-unorm",
"astc-5x5-unorm-srgb",
"astc-6x5-unorm",
"astc-6x5-unorm-srgb",
"astc-6x6-unorm",
"astc-6x6-unorm-srgb",
"astc-8x5-unorm",
"astc-8x5-unorm-srgb",
"astc-8x6-unorm",
"astc-8x6-unorm-srgb",
"astc-8x8-unorm",
"astc-8x8-unorm-srgb",
"astc-10x5-unorm",
"astc-10x5-unorm-srgb",
"astc-10x6-unorm",
"astc-10x6-unorm-srgb",
"astc-10x8-unorm",
"astc-10x8-unorm-srgb",
"astc-10x10-unorm",
"astc-10x10-unorm-srgb",
"astc-12x10-unorm",
"astc-12x10-unorm-srgb",
"astc-12x12-unorm",
"astc-12x12-unorm-srgb",
"depth24unorm-stencil8",
"depth32float-stencil8",
],
@ -1131,7 +1176,7 @@
defaultValue: "none",
},
{
key: "clampDepth",
key: "unclippedDepth",
converter: webidl.converters["boolean"],
defaultValue: false,
},
@ -1458,13 +1503,7 @@
);
// DICTIONARY: GPUCommandEncoderDescriptor
const dictMembersGPUCommandEncoderDescriptor = [
{
key: "measureExecutionTime",
converter: webidl.converters["boolean"],
defaultValue: false,
},
];
const dictMembersGPUCommandEncoderDescriptor = [];
webidl.converters["GPUCommandEncoderDescriptor"] = webidl
.createDictionaryConverter(
"GPUCommandEncoderDescriptor",

View file

@ -1,4 +1,4 @@
# Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
# Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
[package]
name = "deno_webgpu"
@ -7,15 +7,12 @@ authors = ["the Deno authors"]
edition = "2021"
license = "MIT"
readme = "README.md"
repository = "https://github.com/denoland/deno"
repository = "https://github.com/gfx-rs/wgpu"
description = "WebGPU implementation for Deno"
[lib]
path = "lib.rs"
[dependencies]
deno_core = { version = "0.114.0", path = "../../core" }
serde = { version = "1.0.129", features = ["derive"] }
tokio = { version = "1.10.1", features = ["full"] }
wgpu-core = { version = "0.10.1", features = ["trace"] }
wgpu-types = "0.10.0"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.10", features = ["full"] }
wgpu-core = { git = "https://github.com/gfx-rs/wgpu", rev = "cdd480a89c9e3b681d9d174e65082d2bdbc903ef", features = ["trace", "replay", "serde"] }
wgpu-types = { git = "https://github.com/gfx-rs/wgpu", rev = "cdd480a89c9e3b681d9d174e65082d2bdbc903ef", features = ["trace", "replay", "serde"] }

20
ext/webgpu/LICENSE.md Normal file
View file

@ -0,0 +1,20 @@
MIT License
Copyright 2018-2021 the Deno authors
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,791 +0,0 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::ResourceId;
use deno_core::{OpState, Resource};
use serde::Deserialize;
use serde::Serialize;
use std::borrow::Cow;
use crate::sampler::GpuCompareFunction;
use crate::texture::GpuTextureFormat;
use super::error::{WebGpuError, WebGpuResult};
const MAX_BIND_GROUPS: usize = 8;
pub(crate) struct WebGpuPipelineLayout(
pub(crate) wgpu_core::id::PipelineLayoutId,
);
impl Resource for WebGpuPipelineLayout {
fn name(&self) -> Cow<str> {
"webGPUPipelineLayout".into()
}
}
pub(crate) struct WebGpuComputePipeline(
pub(crate) wgpu_core::id::ComputePipelineId,
);
impl Resource for WebGpuComputePipeline {
fn name(&self) -> Cow<str> {
"webGPUComputePipeline".into()
}
}
pub(crate) struct WebGpuRenderPipeline(
pub(crate) wgpu_core::id::RenderPipelineId,
);
impl Resource for WebGpuRenderPipeline {
fn name(&self) -> Cow<str> {
"webGPURenderPipeline".into()
}
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GpuIndexFormat {
Uint16,
Uint32,
}
impl From<GpuIndexFormat> for wgpu_types::IndexFormat {
fn from(value: GpuIndexFormat) -> wgpu_types::IndexFormat {
match value {
GpuIndexFormat::Uint16 => wgpu_types::IndexFormat::Uint16,
GpuIndexFormat::Uint32 => wgpu_types::IndexFormat::Uint32,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GPUStencilOperation {
Keep,
Zero,
Replace,
Invert,
IncrementClamp,
DecrementClamp,
IncrementWrap,
DecrementWrap,
}
impl From<GPUStencilOperation> for wgpu_types::StencilOperation {
fn from(value: GPUStencilOperation) -> wgpu_types::StencilOperation {
match value {
GPUStencilOperation::Keep => wgpu_types::StencilOperation::Keep,
GPUStencilOperation::Zero => wgpu_types::StencilOperation::Zero,
GPUStencilOperation::Replace => wgpu_types::StencilOperation::Replace,
GPUStencilOperation::Invert => wgpu_types::StencilOperation::Invert,
GPUStencilOperation::IncrementClamp => {
wgpu_types::StencilOperation::IncrementClamp
}
GPUStencilOperation::DecrementClamp => {
wgpu_types::StencilOperation::DecrementClamp
}
GPUStencilOperation::IncrementWrap => {
wgpu_types::StencilOperation::IncrementWrap
}
GPUStencilOperation::DecrementWrap => {
wgpu_types::StencilOperation::DecrementWrap
}
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GpuBlendFactor {
Zero,
One,
Src,
OneMinusSrc,
SrcAlpha,
OneMinusSrcAlpha,
Dst,
OneMinusDst,
DstAlpha,
OneMinusDstAlpha,
SrcAlphaSaturated,
Constant,
OneMinusConstant,
}
impl From<GpuBlendFactor> for wgpu_types::BlendFactor {
fn from(value: GpuBlendFactor) -> wgpu_types::BlendFactor {
match value {
GpuBlendFactor::Zero => wgpu_types::BlendFactor::Zero,
GpuBlendFactor::One => wgpu_types::BlendFactor::One,
GpuBlendFactor::Src => wgpu_types::BlendFactor::Src,
GpuBlendFactor::OneMinusSrc => wgpu_types::BlendFactor::OneMinusSrc,
GpuBlendFactor::SrcAlpha => wgpu_types::BlendFactor::SrcAlpha,
GpuBlendFactor::OneMinusSrcAlpha => {
wgpu_types::BlendFactor::OneMinusSrcAlpha
}
GpuBlendFactor::Dst => wgpu_types::BlendFactor::Dst,
GpuBlendFactor::OneMinusDst => wgpu_types::BlendFactor::OneMinusDst,
GpuBlendFactor::DstAlpha => wgpu_types::BlendFactor::DstAlpha,
GpuBlendFactor::OneMinusDstAlpha => {
wgpu_types::BlendFactor::OneMinusDstAlpha
}
GpuBlendFactor::SrcAlphaSaturated => {
wgpu_types::BlendFactor::SrcAlphaSaturated
}
GpuBlendFactor::Constant => wgpu_types::BlendFactor::Constant,
GpuBlendFactor::OneMinusConstant => {
wgpu_types::BlendFactor::OneMinusConstant
}
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GpuBlendOperation {
Add,
Subtract,
ReverseSubtract,
Min,
Max,
}
impl From<GpuBlendOperation> for wgpu_types::BlendOperation {
fn from(value: GpuBlendOperation) -> wgpu_types::BlendOperation {
match value {
GpuBlendOperation::Add => wgpu_types::BlendOperation::Add,
GpuBlendOperation::Subtract => wgpu_types::BlendOperation::Subtract,
GpuBlendOperation::ReverseSubtract => {
wgpu_types::BlendOperation::ReverseSubtract
}
GpuBlendOperation::Min => wgpu_types::BlendOperation::Min,
GpuBlendOperation::Max => wgpu_types::BlendOperation::Max,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GpuPrimitiveTopology {
PointList,
LineList,
LineStrip,
TriangleList,
TriangleStrip,
}
impl From<GpuPrimitiveTopology> for wgpu_types::PrimitiveTopology {
fn from(value: GpuPrimitiveTopology) -> wgpu_types::PrimitiveTopology {
match value {
GpuPrimitiveTopology::PointList => {
wgpu_types::PrimitiveTopology::PointList
}
GpuPrimitiveTopology::LineList => wgpu_types::PrimitiveTopology::LineList,
GpuPrimitiveTopology::LineStrip => {
wgpu_types::PrimitiveTopology::LineStrip
}
GpuPrimitiveTopology::TriangleList => {
wgpu_types::PrimitiveTopology::TriangleList
}
GpuPrimitiveTopology::TriangleStrip => {
wgpu_types::PrimitiveTopology::TriangleStrip
}
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GpuFrontFace {
Ccw,
Cw,
}
impl From<GpuFrontFace> for wgpu_types::FrontFace {
fn from(value: GpuFrontFace) -> wgpu_types::FrontFace {
match value {
GpuFrontFace::Ccw => wgpu_types::FrontFace::Ccw,
GpuFrontFace::Cw => wgpu_types::FrontFace::Cw,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GpuCullMode {
None,
Front,
Back,
}
impl From<GpuCullMode> for Option<wgpu_types::Face> {
fn from(value: GpuCullMode) -> Option<wgpu_types::Face> {
match value {
GpuCullMode::None => None,
GpuCullMode::Front => Some(wgpu_types::Face::Front),
GpuCullMode::Back => Some(wgpu_types::Face::Back),
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuProgrammableStage {
module: ResourceId,
entry_point: String,
// constants: HashMap<String, GPUPipelineConstantValue>
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateComputePipelineArgs {
device_rid: ResourceId,
label: Option<String>,
layout: Option<ResourceId>,
compute: GpuProgrammableStage,
}
pub fn op_webgpu_create_compute_pipeline(
state: &mut OpState,
args: CreateComputePipelineArgs,
_: (),
) -> 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 pipeline_layout = if let Some(rid) = args.layout {
let id = state.resource_table.get::<WebGpuPipelineLayout>(rid)?;
Some(id.0)
} else {
None
};
let compute_shader_module_resource =
state
.resource_table
.get::<super::shader::WebGpuShaderModule>(args.compute.module)?;
let descriptor = wgpu_core::pipeline::ComputePipelineDescriptor {
label: args.label.map(Cow::from),
layout: pipeline_layout,
stage: wgpu_core::pipeline::ProgrammableStageDescriptor {
module: compute_shader_module_resource.0,
entry_point: Cow::from(args.compute.entry_point),
// TODO(lucacasonato): support args.compute.constants
},
};
let implicit_pipelines = match args.layout {
Some(_) => None,
None => Some(wgpu_core::device::ImplicitPipelineIds {
root_id: std::marker::PhantomData,
group_ids: &[std::marker::PhantomData; MAX_BIND_GROUPS],
}),
};
let (compute_pipeline, maybe_err) = gfx_select!(device => instance.device_create_compute_pipeline(
device,
&descriptor,
std::marker::PhantomData,
implicit_pipelines
));
let rid = state
.resource_table
.add(WebGpuComputePipeline(compute_pipeline));
Ok(WebGpuResult::rid_err(rid, maybe_err))
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ComputePipelineGetBindGroupLayoutArgs {
compute_pipeline_rid: ResourceId,
index: u32,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PipelineLayout {
rid: ResourceId,
label: String,
err: Option<WebGpuError>,
}
pub fn op_webgpu_compute_pipeline_get_bind_group_layout(
state: &mut OpState,
args: ComputePipelineGetBindGroupLayoutArgs,
_: (),
) -> Result<PipelineLayout, AnyError> {
let instance = state.borrow::<super::Instance>();
let compute_pipeline_resource = state
.resource_table
.get::<WebGpuComputePipeline>(args.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, args.index, std::marker::PhantomData));
let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout));
let rid = state
.resource_table
.add(super::binding::WebGpuBindGroupLayout(bind_group_layout));
Ok(PipelineLayout {
rid,
label,
err: maybe_err.map(WebGpuError::from),
})
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuPrimitiveState {
topology: GpuPrimitiveTopology,
strip_index_format: Option<GpuIndexFormat>,
front_face: GpuFrontFace,
cull_mode: GpuCullMode,
clamp_depth: bool,
}
impl From<GpuPrimitiveState> for wgpu_types::PrimitiveState {
fn from(value: GpuPrimitiveState) -> wgpu_types::PrimitiveState {
wgpu_types::PrimitiveState {
topology: value.topology.into(),
strip_index_format: value.strip_index_format.map(Into::into),
front_face: value.front_face.into(),
cull_mode: value.cull_mode.into(),
clamp_depth: value.clamp_depth,
polygon_mode: Default::default(), // native-only
conservative: false, // native-only
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuBlendComponent {
src_factor: GpuBlendFactor,
dst_factor: GpuBlendFactor,
operation: GpuBlendOperation,
}
impl From<GpuBlendComponent> for wgpu_types::BlendComponent {
fn from(component: GpuBlendComponent) -> Self {
wgpu_types::BlendComponent {
src_factor: component.src_factor.into(),
dst_factor: component.dst_factor.into(),
operation: component.operation.into(),
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuBlendState {
color: GpuBlendComponent,
alpha: GpuBlendComponent,
}
impl From<GpuBlendState> for wgpu_types::BlendState {
fn from(state: GpuBlendState) -> wgpu_types::BlendState {
wgpu_types::BlendState {
color: state.color.into(),
alpha: state.alpha.into(),
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuColorTargetState {
format: GpuTextureFormat,
blend: Option<GpuBlendState>,
write_mask: u32,
}
impl TryFrom<GpuColorTargetState> for wgpu_types::ColorTargetState {
type Error = AnyError;
fn try_from(
state: GpuColorTargetState,
) -> Result<wgpu_types::ColorTargetState, AnyError> {
Ok(wgpu_types::ColorTargetState {
format: state.format.try_into()?,
blend: state.blend.map(Into::into),
write_mask: wgpu_types::ColorWrites::from_bits_truncate(state.write_mask),
})
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuStencilFaceState {
compare: GpuCompareFunction,
fail_op: GPUStencilOperation,
depth_fail_op: GPUStencilOperation,
pass_op: GPUStencilOperation,
}
impl From<GpuStencilFaceState> for wgpu_types::StencilFaceState {
fn from(state: GpuStencilFaceState) -> Self {
wgpu_types::StencilFaceState {
compare: state.compare.into(),
fail_op: state.fail_op.into(),
depth_fail_op: state.depth_fail_op.into(),
pass_op: state.pass_op.into(),
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuDepthStencilState {
format: GpuTextureFormat,
depth_write_enabled: bool,
depth_compare: GpuCompareFunction,
stencil_front: GpuStencilFaceState,
stencil_back: GpuStencilFaceState,
stencil_read_mask: u32,
stencil_write_mask: u32,
depth_bias: i32,
depth_bias_slope_scale: f32,
depth_bias_clamp: f32,
}
impl TryFrom<GpuDepthStencilState> for wgpu_types::DepthStencilState {
type Error = AnyError;
fn try_from(
state: GpuDepthStencilState,
) -> Result<wgpu_types::DepthStencilState, AnyError> {
Ok(wgpu_types::DepthStencilState {
format: state.format.try_into()?,
depth_write_enabled: state.depth_write_enabled,
depth_compare: state.depth_compare.into(),
stencil: wgpu_types::StencilState {
front: state.stencil_front.into(),
back: state.stencil_back.into(),
read_mask: state.stencil_read_mask,
write_mask: state.stencil_write_mask,
},
bias: wgpu_types::DepthBiasState {
constant: state.depth_bias,
slope_scale: state.depth_bias_slope_scale,
clamp: state.depth_bias_clamp,
},
})
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuVertexAttribute {
format: GpuVertexFormat,
offset: u64,
shader_location: u32,
}
impl From<GpuVertexAttribute> for wgpu_types::VertexAttribute {
fn from(attribute: GpuVertexAttribute) -> Self {
wgpu_types::VertexAttribute {
format: attribute.format.into(),
offset: attribute.offset,
shader_location: attribute.shader_location,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "lowercase")]
enum GpuVertexFormat {
Uint8x2,
Uint8x4,
Sint8x2,
Sint8x4,
Unorm8x2,
Unorm8x4,
Snorm8x2,
Snorm8x4,
Uint16x2,
Uint16x4,
Sint16x2,
Sint16x4,
Unorm16x2,
Unorm16x4,
Snorm16x2,
Snorm16x4,
Float16x2,
Float16x4,
Float32,
Float32x2,
Float32x3,
Float32x4,
Uint32,
Uint32x2,
Uint32x3,
Uint32x4,
Sint32,
Sint32x2,
Sint32x3,
Sint32x4,
Float64,
Float64x2,
Float64x3,
Float64x4,
}
impl From<GpuVertexFormat> for wgpu_types::VertexFormat {
fn from(vf: GpuVertexFormat) -> wgpu_types::VertexFormat {
use wgpu_types::VertexFormat;
match vf {
GpuVertexFormat::Uint8x2 => VertexFormat::Uint8x2,
GpuVertexFormat::Uint8x4 => VertexFormat::Uint8x4,
GpuVertexFormat::Sint8x2 => VertexFormat::Sint8x2,
GpuVertexFormat::Sint8x4 => VertexFormat::Sint8x4,
GpuVertexFormat::Unorm8x2 => VertexFormat::Unorm8x2,
GpuVertexFormat::Unorm8x4 => VertexFormat::Unorm8x4,
GpuVertexFormat::Snorm8x2 => VertexFormat::Snorm8x2,
GpuVertexFormat::Snorm8x4 => VertexFormat::Snorm8x4,
GpuVertexFormat::Uint16x2 => VertexFormat::Uint16x2,
GpuVertexFormat::Uint16x4 => VertexFormat::Uint16x4,
GpuVertexFormat::Sint16x2 => VertexFormat::Sint16x2,
GpuVertexFormat::Sint16x4 => VertexFormat::Sint16x4,
GpuVertexFormat::Unorm16x2 => VertexFormat::Unorm16x2,
GpuVertexFormat::Unorm16x4 => VertexFormat::Unorm16x4,
GpuVertexFormat::Snorm16x2 => VertexFormat::Snorm16x2,
GpuVertexFormat::Snorm16x4 => VertexFormat::Snorm16x4,
GpuVertexFormat::Float16x2 => VertexFormat::Float16x2,
GpuVertexFormat::Float16x4 => VertexFormat::Float16x4,
GpuVertexFormat::Float32 => VertexFormat::Float32,
GpuVertexFormat::Float32x2 => VertexFormat::Float32x2,
GpuVertexFormat::Float32x3 => VertexFormat::Float32x3,
GpuVertexFormat::Float32x4 => VertexFormat::Float32x4,
GpuVertexFormat::Uint32 => VertexFormat::Uint32,
GpuVertexFormat::Uint32x2 => VertexFormat::Uint32x2,
GpuVertexFormat::Uint32x3 => VertexFormat::Uint32x3,
GpuVertexFormat::Uint32x4 => VertexFormat::Uint32x4,
GpuVertexFormat::Sint32 => VertexFormat::Sint32,
GpuVertexFormat::Sint32x2 => VertexFormat::Sint32x2,
GpuVertexFormat::Sint32x3 => VertexFormat::Sint32x3,
GpuVertexFormat::Sint32x4 => VertexFormat::Sint32x4,
GpuVertexFormat::Float64 => VertexFormat::Float64,
GpuVertexFormat::Float64x2 => VertexFormat::Float64x2,
GpuVertexFormat::Float64x3 => VertexFormat::Float64x3,
GpuVertexFormat::Float64x4 => VertexFormat::Float64x4,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
enum GpuVertexStepMode {
Vertex,
Instance,
}
impl From<GpuVertexStepMode> for wgpu_types::VertexStepMode {
fn from(vsm: GpuVertexStepMode) -> wgpu_types::VertexStepMode {
use wgpu_types::VertexStepMode;
match vsm {
GpuVertexStepMode::Vertex => VertexStepMode::Vertex,
GpuVertexStepMode::Instance => VertexStepMode::Instance,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuVertexBufferLayout {
array_stride: u64,
step_mode: GpuVertexStepMode,
attributes: Vec<GpuVertexAttribute>,
}
impl<'a> From<GpuVertexBufferLayout>
for wgpu_core::pipeline::VertexBufferLayout<'a>
{
fn from(
layout: GpuVertexBufferLayout,
) -> wgpu_core::pipeline::VertexBufferLayout<'a> {
wgpu_core::pipeline::VertexBufferLayout {
array_stride: layout.array_stride,
step_mode: layout.step_mode.into(),
attributes: Cow::Owned(
layout.attributes.into_iter().map(Into::into).collect(),
),
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuVertexState {
module: ResourceId,
entry_point: String,
buffers: Vec<Option<GpuVertexBufferLayout>>,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuMultisampleState {
count: u32,
mask: u64,
alpha_to_coverage_enabled: bool,
}
impl From<GpuMultisampleState> for wgpu_types::MultisampleState {
fn from(gms: GpuMultisampleState) -> wgpu_types::MultisampleState {
wgpu_types::MultisampleState {
count: gms.count,
mask: gms.mask,
alpha_to_coverage_enabled: gms.alpha_to_coverage_enabled,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuFragmentState {
targets: Vec<GpuColorTargetState>,
module: u32,
entry_point: String,
// TODO(lucacasonato): constants
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateRenderPipelineArgs {
device_rid: ResourceId,
label: Option<String>,
layout: Option<ResourceId>,
vertex: GpuVertexState,
primitive: GpuPrimitiveState,
depth_stencil: Option<GpuDepthStencilState>,
multisample: GpuMultisampleState,
fragment: Option<GpuFragmentState>,
}
pub fn op_webgpu_create_render_pipeline(
state: &mut OpState,
args: CreateRenderPipelineArgs,
_: (),
) -> 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 layout = if let Some(rid) = args.layout {
let pipeline_layout_resource =
state.resource_table.get::<WebGpuPipelineLayout>(rid)?;
Some(pipeline_layout_resource.0)
} else {
None
};
let vertex_shader_module_resource =
state
.resource_table
.get::<super::shader::WebGpuShaderModule>(args.vertex.module)?;
let fragment = if let Some(fragment) = args.fragment {
let fragment_shader_module_resource =
state
.resource_table
.get::<super::shader::WebGpuShaderModule>(fragment.module)?;
let mut targets = Vec::with_capacity(fragment.targets.len());
for target in fragment.targets {
targets.push(target.try_into()?);
}
Some(wgpu_core::pipeline::FragmentState {
stage: wgpu_core::pipeline::ProgrammableStageDescriptor {
module: fragment_shader_module_resource.0,
entry_point: Cow::from(fragment.entry_point),
},
targets: Cow::from(targets),
})
} else {
None
};
let vertex_buffers = args
.vertex
.buffers
.into_iter()
.flatten()
.map(Into::into)
.collect();
let descriptor = wgpu_core::pipeline::RenderPipelineDescriptor {
label: args.label.map(Cow::Owned),
layout,
vertex: wgpu_core::pipeline::VertexState {
stage: wgpu_core::pipeline::ProgrammableStageDescriptor {
module: vertex_shader_module_resource.0,
entry_point: Cow::Owned(args.vertex.entry_point),
},
buffers: Cow::Owned(vertex_buffers),
},
primitive: args.primitive.into(),
depth_stencil: args.depth_stencil.map(TryInto::try_into).transpose()?,
multisample: args.multisample.into(),
fragment,
};
let implicit_pipelines = match args.layout {
Some(_) => None,
None => Some(wgpu_core::device::ImplicitPipelineIds {
root_id: std::marker::PhantomData,
group_ids: &[std::marker::PhantomData; MAX_BIND_GROUPS],
}),
};
let (render_pipeline, maybe_err) = gfx_select!(device => instance.device_create_render_pipeline(
device,
&descriptor,
std::marker::PhantomData,
implicit_pipelines
));
let rid = state
.resource_table
.add(WebGpuRenderPipeline(render_pipeline));
Ok(WebGpuResult::rid_err(rid, maybe_err))
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RenderPipelineGetBindGroupLayoutArgs {
render_pipeline_rid: ResourceId,
index: u32,
}
pub fn op_webgpu_render_pipeline_get_bind_group_layout(
state: &mut OpState,
args: RenderPipelineGetBindGroupLayoutArgs,
_: (),
) -> Result<PipelineLayout, AnyError> {
let instance = state.borrow::<super::Instance>();
let render_pipeline_resource = state
.resource_table
.get::<WebGpuRenderPipeline>(args.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, args.index, std::marker::PhantomData));
let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout));
let rid = state
.resource_table
.add(super::binding::WebGpuBindGroupLayout(bind_group_layout));
Ok(PipelineLayout {
rid,
label,
err: maybe_err.map(WebGpuError::from),
})
}

View file

@ -1,132 +0,0 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::ResourceId;
use deno_core::{OpState, Resource};
use serde::Deserialize;
use std::borrow::Cow;
use super::error::WebGpuResult;
pub(crate) struct WebGpuSampler(pub(crate) wgpu_core::id::SamplerId);
impl Resource for WebGpuSampler {
fn name(&self) -> Cow<str> {
"webGPUSampler".into()
}
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
enum GpuAddressMode {
ClampToEdge,
Repeat,
MirrorRepeat,
}
impl From<GpuAddressMode> for wgpu_types::AddressMode {
fn from(value: GpuAddressMode) -> wgpu_types::AddressMode {
match value {
GpuAddressMode::ClampToEdge => wgpu_types::AddressMode::ClampToEdge,
GpuAddressMode::Repeat => wgpu_types::AddressMode::Repeat,
GpuAddressMode::MirrorRepeat => wgpu_types::AddressMode::MirrorRepeat,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
enum GpuFilterMode {
Nearest,
Linear,
}
impl From<GpuFilterMode> for wgpu_types::FilterMode {
fn from(value: GpuFilterMode) -> wgpu_types::FilterMode {
match value {
GpuFilterMode::Nearest => wgpu_types::FilterMode::Nearest,
GpuFilterMode::Linear => wgpu_types::FilterMode::Linear,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GpuCompareFunction {
Never,
Less,
Equal,
LessEqual,
Greater,
NotEqual,
GreaterEqual,
Always,
}
impl From<GpuCompareFunction> for wgpu_types::CompareFunction {
fn from(value: GpuCompareFunction) -> wgpu_types::CompareFunction {
match value {
GpuCompareFunction::Never => wgpu_types::CompareFunction::Never,
GpuCompareFunction::Less => wgpu_types::CompareFunction::Less,
GpuCompareFunction::Equal => wgpu_types::CompareFunction::Equal,
GpuCompareFunction::LessEqual => wgpu_types::CompareFunction::LessEqual,
GpuCompareFunction::Greater => wgpu_types::CompareFunction::Greater,
GpuCompareFunction::NotEqual => wgpu_types::CompareFunction::NotEqual,
GpuCompareFunction::GreaterEqual => {
wgpu_types::CompareFunction::GreaterEqual
}
GpuCompareFunction::Always => wgpu_types::CompareFunction::Always,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateSamplerArgs {
device_rid: ResourceId,
label: Option<String>,
address_mode_u: GpuAddressMode,
address_mode_v: GpuAddressMode,
address_mode_w: GpuAddressMode,
mag_filter: GpuFilterMode,
min_filter: GpuFilterMode,
mipmap_filter: GpuFilterMode,
lod_min_clamp: f32,
lod_max_clamp: f32,
compare: Option<GpuCompareFunction>,
max_anisotropy: u8,
}
pub fn op_webgpu_create_sampler(
state: &mut OpState,
args: CreateSamplerArgs,
_: (),
) -> 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 descriptor = wgpu_core::resource::SamplerDescriptor {
label: args.label.map(Cow::from),
address_modes: [
args.address_mode_u.into(),
args.address_mode_v.into(),
args.address_mode_w.into(),
],
mag_filter: args.mag_filter.into(),
min_filter: args.min_filter.into(),
mipmap_filter: args.mipmap_filter.into(),
lod_min_clamp: args.lod_min_clamp,
lod_max_clamp: args.lod_max_clamp,
compare: args.compare.map(Into::into),
anisotropy_clamp: std::num::NonZeroU8::new(args.max_anisotropy),
border_color: None, // native-only
};
gfx_put!(device => instance.device_create_sampler(
device,
&descriptor,
std::marker::PhantomData
) => state, WebGpuSampler)
}

View file

@ -1,12 +1,11 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::ResourceId;
use deno_core::{OpState, Resource};
use serde::Deserialize;
use std::borrow::Cow;
use crate::texture::{GpuTextureFormat, GpuTextureViewDimension};
use std::convert::{TryFrom, TryInto};
use super::error::WebGpuResult;
@ -59,41 +58,14 @@ impl From<GpuBufferBindingType> for wgpu_types::BufferBindingType {
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuSamplerBindingLayout {
r#type: GpuSamplerBindingType,
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
enum GpuSamplerBindingType {
Filtering,
NonFiltering,
Comparison,
}
impl From<GpuSamplerBindingType> for wgpu_types::BindingType {
fn from(binding_type: GpuSamplerBindingType) -> Self {
match binding_type {
GpuSamplerBindingType::Filtering => wgpu_types::BindingType::Sampler {
filtering: true,
comparison: false,
},
GpuSamplerBindingType::NonFiltering => wgpu_types::BindingType::Sampler {
filtering: false,
comparison: false,
},
GpuSamplerBindingType::Comparison => wgpu_types::BindingType::Sampler {
filtering: true,
comparison: true,
},
}
}
r#type: wgpu_types::SamplerBindingType,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuTextureBindingLayout {
sample_type: GpuTextureSampleType,
view_dimension: GpuTextureViewDimension,
view_dimension: wgpu_types::TextureViewDimension,
multisampled: bool,
}
@ -127,8 +99,8 @@ impl From<GpuTextureSampleType> for wgpu_types::TextureSampleType {
#[serde(rename_all = "camelCase")]
struct GpuStorageTextureBindingLayout {
access: GpuStorageTextureAccess,
format: GpuTextureFormat,
view_dimension: GpuTextureViewDimension,
format: wgpu_types::TextureFormat,
view_dimension: wgpu_types::TextureViewDimension,
}
#[derive(Deserialize)]
@ -177,17 +149,19 @@ impl TryFrom<GpuBindingType> for wgpu_types::BindingType {
has_dynamic_offset: buffer.has_dynamic_offset,
min_binding_size: std::num::NonZeroU64::new(buffer.min_binding_size),
},
GpuBindingType::Sampler(sampler) => sampler.r#type.into(),
GpuBindingType::Sampler(sampler) => {
wgpu_types::BindingType::Sampler(sampler.r#type)
}
GpuBindingType::Texture(texture) => wgpu_types::BindingType::Texture {
sample_type: texture.sample_type.into(),
view_dimension: texture.view_dimension.into(),
view_dimension: texture.view_dimension,
multisampled: texture.multisampled,
},
GpuBindingType::StorageTexture(storage_texture) => {
wgpu_types::BindingType::StorageTexture {
access: storage_texture.access.into(),
format: storage_texture.format.try_into()?,
view_dimension: storage_texture.view_dimension.into(),
format: storage_texture.format,
view_dimension: storage_texture.view_dimension,
}
}
};

View file

@ -1,4 +1,4 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use deno_core::error::type_error;
use deno_core::error::AnyError;

View file

@ -1,4 +1,4 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::ResourceId;
@ -9,9 +9,6 @@ use std::borrow::Cow;
use std::cell::RefCell;
use std::rc::Rc;
use crate::pipeline::GpuIndexFormat;
use crate::texture::GpuTextureFormat;
use super::error::WebGpuResult;
struct WebGpuRenderBundleEncoder(
@ -35,8 +32,8 @@ impl Resource for WebGpuRenderBundle {
pub struct CreateRenderBundleEncoderArgs {
device_rid: ResourceId,
label: Option<String>,
color_formats: Vec<GpuTextureFormat>,
depth_stencil_format: Option<GpuTextureFormat>,
color_formats: Vec<wgpu_types::TextureFormat>,
depth_stencil_format: Option<wgpu_types::TextureFormat>,
sample_count: u32,
depth_read_only: bool,
stencil_read_only: bool,
@ -55,12 +52,12 @@ pub fn op_webgpu_create_render_bundle_encoder(
let mut color_formats = vec![];
for format in args.color_formats {
color_formats.push(format.try_into()?);
color_formats.push(format);
}
let depth_stencil = if let Some(format) = args.depth_stencil_format {
Some(wgpu_types::RenderBundleDepthStencil {
format: format.try_into()?,
format,
depth_read_only: args.depth_read_only,
stencil_read_only: args.stencil_read_only,
})
@ -73,6 +70,7 @@ pub fn op_webgpu_create_render_bundle_encoder(
color_formats: Cow::from(color_formats),
sample_count: args.sample_count,
depth_stencil,
multiview: None,
};
let res =
@ -301,7 +299,7 @@ pub fn op_webgpu_render_bundle_encoder_set_pipeline(
pub struct RenderBundleEncoderSetIndexBufferArgs {
render_bundle_encoder_rid: ResourceId,
buffer: ResourceId,
index_format: GpuIndexFormat,
index_format: wgpu_types::IndexFormat,
offset: u64,
size: u64,
}
@ -324,7 +322,7 @@ pub fn op_webgpu_render_bundle_encoder_set_index_buffer(
.borrow_mut()
.set_index_buffer(
buffer_resource.0,
args.index_format.into(),
args.index_format,
args.offset,
std::num::NonZeroU64::new(args.size),
);

View file

@ -1,4 +1,4 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::ResourceId;
@ -8,8 +8,6 @@ use std::borrow::Cow;
use std::cell::RefCell;
use std::num::NonZeroU32;
use crate::texture::GpuTextureAspect;
use super::error::WebGpuResult;
pub(crate) struct WebGpuCommandEncoder(
@ -65,8 +63,8 @@ pub fn op_webgpu_create_command_encoder(
pub struct GpuRenderPassColorAttachment {
view: ResourceId,
resolve_target: Option<ResourceId>,
load_op: GpuLoadOp<super::render_pass::GpuColor>,
store_op: GpuStoreOp,
load_op: GpuLoadOp<wgpu_types::Color>,
store_op: wgpu_core::command::StoreOp,
}
#[derive(Deserialize)]
@ -76,31 +74,15 @@ enum GpuLoadOp<T> {
Clear(T),
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
enum GpuStoreOp {
Store,
Discard,
}
impl From<GpuStoreOp> for wgpu_core::command::StoreOp {
fn from(value: GpuStoreOp) -> wgpu_core::command::StoreOp {
match value {
GpuStoreOp::Store => wgpu_core::command::StoreOp::Store,
GpuStoreOp::Discard => wgpu_core::command::StoreOp::Discard,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuRenderPassDepthStencilAttachment {
view: ResourceId,
depth_load_op: GpuLoadOp<f32>,
depth_store_op: GpuStoreOp,
depth_store_op: wgpu_core::command::StoreOp,
depth_read_only: bool,
stencil_load_op: GpuLoadOp<u32>,
stencil_store_op: GpuStoreOp,
stencil_store_op: wgpu_core::command::StoreOp,
stencil_read_only: bool,
}
@ -147,19 +129,14 @@ pub fn op_webgpu_command_encoder_begin_render_pass(
channel: match color_attachment.load_op {
GpuLoadOp::Load => wgpu_core::command::PassChannel {
load_op: wgpu_core::command::LoadOp::Load,
store_op: color_attachment.store_op.into(),
store_op: color_attachment.store_op,
clear_value: Default::default(),
read_only: false,
},
GpuLoadOp::Clear(color) => wgpu_core::command::PassChannel {
load_op: wgpu_core::command::LoadOp::Clear,
store_op: color_attachment.store_op.into(),
clear_value: wgpu_types::Color {
r: color.r,
g: color.g,
b: color.b,
a: color.a,
},
store_op: color_attachment.store_op,
clear_value: color,
read_only: false,
},
},
@ -182,13 +159,13 @@ pub fn op_webgpu_command_encoder_begin_render_pass(
depth: match attachment.depth_load_op {
GpuLoadOp::Load => wgpu_core::command::PassChannel {
load_op: wgpu_core::command::LoadOp::Load,
store_op: attachment.depth_store_op.into(),
store_op: attachment.depth_store_op,
clear_value: 0.0,
read_only: attachment.depth_read_only,
},
GpuLoadOp::Clear(value) => wgpu_core::command::PassChannel {
load_op: wgpu_core::command::LoadOp::Clear,
store_op: attachment.depth_store_op.into(),
store_op: attachment.depth_store_op,
clear_value: value,
read_only: attachment.depth_read_only,
},
@ -196,13 +173,13 @@ pub fn op_webgpu_command_encoder_begin_render_pass(
stencil: match attachment.stencil_load_op {
GpuLoadOp::Load => wgpu_core::command::PassChannel {
load_op: wgpu_core::command::LoadOp::Load,
store_op: attachment.stencil_store_op.into(),
store_op: attachment.stencil_store_op,
clear_value: 0,
read_only: attachment.stencil_read_only,
},
GpuLoadOp::Clear(value) => wgpu_core::command::PassChannel {
load_op: wgpu_core::command::LoadOp::Clear,
store_op: attachment.stencil_store_op.into(),
store_op: attachment.stencil_store_op,
clear_value: value,
read_only: attachment.stencil_read_only,
},
@ -315,31 +292,13 @@ pub struct GpuImageCopyBuffer {
rows_per_image: Option<u32>,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GpuOrigin3D {
pub x: u32,
pub y: u32,
pub z: u32,
}
impl From<GpuOrigin3D> for wgpu_types::Origin3d {
fn from(origin: GpuOrigin3D) -> wgpu_types::Origin3d {
wgpu_types::Origin3d {
x: origin.x,
y: origin.y,
z: origin.z,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GpuImageCopyTexture {
pub texture: ResourceId,
pub mip_level: u32,
pub origin: GpuOrigin3D,
pub aspect: GpuTextureAspect,
pub origin: wgpu_types::Origin3d,
pub aspect: wgpu_types::TextureAspect,
}
#[derive(Deserialize)]
@ -348,7 +307,7 @@ pub struct CommandEncoderCopyBufferToTextureArgs {
command_encoder_rid: ResourceId,
source: GpuImageCopyBuffer,
destination: GpuImageCopyTexture,
copy_size: super::texture::GpuExtent3D,
copy_size: wgpu_types::Extent3d,
}
pub fn op_webgpu_command_encoder_copy_buffer_to_texture(
@ -381,14 +340,14 @@ pub fn op_webgpu_command_encoder_copy_buffer_to_texture(
let destination = wgpu_core::command::ImageCopyTexture {
texture: destination_texture_resource.0,
mip_level: args.destination.mip_level,
origin: args.destination.origin.into(),
aspect: args.destination.aspect.into(),
origin: args.destination.origin,
aspect: args.destination.aspect,
};
gfx_ok!(command_encoder => instance.command_encoder_copy_buffer_to_texture(
command_encoder,
&source,
&destination,
&args.copy_size.into()
&args.copy_size
))
}
@ -398,7 +357,7 @@ pub struct CommandEncoderCopyTextureToBufferArgs {
command_encoder_rid: ResourceId,
source: GpuImageCopyTexture,
destination: GpuImageCopyBuffer,
copy_size: super::texture::GpuExtent3D,
copy_size: wgpu_types::Extent3d,
}
pub fn op_webgpu_command_encoder_copy_texture_to_buffer(
@ -423,8 +382,8 @@ pub fn op_webgpu_command_encoder_copy_texture_to_buffer(
let source = wgpu_core::command::ImageCopyTexture {
texture: source_texture_resource.0,
mip_level: args.source.mip_level,
origin: args.source.origin.into(),
aspect: args.source.aspect.into(),
origin: args.source.origin,
aspect: args.source.aspect,
};
let destination = wgpu_core::command::ImageCopyBuffer {
buffer: destination_buffer_resource.0,
@ -442,7 +401,7 @@ pub fn op_webgpu_command_encoder_copy_texture_to_buffer(
command_encoder,
&source,
&destination,
&args.copy_size.into()
&args.copy_size
))
}
@ -452,7 +411,7 @@ pub struct CommandEncoderCopyTextureToTextureArgs {
command_encoder_rid: ResourceId,
source: GpuImageCopyTexture,
destination: GpuImageCopyTexture,
copy_size: super::texture::GpuExtent3D,
copy_size: wgpu_types::Extent3d,
}
pub fn op_webgpu_command_encoder_copy_texture_to_texture(
@ -477,20 +436,51 @@ pub fn op_webgpu_command_encoder_copy_texture_to_texture(
let source = wgpu_core::command::ImageCopyTexture {
texture: source_texture_resource.0,
mip_level: args.source.mip_level,
origin: args.source.origin.into(),
aspect: args.source.aspect.into(),
origin: args.source.origin,
aspect: args.source.aspect,
};
let destination = wgpu_core::command::ImageCopyTexture {
texture: destination_texture_resource.0,
mip_level: args.destination.mip_level,
origin: args.destination.origin.into(),
aspect: args.destination.aspect.into(),
origin: args.destination.origin,
aspect: args.destination.aspect,
};
gfx_ok!(command_encoder => instance.command_encoder_copy_texture_to_texture(
command_encoder,
&source,
&destination,
&args.copy_size.into()
&args.copy_size
))
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CommandEncoderClearBufferArgs {
command_encoder_rid: u32,
destination_rid: u32,
destination_offset: u64,
size: u64,
}
pub fn op_webgpu_command_encoder_clear_buffer(
state: &mut OpState,
args: CommandEncoderClearBufferArgs,
_: (),
) -> Result<WebGpuResult, AnyError> {
let instance = state.borrow::<super::Instance>();
let command_encoder_resource = state
.resource_table
.get::<WebGpuCommandEncoder>(args.command_encoder_rid)?;
let command_encoder = command_encoder_resource.0;
let destination_resource = state
.resource_table
.get::<super::buffer::WebGpuBuffer>(args.destination_rid)?;
gfx_ok!(command_encoder => instance.command_encoder_clear_buffer(
command_encoder,
destination_resource.0,
args.destination_offset,
std::num::NonZeroU64::new(args.size)
))
}

View file

@ -1,4 +1,4 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::ResourceId;
@ -125,10 +125,10 @@ pub fn op_webgpu_compute_pass_begin_pipeline_statistics_query(
.get::<super::WebGpuQuerySet>(args.query_set)?;
wgpu_core::command::compute_ffi::wgpu_compute_pass_begin_pipeline_statistics_query(
&mut compute_pass_resource.0.borrow_mut(),
query_set_resource.0,
args.query_index,
);
&mut compute_pass_resource.0.borrow_mut(),
query_set_resource.0,
args.query_index,
);
Ok(WebGpuResult::empty())
}
@ -149,8 +149,8 @@ pub fn op_webgpu_compute_pass_end_pipeline_statistics_query(
.get::<WebGpuComputePass>(args.compute_pass_rid)?;
wgpu_core::command::compute_ffi::wgpu_compute_pass_end_pipeline_statistics_query(
&mut compute_pass_resource.0.borrow_mut(),
);
&mut compute_pass_resource.0.borrow_mut(),
);
Ok(WebGpuResult::empty())
}

View file

@ -1,4 +1,4 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::ResourceId;
use serde::Serialize;
@ -8,6 +8,7 @@ use wgpu_core::binding_model::CreateBindGroupError;
use wgpu_core::binding_model::CreateBindGroupLayoutError;
use wgpu_core::binding_model::CreatePipelineLayoutError;
use wgpu_core::binding_model::GetBindGroupLayoutError;
use wgpu_core::command::ClearError;
use wgpu_core::command::CommandEncoderError;
use wgpu_core::command::ComputePassError;
use wgpu_core::command::CopyError;
@ -258,6 +259,12 @@ impl From<QueueWriteError> for WebGpuError {
}
}
impl From<ClearError> for WebGpuError {
fn from(err: ClearError) -> Self {
WebGpuError::Validation(err.to_string())
}
}
#[derive(Debug)]
pub struct DomExceptionOperationError {
pub msg: String,

View file

@ -1,4 +1,4 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::include_js_files;
@ -14,7 +14,6 @@ use serde::Serialize;
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashSet;
use std::path::PathBuf;
use std::rc::Rc;
pub use wgpu_core;
pub use wgpu_types;
@ -125,15 +124,11 @@ pub fn init(unstable: bool) -> Extension {
.build()
}
pub fn get_declaration() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_webgpu.d.ts")
}
fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> {
let mut return_features: Vec<&'static str> = vec![];
if features.contains(wgpu_types::Features::DEPTH_CLAMPING) {
return_features.push("depth-clamping");
if features.contains(wgpu_types::Features::DEPTH_CLIP_CONTROL) {
return_features.push("depth-clip-control");
}
if features.contains(wgpu_types::Features::PIPELINE_STATISTICS_QUERY) {
return_features.push("pipeline-statistics-query");
@ -141,9 +136,18 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> {
if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_BC) {
return_features.push("texture-compression-bc");
}
if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ETC2) {
return_features.push("texture-compression-etc2");
}
if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR) {
return_features.push("texture-compression-astc");
}
if features.contains(wgpu_types::Features::TIMESTAMP_QUERY) {
return_features.push("timestamp-query");
}
if features.contains(wgpu_types::Features::INDIRECT_FIRST_INSTANCE) {
return_features.push("indirect-first-instance");
}
// extended from spec
if features.contains(wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS) {
@ -158,12 +162,16 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> {
if features.contains(wgpu_types::Features::STORAGE_RESOURCE_BINDING_ARRAY) {
return_features.push("storage-resource-binding-array");
}
if features.contains(wgpu_types::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING) {
return_features.push("sampled-texture-and-storage-buffer-array-non-uniform-indexing");
}
if features.contains(wgpu_types::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING) {
return_features.push("uniform-buffer-and-storage-buffer-texture-non-uniform-indexing");
}
if features.contains(
wgpu_types::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
) {
return_features.push("sampled-texture-and-storage-buffer-array-non-uniform-indexing");
}
if features.contains(
wgpu_types::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
) {
return_features.push("uniform-buffer-and-storage-buffer-texture-non-uniform-indexing");
}
if features.contains(wgpu_types::Features::UNSIZED_BINDING_ARRAY) {
return_features.push("unsized-binding-array");
}
@ -179,15 +187,6 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> {
if features.contains(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER) {
return_features.push("address-mode-clamp-to-border");
}
if features.contains(wgpu_types::Features::NON_FILL_POLYGON_MODE) {
return_features.push("non-fill-polygon-mode");
}
if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ETC2) {
return_features.push("texture-compression-etc2");
}
if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR) {
return_features.push("texture-compression-astc-ldr");
}
if features
.contains(wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES)
{
@ -205,8 +204,8 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> {
if features.contains(wgpu_types::Features::VERTEX_WRITABLE_STORAGE) {
return_features.push("vertex-writable-storage");
}
if features.contains(wgpu_types::Features::CLEAR_COMMANDS) {
return_features.push("clear-commands");
if features.contains(wgpu_types::Features::CLEAR_TEXTURE) {
return_features.push("clear-texture");
}
if features.contains(wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH) {
return_features.push("spirv-shader-passthrough");
@ -218,28 +217,11 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> {
return_features
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
enum GpuPowerPreference {
LowPower,
HighPerformance,
}
impl From<GpuPowerPreference> for wgpu_types::PowerPreference {
fn from(value: GpuPowerPreference) -> wgpu_types::PowerPreference {
match value {
GpuPowerPreference::LowPower => wgpu_types::PowerPreference::LowPower,
GpuPowerPreference::HighPerformance => {
wgpu_types::PowerPreference::HighPerformance
}
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RequestAdapterArgs {
power_preference: Option<GpuPowerPreference>,
power_preference: Option<wgpu_types::PowerPreference>,
force_fallback_adapter: bool,
}
#[derive(Serialize)]
@ -266,31 +248,35 @@ pub async fn op_webgpu_request_adapter(
) -> Result<GpuAdapterDeviceOrErr, AnyError> {
let mut state = state.borrow_mut();
check_unstable(&state, "navigator.gpu.requestAdapter");
let backends = std::env::var("DENO_WEBGPU_BACKEND")
.ok()
.map_or_else(wgpu_types::Backends::all, |s| {
wgpu_core::instance::parse_backends_from_comma_list(&s)
});
let instance = if let Some(instance) = state.try_borrow::<Instance>() {
instance
} else {
state.put(wgpu_core::hub::Global::new(
"webgpu",
wgpu_core::hub::IdentityManagerFactory,
wgpu_types::Backends::PRIMARY,
backends,
));
state.borrow::<Instance>()
};
let descriptor = wgpu_core::instance::RequestAdapterOptions {
power_preference: match args.power_preference {
Some(power_preference) => power_preference.into(),
Some(power_preference) => power_preference,
None => PowerPreference::default(),
},
// TODO(lucacasonato): respect forceFallbackAdapter
force_fallback_adapter: args.force_fallback_adapter,
compatible_surface: None, // windowless
};
let res = instance.request_adapter(
&descriptor,
wgpu_core::instance::AdapterInputs::Mask(
wgpu_types::Backends::PRIMARY,
|_| std::marker::PhantomData,
),
wgpu_core::instance::AdapterInputs::Mask(backends, |_| {
std::marker::PhantomData
}),
);
let adapter = match res {
@ -319,116 +305,13 @@ pub async fn op_webgpu_request_adapter(
}))
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuLimits {
max_texture_dimension_1d: Option<u32>,
max_texture_dimension_2d: Option<u32>,
max_texture_dimension_3d: Option<u32>,
max_texture_array_layers: Option<u32>,
max_bind_groups: Option<u32>,
max_dynamic_uniform_buffers_per_pipeline_layout: Option<u32>,
max_dynamic_storage_buffers_per_pipeline_layout: Option<u32>,
max_sampled_textures_per_shader_stage: Option<u32>,
max_samplers_per_shader_stage: Option<u32>,
max_storage_buffers_per_shader_stage: Option<u32>,
max_storage_textures_per_shader_stage: Option<u32>,
max_uniform_buffers_per_shader_stage: Option<u32>,
max_uniform_buffer_binding_size: Option<u32>, // TODO(@crowlkats): u64
max_storage_buffer_binding_size: Option<u32>, // TODO(@crowlkats): u64
// min_uniform_buffer_offset_alignment: Option<u32>,
// min_storage_buffer_offset_alignment: Option<u32>,
max_vertex_buffers: Option<u32>,
max_vertex_attributes: Option<u32>,
max_vertex_buffer_array_stride: Option<u32>,
// max_inter_stage_shader_components: Option<u32>,
// max_compute_workgroup_storage_size: Option<u32>,
// max_compute_invocations_per_workgroup: Option<u32>,
// max_compute_workgroup_size_x: Option<u32>,
// max_compute_workgroup_size_y: Option<u32>,
// max_compute_workgroup_size_z: Option<u32>,
// max_compute_workgroups_per_dimension: Option<u32>,
}
impl From<GpuLimits> for wgpu_types::Limits {
fn from(limits: GpuLimits) -> wgpu_types::Limits {
wgpu_types::Limits {
max_texture_dimension_1d: limits.max_texture_dimension_1d.unwrap_or(8192),
max_texture_dimension_2d: limits.max_texture_dimension_2d.unwrap_or(8192),
max_texture_dimension_3d: limits.max_texture_dimension_3d.unwrap_or(2048),
max_texture_array_layers: limits.max_texture_array_layers.unwrap_or(2048),
max_bind_groups: limits.max_bind_groups.unwrap_or(4),
max_dynamic_uniform_buffers_per_pipeline_layout: limits
.max_dynamic_uniform_buffers_per_pipeline_layout
.unwrap_or(8),
max_dynamic_storage_buffers_per_pipeline_layout: limits
.max_dynamic_storage_buffers_per_pipeline_layout
.unwrap_or(4),
max_sampled_textures_per_shader_stage: limits
.max_sampled_textures_per_shader_stage
.unwrap_or(16),
max_samplers_per_shader_stage: limits
.max_samplers_per_shader_stage
.unwrap_or(16),
max_storage_buffers_per_shader_stage: limits
.max_storage_buffers_per_shader_stage
.unwrap_or(4),
max_storage_textures_per_shader_stage: limits
.max_storage_textures_per_shader_stage
.unwrap_or(4),
max_uniform_buffers_per_shader_stage: limits
.max_uniform_buffers_per_shader_stage
.unwrap_or(12),
max_uniform_buffer_binding_size: limits
.max_uniform_buffer_binding_size
.unwrap_or(16384),
max_storage_buffer_binding_size: limits
.max_storage_buffer_binding_size
.unwrap_or(134217728),
// min_uniform_buffer_offset_alignment: limits
// .min_uniform_buffer_offset_alignment
// .unwrap_or(default),
// min_storage_buffer_offset_alignment: limits
// .min_storage_buffer_offset_alignment
// .unwrap_or(default),
max_vertex_buffers: limits.max_vertex_buffers.unwrap_or(8),
max_vertex_attributes: limits.max_vertex_attributes.unwrap_or(16),
max_vertex_buffer_array_stride: limits
.max_vertex_buffer_array_stride
.unwrap_or(2048),
// max_inter_stage_shader_components: limits
// .max_inter_stage_shader_components
// .unwrap_or(default),
// max_compute_workgroup_storage_size: limits
// .max_compute_workgroup_storage_size
// .unwrap_or(default),
// max_compute_invocations_per_workgroup: limits
// .max_compute_invocations_per_workgroup
// .unwrap_or(default),
// max_compute_workgroup_size_x: limits
// .max_compute_workgroup_size_x
// .unwrap_or(default),
// max_compute_workgroup_size_y: limits
// .max_compute_workgroup_size_y
// .unwrap_or(default),
// max_compute_workgroup_size_z: limits
// .max_compute_workgroup_size_z
// .unwrap_or(default),
// max_compute_workgroups_per_dimension: limits
// .max_compute_workgroups_per_dimension
// .unwrap_or(default),
max_push_constant_size: 0,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RequestDeviceArgs {
adapter_rid: ResourceId,
label: Option<String>,
required_features: Option<GpuRequiredFeatures>,
required_limits: Option<GpuLimits>,
required_limits: Option<wgpu_types::Limits>,
}
#[derive(Deserialize)]
@ -437,101 +320,120 @@ pub struct GpuRequiredFeatures(HashSet<String>);
impl From<GpuRequiredFeatures> for wgpu_types::Features {
fn from(required_features: GpuRequiredFeatures) -> wgpu_types::Features {
let mut features: wgpu_types::Features = wgpu_types::Features::empty();
if required_features.0.contains("depth-clamping") {
features.set(wgpu_types::Features::DEPTH_CLAMPING, true);
}
if required_features.0.contains("pipeline-statistics-query") {
features.set(wgpu_types::Features::PIPELINE_STATISTICS_QUERY, true);
}
if required_features.0.contains("texture-compression-bc") {
features.set(wgpu_types::Features::TEXTURE_COMPRESSION_BC, true);
}
if required_features.0.contains("timestamp-query") {
features.set(wgpu_types::Features::TIMESTAMP_QUERY, true);
}
features.set(
wgpu_types::Features::DEPTH_CLIP_CONTROL,
required_features.0.contains("depth-clip-control"),
);
features.set(
wgpu_types::Features::PIPELINE_STATISTICS_QUERY,
required_features.0.contains("pipeline-statistics-query"),
);
features.set(
wgpu_types::Features::TEXTURE_COMPRESSION_BC,
required_features.0.contains("texture-compression-bc"),
);
features.set(
wgpu_types::Features::TEXTURE_COMPRESSION_ETC2,
required_features.0.contains("texture-compression-etc2"),
);
features.set(
wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR,
required_features.0.contains("texture-compression-astc"),
);
features.set(
wgpu_types::Features::TIMESTAMP_QUERY,
required_features.0.contains("timestamp-query"),
);
features.set(
wgpu_types::Features::INDIRECT_FIRST_INSTANCE,
required_features.0.contains("indirect-first-instance"),
);
// extended from spec
if required_features.0.contains("mappable-primary-buffers") {
features.set(wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS, true);
}
if required_features.0.contains("texture-binding-array") {
features.set(wgpu_types::Features::TEXTURE_BINDING_ARRAY, true);
}
if required_features.0.contains("buffer-binding-array") {
features.set(wgpu_types::Features::BUFFER_BINDING_ARRAY, true);
}
if required_features
.0
.contains("storage-resource-binding-array")
{
features.set(wgpu_types::Features::STORAGE_RESOURCE_BINDING_ARRAY, true);
}
if required_features
.0
.contains("sampled-texture-and-storage-buffer-array-non-uniform-indexing")
{
features.set(wgpu_types::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING, true);
}
if required_features.0.contains(
"uniform-buffer-and-storage-buffer-texture-non-uniform-indexing",
) {
features.set(wgpu_types::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING, true);
}
if required_features.0.contains("unsized-binding-array") {
features.set(wgpu_types::Features::UNSIZED_BINDING_ARRAY, true);
}
if required_features.0.contains("multi-draw-indirect") {
features.set(wgpu_types::Features::MULTI_DRAW_INDIRECT, true);
}
if required_features.0.contains("multi-draw-indirect-count") {
features.set(wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT, true);
}
if required_features.0.contains("push-constants") {
features.set(wgpu_types::Features::PUSH_CONSTANTS, true);
}
if required_features.0.contains("address-mode-clamp-to-border") {
features.set(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER, true);
}
if required_features.0.contains("non-fill-polygon-mode") {
features.set(wgpu_types::Features::NON_FILL_POLYGON_MODE, true);
}
if required_features.0.contains("texture-compression-etc2") {
features.set(wgpu_types::Features::TEXTURE_COMPRESSION_ETC2, true);
}
if required_features.0.contains("texture-compression-astc-ldr") {
features.set(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_LDR, true);
}
if required_features
.0
.contains("texture-adapter-specific-format-features")
{
features.set(
wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES,
true,
);
}
if required_features.0.contains("shader-float64") {
features.set(wgpu_types::Features::SHADER_FLOAT64, true);
}
if required_features.0.contains("vertex-attribute-64bit") {
features.set(wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT, true);
}
if required_features.0.contains("conservative-rasterization") {
features.set(wgpu_types::Features::CONSERVATIVE_RASTERIZATION, true);
}
if required_features.0.contains("vertex-writable-storage") {
features.set(wgpu_types::Features::VERTEX_WRITABLE_STORAGE, true);
}
if required_features.0.contains("clear-commands") {
features.set(wgpu_types::Features::CLEAR_COMMANDS, true);
}
if required_features.0.contains("spirv-shader-passthrough") {
features.set(wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH, true);
}
if required_features.0.contains("shader-primitive-index") {
features.set(wgpu_types::Features::SHADER_PRIMITIVE_INDEX, true);
}
features.set(
wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS,
required_features.0.contains("mappable-primary-buffers"),
);
features.set(
wgpu_types::Features::TEXTURE_BINDING_ARRAY,
required_features.0.contains("texture-binding-array"),
);
features.set(
wgpu_types::Features::BUFFER_BINDING_ARRAY,
required_features.0.contains("buffer-binding-array"),
);
features.set(
wgpu_types::Features::STORAGE_RESOURCE_BINDING_ARRAY,
required_features
.0
.contains("storage-resource-binding-array"),
);
features.set(
wgpu_types::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
required_features
.0
.contains("sampled-texture-and-storage-buffer-array-non-uniform-indexing"),
);
features.set(
wgpu_types::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
required_features
.0
.contains("uniform-buffer-and-storage-buffer-texture-non-uniform-indexing"),
);
features.set(
wgpu_types::Features::UNSIZED_BINDING_ARRAY,
required_features.0.contains("unsized-binding-array"),
);
features.set(
wgpu_types::Features::MULTI_DRAW_INDIRECT,
required_features.0.contains("multi-draw-indirect"),
);
features.set(
wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT,
required_features.0.contains("multi-draw-indirect-count"),
);
features.set(
wgpu_types::Features::PUSH_CONSTANTS,
required_features.0.contains("push-constants"),
);
features.set(
wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER,
required_features.0.contains("address-mode-clamp-to-border"),
);
features.set(
wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES,
required_features
.0
.contains("texture-adapter-specific-format-features"),
);
features.set(
wgpu_types::Features::SHADER_FLOAT64,
required_features.0.contains("shader-float64"),
);
features.set(
wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT,
required_features.0.contains("vertex-attribute-64bit"),
);
features.set(
wgpu_types::Features::CONSERVATIVE_RASTERIZATION,
required_features.0.contains("conservative-rasterization"),
);
features.set(
wgpu_types::Features::VERTEX_WRITABLE_STORAGE,
required_features.0.contains("vertex-writable-storage"),
);
features.set(
wgpu_types::Features::CLEAR_TEXTURE,
required_features.0.contains("clear-commands"),
);
features.set(
wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH,
required_features.0.contains("spirv-shader-passthrough"),
);
features.set(
wgpu_types::Features::SHADER_PRIMITIVE_INDEX,
required_features.0.contains("shader-primitive-index"),
);
features
}
@ -775,6 +677,10 @@ fn declare_webgpu_ops() -> Vec<(&'static str, Box<OpFn>)> {
command_encoder::op_webgpu_command_encoder_copy_texture_to_texture,
),
),
(
"op_webgpu_command_encoder_clear_buffer",
op_sync(command_encoder::op_webgpu_command_encoder_clear_buffer),
),
(
"op_webgpu_command_encoder_push_debug_group",
op_sync(command_encoder::op_webgpu_command_encoder_push_debug_group),
@ -895,6 +801,22 @@ fn declare_webgpu_ops() -> Vec<(&'static str, Box<OpFn>)> {
"op_webgpu_compute_pass_dispatch_indirect",
op_sync(compute_pass::op_webgpu_compute_pass_dispatch_indirect),
),
(
"op_webgpu_compute_pass_begin_pipeline_statistics_query",
op_sync(
compute_pass::op_webgpu_compute_pass_begin_pipeline_statistics_query,
),
),
(
"op_webgpu_compute_pass_end_pipeline_statistics_query",
op_sync(
compute_pass::op_webgpu_compute_pass_end_pipeline_statistics_query,
),
),
(
"op_webgpu_compute_pass_write_timestamp",
op_sync(compute_pass::op_webgpu_compute_pass_write_timestamp),
),
(
"op_webgpu_compute_pass_end_pass",
op_sync(compute_pass::op_webgpu_compute_pass_end_pass),

431
ext/webgpu/src/pipeline.rs Normal file
View file

@ -0,0 +1,431 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::ResourceId;
use deno_core::{OpState, Resource};
use serde::Deserialize;
use serde::Serialize;
use std::borrow::Cow;
use std::convert::{TryFrom, TryInto};
use super::error::WebGpuError;
use super::error::WebGpuResult;
const MAX_BIND_GROUPS: usize = 8;
pub(crate) struct WebGpuPipelineLayout(
pub(crate) wgpu_core::id::PipelineLayoutId,
);
impl Resource for WebGpuPipelineLayout {
fn name(&self) -> Cow<str> {
"webGPUPipelineLayout".into()
}
}
pub(crate) struct WebGpuComputePipeline(
pub(crate) wgpu_core::id::ComputePipelineId,
);
impl Resource for WebGpuComputePipeline {
fn name(&self) -> Cow<str> {
"webGPUComputePipeline".into()
}
}
pub(crate) struct WebGpuRenderPipeline(
pub(crate) wgpu_core::id::RenderPipelineId,
);
impl Resource for WebGpuRenderPipeline {
fn name(&self) -> Cow<str> {
"webGPURenderPipeline".into()
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuProgrammableStage {
module: ResourceId,
entry_point: String,
// constants: HashMap<String, GPUPipelineConstantValue>
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateComputePipelineArgs {
device_rid: ResourceId,
label: Option<String>,
layout: Option<ResourceId>,
compute: GpuProgrammableStage,
}
pub fn op_webgpu_create_compute_pipeline(
state: &mut OpState,
args: CreateComputePipelineArgs,
_: (),
) -> 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 pipeline_layout = if let Some(rid) = args.layout {
let id = state.resource_table.get::<WebGpuPipelineLayout>(rid)?;
Some(id.0)
} else {
None
};
let compute_shader_module_resource =
state
.resource_table
.get::<super::shader::WebGpuShaderModule>(args.compute.module)?;
let descriptor = wgpu_core::pipeline::ComputePipelineDescriptor {
label: args.label.map(Cow::from),
layout: pipeline_layout,
stage: wgpu_core::pipeline::ProgrammableStageDescriptor {
module: compute_shader_module_resource.0,
entry_point: Cow::from(args.compute.entry_point),
// TODO(lucacasonato): support args.compute.constants
},
};
let implicit_pipelines = match args.layout {
Some(_) => None,
None => Some(wgpu_core::device::ImplicitPipelineIds {
root_id: std::marker::PhantomData,
group_ids: &[std::marker::PhantomData; MAX_BIND_GROUPS],
}),
};
let (compute_pipeline, maybe_err) = gfx_select!(device => instance.device_create_compute_pipeline(
device,
&descriptor,
std::marker::PhantomData,
implicit_pipelines
));
let rid = state
.resource_table
.add(WebGpuComputePipeline(compute_pipeline));
Ok(WebGpuResult::rid_err(rid, maybe_err))
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ComputePipelineGetBindGroupLayoutArgs {
compute_pipeline_rid: ResourceId,
index: u32,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PipelineLayout {
rid: ResourceId,
label: String,
err: Option<WebGpuError>,
}
pub fn op_webgpu_compute_pipeline_get_bind_group_layout(
state: &mut OpState,
args: ComputePipelineGetBindGroupLayoutArgs,
_: (),
) -> Result<PipelineLayout, AnyError> {
let instance = state.borrow::<super::Instance>();
let compute_pipeline_resource = state
.resource_table
.get::<WebGpuComputePipeline>(args.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, args.index, std::marker::PhantomData));
let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout));
let rid = state
.resource_table
.add(super::binding::WebGpuBindGroupLayout(bind_group_layout));
Ok(PipelineLayout {
rid,
label,
err: maybe_err.map(WebGpuError::from),
})
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GpuCullMode {
None,
Front,
Back,
}
impl From<GpuCullMode> for Option<wgpu_types::Face> {
fn from(value: GpuCullMode) -> Option<wgpu_types::Face> {
match value {
GpuCullMode::None => None,
GpuCullMode::Front => Some(wgpu_types::Face::Front),
GpuCullMode::Back => Some(wgpu_types::Face::Back),
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuPrimitiveState {
topology: wgpu_types::PrimitiveTopology,
strip_index_format: Option<wgpu_types::IndexFormat>,
front_face: wgpu_types::FrontFace,
cull_mode: GpuCullMode,
unclipped_depth: bool,
}
impl From<GpuPrimitiveState> for wgpu_types::PrimitiveState {
fn from(value: GpuPrimitiveState) -> wgpu_types::PrimitiveState {
wgpu_types::PrimitiveState {
topology: value.topology,
strip_index_format: value.strip_index_format,
front_face: value.front_face,
cull_mode: value.cull_mode.into(),
unclipped_depth: value.unclipped_depth,
polygon_mode: Default::default(), // native-only
conservative: false, // native-only
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuDepthStencilState {
format: wgpu_types::TextureFormat,
depth_write_enabled: bool,
depth_compare: wgpu_types::CompareFunction,
stencil_front: wgpu_types::StencilFaceState,
stencil_back: wgpu_types::StencilFaceState,
stencil_read_mask: u32,
stencil_write_mask: u32,
depth_bias: i32,
depth_bias_slope_scale: f32,
depth_bias_clamp: f32,
}
impl TryFrom<GpuDepthStencilState> for wgpu_types::DepthStencilState {
type Error = AnyError;
fn try_from(
state: GpuDepthStencilState,
) -> Result<wgpu_types::DepthStencilState, AnyError> {
Ok(wgpu_types::DepthStencilState {
format: state.format,
depth_write_enabled: state.depth_write_enabled,
depth_compare: state.depth_compare,
stencil: wgpu_types::StencilState {
front: state.stencil_front,
back: state.stencil_back,
read_mask: state.stencil_read_mask,
write_mask: state.stencil_write_mask,
},
bias: wgpu_types::DepthBiasState {
constant: state.depth_bias,
slope_scale: state.depth_bias_slope_scale,
clamp: state.depth_bias_clamp,
},
})
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuVertexBufferLayout {
array_stride: u64,
step_mode: wgpu_types::VertexStepMode,
attributes: Vec<wgpu_types::VertexAttribute>,
}
impl<'a> From<GpuVertexBufferLayout>
for wgpu_core::pipeline::VertexBufferLayout<'a>
{
fn from(
layout: GpuVertexBufferLayout,
) -> wgpu_core::pipeline::VertexBufferLayout<'a> {
wgpu_core::pipeline::VertexBufferLayout {
array_stride: layout.array_stride,
step_mode: layout.step_mode,
attributes: Cow::Owned(layout.attributes),
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuVertexState {
module: ResourceId,
entry_point: String,
buffers: Vec<Option<GpuVertexBufferLayout>>,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuMultisampleState {
count: u32,
mask: u64,
alpha_to_coverage_enabled: bool,
}
impl From<GpuMultisampleState> for wgpu_types::MultisampleState {
fn from(gms: GpuMultisampleState) -> wgpu_types::MultisampleState {
wgpu_types::MultisampleState {
count: gms.count,
mask: gms.mask,
alpha_to_coverage_enabled: gms.alpha_to_coverage_enabled,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuFragmentState {
targets: Vec<wgpu_types::ColorTargetState>,
module: u32,
entry_point: String,
// TODO(lucacasonato): constants
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateRenderPipelineArgs {
device_rid: ResourceId,
label: Option<String>,
layout: Option<ResourceId>,
vertex: GpuVertexState,
primitive: GpuPrimitiveState,
depth_stencil: Option<GpuDepthStencilState>,
multisample: wgpu_types::MultisampleState,
fragment: Option<GpuFragmentState>,
}
pub fn op_webgpu_create_render_pipeline(
state: &mut OpState,
args: CreateRenderPipelineArgs,
_: (),
) -> 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 layout = if let Some(rid) = args.layout {
let pipeline_layout_resource =
state.resource_table.get::<WebGpuPipelineLayout>(rid)?;
Some(pipeline_layout_resource.0)
} else {
None
};
let vertex_shader_module_resource =
state
.resource_table
.get::<super::shader::WebGpuShaderModule>(args.vertex.module)?;
let fragment = if let Some(fragment) = args.fragment {
let fragment_shader_module_resource =
state
.resource_table
.get::<super::shader::WebGpuShaderModule>(fragment.module)?;
let mut targets = Vec::with_capacity(fragment.targets.len());
for target in fragment.targets {
targets.push(target);
}
Some(wgpu_core::pipeline::FragmentState {
stage: wgpu_core::pipeline::ProgrammableStageDescriptor {
module: fragment_shader_module_resource.0,
entry_point: Cow::from(fragment.entry_point),
},
targets: Cow::from(targets),
})
} else {
None
};
let vertex_buffers = args
.vertex
.buffers
.into_iter()
.flatten()
.map(Into::into)
.collect();
let descriptor = wgpu_core::pipeline::RenderPipelineDescriptor {
label: args.label.map(Cow::Owned),
layout,
vertex: wgpu_core::pipeline::VertexState {
stage: wgpu_core::pipeline::ProgrammableStageDescriptor {
module: vertex_shader_module_resource.0,
entry_point: Cow::Owned(args.vertex.entry_point),
},
buffers: Cow::Owned(vertex_buffers),
},
primitive: args.primitive.into(),
depth_stencil: args.depth_stencil.map(TryInto::try_into).transpose()?,
multisample: args.multisample,
fragment,
multiview: None,
};
let implicit_pipelines = match args.layout {
Some(_) => None,
None => Some(wgpu_core::device::ImplicitPipelineIds {
root_id: std::marker::PhantomData,
group_ids: &[std::marker::PhantomData; MAX_BIND_GROUPS],
}),
};
let (render_pipeline, maybe_err) = gfx_select!(device => instance.device_create_render_pipeline(
device,
&descriptor,
std::marker::PhantomData,
implicit_pipelines
));
let rid = state
.resource_table
.add(WebGpuRenderPipeline(render_pipeline));
Ok(WebGpuResult::rid_err(rid, maybe_err))
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RenderPipelineGetBindGroupLayoutArgs {
render_pipeline_rid: ResourceId,
index: u32,
}
pub fn op_webgpu_render_pipeline_get_bind_group_layout(
state: &mut OpState,
args: RenderPipelineGetBindGroupLayoutArgs,
_: (),
) -> Result<PipelineLayout, AnyError> {
let instance = state.borrow::<super::Instance>();
let render_pipeline_resource = state
.resource_table
.get::<WebGpuRenderPipeline>(args.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, args.index, std::marker::PhantomData));
let label = gfx_select!(bind_group_layout => instance.bind_group_layout_label(bind_group_layout));
let rid = state
.resource_table
.add(super::binding::WebGpuBindGroupLayout(bind_group_layout));
Ok(PipelineLayout {
rid,
label,
err: maybe_err.map(WebGpuError::from),
})
}

View file

@ -1,4 +1,4 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use std::num::NonZeroU32;
@ -108,7 +108,7 @@ pub struct QueueWriteTextureArgs {
queue_rid: ResourceId,
destination: super::command_encoder::GpuImageCopyTexture,
data_layout: GpuImageDataLayout,
size: super::texture::GpuExtent3D,
size: wgpu_types::Extent3d,
}
pub fn op_webgpu_write_texture(
@ -127,8 +127,8 @@ pub fn op_webgpu_write_texture(
let destination = wgpu_core::command::ImageCopyTexture {
texture: texture_resource.0,
mip_level: args.destination.mip_level,
origin: args.destination.origin.into(),
aspect: args.destination.aspect.into(),
origin: args.destination.origin,
aspect: args.destination.aspect,
};
let data_layout = args.data_layout.into();
@ -137,6 +137,6 @@ pub fn op_webgpu_write_texture(
&destination,
&*zero_copy,
&data_layout,
&args.size.into()
&args.size
))
}

View file

@ -1,4 +1,4 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use deno_core::error::type_error;
use deno_core::error::AnyError;
@ -9,8 +9,6 @@ use serde::Deserialize;
use std::borrow::Cow;
use std::cell::RefCell;
use crate::pipeline::GpuIndexFormat;
use super::error::WebGpuResult;
pub(crate) struct WebGpuRenderPass(
@ -86,20 +84,11 @@ pub fn op_webgpu_render_pass_set_scissor_rect(
Ok(WebGpuResult::empty())
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GpuColor {
pub r: f64,
pub g: f64,
pub b: f64,
pub a: f64,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RenderPassSetBlendConstantArgs {
render_pass_rid: ResourceId,
color: GpuColor,
color: wgpu_types::Color,
}
pub fn op_webgpu_render_pass_set_blend_constant(
@ -113,12 +102,7 @@ pub fn op_webgpu_render_pass_set_blend_constant(
wgpu_core::command::render_ffi::wgpu_render_pass_set_blend_constant(
&mut render_pass_resource.0.borrow_mut(),
&wgpu_types::Color {
r: args.color.r,
g: args.color.g,
b: args.color.b,
a: args.color.a,
},
&args.color,
);
Ok(WebGpuResult::empty())
@ -169,10 +153,10 @@ pub fn op_webgpu_render_pass_begin_pipeline_statistics_query(
.get::<super::WebGpuQuerySet>(args.query_set)?;
wgpu_core::command::render_ffi::wgpu_render_pass_begin_pipeline_statistics_query(
&mut render_pass_resource.0.borrow_mut(),
query_set_resource.0,
args.query_index,
);
&mut render_pass_resource.0.borrow_mut(),
query_set_resource.0,
args.query_index,
);
Ok(WebGpuResult::empty())
}
@ -193,8 +177,8 @@ pub fn op_webgpu_render_pass_end_pipeline_statistics_query(
.get::<WebGpuRenderPass>(args.render_pass_rid)?;
wgpu_core::command::render_ffi::wgpu_render_pass_end_pipeline_statistics_query(
&mut render_pass_resource.0.borrow_mut(),
);
&mut render_pass_resource.0.borrow_mut(),
);
Ok(WebGpuResult::empty())
}
@ -466,7 +450,7 @@ pub fn op_webgpu_render_pass_set_pipeline(
pub struct RenderPassSetIndexBufferArgs {
render_pass_rid: ResourceId,
buffer: u32,
index_format: GpuIndexFormat,
index_format: wgpu_types::IndexFormat,
offset: u64,
size: Option<u64>,
}
@ -494,7 +478,7 @@ pub fn op_webgpu_render_pass_set_index_buffer(
render_pass_resource.0.borrow_mut().set_index_buffer(
buffer_resource.0,
args.index_format.into(),
args.index_format,
args.offset,
size,
);

68
ext/webgpu/src/sampler.rs Normal file
View file

@ -0,0 +1,68 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::ResourceId;
use deno_core::{OpState, Resource};
use serde::Deserialize;
use std::borrow::Cow;
use super::error::WebGpuResult;
pub(crate) struct WebGpuSampler(pub(crate) wgpu_core::id::SamplerId);
impl Resource for WebGpuSampler {
fn name(&self) -> Cow<str> {
"webGPUSampler".into()
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateSamplerArgs {
device_rid: ResourceId,
label: Option<String>,
address_mode_u: wgpu_types::AddressMode,
address_mode_v: wgpu_types::AddressMode,
address_mode_w: wgpu_types::AddressMode,
mag_filter: wgpu_types::FilterMode,
min_filter: wgpu_types::FilterMode,
mipmap_filter: wgpu_types::FilterMode,
lod_min_clamp: f32,
lod_max_clamp: f32,
compare: Option<wgpu_types::CompareFunction>,
max_anisotropy: u8,
}
pub fn op_webgpu_create_sampler(
state: &mut OpState,
args: CreateSamplerArgs,
_: (),
) -> 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 descriptor = wgpu_core::resource::SamplerDescriptor {
label: args.label.map(Cow::from),
address_modes: [
args.address_mode_u,
args.address_mode_v,
args.address_mode_w,
],
mag_filter: args.mag_filter,
min_filter: args.min_filter,
mipmap_filter: args.mipmap_filter,
lod_min_clamp: args.lod_min_clamp,
lod_max_clamp: args.lod_max_clamp,
compare: args.compare,
anisotropy_clamp: std::num::NonZeroU8::new(args.max_anisotropy),
border_color: None, // native-only
};
gfx_put!(device => instance.device_create_sampler(
device,
&descriptor,
std::marker::PhantomData
) => state, WebGpuSampler)
}

View file

@ -1,4 +1,4 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::ResourceId;
@ -40,6 +40,7 @@ pub fn op_webgpu_create_shader_module(
let descriptor = wgpu_core::pipeline::ShaderModuleDescriptor {
label: args.label.map(Cow::from),
shader_bound_checks: wgpu_types::ShaderBoundChecks::default(),
};
gfx_put!(device => instance.device_create_shader_module(

112
ext/webgpu/src/texture.rs Normal file
View file

@ -0,0 +1,112 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use deno_core::error::AnyError;
use deno_core::ResourceId;
use deno_core::{OpState, Resource};
use serde::Deserialize;
use std::borrow::Cow;
use super::error::WebGpuResult;
pub(crate) struct WebGpuTexture(pub(crate) wgpu_core::id::TextureId);
impl Resource for WebGpuTexture {
fn name(&self) -> Cow<str> {
"webGPUTexture".into()
}
}
pub(crate) struct WebGpuTextureView(pub(crate) wgpu_core::id::TextureViewId);
impl Resource for WebGpuTextureView {
fn name(&self) -> Cow<str> {
"webGPUTextureView".into()
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateTextureArgs {
device_rid: ResourceId,
label: Option<String>,
size: wgpu_types::Extent3d,
mip_level_count: u32,
sample_count: u32,
dimension: wgpu_types::TextureDimension,
format: wgpu_types::TextureFormat,
usage: u32,
}
pub fn op_webgpu_create_texture(
state: &mut OpState,
args: CreateTextureArgs,
_: (),
) -> 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 descriptor = wgpu_core::resource::TextureDescriptor {
label: args.label.map(Cow::from),
size: args.size,
mip_level_count: args.mip_level_count,
sample_count: args.sample_count,
dimension: args.dimension,
format: args.format,
usage: wgpu_types::TextureUsages::from_bits_truncate(args.usage),
};
gfx_put!(device => instance.device_create_texture(
device,
&descriptor,
std::marker::PhantomData
) => state, WebGpuTexture)
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateTextureViewArgs {
texture_rid: ResourceId,
label: Option<String>,
format: Option<wgpu_types::TextureFormat>,
dimension: Option<wgpu_types::TextureViewDimension>,
aspect: wgpu_types::TextureAspect,
base_mip_level: u32,
mip_level_count: Option<u32>,
base_array_layer: u32,
array_layer_count: Option<u32>,
}
pub fn op_webgpu_create_texture_view(
state: &mut OpState,
args: CreateTextureViewArgs,
_: (),
) -> Result<WebGpuResult, AnyError> {
let instance = state.borrow::<super::Instance>();
let texture_resource = state
.resource_table
.get::<WebGpuTexture>(args.texture_rid)?;
let texture = texture_resource.0;
let descriptor = wgpu_core::resource::TextureViewDescriptor {
label: args.label.map(Cow::from),
format: args.format,
dimension: args.dimension,
range: wgpu_types::ImageSubresourceRange {
aspect: args.aspect,
base_mip_level: args.base_mip_level,
mip_level_count: std::num::NonZeroU32::new(
args.mip_level_count.unwrap_or(0),
),
base_array_layer: args.base_array_layer,
array_layer_count: std::num::NonZeroU32::new(
args.array_layer_count.unwrap_or(0),
),
},
};
gfx_put!(texture => instance.texture_create_view(
texture,
&descriptor,
std::marker::PhantomData
) => state, WebGpuTextureView)
}

View file

@ -1,419 +0,0 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use deno_core::error::not_supported;
use deno_core::error::AnyError;
use deno_core::ResourceId;
use deno_core::{OpState, Resource};
use serde::Deserialize;
use std::borrow::Cow;
use super::error::WebGpuResult;
pub(crate) struct WebGpuTexture(pub(crate) wgpu_core::id::TextureId);
impl Resource for WebGpuTexture {
fn name(&self) -> Cow<str> {
"webGPUTexture".into()
}
}
pub(crate) struct WebGpuTextureView(pub(crate) wgpu_core::id::TextureViewId);
impl Resource for WebGpuTextureView {
fn name(&self) -> Cow<str> {
"webGPUTextureView".into()
}
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GpuTextureFormat {
// 8-bit formats
#[serde(rename = "r8unorm")]
R8Unorm,
#[serde(rename = "r8snorm")]
R8Snorm,
#[serde(rename = "r8uint")]
R8Uint,
#[serde(rename = "r8sint")]
R8Sint,
// 16-bit formats
#[serde(rename = "r16uint")]
R16Uint,
#[serde(rename = "r16sint")]
R16Sint,
#[serde(rename = "r16float")]
R16Float,
#[serde(rename = "rg8unorm")]
Rg8Unorm,
#[serde(rename = "rg8snorm")]
Rg8Snorm,
#[serde(rename = "rg8uint")]
Rg8Uint,
#[serde(rename = "rg8sint")]
Rg8Sint,
// 32-bit formats
#[serde(rename = "r32uint")]
R32Uint,
#[serde(rename = "r32sint")]
R32Sint,
#[serde(rename = "r32float")]
R32Float,
#[serde(rename = "rg16uint")]
Rg16Uint,
#[serde(rename = "rg16sint")]
Rg16Sint,
#[serde(rename = "rg16float")]
Rg16Float,
#[serde(rename = "rgba8unorm")]
Rgba8Unorm,
#[serde(rename = "rgba8unorm-srgb")]
Rgba8UnormSrgb,
#[serde(rename = "rgba8snorm")]
Rgba8Snorm,
#[serde(rename = "rgba8uint")]
Rgba8Uint,
#[serde(rename = "rgba8sint")]
Rgba8Sint,
#[serde(rename = "bgra8unorm")]
Bgra8Unorm,
#[serde(rename = "bgra8unorm-srgb")]
Bgra8UnormSrgb,
// Packed 32-bit formats
#[serde(rename = "rgb9e5ufloat")]
RgB9E5UFloat,
#[serde(rename = "rgb10a2unorm")]
Rgb10a2Unorm,
#[serde(rename = "rg11b10ufloat")]
Rg11b10Float,
// 64-bit formats
#[serde(rename = "rg32uint")]
Rg32Uint,
#[serde(rename = "rg32sint")]
Rg32Sint,
#[serde(rename = "rg32float")]
Rg32Float,
#[serde(rename = "rgba16uint")]
Rgba16Uint,
#[serde(rename = "rgba16sint")]
Rgba16Sint,
#[serde(rename = "rgba16float")]
Rgba16Float,
// 128-bit formats
#[serde(rename = "rgba32uint")]
Rgba32Uint,
#[serde(rename = "rgba32sint")]
Rgba32Sint,
#[serde(rename = "rgba32float")]
Rgba32Float,
// Depth and stencil formats
#[serde(rename = "stencil8")]
Stencil8,
#[serde(rename = "depth16unorm")]
Depth16Unorm,
#[serde(rename = "depth24plus")]
Depth24Plus,
#[serde(rename = "depth24plus-stencil8")]
Depth24PlusStencil8,
#[serde(rename = "depth32float")]
Depth32Float,
// BC compressed formats usable if "texture-compression-bc" is both
// supported by the device/user agent and enabled in requestDevice.
#[serde(rename = "bc1-rgba-unorm")]
Bc1RgbaUnorm,
#[serde(rename = "bc1-rgba-unorm-srgb")]
Bc1RgbaUnormSrgb,
#[serde(rename = "bc2-rgba-unorm")]
Bc2RgbaUnorm,
#[serde(rename = "bc2-rgba-unorm-srgb")]
Bc2RgbaUnormSrgb,
#[serde(rename = "bc3-rgba-unorm")]
Bc3RgbaUnorm,
#[serde(rename = "bc3-rgba-unorm-srgb")]
Bc3RgbaUnormSrgb,
#[serde(rename = "bc4-r-unorm")]
Bc4RUnorm,
#[serde(rename = "bc4-r-snorm")]
Bc4RSnorm,
#[serde(rename = "bc5-rg-unorm")]
Bc5RgUnorm,
#[serde(rename = "bc5-rg-snorm")]
Bc5RgSnorm,
#[serde(rename = "bc6h-rgb-ufloat")]
Bc6hRgbUfloat,
#[serde(rename = "bc6h-rgb-float")]
Bc6HRgbFloat,
#[serde(rename = "bc7-rgba-unorm")]
Bc7RgbaUnorm,
#[serde(rename = "bc7-rgba-unorm-srgb")]
Bc7RgbaUnormSrgb,
// "depth24unorm-stencil8" feature
#[serde(rename = "depth24unorm-stencil8")]
Depth24UnormStencil8,
// "depth32float-stencil8" feature
#[serde(rename = "depth32float-stencil8")]
Depth32FloatStencil8,
}
impl TryFrom<GpuTextureFormat> for wgpu_types::TextureFormat {
type Error = AnyError;
fn try_from(value: GpuTextureFormat) -> Result<Self, Self::Error> {
use wgpu_types::TextureFormat;
match value {
GpuTextureFormat::R8Unorm => Ok(TextureFormat::R8Unorm),
GpuTextureFormat::R8Snorm => Ok(TextureFormat::R8Snorm),
GpuTextureFormat::R8Uint => Ok(TextureFormat::R8Uint),
GpuTextureFormat::R8Sint => Ok(TextureFormat::R8Sint),
GpuTextureFormat::R16Uint => Ok(TextureFormat::R16Uint),
GpuTextureFormat::R16Sint => Ok(TextureFormat::R16Sint),
GpuTextureFormat::R16Float => Ok(TextureFormat::R16Float),
GpuTextureFormat::Rg8Unorm => Ok(TextureFormat::Rg8Unorm),
GpuTextureFormat::Rg8Snorm => Ok(TextureFormat::Rg8Snorm),
GpuTextureFormat::Rg8Uint => Ok(TextureFormat::Rg8Uint),
GpuTextureFormat::Rg8Sint => Ok(TextureFormat::Rg8Sint),
GpuTextureFormat::R32Uint => Ok(TextureFormat::R32Uint),
GpuTextureFormat::R32Sint => Ok(TextureFormat::R32Sint),
GpuTextureFormat::R32Float => Ok(TextureFormat::R32Float),
GpuTextureFormat::Rg16Uint => Ok(TextureFormat::Rg16Uint),
GpuTextureFormat::Rg16Sint => Ok(TextureFormat::Rg16Sint),
GpuTextureFormat::Rg16Float => Ok(TextureFormat::Rg16Float),
GpuTextureFormat::Rgba8Unorm => Ok(TextureFormat::Rgba8Unorm),
GpuTextureFormat::Rgba8UnormSrgb => Ok(TextureFormat::Rgba8UnormSrgb),
GpuTextureFormat::Rgba8Snorm => Ok(TextureFormat::Rgba8Snorm),
GpuTextureFormat::Rgba8Uint => Ok(TextureFormat::Rgba8Uint),
GpuTextureFormat::Rgba8Sint => Ok(TextureFormat::Rgba8Sint),
GpuTextureFormat::Bgra8Unorm => Ok(TextureFormat::Bgra8Unorm),
GpuTextureFormat::Bgra8UnormSrgb => Ok(TextureFormat::Bgra8UnormSrgb),
GpuTextureFormat::RgB9E5UFloat => Err(not_supported()), // wgpu#967
GpuTextureFormat::Rgb10a2Unorm => Ok(TextureFormat::Rgb10a2Unorm),
GpuTextureFormat::Rg11b10Float => Ok(TextureFormat::Rg11b10Float),
GpuTextureFormat::Rg32Uint => Ok(TextureFormat::Rg32Uint),
GpuTextureFormat::Rg32Sint => Ok(TextureFormat::Rg32Sint),
GpuTextureFormat::Rg32Float => Ok(TextureFormat::Rg32Float),
GpuTextureFormat::Rgba16Uint => Ok(TextureFormat::Rgba16Uint),
GpuTextureFormat::Rgba16Sint => Ok(TextureFormat::Rgba16Sint),
GpuTextureFormat::Rgba16Float => Ok(TextureFormat::Rgba16Float),
GpuTextureFormat::Rgba32Uint => Ok(TextureFormat::Rgba32Uint),
GpuTextureFormat::Rgba32Sint => Ok(TextureFormat::Rgba32Sint),
GpuTextureFormat::Rgba32Float => Ok(TextureFormat::Rgba32Float),
GpuTextureFormat::Stencil8 => Err(not_supported()), // wgpu#967
GpuTextureFormat::Depth16Unorm => Err(not_supported()), // wgpu#967
GpuTextureFormat::Depth24Plus => Ok(TextureFormat::Depth24Plus),
GpuTextureFormat::Depth24PlusStencil8 => {
Ok(TextureFormat::Depth24PlusStencil8)
}
GpuTextureFormat::Depth32Float => Ok(TextureFormat::Depth32Float),
GpuTextureFormat::Bc1RgbaUnorm => Ok(TextureFormat::Bc1RgbaUnorm),
GpuTextureFormat::Bc1RgbaUnormSrgb => Ok(TextureFormat::Bc1RgbaUnormSrgb),
GpuTextureFormat::Bc2RgbaUnorm => Ok(TextureFormat::Bc2RgbaUnorm),
GpuTextureFormat::Bc2RgbaUnormSrgb => Ok(TextureFormat::Bc2RgbaUnormSrgb),
GpuTextureFormat::Bc3RgbaUnorm => Ok(TextureFormat::Bc3RgbaUnorm),
GpuTextureFormat::Bc3RgbaUnormSrgb => Ok(TextureFormat::Bc3RgbaUnormSrgb),
GpuTextureFormat::Bc4RUnorm => Ok(TextureFormat::Bc4RUnorm),
GpuTextureFormat::Bc4RSnorm => Ok(TextureFormat::Bc4RSnorm),
GpuTextureFormat::Bc5RgUnorm => Ok(TextureFormat::Bc5RgUnorm),
GpuTextureFormat::Bc5RgSnorm => Ok(TextureFormat::Bc5RgSnorm),
GpuTextureFormat::Bc6hRgbUfloat => Ok(TextureFormat::Bc6hRgbUfloat),
GpuTextureFormat::Bc6HRgbFloat => Ok(TextureFormat::Bc6hRgbSfloat), // wgpu#967
GpuTextureFormat::Bc7RgbaUnorm => Ok(TextureFormat::Bc7RgbaUnorm),
GpuTextureFormat::Bc7RgbaUnormSrgb => Ok(TextureFormat::Bc7RgbaUnormSrgb),
GpuTextureFormat::Depth24UnormStencil8 => Err(not_supported()), // wgpu#967,
GpuTextureFormat::Depth32FloatStencil8 => Err(not_supported()), // wgpu#967
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GpuTextureViewDimension {
#[serde(rename = "1d")]
D1,
#[serde(rename = "2d")]
D2,
#[serde(rename = "2d-array")]
D2Array,
#[serde(rename = "cube")]
Cube,
#[serde(rename = "cube-array")]
CubeArray,
#[serde(rename = "3d")]
D3,
}
impl From<GpuTextureViewDimension> for wgpu_types::TextureViewDimension {
fn from(view_dimension: GpuTextureViewDimension) -> Self {
match view_dimension {
GpuTextureViewDimension::D1 => wgpu_types::TextureViewDimension::D1,
GpuTextureViewDimension::D2 => wgpu_types::TextureViewDimension::D2,
GpuTextureViewDimension::D2Array => {
wgpu_types::TextureViewDimension::D2Array
}
GpuTextureViewDimension::Cube => wgpu_types::TextureViewDimension::Cube,
GpuTextureViewDimension::CubeArray => {
wgpu_types::TextureViewDimension::CubeArray
}
GpuTextureViewDimension::D3 => wgpu_types::TextureViewDimension::D3,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GpuTextureDimension {
#[serde(rename = "1d")]
D1,
#[serde(rename = "2d")]
D2,
#[serde(rename = "3d")]
D3,
}
impl From<GpuTextureDimension> for wgpu_types::TextureDimension {
fn from(texture_dimension: GpuTextureDimension) -> Self {
match texture_dimension {
GpuTextureDimension::D1 => wgpu_types::TextureDimension::D1,
GpuTextureDimension::D2 => wgpu_types::TextureDimension::D2,
GpuTextureDimension::D3 => wgpu_types::TextureDimension::D3,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum GpuTextureAspect {
All,
StencilOnly,
DepthOnly,
}
impl From<GpuTextureAspect> for wgpu_types::TextureAspect {
fn from(aspect: GpuTextureAspect) -> wgpu_types::TextureAspect {
match aspect {
GpuTextureAspect::All => wgpu_types::TextureAspect::All,
GpuTextureAspect::StencilOnly => wgpu_types::TextureAspect::StencilOnly,
GpuTextureAspect::DepthOnly => wgpu_types::TextureAspect::DepthOnly,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GpuExtent3D {
pub width: u32,
pub height: u32,
pub depth_or_array_layers: u32,
}
impl From<GpuExtent3D> for wgpu_types::Extent3d {
fn from(extent: GpuExtent3D) -> Self {
wgpu_types::Extent3d {
width: extent.width,
height: extent.height,
depth_or_array_layers: extent.depth_or_array_layers,
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateTextureArgs {
device_rid: ResourceId,
label: Option<String>,
size: GpuExtent3D,
mip_level_count: u32,
sample_count: u32,
dimension: GpuTextureDimension,
format: GpuTextureFormat,
usage: u32,
}
pub fn op_webgpu_create_texture(
state: &mut OpState,
args: CreateTextureArgs,
_: (),
) -> 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 descriptor = wgpu_core::resource::TextureDescriptor {
label: args.label.map(Cow::from),
size: args.size.into(),
mip_level_count: args.mip_level_count,
sample_count: args.sample_count,
dimension: args.dimension.into(),
format: args.format.try_into()?,
usage: wgpu_types::TextureUsages::from_bits_truncate(args.usage),
};
gfx_put!(device => instance.device_create_texture(
device,
&descriptor,
std::marker::PhantomData
) => state, WebGpuTexture)
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateTextureViewArgs {
texture_rid: ResourceId,
label: Option<String>,
format: Option<GpuTextureFormat>,
dimension: Option<GpuTextureViewDimension>,
aspect: GpuTextureAspect,
base_mip_level: u32,
mip_level_count: Option<u32>,
base_array_layer: u32,
array_layer_count: Option<u32>,
}
pub fn op_webgpu_create_texture_view(
state: &mut OpState,
args: CreateTextureViewArgs,
_: (),
) -> Result<WebGpuResult, AnyError> {
let instance = state.borrow::<super::Instance>();
let texture_resource = state
.resource_table
.get::<WebGpuTexture>(args.texture_rid)?;
let texture = texture_resource.0;
let descriptor = wgpu_core::resource::TextureViewDescriptor {
label: args.label.map(Cow::from),
format: args.format.map(|s| s.try_into()).transpose()?,
dimension: args.dimension.map(|s| s.into()),
range: wgpu_types::ImageSubresourceRange {
aspect: args.aspect.into(),
base_mip_level: args.base_mip_level,
mip_level_count: std::num::NonZeroU32::new(
args.mip_level_count.unwrap_or(0),
),
base_array_layer: args.base_array_layer,
array_layer_count: std::num::NonZeroU32::new(
args.array_layer_count.unwrap_or(0),
),
},
};
gfx_put!(texture => instance.texture_create_view(
texture,
&descriptor,
std::marker::PhantomData
) => state, WebGpuTextureView)
}

View file

@ -6,7 +6,7 @@ dictionary GPUObjectDescriptorBase {
USVString label;
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUSupportedLimits {
readonly attribute unsigned long maxTextureDimension1D;
readonly attribute unsigned long maxTextureDimension2D;
@ -36,7 +36,7 @@ interface GPUSupportedLimits {
readonly attribute unsigned long maxComputeWorkgroupsPerDimension;
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUSupportedFeatures {
readonly setlike<DOMString>;
};
@ -46,12 +46,12 @@ enum GPUPredefinedColorSpace {
};
interface mixin NavigatorGPU {
[SameObject] readonly attribute GPU gpu;
[SameObject, SecureContext] readonly attribute GPU gpu;
};
Navigator includes NavigatorGPU;
WorkerNavigator includes NavigatorGPU;
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPU {
Promise<GPUAdapter?> requestAdapter(optional GPURequestAdapterOptions options = {});
};
@ -63,10 +63,10 @@ dictionary GPURequestAdapterOptions {
enum GPUPowerPreference {
"low-power",
"high-performance"
"high-performance",
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUAdapter {
readonly attribute DOMString name;
[SameObject] readonly attribute GPUSupportedFeatures features;
@ -82,15 +82,18 @@ dictionary GPUDeviceDescriptor : GPUObjectDescriptorBase {
};
enum GPUFeatureName {
"depth-clamping",
"depth-clip-control",
"depth24unorm-stencil8",
"depth32float-stencil8",
"pipeline-statistics-query",
"texture-compression-bc",
"texture-compression-etc2",
"texture-compression-astc",
"timestamp-query",
"indirect-first-instance",
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUDevice : EventTarget {
[SameObject] readonly attribute GPUSupportedFeatures features;
[SameObject] readonly attribute GPUSupportedLimits limits;
@ -120,7 +123,7 @@ interface GPUDevice : EventTarget {
};
GPUDevice includes GPUObjectBase;
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUBuffer {
Promise<undefined> mapAsync(GPUMapModeFlags mode, optional GPUSize64 offset = 0, optional GPUSize64 size);
ArrayBuffer getMappedRange(optional GPUSize64 offset = 0, optional GPUSize64 size);
@ -158,7 +161,7 @@ interface GPUMapMode {
const GPUFlagsConstant WRITE = 0x0002;
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUTexture {
GPUTextureView createView(optional GPUTextureViewDescriptor descriptor = {});
@ -191,7 +194,7 @@ interface GPUTextureUsage {
const GPUFlagsConstant RENDER_ATTACHMENT = 0x10;
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUTextureView {
};
GPUTextureView includes GPUObjectBase;
@ -212,13 +215,13 @@ enum GPUTextureViewDimension {
"2d-array",
"cube",
"cube-array",
"3d"
"3d",
};
enum GPUTextureAspect {
"all",
"stencil-only",
"depth-only"
"depth-only",
};
enum GPUTextureFormat {
@ -293,6 +296,50 @@ enum GPUTextureFormat {
"bc7-rgba-unorm",
"bc7-rgba-unorm-srgb",
// ETC2 compressed formats usable if "texture-compression-etc2" is both
// supported by the device/user agent and enabled in requestDevice.
"etc2-rgb8unorm",
"etc2-rgb8unorm-srgb",
"etc2-rgb8a1unorm",
"etc2-rgb8a1unorm-srgb",
"etc2-rgba8unorm",
"etc2-rgba8unorm-srgb",
"eac-r11unorm",
"eac-r11snorm",
"eac-rg11unorm",
"eac-rg11snorm",
// ASTC compressed formats usable if "texture-compression-astc" is both
// supported by the device/user agent and enabled in requestDevice.
"astc-4x4-unorm",
"astc-4x4-unorm-srgb",
"astc-5x4-unorm",
"astc-5x4-unorm-srgb",
"astc-5x5-unorm",
"astc-5x5-unorm-srgb",
"astc-6x5-unorm",
"astc-6x5-unorm-srgb",
"astc-6x6-unorm",
"astc-6x6-unorm-srgb",
"astc-8x5-unorm",
"astc-8x5-unorm-srgb",
"astc-8x6-unorm",
"astc-8x6-unorm-srgb",
"astc-8x8-unorm",
"astc-8x8-unorm-srgb",
"astc-10x5-unorm",
"astc-10x5-unorm-srgb",
"astc-10x6-unorm",
"astc-10x6-unorm-srgb",
"astc-10x8-unorm",
"astc-10x8-unorm-srgb",
"astc-10x10-unorm",
"astc-10x10-unorm-srgb",
"astc-12x10-unorm",
"astc-12x10-unorm-srgb",
"astc-12x12-unorm",
"astc-12x12-unorm-srgb",
// "depth24unorm-stencil8" feature
"depth24unorm-stencil8",
@ -300,7 +347,7 @@ enum GPUTextureFormat {
"depth32float-stencil8",
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUSampler {
};
GPUSampler includes GPUObjectBase;
@ -321,12 +368,12 @@ dictionary GPUSamplerDescriptor : GPUObjectDescriptorBase {
enum GPUAddressMode {
"clamp-to-edge",
"repeat",
"mirror-repeat"
"mirror-repeat",
};
enum GPUFilterMode {
"nearest",
"linear"
"linear",
};
enum GPUCompareFunction {
@ -337,10 +384,10 @@ enum GPUCompareFunction {
"greater",
"not-equal",
"greater-equal",
"always"
"always",
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUBindGroupLayout {
};
GPUBindGroupLayout includes GPUObjectBase;
@ -390,11 +437,11 @@ dictionary GPUSamplerBindingLayout {
};
enum GPUTextureSampleType {
"float",
"unfilterable-float",
"depth",
"sint",
"uint",
"float",
"unfilterable-float",
"depth",
"sint",
"uint",
};
dictionary GPUTextureBindingLayout {
@ -413,7 +460,7 @@ dictionary GPUStorageTextureBindingLayout {
GPUTextureViewDimension viewDimension = "2d";
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUBindGroup {
};
GPUBindGroup includes GPUObjectBase;
@ -436,7 +483,7 @@ dictionary GPUBufferBinding {
GPUSize64 size;
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUPipelineLayout {
};
GPUPipelineLayout includes GPUObjectBase;
@ -445,7 +492,7 @@ dictionary GPUPipelineLayoutDescriptor : GPUObjectDescriptorBase {
required sequence<GPUBindGroupLayout> bindGroupLayouts;
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUShaderModule {
Promise<GPUCompilationInfo> compilationInfo();
};
@ -459,10 +506,10 @@ dictionary GPUShaderModuleDescriptor : GPUObjectDescriptorBase {
enum GPUCompilationMessageType {
"error",
"warning",
"info"
"info",
};
[Exposed=(Window, DedicatedWorker), Serializable]
[Exposed=(Window, DedicatedWorker), Serializable, SecureContext]
interface GPUCompilationMessage {
readonly attribute DOMString message;
readonly attribute GPUCompilationMessageType type;
@ -472,7 +519,7 @@ interface GPUCompilationMessage {
readonly attribute unsigned long long length;
};
[Exposed=(Window, DedicatedWorker), Serializable]
[Exposed=(Window, DedicatedWorker), Serializable, SecureContext]
interface GPUCompilationInfo {
readonly attribute FrozenArray<GPUCompilationMessage> messages;
};
@ -493,7 +540,7 @@ dictionary GPUProgrammableStage {
typedef double GPUPipelineConstantValue; // May represent WGSLs bool, f32, i32, u32.
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUComputePipeline {
};
GPUComputePipeline includes GPUObjectBase;
@ -503,7 +550,7 @@ dictionary GPUComputePipelineDescriptor : GPUPipelineDescriptorBase {
required GPUProgrammableStage compute;
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPURenderPipeline {
};
GPURenderPipeline includes GPUObjectBase;
@ -522,7 +569,7 @@ enum GPUPrimitiveTopology {
"line-list",
"line-strip",
"triangle-list",
"triangle-strip"
"triangle-strip",
};
dictionary GPUPrimitiveState {
@ -531,19 +578,19 @@ dictionary GPUPrimitiveState {
GPUFrontFace frontFace = "ccw";
GPUCullMode cullMode = "none";
// Enable depth clamping (requires "depth-clamping" feature)
boolean clampDepth = false;
// Requires "depth-clip-control" feature.
boolean unclippedDepth = false;
};
enum GPUFrontFace {
"ccw",
"cw"
"cw",
};
enum GPUCullMode {
"none",
"front",
"back"
"back",
};
dictionary GPUMultisampleState {
@ -552,7 +599,7 @@ dictionary GPUMultisampleState {
boolean alphaToCoverageEnabled = false;
};
dictionary GPUFragmentState: GPUProgrammableStage {
dictionary GPUFragmentState : GPUProgrammableStage {
required sequence<GPUColorTargetState> targets;
};
@ -579,9 +626,9 @@ interface GPUColorWrite {
};
dictionary GPUBlendComponent {
GPUBlendOperation operation = "add";
GPUBlendFactor srcFactor = "one";
GPUBlendFactor dstFactor = "zero";
GPUBlendOperation operation = "add";
};
enum GPUBlendFactor {
@ -597,7 +644,7 @@ enum GPUBlendFactor {
"one-minus-dst-alpha",
"src-alpha-saturated",
"constant",
"one-minus-constant"
"one-minus-constant",
};
enum GPUBlendOperation {
@ -605,7 +652,7 @@ enum GPUBlendOperation {
"subtract",
"reverse-subtract",
"min",
"max"
"max",
};
dictionary GPUDepthStencilState {
@ -640,12 +687,12 @@ enum GPUStencilOperation {
"increment-clamp",
"decrement-clamp",
"increment-wrap",
"decrement-wrap"
"decrement-wrap",
};
enum GPUIndexFormat {
"uint16",
"uint32"
"uint32",
};
enum GPUVertexFormat {
@ -683,10 +730,10 @@ enum GPUVertexFormat {
enum GPUVertexStepMode {
"vertex",
"instance"
"instance",
};
dictionary GPUVertexState: GPUProgrammableStage {
dictionary GPUVertexState : GPUProgrammableStage {
sequence<GPUVertexBufferLayout?> buffers = [];
};
@ -703,16 +750,15 @@ dictionary GPUVertexAttribute {
required GPUIndex32 shaderLocation;
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUCommandBuffer {
readonly attribute Promise<double> executionTime;
};
GPUCommandBuffer includes GPUObjectBase;
dictionary GPUCommandBufferDescriptor : GPUObjectDescriptorBase {
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUCommandEncoder {
GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor);
GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {});
@ -739,6 +785,11 @@ interface GPUCommandEncoder {
GPUImageCopyTexture destination,
GPUExtent3D copySize);
undefined clearBuffer(
GPUBuffer destination,
GPUSize64 destinationOffset,
GPUSize64 size);
undefined pushDebugGroup(USVString groupLabel);
undefined popDebugGroup();
undefined insertDebugMarker(USVString markerLabel);
@ -757,7 +808,6 @@ interface GPUCommandEncoder {
GPUCommandEncoder includes GPUObjectBase;
dictionary GPUCommandEncoderDescriptor : GPUObjectDescriptorBase {
boolean measureExecutionTime = false;
};
dictionary GPUImageDataLayout {
@ -791,7 +841,7 @@ interface mixin GPUProgrammablePassEncoder {
undefined insertDebugMarker(USVString markerLabel);
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUComputePassEncoder {
undefined setPipeline(GPUComputePipeline pipeline);
undefined dispatch(GPUSize32 x, optional GPUSize32 y = 1, optional GPUSize32 z = 1);
@ -827,7 +877,7 @@ interface mixin GPURenderEncoderBase {
undefined drawIndexedIndirect(GPUBuffer indirectBuffer, GPUSize64 indirectOffset);
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPURenderPassEncoder {
undefined setViewport(float x, float y,
float width, float height,
@ -881,12 +931,12 @@ dictionary GPURenderPassDepthStencilAttachment {
};
enum GPULoadOp {
"load"
"load",
};
enum GPUStoreOp {
"store",
"discard"
"discard",
};
dictionary GPURenderPassLayout: GPUObjectDescriptorBase {
@ -895,7 +945,7 @@ dictionary GPURenderPassLayout: GPUObjectDescriptorBase {
GPUSize32 sampleCount = 1;
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPURenderBundle {
};
GPURenderBundle includes GPUObjectBase;
@ -903,7 +953,7 @@ GPURenderBundle includes GPUObjectBase;
dictionary GPURenderBundleDescriptor : GPUObjectDescriptorBase {
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPURenderBundleEncoder {
GPURenderBundle finish(optional GPURenderBundleDescriptor descriptor = {});
};
@ -916,7 +966,7 @@ dictionary GPURenderBundleEncoderDescriptor : GPURenderPassLayout {
boolean stencilReadOnly = false;
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUQueue {
undefined submit(sequence<GPUCommandBuffer> commandBuffers);
@ -930,14 +980,14 @@ interface GPUQueue {
optional GPUSize64 size);
undefined writeTexture(
GPUImageCopyTexture destination,
[AllowShared] BufferSource data,
GPUImageDataLayout dataLayout,
GPUExtent3D size);
GPUImageCopyTexture destination,
[AllowShared] BufferSource data,
GPUImageDataLayout dataLayout,
GPUExtent3D size);
};
GPUQueue includes GPUObjectBase;
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUQuerySet {
undefined destroy();
};
@ -952,7 +1002,7 @@ dictionary GPUQuerySetDescriptor : GPUObjectDescriptorBase {
enum GPUQueryType {
"occlusion",
"pipeline-statistics",
"timestamp"
"timestamp",
};
enum GPUPipelineStatisticName {
@ -960,14 +1010,14 @@ enum GPUPipelineStatisticName {
"clipper-invocations",
"clipper-primitives-out",
"fragment-shader-invocations",
"compute-shader-invocations"
"compute-shader-invocations",
};
enum GPUDeviceLostReason {
"destroyed",
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUDeviceLostInfo {
readonly attribute (GPUDeviceLostReason or undefined) reason;
readonly attribute DOMString message;
@ -979,15 +1029,15 @@ partial interface GPUDevice {
enum GPUErrorFilter {
"out-of-memory",
"validation"
"validation",
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUOutOfMemoryError {
constructor();
};
[Exposed=(Window, DedicatedWorker)]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUValidationError {
constructor(DOMString message);
readonly attribute DOMString message;
@ -1000,9 +1050,7 @@ partial interface GPUDevice {
Promise<GPUError?> popErrorScope();
};
[
Exposed=(Window, DedicatedWorker)
]
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUUncapturedErrorEvent : Event {
constructor(
DOMString type,
@ -1060,3 +1108,4 @@ dictionary GPUExtent3DDict {
GPUIntegerCoordinate depthOrArrayLayers = 1;
};
typedef (sequence<GPUIntegerCoordinate> or GPUExtent3DDict) GPUExtent3D;

View file

@ -59,3 +59,16 @@ So you can simply run `./tools/flamebench.js op_baseline bench_op_async` or
Tip: the `[bench_filter]` argument doesn't have to be an exact bench name, you
can use a shorthand or a partial match to profile a group of benches, e.g:
`./tools/flamebench.js de v8`
## wgpu_sync.js
`wgpu_sync.js` streamlines updating `deno_webgpu` from
[gfx-rs/wgpu](https://github.com/gfx-rs/wgpu/).
It essentially vendors the `deno_webgpu` tree with a few minor patches applied
on top, somewhat similar to `git subtree`.
1. Update `COMMIT` in `./tools/wgpu_sync.js`
2. Run `./tools/wgpu_sync.js`
3. Double check changes, possibly patch
4. Commit & send a PR with the updates

90
tools/wgpu_sync.js Executable file
View file

@ -0,0 +1,90 @@
#!/usr/bin/env -S deno run --unstable --allow-read --allow-write --allow-run
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import { join, ROOT_PATH } from "./util.js";
// const COMMIT = "c00e471274b6c21acda89b4b13d41742c0285d71"; // Release 12
const COMMIT = "cdd480a89c9e3b681d9d174e65082d2bdbc903ef"; // tip
const REPO = "gfx-rs/wgpu";
// const V_WGPU = "0.12.0";
const TARGET_DIR = join(ROOT_PATH, "ext", "webgpu");
async function bash(subcmd, opts = {}) {
const p = Deno.run({ ...opts, cmd: ["bash", "-c", subcmd] });
// Exit process on failure
const { success, code } = await p.status();
if (!success) {
Deno.exit(code);
}
// Cleanup
p.close();
}
async function clearTargetDir() {
await bash(`rm -r ${TARGET_DIR}/*`);
}
async function checkoutUpstream() {
// Path of deno_webgpu inside the TAR
const tarPrefix = `gfx-rs-wgpu-${COMMIT.slice(0, 7)}/deno_webgpu/`;
const cmd =
`curl -L https://api.github.com/repos/${REPO}/tarball/${COMMIT} | tar -C '${TARGET_DIR}' -xzvf - --strip=2 '${tarPrefix}'`;
// console.log(cmd);
await bash(cmd);
}
async function denoCoreVersion() {
const coreCargo = join(ROOT_PATH, "core", "Cargo.toml");
const contents = await Deno.readTextFile(coreCargo);
return contents.match(/^version = "(\d+\.\d+\.\d+)"$/m)[1];
}
async function patchCargo() {
const vDenoCore = await denoCoreVersion();
const webgpuCargo = join(ROOT_PATH, "ext", "webgpu", "Cargo.toml");
const data = await Deno.readTextFile(webgpuCargo);
// Patch ext/webgpu/Cargo.toml's contents
const patched = data
.replace(`version = "0.17.0"`, `version = "0.33.0"`)
.replace(`edition = "2018"`, `edition = "2021"`)
.replace(
/^deno_core \= .*$/gm,
`deno_core = { version = "${vDenoCore}", path = "../../core" }`,
)
// .replace(/^wgpu-core \= .*$/gm, `wgpu-core = { version = "${V_WGPU}", features = ["trace", "replay", "serde"] }`)
// .replace(/^wgpu-types \= .*$/gm, `wgpu-types = { version = "${V_WGPU}", features = ["trace", "replay", "serde"] }`)
.replace(
/^wgpu-core \= .*$/gm,
`wgpu-core = { git = "https://github.com/${REPO}", rev = "${COMMIT}", features = ["trace", "replay", "serde"] }`,
)
.replace(
/^wgpu-types \= .*$/gm,
`wgpu-types = { git = "https://github.com/${REPO}", rev = "${COMMIT}", features = ["trace", "replay", "serde"] }`,
);
await Deno.writeTextFile(webgpuCargo, patched);
}
async function patchSrcLib() {
const srcLib = join(ROOT_PATH, "ext", "webgpu", "src", "lib.rs");
const data = await Deno.readTextFile(srcLib);
// Patch ext/webgpu/src/lib.rs's contents
const patched = data
.replace(`prefix "deno:deno_webgpu",`, `prefix "deno:ext/webgpu",`);
await Deno.writeTextFile(srcLib, patched);
}
async function main() {
await clearTargetDir();
await checkoutUpstream();
await patchCargo();
await patchSrcLib();
await bash(join(ROOT_PATH, "tools", "format.js"));
}
await main();