summaryrefslogtreecommitdiff
path: root/ext/webgpu/lib.rs
diff options
context:
space:
mode:
authorLeo Kettmeir <crowlkats@toaxl.com>2023-12-09 01:19:16 +0100
committerGitHub <noreply@github.com>2023-12-09 01:19:16 +0100
commit393abed3873d83019feb5bcebb10a6929133862a (patch)
treec346e6d628e6b037fb8f881a70ca2ae6f70692b6 /ext/webgpu/lib.rs
parent123d9ea047a2e10803e260ebf00f31fcc98463ee (diff)
feat: bring back WebGPU (#20812)
Signed-off-by: Leo Kettmeir <crowlkats@toaxl.com> Co-authored-by: Kenta Moriuchi <moriken@kimamass.com> Co-authored-by: Bartek IwaƄczuk <biwanczuk@gmail.com>
Diffstat (limited to 'ext/webgpu/lib.rs')
-rw-r--r--ext/webgpu/lib.rs768
1 files changed, 768 insertions, 0 deletions
diff --git a/ext/webgpu/lib.rs b/ext/webgpu/lib.rs
new file mode 100644
index 000000000..0d0ff633d
--- /dev/null
+++ b/ext/webgpu/lib.rs
@@ -0,0 +1,768 @@
+// 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::op2;
+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::rc::Rc;
+pub use wgpu_core;
+pub use wgpu_types;
+
+use error::DomExceptionOperationError;
+use error::WebGpuResult;
+
+pub const UNSTABLE_FEATURE_NAME: &str = "webgpu";
+
+#[macro_use]
+mod macros {
+ macro_rules! gfx_select {
+ ($id:expr => $global:ident.$method:ident( $($param:expr),* )) => {
+ match $id.backend() {
+ #[cfg(any(
+ all(not(target_arch = "wasm32"), not(target_os = "ios"), not(target_os = "macos")),
+ feature = "vulkan-portability"
+ ))]
+ wgpu_types::Backend::Vulkan => $global.$method::<wgpu_core::api::Vulkan>( $($param),* ),
+ #[cfg(all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos")))]
+ wgpu_types::Backend::Metal => $global.$method::<wgpu_core::api::Metal>( $($param),* ),
+ #[cfg(all(not(target_arch = "wasm32"), windows))]
+ wgpu_types::Backend::Dx12 => $global.$method::<wgpu_core::api::Dx12>( $($param),* ),
+ #[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;
+#[cfg(feature = "surface")]
+pub mod surface;
+pub mod texture;
+
+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));
+ }
+}
+
+deno_core::extension!(
+ deno_webgpu,
+ deps = [deno_webidl, deno_web],
+ ops = [
+ // Request device/adapter
+ op_webgpu_request_adapter,
+ op_webgpu_request_device,
+ op_webgpu_request_adapter_info,
+ // Query Set
+ op_webgpu_create_query_set,
+ // buffer
+ buffer::op_webgpu_create_buffer,
+ buffer::op_webgpu_buffer_get_mapped_range,
+ buffer::op_webgpu_buffer_unmap,
+ // buffer async
+ buffer::op_webgpu_buffer_get_map_async,
+ // remaining sync ops
+
+ // texture
+ texture::op_webgpu_create_texture,
+ texture::op_webgpu_create_texture_view,
+ // sampler
+ sampler::op_webgpu_create_sampler,
+ // binding
+ binding::op_webgpu_create_bind_group_layout,
+ binding::op_webgpu_create_pipeline_layout,
+ binding::op_webgpu_create_bind_group,
+ // pipeline
+ pipeline::op_webgpu_create_compute_pipeline,
+ pipeline::op_webgpu_compute_pipeline_get_bind_group_layout,
+ pipeline::op_webgpu_create_render_pipeline,
+ pipeline::op_webgpu_render_pipeline_get_bind_group_layout,
+ // command_encoder
+ command_encoder::op_webgpu_create_command_encoder,
+ command_encoder::op_webgpu_command_encoder_begin_render_pass,
+ command_encoder::op_webgpu_command_encoder_begin_compute_pass,
+ command_encoder::op_webgpu_command_encoder_copy_buffer_to_buffer,
+ command_encoder::op_webgpu_command_encoder_copy_buffer_to_texture,
+ command_encoder::op_webgpu_command_encoder_copy_texture_to_buffer,
+ command_encoder::op_webgpu_command_encoder_copy_texture_to_texture,
+ command_encoder::op_webgpu_command_encoder_clear_buffer,
+ command_encoder::op_webgpu_command_encoder_push_debug_group,
+ command_encoder::op_webgpu_command_encoder_pop_debug_group,
+ command_encoder::op_webgpu_command_encoder_insert_debug_marker,
+ command_encoder::op_webgpu_command_encoder_write_timestamp,
+ command_encoder::op_webgpu_command_encoder_resolve_query_set,
+ command_encoder::op_webgpu_command_encoder_finish,
+ render_pass::op_webgpu_render_pass_set_viewport,
+ render_pass::op_webgpu_render_pass_set_scissor_rect,
+ render_pass::op_webgpu_render_pass_set_blend_constant,
+ render_pass::op_webgpu_render_pass_set_stencil_reference,
+ render_pass::op_webgpu_render_pass_begin_occlusion_query,
+ render_pass::op_webgpu_render_pass_end_occlusion_query,
+ render_pass::op_webgpu_render_pass_execute_bundles,
+ render_pass::op_webgpu_render_pass_end,
+ render_pass::op_webgpu_render_pass_set_bind_group,
+ render_pass::op_webgpu_render_pass_push_debug_group,
+ render_pass::op_webgpu_render_pass_pop_debug_group,
+ render_pass::op_webgpu_render_pass_insert_debug_marker,
+ render_pass::op_webgpu_render_pass_set_pipeline,
+ render_pass::op_webgpu_render_pass_set_index_buffer,
+ render_pass::op_webgpu_render_pass_set_vertex_buffer,
+ render_pass::op_webgpu_render_pass_draw,
+ render_pass::op_webgpu_render_pass_draw_indexed,
+ render_pass::op_webgpu_render_pass_draw_indirect,
+ render_pass::op_webgpu_render_pass_draw_indexed_indirect,
+ compute_pass::op_webgpu_compute_pass_set_pipeline,
+ compute_pass::op_webgpu_compute_pass_dispatch_workgroups,
+ compute_pass::op_webgpu_compute_pass_dispatch_workgroups_indirect,
+ compute_pass::op_webgpu_compute_pass_end,
+ compute_pass::op_webgpu_compute_pass_set_bind_group,
+ compute_pass::op_webgpu_compute_pass_push_debug_group,
+ compute_pass::op_webgpu_compute_pass_pop_debug_group,
+ compute_pass::op_webgpu_compute_pass_insert_debug_marker,
+ // bundle
+ bundle::op_webgpu_create_render_bundle_encoder,
+ bundle::op_webgpu_render_bundle_encoder_finish,
+ bundle::op_webgpu_render_bundle_encoder_set_bind_group,
+ bundle::op_webgpu_render_bundle_encoder_push_debug_group,
+ bundle::op_webgpu_render_bundle_encoder_pop_debug_group,
+ bundle::op_webgpu_render_bundle_encoder_insert_debug_marker,
+ bundle::op_webgpu_render_bundle_encoder_set_pipeline,
+ bundle::op_webgpu_render_bundle_encoder_set_index_buffer,
+ bundle::op_webgpu_render_bundle_encoder_set_vertex_buffer,
+ bundle::op_webgpu_render_bundle_encoder_draw,
+ bundle::op_webgpu_render_bundle_encoder_draw_indexed,
+ bundle::op_webgpu_render_bundle_encoder_draw_indirect,
+ // queue
+ queue::op_webgpu_queue_submit,
+ queue::op_webgpu_write_buffer,
+ queue::op_webgpu_write_texture,
+ // shader
+ shader::op_webgpu_create_shader_module,
+ ],
+ lazy_loaded_esm = ["01_webgpu.js"],
+);
+
+fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> {
+ let mut return_features: Vec<&'static str> = vec![];
+
+ // api
+ if features.contains(wgpu_types::Features::DEPTH_CLIP_CONTROL) {
+ return_features.push("depth-clip-control");
+ }
+ 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");
+ }
+ 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");
+ }
+ if features.contains(wgpu_types::Features::BGRA8UNORM_STORAGE) {
+ return_features.push("bgra8unorm-storage");
+ }
+
+ // extended from spec
+
+ // texture formats
+ if features.contains(wgpu_types::Features::TEXTURE_FORMAT_16BIT_NORM) {
+ return_features.push("texture-format-16-bit-norm");
+ }
+ if features.contains(wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_HDR) {
+ return_features.push("texture-compression-astc-hdr");
+ }
+ 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,
+ ) {
+ 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");
+ }
+ if features.contains(wgpu_types::Features::POLYGON_MODE_LINE) {
+ return_features.push("polygon-mode-line");
+ }
+ if features.contains(wgpu_types::Features::POLYGON_MODE_POINT) {
+ return_features.push("polygon-mode-point");
+ }
+ 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");
+ }
+ 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");
+ }
+ 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");
+ }
+ if features.contains(wgpu_types::Features::SHADER_I16) {
+ return_features.push("shader-i16");
+ }
+ 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");
+ }
+ if features.contains(wgpu_types::Features::SHADER_UNUSED_VERTEX_OUTPUT) {
+ return_features.push("shader-unused-vertex-output");
+ }
+
+ 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,
+}
+
+#[op2(async)]
+#[serde]
+pub async fn op_webgpu_request_adapter(
+ state: Rc<RefCell<OpState>>,
+ #[serde] power_preference: Option<wgpu_types::PowerPreference>,
+ force_fallback_adapter: bool,
+) -> Result<GpuAdapterDeviceOrErr, AnyError> {
+ let mut state = state.borrow_mut();
+
+ // TODO(bartlomieju): replace with `state.feature_checker.check_or_exit`
+ // once we phase out `check_or_exit_with_legacy_fallback`
+ state.feature_checker.check_or_exit_with_legacy_fallback(
+ UNSTABLE_FEATURE_NAME,
+ "navigator.gpu.requestAdapter",
+ );
+
+ 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,
+ flags: wgpu_types::InstanceFlags::from_build_config(),
+ dx12_shader_compiler: wgpu_types::Dx12Compiler::Fxc,
+ gles_minor_version: wgpu_types::Gles3MinorVersion::default(),
+ },
+ )));
+ state.borrow::<Instance>()
+ };
+
+ let descriptor = wgpu_core::instance::RequestAdapterOptions {
+ 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();
+ // api
+ features.set(
+ wgpu_types::Features::DEPTH_CLIP_CONTROL,
+ required_features.0.contains("depth-clip-control"),
+ );
+ 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"),
+ );
+ // 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(
+ 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"),
+ );
+ features.set(
+ wgpu_types::Features::BGRA8UNORM_STORAGE,
+ required_features.0.contains("bgra8unorm-storage"),
+ );
+
+ // extended from spec
+
+ // texture formats
+ features.set(
+ wgpu_types::Features::TEXTURE_FORMAT_16BIT_NORM,
+ required_features.0.contains("texture-format-16-bit-norm"),
+ );
+ features.set(
+ wgpu_types::Features::TEXTURE_COMPRESSION_ASTC_HDR,
+ required_features.0.contains("texture-compression-astc-hdr"),
+ );
+ features.set(
+ 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
+ .contains("uniform-buffer-and-storage-texture-array-non-uniform-indexing"),
+ );
+ features.set(
+ wgpu_types::Features::PARTIALLY_BOUND_BINDING_ARRAY,
+ required_features
+ .0
+ .contains("partially-bound-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_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(
+ wgpu_types::Features::CLEAR_TEXTURE,
+ 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"),
+ );
+ features.set(
+ wgpu_types::Features::SHADER_EARLY_DEPTH_TEST,
+ required_features.0.contains("shader-early-depth-test"),
+ );
+ features.set(
+ wgpu_types::Features::SHADER_UNUSED_VERTEX_OUTPUT,
+ required_features.0.contains("shader-unused-vertex-output"),
+ );
+
+ features
+ }
+}
+
+#[op2(async)]
+#[serde]
+pub async fn op_webgpu_request_device(
+ state: Rc<RefCell<OpState>>,
+ #[smi] adapter_rid: ResourceId,
+ #[string] label: String,
+ #[serde] required_features: GpuRequiredFeatures,
+ #[serde] required_limits: Option<wgpu_types::Limits>,
+) -> Result<GpuAdapterDevice, AnyError> {
+ let mut 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 descriptor = wgpu_types::DeviceDescriptor {
+ label: Some(Cow::Owned(label)),
+ 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,
+}
+
+#[op2(async)]
+#[serde]
+pub async fn op_webgpu_request_adapter_info(
+ state: Rc<RefCell<OpState>>,
+ #[smi] 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: String,
+ #[serde(flatten)]
+ r#type: GpuQueryType,
+ count: u32,
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "kebab-case", tag = "type")]
+enum GpuQueryType {
+ Occlusion,
+ Timestamp,
+}
+
+impl From<GpuQueryType> for wgpu_types::QueryType {
+ fn from(query_type: GpuQueryType) -> Self {
+ match query_type {
+ GpuQueryType::Occlusion => wgpu_types::QueryType::Occlusion,
+ GpuQueryType::Timestamp => wgpu_types::QueryType::Timestamp,
+ }
+ }
+}
+
+#[op2]
+#[serde]
+pub fn op_webgpu_create_query_set(
+ state: &mut OpState,
+ #[serde] 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: Some(Cow::Owned(args.label)),
+ ty: args.r#type.into(),
+ count: args.count,
+ };
+
+ gfx_put!(device => instance.device_create_query_set(
+ device,
+ &descriptor,
+ ()
+ ) => state, WebGpuQuerySet)
+}