wgpu/deno_webgpu/lib.rs

804 lines
30 KiB
Rust
Raw Normal View History

// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
#![cfg(not(target_arch = "wasm32"))]
#![warn(unsafe_op_in_unsafe_fn)]
use deno_core::error::AnyError;
use deno_core::include_js_files;
use deno_core::op;
use deno_core::Extension;
use deno_core::ExtensionBuilder;
use deno_core::OpState;
use deno_core::Resource;
use deno_core::ResourceId;
use serde::Deserialize;
use serde::Serialize;
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashSet;
use std::convert::TryFrom;
use std::rc::Rc;
pub use wgpu_core;
pub use wgpu_types;
use error::DomExceptionOperationError;
use error::WebGpuResult;
#[macro_use]
mod macros {
macro_rules! gfx_select {
($id:expr => $global:ident.$method:ident( $($param:expr),* )) => {
match $id.backend() {
2023-01-09 15:44:20 +00:00
#[cfg(any(
all(not(target_arch = "wasm32"), not(target_os = "ios"), not(target_os = "macos")),
feature = "vulkan-portability"
))]
wgpu_types::Backend::Vulkan => $global.$method::<wgpu_core::api::Vulkan>( $($param),* ),
2023-01-09 15:44:20 +00:00
#[cfg(all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos")))]
wgpu_types::Backend::Metal => $global.$method::<wgpu_core::api::Metal>( $($param),* ),
2023-01-09 15:44:20 +00:00
#[cfg(all(not(target_arch = "wasm32"), windows))]
wgpu_types::Backend::Dx12 => $global.$method::<wgpu_core::api::Dx12>( $($param),* ),
2023-01-09 15:44:20 +00:00
#[cfg(all(not(target_arch = "wasm32"), windows))]
wgpu_types::Backend::Dx11 => $global.$method::<wgpu_core::api::Dx11>( $($param),* ),
#[cfg(any(
all(unix, not(target_os = "macos"), not(target_os = "ios")),
feature = "angle",
target_arch = "wasm32"
))]
wgpu_types::Backend::Gl => $global.$method::<wgpu_core::api::Gles>( $($param),+ ),
other => panic!("Unexpected backend {:?}", other),
}
};
}
macro_rules! gfx_put {
($id:expr => $global:ident.$method:ident( $($param:expr),* ) => $state:expr, $rc:expr) => {{
let (val, maybe_err) = gfx_select!($id => $global.$method($($param),*));
let rid = $state.resource_table.add($rc($global.clone(), val));
Ok(WebGpuResult::rid_err(rid, maybe_err))
}};
}
macro_rules! gfx_ok {
($id:expr => $global:ident.$method:ident( $($param:expr),* )) => {{
let maybe_err = gfx_select!($id => $global.$method($($param),*)).err();
Ok(WebGpuResult::maybe_err(maybe_err))
}};
}
}
pub mod binding;
pub mod buffer;
pub mod bundle;
pub mod command_encoder;
pub mod compute_pass;
pub mod error;
pub mod pipeline;
pub mod queue;
pub mod render_pass;
pub mod sampler;
pub mod shader;
2023-01-09 15:44:20 +00:00
#[cfg(feature = "surface")]
pub mod surface;
pub mod texture;
pub struct Unstable(pub bool);
fn check_unstable(state: &OpState, api_name: &str) {
let unstable = state.borrow::<Unstable>();
if !unstable.0 {
eprintln!(
"Unstable API '{}'. The --unstable flag must be provided.",
api_name
);
std::process::exit(70);
}
}
pub type Instance =
std::sync::Arc<wgpu_core::global::Global<wgpu_core::identity::IdentityManagerFactory>>;
struct WebGpuAdapter(Instance, wgpu_core::id::AdapterId);
impl Resource for WebGpuAdapter {
fn name(&self) -> Cow<str> {
"webGPUAdapter".into()
}
fn close(self: Rc<Self>) {
let instance = &self.0;
gfx_select!(self.1 => instance.adapter_drop(self.1));
}
}
struct WebGpuDevice(Instance, wgpu_core::id::DeviceId);
impl Resource for WebGpuDevice {
fn name(&self) -> Cow<str> {
"webGPUDevice".into()
}
fn close(self: Rc<Self>) {
let instance = &self.0;
gfx_select!(self.1 => instance.device_drop(self.1));
}
}
struct WebGpuQuerySet(Instance, wgpu_core::id::QuerySetId);
impl Resource for WebGpuQuerySet {
fn name(&self) -> Cow<str> {
"webGPUQuerySet".into()
}
fn close(self: Rc<Self>) {
let instance = &self.0;
gfx_select!(self.1 => instance.query_set_drop(self.1));
}
}
fn ext() -> ExtensionBuilder {
Extension::builder_with_deps(env!("CARGO_PKG_NAME"), &["deno_webidl", "deno_web"])
}
fn ops(ext: &mut ExtensionBuilder, unstable: bool) -> &mut ExtensionBuilder {
ext.ops(declare_webgpu_ops()).state(move |state| {
// TODO: check & possibly streamline this
// Unstable might be able to be OpMiddleware
// let unstable_checker = state.borrow::<super::UnstableChecker>();
// let unstable = unstable_checker.unstable;
state.put(Unstable(unstable));
})
}
pub fn init_ops_and_esm(unstable: bool) -> Extension {
ops(&mut ext(), unstable)
.esm(include_js_files!("01_webgpu.js", "02_idl_types.js",))
.build()
}
pub fn init_ops(unstable: bool) -> Extension {
ops(&mut ext(), unstable).build()
}
fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> {
let mut return_features: Vec<&'static str> = vec![];
2023-03-03 17:09:17 +00:00
// api
if features.contains(wgpu_types::Features::DEPTH_CLIP_CONTROL) {
return_features.push("depth-clip-control");
}
2023-03-03 17:09:17 +00:00
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");
}
// shader
if features.contains(wgpu_types::Features::SHADER_F16) {
return_features.push("shader-f16");
}
// texture formats
if features.contains(wgpu_types::Features::DEPTH32FLOAT_STENCIL8) {
return_features.push("depth32float-stencil8");
}
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");
}
2023-03-03 17:09:17 +00:00
if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC) {
return_features.push("texture-compression-astc");
}
if features.contains(wgpu_types::Features::RG11B10UFLOAT_RENDERABLE) {
return_features.push("rg11b10ufloat-renderable");
}
2023-03-03 17:09:17 +00:00
// extended from spec
// texture formats
if features.contains(wgpu_types::Features::TEXTURE_FORMAT_16BIT_NORM) {
return_features.push("texture-format-16-bit-norm");
}
2023-03-03 17:09:17 +00:00
if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_HDR) {
return_features.push("texture-compression-astc-hdr");
}
2023-03-03 17:09:17 +00:00
if features.contains(wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES) {
return_features.push("texture-adapter-specific-format-features");
}
// api
if features.contains(wgpu_types::Features::PIPELINE_STATISTICS_QUERY) {
return_features.push("pipeline-statistics-query");
}
if features.contains(wgpu_types::Features::TIMESTAMP_QUERY_INSIDE_PASSES) {
return_features.push("timestamp-query-inside-passes");
}
if features.contains(wgpu_types::Features::MAPPABLE_PRIMARY_BUFFERS) {
return_features.push("mappable-primary-buffers");
}
if features.contains(wgpu_types::Features::TEXTURE_BINDING_ARRAY) {
return_features.push("texture-binding-array");
}
if features.contains(wgpu_types::Features::BUFFER_BINDING_ARRAY) {
return_features.push("buffer-binding-array");
}
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,
) {
2023-03-03 17:09:17 +00:00
return_features.push("uniform-buffer-and-storage-texture-array-non-uniform-indexing");
}
if features.contains(wgpu_types::Features::PARTIALLY_BOUND_BINDING_ARRAY) {
return_features.push("partially-bound-binding-array");
}
if features.contains(wgpu_types::Features::MULTI_DRAW_INDIRECT) {
return_features.push("multi-draw-indirect");
}
if features.contains(wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT) {
return_features.push("multi-draw-indirect-count");
}
if features.contains(wgpu_types::Features::PUSH_CONSTANTS) {
return_features.push("push-constants");
}
if features.contains(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_ZERO) {
return_features.push("address-mode-clamp-to-zero");
}
if features.contains(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER) {
return_features.push("address-mode-clamp-to-border");
}
2023-03-03 17:09:17 +00:00
if features.contains(wgpu_types::Features::POLYGON_MODE_LINE) {
return_features.push("polygon-mode-line");
}
2023-03-03 17:09:17 +00:00
if features.contains(wgpu_types::Features::POLYGON_MODE_POINT) {
return_features.push("polygon-mode-point");
}
2023-03-03 17:09:17 +00:00
if features.contains(wgpu_types::Features::CONSERVATIVE_RASTERIZATION) {
return_features.push("conservative-rasterization");
}
if features.contains(wgpu_types::Features::VERTEX_WRITABLE_STORAGE) {
return_features.push("vertex-writable-storage");
}
Do texture init via clear passes when possible (#2307) * CLEAR_COMMANDS extension is now more of a window into wgpu zero-init this has mostly implications on the constraints, but also allows a more leaky documentation which makes sense for this non-standard function as there is no other place to look it up * clear_texture via renderpasses wip * 3D depth textures are no longer allowed, volumes are always cleared via CPY_DST * cleanup texture's clear_views * rename CLEAR_COMMANDS to CLEAR_TEXTURE * separate clear_texture into reusable & more descriptive parts * texture clear views are now created ahead of time * discarded surface fixup goes through new clear_texture method now * onq ueue texture initialization now goes threw clear_texture pending inits need to store Stored textures now though, causing more ref count bumping * texture init on queue_write_texture now also goes through new clear_texture * transfer functions on commandbuffer use now new texture init route * merge collect_zero_buffer_copies_for_clear_texture into clear_texture_via_buffer_copies * clear functions now take TextureInitRange * Fix clippy lints * command_encoder_clear_texture no longer takes write lock on texture * TextureClearMode encodes now is_color * code cleanup, mostly about `use` * Handle volume textures in clear_texture_via_render_passes properly * texture clear no longer requires id::Stored * init tracking fixes for volumes and init on partial subresource writes * texture creation enforces COPY_DST only if absolutely necessary * unrolled functional chain, reduce unsafe scope size * fix clippy lints * clear_texture test no longer creates 1D textures see #2323 * 3D textures are no longer cleared as render target since this isn't supported on Metal * fix deno building issue, fix formatting * TextureInner::Surface can now be zero initialized
2021-12-28 22:05:53 +00:00
if features.contains(wgpu_types::Features::CLEAR_TEXTURE) {
return_features.push("clear-texture");
}
2023-03-03 17:09:17 +00:00
if features.contains(wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH) {
return_features.push("spirv-shader-passthrough");
}
2023-03-03 17:09:17 +00:00
if features.contains(wgpu_types::Features::MULTIVIEW) {
return_features.push("multiview");
}
if features.contains(wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT) {
return_features.push("vertex-attribute-64-bit");
}
// shader
if features.contains(wgpu_types::Features::SHADER_F64) {
return_features.push("shader-f64");
2022-02-01 23:06:07 +00:00
}
2023-03-03 17:09:17 +00:00
if features.contains(wgpu_types::Features::SHADER_I16) {
return_features.push("shader-i16");
}
2023-03-03 17:09:17 +00:00
if features.contains(wgpu_types::Features::SHADER_PRIMITIVE_INDEX) {
return_features.push("shader-primitive-index");
}
if features.contains(wgpu_types::Features::SHADER_EARLY_DEPTH_TEST) {
return_features.push("shader-early-depth-test");
}
return_features
}
#[derive(Serialize)]
#[serde(untagged)]
pub enum GpuAdapterDeviceOrErr {
Error { err: String },
Features(GpuAdapterDevice),
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GpuAdapterDevice {
rid: ResourceId,
limits: wgpu_types::Limits,
features: Vec<&'static str>,
is_software: bool,
}
#[op]
pub async fn op_webgpu_request_adapter(
state: Rc<RefCell<OpState>>,
2022-03-24 17:20:10 +00:00
power_preference: Option<wgpu_types::PowerPreference>,
force_fallback_adapter: bool,
) -> Result<GpuAdapterDeviceOrErr, AnyError> {
let mut state = state.borrow_mut();
check_unstable(&state, "navigator.gpu.requestAdapter");
2022-03-24 17:20:10 +00:00
let backends = std::env::var("DENO_WEBGPU_BACKEND").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(std::sync::Arc::new(wgpu_core::global::Global::new(
"webgpu",
wgpu_core::identity::IdentityManagerFactory,
wgpu_types::InstanceDescriptor {
backends,
dx12_shader_compiler: wgpu_types::Dx12Compiler::Fxc,
},
)));
state.borrow::<Instance>()
};
let descriptor = wgpu_core::instance::RequestAdapterOptions {
2022-03-24 17:20:10 +00:00
power_preference: power_preference.unwrap_or_default(),
force_fallback_adapter,
compatible_surface: None, // windowless
};
let res = instance.request_adapter(
&descriptor,
wgpu_core::instance::AdapterInputs::Mask(backends, |_| ()),
);
let adapter = match res {
Ok(adapter) => adapter,
Err(err) => {
return Ok(GpuAdapterDeviceOrErr::Error {
err: err.to_string(),
})
}
};
let adapter_features = gfx_select!(adapter => instance.adapter_features(adapter))?;
let features = deserialize_features(&adapter_features);
let adapter_limits = gfx_select!(adapter => instance.adapter_limits(adapter))?;
let instance = instance.clone();
let rid = state.resource_table.add(WebGpuAdapter(instance, adapter));
Ok(GpuAdapterDeviceOrErr::Features(GpuAdapterDevice {
rid,
features,
limits: adapter_limits,
is_software: false,
}))
}
#[derive(Deserialize)]
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();
2023-03-03 17:09:17 +00:00
// api
features.set(
wgpu_types::Features::DEPTH_CLIP_CONTROL,
required_features.0.contains("depth-clip-control"),
);
features.set(
2023-03-03 17:09:17 +00:00
wgpu_types::Features::TIMESTAMP_QUERY,
required_features.0.contains("timestamp-query"),
);
features.set(
2023-03-03 17:09:17 +00:00
wgpu_types::Features::INDIRECT_FIRST_INSTANCE,
required_features.0.contains("indirect-first-instance"),
);
// shader
features.set(
wgpu_types::Features::SHADER_F16,
required_features.0.contains("shader-f16"),
);
// texture formats
features.set(
wgpu_types::Features::DEPTH32FLOAT_STENCIL8,
required_features.0.contains("depth32float-stencil8"),
);
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(
2023-03-03 17:09:17 +00:00
wgpu_types::Features::TEXTURE_COMPRESSION_ASTC,
required_features.0.contains("texture-compression-astc"),
);
features.set(
wgpu_types::Features::RG11B10UFLOAT_RENDERABLE,
required_features.0.contains("rg11b10ufloat-renderable"),
);
2023-03-03 17:09:17 +00:00
// extended from spec
// texture formats
features.set(
2023-03-03 17:09:17 +00:00
wgpu_types::Features::TEXTURE_FORMAT_16BIT_NORM,
required_features.0.contains("texture-format-16-bit-norm"),
);
features.set(
2023-03-03 17:09:17 +00:00
wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_HDR,
required_features.0.contains("texture-compression-astc-hdr"),
);
features.set(
2023-03-03 17:09:17 +00:00
wgpu_types::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES,
required_features
.0
.contains("texture-adapter-specific-format-features"),
);
// api
features.set(
wgpu_types::Features::PIPELINE_STATISTICS_QUERY,
required_features.0.contains("pipeline-statistics-query"),
);
features.set(
wgpu_types::Features::TIMESTAMP_QUERY_INSIDE_PASSES,
required_features
.0
.contains("timestamp-query-inside-passes"),
);
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
2023-03-03 17:09:17 +00:00
.contains("uniform-buffer-and-storage-texture-array-non-uniform-indexing"),
);
features.set(
2023-03-03 17:09:17 +00:00
wgpu_types::Features::PARTIALLY_BOUND_BINDING_ARRAY,
required_features
.0
2023-03-03 17:09:17 +00:00
.contains("partially-bound-binding-array"),
);
features.set(
2023-03-03 17:09:17 +00:00
wgpu_types::Features::MULTI_DRAW_INDIRECT,
required_features.0.contains("multi-draw-indirect"),
);
features.set(
2023-03-03 17:09:17 +00:00
wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT,
required_features.0.contains("multi-draw-indirect-count"),
);
features.set(
2023-03-03 17:09:17 +00:00
wgpu_types::Features::PUSH_CONSTANTS,
required_features.0.contains("push-constants"),
);
features.set(
wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_ZERO,
required_features.0.contains("address-mode-clamp-to-zero"),
);
features.set(
wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER,
required_features.0.contains("address-mode-clamp-to-border"),
);
features.set(
wgpu_types::Features::POLYGON_MODE_LINE,
required_features.0.contains("polygon-mode-line"),
);
features.set(
wgpu_types::Features::POLYGON_MODE_POINT,
required_features.0.contains("polygon-mode-point"),
);
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(
Do texture init via clear passes when possible (#2307) * CLEAR_COMMANDS extension is now more of a window into wgpu zero-init this has mostly implications on the constraints, but also allows a more leaky documentation which makes sense for this non-standard function as there is no other place to look it up * clear_texture via renderpasses wip * 3D depth textures are no longer allowed, volumes are always cleared via CPY_DST * cleanup texture's clear_views * rename CLEAR_COMMANDS to CLEAR_TEXTURE * separate clear_texture into reusable & more descriptive parts * texture clear views are now created ahead of time * discarded surface fixup goes through new clear_texture method now * onq ueue texture initialization now goes threw clear_texture pending inits need to store Stored textures now though, causing more ref count bumping * texture init on queue_write_texture now also goes through new clear_texture * transfer functions on commandbuffer use now new texture init route * merge collect_zero_buffer_copies_for_clear_texture into clear_texture_via_buffer_copies * clear functions now take TextureInitRange * Fix clippy lints * command_encoder_clear_texture no longer takes write lock on texture * TextureClearMode encodes now is_color * code cleanup, mostly about `use` * Handle volume textures in clear_texture_via_render_passes properly * texture clear no longer requires id::Stored * init tracking fixes for volumes and init on partial subresource writes * texture creation enforces COPY_DST only if absolutely necessary * unrolled functional chain, reduce unsafe scope size * fix clippy lints * clear_texture test no longer creates 1D textures see #2323 * 3D textures are no longer cleared as render target since this isn't supported on Metal * fix deno building issue, fix formatting * TextureInner::Surface can now be zero initialized
2021-12-28 22:05:53 +00:00
wgpu_types::Features::CLEAR_TEXTURE,
2023-03-03 17:09:17 +00:00
required_features.0.contains("clear-texture"),
);
features.set(
wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH,
required_features.0.contains("spirv-shader-passthrough"),
);
features.set(
wgpu_types::Features::MULTIVIEW,
required_features.0.contains("multiview"),
);
features.set(
wgpu_types::Features::VERTEX_ATTRIBUTE_64BIT,
required_features.0.contains("vertex-attribute-64-bit"),
);
// shader
features.set(
wgpu_types::Features::SHADER_F64,
required_features.0.contains("shader-f64"),
);
features.set(
wgpu_types::Features::SHADER_I16,
required_features.0.contains("shader-i16"),
);
features.set(
wgpu_types::Features::SHADER_PRIMITIVE_INDEX,
required_features.0.contains("shader-primitive-index"),
);
2022-02-01 23:06:07 +00:00
features.set(
2023-03-03 17:09:17 +00:00
wgpu_types::Features::SHADER_EARLY_DEPTH_TEST,
required_features.0.contains("shader-early-depth-test"),
2022-02-01 23:06:07 +00:00
);
features
}
}
#[op]
pub async fn op_webgpu_request_device(
state: Rc<RefCell<OpState>>,
2022-03-24 17:20:10 +00:00
adapter_rid: ResourceId,
label: Option<String>,
2023-01-16 17:23:52 +00:00
required_features: GpuRequiredFeatures,
2022-03-24 17:20:10 +00:00
required_limits: Option<wgpu_types::Limits>,
) -> Result<GpuAdapterDevice, AnyError> {
let mut state = state.borrow_mut();
2022-03-24 17:20:10 +00:00
let adapter_resource = state.resource_table.get::<WebGpuAdapter>(adapter_rid)?;
let adapter = adapter_resource.1;
let instance = state.borrow::<Instance>();
let descriptor = wgpu_types::DeviceDescriptor {
2022-03-24 17:20:10 +00:00
label: label.map(Cow::from),
2023-01-16 17:23:52 +00:00
features: required_features.into(),
limits: required_limits.unwrap_or_default(),
};
let (device, maybe_err) = gfx_select!(adapter => instance.adapter_request_device(
adapter,
&descriptor,
std::env::var("DENO_WEBGPU_TRACE").ok().as_ref().map(std::path::Path::new),
()
));
if let Some(err) = maybe_err {
return Err(DomExceptionOperationError::new(&err.to_string()).into());
}
let device_features = gfx_select!(device => instance.device_features(device))?;
let features = deserialize_features(&device_features);
let limits = gfx_select!(device => instance.device_limits(device))?;
let instance = instance.clone();
let rid = state.resource_table.add(WebGpuDevice(instance, device));
Ok(GpuAdapterDevice {
rid,
features,
limits,
// TODO(lucacasonato): report correctly from wgpu
is_software: false,
})
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GPUAdapterInfo {
vendor: String,
architecture: String,
device: String,
description: String,
}
#[op]
pub async fn op_webgpu_request_adapter_info(
state: Rc<RefCell<OpState>>,
adapter_rid: ResourceId,
) -> Result<GPUAdapterInfo, AnyError> {
let state = state.borrow_mut();
let adapter_resource = state.resource_table.get::<WebGpuAdapter>(adapter_rid)?;
let adapter = adapter_resource.1;
let instance = state.borrow::<Instance>();
let info = gfx_select!(adapter => instance.adapter_get_info(adapter))?;
Ok(GPUAdapterInfo {
vendor: info.vendor.to_string(),
architecture: String::new(), // TODO(#2170)
device: info.device.to_string(),
description: info.name,
})
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateQuerySetArgs {
device_rid: ResourceId,
label: Option<String>,
#[serde(flatten)]
r#type: GpuQueryType,
count: u32,
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case", tag = "type")]
enum GpuQueryType {
Occlusion,
#[serde(rename_all = "camelCase")]
PipelineStatistics {
pipeline_statistics: HashSet<String>,
},
Timestamp,
}
impl From<GpuQueryType> for wgpu_types::QueryType {
fn from(query_type: GpuQueryType) -> Self {
match query_type {
GpuQueryType::Occlusion => wgpu_types::QueryType::Occlusion,
GpuQueryType::PipelineStatistics {
pipeline_statistics,
} => {
use wgpu_types::PipelineStatisticsTypes;
let mut types = PipelineStatisticsTypes::empty();
if pipeline_statistics.contains("vertex-shader-invocations") {
types.set(PipelineStatisticsTypes::VERTEX_SHADER_INVOCATIONS, true);
}
if pipeline_statistics.contains("clipper-invocations") {
types.set(PipelineStatisticsTypes::CLIPPER_INVOCATIONS, true);
}
if pipeline_statistics.contains("clipper-primitives-out") {
types.set(PipelineStatisticsTypes::CLIPPER_PRIMITIVES_OUT, true);
}
if pipeline_statistics.contains("fragment-shader-invocations") {
types.set(PipelineStatisticsTypes::FRAGMENT_SHADER_INVOCATIONS, true);
}
if pipeline_statistics.contains("compute-shader-invocations") {
types.set(PipelineStatisticsTypes::COMPUTE_SHADER_INVOCATIONS, true);
}
wgpu_types::QueryType::PipelineStatistics(types)
}
GpuQueryType::Timestamp => wgpu_types::QueryType::Timestamp,
}
}
}
#[op]
pub fn op_webgpu_create_query_set(
state: &mut OpState,
args: CreateQuerySetArgs,
) -> Result<WebGpuResult, AnyError> {
let device_resource = state.resource_table.get::<WebGpuDevice>(args.device_rid)?;
let device = device_resource.1;
let instance = state.borrow::<Instance>();
let descriptor = wgpu_types::QuerySetDescriptor {
label: args.label.map(Cow::from),
ty: args.r#type.into(),
count: args.count,
};
gfx_put!(device => instance.device_create_query_set(
device,
&descriptor,
()
) => state, WebGpuQuerySet)
}
fn declare_webgpu_ops() -> Vec<deno_core::OpDecl> {
vec![
// Request device/adapter
op_webgpu_request_adapter::decl(),
op_webgpu_request_device::decl(),
op_webgpu_request_adapter_info::decl(),
// Query Set
op_webgpu_create_query_set::decl(),
// buffer
buffer::op_webgpu_create_buffer::decl(),
buffer::op_webgpu_buffer_get_mapped_range::decl(),
buffer::op_webgpu_buffer_unmap::decl(),
// buffer async
buffer::op_webgpu_buffer_get_map_async::decl(),
// remaining sync ops
// texture
texture::op_webgpu_create_texture::decl(),
texture::op_webgpu_create_texture_view::decl(),
// sampler
sampler::op_webgpu_create_sampler::decl(),
// binding
binding::op_webgpu_create_bind_group_layout::decl(),
binding::op_webgpu_create_pipeline_layout::decl(),
binding::op_webgpu_create_bind_group::decl(),
// pipeline
pipeline::op_webgpu_create_compute_pipeline::decl(),
pipeline::op_webgpu_compute_pipeline_get_bind_group_layout::decl(),
pipeline::op_webgpu_create_render_pipeline::decl(),
pipeline::op_webgpu_render_pipeline_get_bind_group_layout::decl(),
// command_encoder
command_encoder::op_webgpu_create_command_encoder::decl(),
command_encoder::op_webgpu_command_encoder_begin_render_pass::decl(),
command_encoder::op_webgpu_command_encoder_begin_compute_pass::decl(),
command_encoder::op_webgpu_command_encoder_copy_buffer_to_buffer::decl(),
command_encoder::op_webgpu_command_encoder_copy_buffer_to_texture::decl(),
command_encoder::op_webgpu_command_encoder_copy_texture_to_buffer::decl(),
command_encoder::op_webgpu_command_encoder_copy_texture_to_texture::decl(),
command_encoder::op_webgpu_command_encoder_clear_buffer::decl(),
command_encoder::op_webgpu_command_encoder_push_debug_group::decl(),
command_encoder::op_webgpu_command_encoder_pop_debug_group::decl(),
command_encoder::op_webgpu_command_encoder_insert_debug_marker::decl(),
command_encoder::op_webgpu_command_encoder_write_timestamp::decl(),
command_encoder::op_webgpu_command_encoder_resolve_query_set::decl(),
command_encoder::op_webgpu_command_encoder_finish::decl(),
// render_pass
render_pass::op_webgpu_render_pass_set_viewport::decl(),
render_pass::op_webgpu_render_pass_set_scissor_rect::decl(),
render_pass::op_webgpu_render_pass_set_blend_constant::decl(),
render_pass::op_webgpu_render_pass_set_stencil_reference::decl(),
render_pass::op_webgpu_render_pass_begin_pipeline_statistics_query::decl(),
render_pass::op_webgpu_render_pass_end_pipeline_statistics_query::decl(),
render_pass::op_webgpu_render_pass_write_timestamp::decl(),
render_pass::op_webgpu_render_pass_execute_bundles::decl(),
render_pass::op_webgpu_render_pass_end::decl(),
render_pass::op_webgpu_render_pass_set_bind_group::decl(),
render_pass::op_webgpu_render_pass_push_debug_group::decl(),
render_pass::op_webgpu_render_pass_pop_debug_group::decl(),
render_pass::op_webgpu_render_pass_insert_debug_marker::decl(),
render_pass::op_webgpu_render_pass_set_pipeline::decl(),
render_pass::op_webgpu_render_pass_set_index_buffer::decl(),
render_pass::op_webgpu_render_pass_set_vertex_buffer::decl(),
render_pass::op_webgpu_render_pass_draw::decl(),
render_pass::op_webgpu_render_pass_draw_indexed::decl(),
render_pass::op_webgpu_render_pass_draw_indirect::decl(),
render_pass::op_webgpu_render_pass_draw_indexed_indirect::decl(),
// compute_pass
compute_pass::op_webgpu_compute_pass_set_pipeline::decl(),
2022-04-21 04:28:56 +00:00
compute_pass::op_webgpu_compute_pass_dispatch_workgroups::decl(),
compute_pass::op_webgpu_compute_pass_dispatch_workgroups_indirect::decl(),
compute_pass::op_webgpu_compute_pass_begin_pipeline_statistics_query::decl(),
compute_pass::op_webgpu_compute_pass_end_pipeline_statistics_query::decl(),
compute_pass::op_webgpu_compute_pass_write_timestamp::decl(),
compute_pass::op_webgpu_compute_pass_end::decl(),
compute_pass::op_webgpu_compute_pass_set_bind_group::decl(),
compute_pass::op_webgpu_compute_pass_push_debug_group::decl(),
compute_pass::op_webgpu_compute_pass_pop_debug_group::decl(),
compute_pass::op_webgpu_compute_pass_insert_debug_marker::decl(),
// bundle
bundle::op_webgpu_create_render_bundle_encoder::decl(),
bundle::op_webgpu_render_bundle_encoder_finish::decl(),
bundle::op_webgpu_render_bundle_encoder_set_bind_group::decl(),
bundle::op_webgpu_render_bundle_encoder_push_debug_group::decl(),
bundle::op_webgpu_render_bundle_encoder_pop_debug_group::decl(),
bundle::op_webgpu_render_bundle_encoder_insert_debug_marker::decl(),
bundle::op_webgpu_render_bundle_encoder_set_pipeline::decl(),
bundle::op_webgpu_render_bundle_encoder_set_index_buffer::decl(),
bundle::op_webgpu_render_bundle_encoder_set_vertex_buffer::decl(),
bundle::op_webgpu_render_bundle_encoder_draw::decl(),
bundle::op_webgpu_render_bundle_encoder_draw_indexed::decl(),
bundle::op_webgpu_render_bundle_encoder_draw_indirect::decl(),
// queue
queue::op_webgpu_queue_submit::decl(),
queue::op_webgpu_write_buffer::decl(),
queue::op_webgpu_write_texture::decl(),
// shader
shader::op_webgpu_create_shader_module::decl(),
]
}