[deno] Format with Deno's rustfmt config

This commit is contained in:
Andy Leiserson 2025-09-17 11:46:34 -04:00 committed by Erich Gubler
parent 099a95ba64
commit e714cb0339
24 changed files with 5502 additions and 5275 deletions

View File

@ -20,194 +20,197 @@ use crate::Instance;
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPURequestAdapterOptions {
pub power_preference: Option<GPUPowerPreference>,
#[webidl(default = false)]
pub force_fallback_adapter: bool,
pub power_preference: Option<GPUPowerPreference>,
#[webidl(default = false)]
pub force_fallback_adapter: bool,
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUPowerPreference {
LowPower,
HighPerformance,
LowPower,
HighPerformance,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
struct GPUDeviceDescriptor {
#[webidl(default = String::new())]
label: String,
#[webidl(default = String::new())]
label: String,
#[webidl(default = vec![])]
required_features: Vec<GPUFeatureName>,
#[webidl(default = Default::default())]
#[options(enforce_range = true)]
required_limits: indexmap::IndexMap<String, Option<u64>>,
#[webidl(default = vec![])]
required_features: Vec<GPUFeatureName>,
#[webidl(default = Default::default())]
#[options(enforce_range = true)]
required_limits: indexmap::IndexMap<String, Option<u64>>,
}
pub struct GPUAdapter {
pub instance: Instance,
pub id: wgpu_core::id::AdapterId,
pub instance: Instance,
pub id: wgpu_core::id::AdapterId,
pub features: SameObject<GPUSupportedFeatures>,
pub limits: SameObject<GPUSupportedLimits>,
pub info: Rc<SameObject<GPUAdapterInfo>>,
pub features: SameObject<GPUSupportedFeatures>,
pub limits: SameObject<GPUSupportedLimits>,
pub info: Rc<SameObject<GPUAdapterInfo>>,
}
impl Drop for GPUAdapter {
fn drop(&mut self) {
self.instance.adapter_drop(self.id);
}
fn drop(&mut self) {
self.instance.adapter_drop(self.id);
}
}
impl GarbageCollected for GPUAdapter {}
#[op2]
impl GPUAdapter {
#[getter]
#[global]
fn info(&self, scope: &mut v8::HandleScope) -> v8::Global<v8::Object> {
self.info.get(scope, |_| {
let info = self.instance.adapter_get_info(self.id);
let limits = self.instance.adapter_limits(self.id);
#[getter]
#[global]
fn info(&self, scope: &mut v8::HandleScope) -> v8::Global<v8::Object> {
self.info.get(scope, |_| {
let info = self.instance.adapter_get_info(self.id);
let limits = self.instance.adapter_limits(self.id);
GPUAdapterInfo {
info,
subgroup_min_size: limits.min_subgroup_size,
subgroup_max_size: limits.max_subgroup_size,
}
})
GPUAdapterInfo {
info,
subgroup_min_size: limits.min_subgroup_size,
subgroup_max_size: limits.max_subgroup_size,
}
})
}
#[getter]
#[global]
fn features(&self, scope: &mut v8::HandleScope) -> v8::Global<v8::Object> {
self.features.get(scope, |scope| {
let features = self.instance.adapter_features(self.id);
// Only expose WebGPU features, not wgpu native-only features
let features = features & wgpu_types::Features::all_webgpu_mask();
let features = features_to_feature_names(features);
GPUSupportedFeatures::new(scope, features)
})
}
#[getter]
#[global]
fn limits(&self, scope: &mut v8::HandleScope) -> v8::Global<v8::Object> {
self.limits.get(scope, |_| {
let adapter_limits = self.instance.adapter_limits(self.id);
GPUSupportedLimits(adapter_limits)
})
}
#[getter]
fn is_fallback_adapter(&self) -> bool {
// TODO(lucacasonato): report correctly from wgpu
false
}
#[async_method(fake)]
#[global]
fn request_device(
&self,
state: &mut OpState,
scope: &mut v8::HandleScope,
#[webidl] descriptor: GPUDeviceDescriptor,
) -> Result<v8::Global<v8::Value>, CreateDeviceError> {
let features = self.instance.adapter_features(self.id);
let supported_features = features_to_feature_names(features);
#[allow(clippy::disallowed_types)]
let required_features = descriptor
.required_features
.iter()
.cloned()
.collect::<HashSet<_>>();
if !required_features.is_subset(&supported_features) {
return Err(CreateDeviceError::RequiredFeaturesNotASubset);
}
#[getter]
#[global]
fn features(&self, scope: &mut v8::HandleScope) -> v8::Global<v8::Object> {
self.features.get(scope, |scope| {
let features = self.instance.adapter_features(self.id);
// Only expose WebGPU features, not wgpu native-only features
let features = features & wgpu_types::Features::all_webgpu_mask();
let features = features_to_feature_names(features);
GPUSupportedFeatures::new(scope, features)
})
}
#[getter]
#[global]
fn limits(&self, scope: &mut v8::HandleScope) -> v8::Global<v8::Object> {
self.limits.get(scope, |_| {
let adapter_limits = self.instance.adapter_limits(self.id);
GPUSupportedLimits(adapter_limits)
})
}
#[getter]
fn is_fallback_adapter(&self) -> bool {
// TODO(lucacasonato): report correctly from wgpu
false
}
// When support for compatibility mode is added, this will need to look
// at whether the adapter is "compatibility-defaulting" or
// "core-defaulting", and choose the appropriate set of defaults.
//
// Support for compatibility mode is tracked in
// https://github.com/gfx-rs/wgpu/issues/8124.
let required_limits = serde_json::from_value::<wgpu_types::Limits>(
serde_json::to_value(descriptor.required_limits)?,
)?
.or_better_values_from(&wgpu_types::Limits::default());
#[async_method(fake)]
#[global]
fn request_device(
&self,
state: &mut OpState,
scope: &mut v8::HandleScope,
#[webidl] descriptor: GPUDeviceDescriptor,
) -> Result<v8::Global<v8::Value>, CreateDeviceError> {
let features = self.instance.adapter_features(self.id);
let supported_features = features_to_feature_names(features);
#[allow(clippy::disallowed_types)]
let required_features = descriptor
.required_features
.iter()
.cloned()
.collect::<HashSet<_>>();
let trace = std::env::var_os("DENO_WEBGPU_TRACE")
.map(|path| wgpu_types::Trace::Directory(std::path::PathBuf::from(path)))
.unwrap_or_default();
if !required_features.is_subset(&supported_features) {
return Err(CreateDeviceError::RequiredFeaturesNotASubset);
}
let wgpu_descriptor = wgpu_types::DeviceDescriptor {
label: crate::transform_label(descriptor.label.clone()),
required_features: super::webidl::feature_names_to_features(
descriptor.required_features,
),
required_limits,
experimental_features: wgpu_types::ExperimentalFeatures::disabled(),
memory_hints: Default::default(),
trace,
};
// When support for compatibility mode is added, this will need to look
// at whether the adapter is "compatibility-defaulting" or
// "core-defaulting", and choose the appropriate set of defaults.
//
// Support for compatibility mode is tracked in
// https://github.com/gfx-rs/wgpu/issues/8124.
let required_limits = serde_json::from_value::<wgpu_types::Limits>(serde_json::to_value(
descriptor.required_limits,
)?)?
.or_better_values_from(&wgpu_types::Limits::default());
let (device, queue) = self.instance.adapter_request_device(
self.id,
&wgpu_descriptor,
None,
None,
)?;
let trace = std::env::var_os("DENO_WEBGPU_TRACE")
.map(|path| wgpu_types::Trace::Directory(std::path::PathBuf::from(path)))
.unwrap_or_default();
let spawner = state.borrow::<V8TaskSpawner>().clone();
let lost_resolver = v8::PromiseResolver::new(scope).unwrap();
let lost_promise = lost_resolver.get_promise(scope);
let device = GPUDevice {
instance: self.instance.clone(),
id: device,
queue,
label: descriptor.label,
queue_obj: SameObject::new(),
adapter_info: self.info.clone(),
error_handler: Rc::new(super::error::DeviceErrorHandler::new(
v8::Global::new(scope, lost_resolver),
spawner,
)),
adapter: self.id,
lost_promise: v8::Global::new(scope, lost_promise),
limits: SameObject::new(),
features: SameObject::new(),
};
let device = deno_core::cppgc::make_cppgc_object(scope, device);
let weak_device = v8::Weak::new(scope, device);
let event_target_setup = state.borrow::<crate::EventTargetSetup>();
let webidl_brand = v8::Local::new(scope, event_target_setup.brand.clone());
device.set(scope, webidl_brand, webidl_brand);
let set_event_target_data =
v8::Local::new(scope, event_target_setup.set_event_target_data.clone())
.cast::<v8::Function>();
let null = v8::null(scope);
set_event_target_data.call(scope, null.into(), &[device.into()]);
let wgpu_descriptor = wgpu_types::DeviceDescriptor {
label: crate::transform_label(descriptor.label.clone()),
required_features: super::webidl::feature_names_to_features(
descriptor.required_features,
),
required_limits,
experimental_features: wgpu_types::ExperimentalFeatures::disabled(),
memory_hints: Default::default(),
trace,
};
// Now that the device is fully constructed, give the error handler a
// weak reference to it.
let device = device.cast::<v8::Value>();
deno_core::cppgc::try_unwrap_cppgc_object::<GPUDevice>(scope, device)
.unwrap()
.error_handler
.set_device(weak_device);
let (device, queue) =
self.instance
.adapter_request_device(self.id, &wgpu_descriptor, None, None)?;
let spawner = state.borrow::<V8TaskSpawner>().clone();
let lost_resolver = v8::PromiseResolver::new(scope).unwrap();
let lost_promise = lost_resolver.get_promise(scope);
let device = GPUDevice {
instance: self.instance.clone(),
id: device,
queue,
label: descriptor.label,
queue_obj: SameObject::new(),
adapter_info: self.info.clone(),
error_handler: Rc::new(super::error::DeviceErrorHandler::new(
v8::Global::new(scope, lost_resolver),
spawner,
)),
adapter: self.id,
lost_promise: v8::Global::new(scope, lost_promise),
limits: SameObject::new(),
features: SameObject::new(),
};
let device = deno_core::cppgc::make_cppgc_object(scope, device);
let weak_device = v8::Weak::new(scope, device);
let event_target_setup = state.borrow::<crate::EventTargetSetup>();
let webidl_brand = v8::Local::new(scope, event_target_setup.brand.clone());
device.set(scope, webidl_brand, webidl_brand);
let set_event_target_data =
v8::Local::new(scope, event_target_setup.set_event_target_data.clone())
.cast::<v8::Function>();
let null = v8::null(scope);
set_event_target_data.call(scope, null.into(), &[device.into()]);
// Now that the device is fully constructed, give the error handler a
// weak reference to it.
let device = device.cast::<v8::Value>();
deno_core::cppgc::try_unwrap_cppgc_object::<GPUDevice>(scope, device)
.unwrap()
.error_handler
.set_device(weak_device);
Ok(v8::Global::new(scope, device))
}
Ok(v8::Global::new(scope, device))
}
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum CreateDeviceError {
#[class(type)]
#[error("requiredFeatures must be a subset of the adapter features")]
RequiredFeaturesNotASubset,
#[class(inherit)]
#[error(transparent)]
Serde(#[from] serde_json::Error),
#[class("DOMExceptionOperationError")]
#[error(transparent)]
Device(#[from] wgpu_core::instance::RequestDeviceError),
#[class(type)]
#[error("requiredFeatures must be a subset of the adapter features")]
RequiredFeaturesNotASubset,
#[class(inherit)]
#[error(transparent)]
Serde(#[from] serde_json::Error),
#[class("DOMExceptionOperationError")]
#[error(transparent)]
Device(#[from] wgpu_core::instance::RequestDeviceError),
}
pub struct GPUSupportedLimits(pub wgpu_types::Limits);
@ -216,155 +219,155 @@ impl GarbageCollected for GPUSupportedLimits {}
#[op2]
impl GPUSupportedLimits {
#[getter]
fn maxTextureDimension1D(&self) -> u32 {
self.0.max_texture_dimension_1d
}
#[getter]
fn maxTextureDimension1D(&self) -> u32 {
self.0.max_texture_dimension_1d
}
#[getter]
fn maxTextureDimension2D(&self) -> u32 {
self.0.max_texture_dimension_2d
}
#[getter]
fn maxTextureDimension2D(&self) -> u32 {
self.0.max_texture_dimension_2d
}
#[getter]
fn maxTextureDimension3D(&self) -> u32 {
self.0.max_texture_dimension_3d
}
#[getter]
fn maxTextureDimension3D(&self) -> u32 {
self.0.max_texture_dimension_3d
}
#[getter]
fn maxTextureArrayLayers(&self) -> u32 {
self.0.max_texture_array_layers
}
#[getter]
fn maxTextureArrayLayers(&self) -> u32 {
self.0.max_texture_array_layers
}
#[getter]
fn maxBindGroups(&self) -> u32 {
self.0.max_bind_groups
}
#[getter]
fn maxBindGroups(&self) -> u32 {
self.0.max_bind_groups
}
// TODO(@crowlKats): support max_bind_groups_plus_vertex_buffers
// TODO(@crowlKats): support max_bind_groups_plus_vertex_buffers
#[getter]
fn maxBindingsPerBindGroup(&self) -> u32 {
self.0.max_bindings_per_bind_group
}
#[getter]
fn maxBindingsPerBindGroup(&self) -> u32 {
self.0.max_bindings_per_bind_group
}
#[getter]
fn maxDynamicUniformBuffersPerPipelineLayout(&self) -> u32 {
self.0.max_dynamic_uniform_buffers_per_pipeline_layout
}
#[getter]
fn maxDynamicUniformBuffersPerPipelineLayout(&self) -> u32 {
self.0.max_dynamic_uniform_buffers_per_pipeline_layout
}
#[getter]
fn maxDynamicStorageBuffersPerPipelineLayout(&self) -> u32 {
self.0.max_dynamic_storage_buffers_per_pipeline_layout
}
#[getter]
fn maxDynamicStorageBuffersPerPipelineLayout(&self) -> u32 {
self.0.max_dynamic_storage_buffers_per_pipeline_layout
}
#[getter]
fn maxSampledTexturesPerShaderStage(&self) -> u32 {
self.0.max_sampled_textures_per_shader_stage
}
#[getter]
fn maxSampledTexturesPerShaderStage(&self) -> u32 {
self.0.max_sampled_textures_per_shader_stage
}
#[getter]
fn maxSamplersPerShaderStage(&self) -> u32 {
self.0.max_samplers_per_shader_stage
}
#[getter]
fn maxSamplersPerShaderStage(&self) -> u32 {
self.0.max_samplers_per_shader_stage
}
#[getter]
fn maxStorageBuffersPerShaderStage(&self) -> u32 {
self.0.max_storage_buffers_per_shader_stage
}
#[getter]
fn maxStorageBuffersPerShaderStage(&self) -> u32 {
self.0.max_storage_buffers_per_shader_stage
}
#[getter]
fn maxStorageTexturesPerShaderStage(&self) -> u32 {
self.0.max_storage_textures_per_shader_stage
}
#[getter]
fn maxStorageTexturesPerShaderStage(&self) -> u32 {
self.0.max_storage_textures_per_shader_stage
}
#[getter]
fn maxUniformBuffersPerShaderStage(&self) -> u32 {
self.0.max_uniform_buffers_per_shader_stage
}
#[getter]
fn maxUniformBuffersPerShaderStage(&self) -> u32 {
self.0.max_uniform_buffers_per_shader_stage
}
#[getter]
fn maxUniformBufferBindingSize(&self) -> u32 {
self.0.max_uniform_buffer_binding_size
}
#[getter]
fn maxUniformBufferBindingSize(&self) -> u32 {
self.0.max_uniform_buffer_binding_size
}
#[getter]
fn maxStorageBufferBindingSize(&self) -> u32 {
self.0.max_storage_buffer_binding_size
}
#[getter]
fn maxStorageBufferBindingSize(&self) -> u32 {
self.0.max_storage_buffer_binding_size
}
#[getter]
fn minUniformBufferOffsetAlignment(&self) -> u32 {
self.0.min_uniform_buffer_offset_alignment
}
#[getter]
fn minUniformBufferOffsetAlignment(&self) -> u32 {
self.0.min_uniform_buffer_offset_alignment
}
#[getter]
fn minStorageBufferOffsetAlignment(&self) -> u32 {
self.0.min_storage_buffer_offset_alignment
}
#[getter]
fn minStorageBufferOffsetAlignment(&self) -> u32 {
self.0.min_storage_buffer_offset_alignment
}
#[getter]
fn maxVertexBuffers(&self) -> u32 {
self.0.max_vertex_buffers
}
#[getter]
fn maxVertexBuffers(&self) -> u32 {
self.0.max_vertex_buffers
}
#[getter]
#[number]
fn maxBufferSize(&self) -> u64 {
self.0.max_buffer_size
}
#[getter]
#[number]
fn maxBufferSize(&self) -> u64 {
self.0.max_buffer_size
}
#[getter]
fn maxVertexAttributes(&self) -> u32 {
self.0.max_vertex_attributes
}
#[getter]
fn maxVertexAttributes(&self) -> u32 {
self.0.max_vertex_attributes
}
#[getter]
fn maxVertexBufferArrayStride(&self) -> u32 {
self.0.max_vertex_buffer_array_stride
}
#[getter]
fn maxVertexBufferArrayStride(&self) -> u32 {
self.0.max_vertex_buffer_array_stride
}
// TODO(@crowlKats): support max_inter_stage_shader_variables
// TODO(@crowlKats): support max_inter_stage_shader_variables
#[getter]
fn maxColorAttachments(&self) -> u32 {
self.0.max_color_attachments
}
#[getter]
fn maxColorAttachments(&self) -> u32 {
self.0.max_color_attachments
}
#[getter]
fn maxColorAttachmentBytesPerSample(&self) -> u32 {
self.0.max_color_attachment_bytes_per_sample
}
#[getter]
fn maxColorAttachmentBytesPerSample(&self) -> u32 {
self.0.max_color_attachment_bytes_per_sample
}
#[getter]
fn maxComputeWorkgroupStorageSize(&self) -> u32 {
self.0.max_compute_workgroup_storage_size
}
#[getter]
fn maxComputeWorkgroupStorageSize(&self) -> u32 {
self.0.max_compute_workgroup_storage_size
}
#[getter]
fn maxComputeInvocationsPerWorkgroup(&self) -> u32 {
self.0.max_compute_invocations_per_workgroup
}
#[getter]
fn maxComputeInvocationsPerWorkgroup(&self) -> u32 {
self.0.max_compute_invocations_per_workgroup
}
#[getter]
fn maxComputeWorkgroupSizeX(&self) -> u32 {
self.0.max_compute_workgroup_size_x
}
#[getter]
fn maxComputeWorkgroupSizeX(&self) -> u32 {
self.0.max_compute_workgroup_size_x
}
#[getter]
fn maxComputeWorkgroupSizeY(&self) -> u32 {
self.0.max_compute_workgroup_size_y
}
#[getter]
fn maxComputeWorkgroupSizeY(&self) -> u32 {
self.0.max_compute_workgroup_size_y
}
#[getter]
fn maxComputeWorkgroupSizeZ(&self) -> u32 {
self.0.max_compute_workgroup_size_z
}
#[getter]
fn maxComputeWorkgroupSizeZ(&self) -> u32 {
self.0.max_compute_workgroup_size_z
}
#[getter]
fn maxComputeWorkgroupsPerDimension(&self) -> u32 {
self.0.max_compute_workgroups_per_dimension
}
#[getter]
fn maxComputeWorkgroupsPerDimension(&self) -> u32 {
self.0.max_compute_workgroups_per_dimension
}
}
pub struct GPUSupportedFeatures(v8::Global<v8::Value>);
@ -372,69 +375,72 @@ pub struct GPUSupportedFeatures(v8::Global<v8::Value>);
impl GarbageCollected for GPUSupportedFeatures {}
impl GPUSupportedFeatures {
#[allow(clippy::disallowed_types)]
pub fn new(scope: &mut v8::HandleScope, features: HashSet<GPUFeatureName>) -> Self {
let set = v8::Set::new(scope);
#[allow(clippy::disallowed_types)]
pub fn new(
scope: &mut v8::HandleScope,
features: HashSet<GPUFeatureName>,
) -> Self {
let set = v8::Set::new(scope);
for feature in features {
let key = v8::String::new(scope, feature.as_str()).unwrap();
set.add(scope, key.into());
}
Self(v8::Global::new(scope, <v8::Local<v8::Value>>::from(set)))
for feature in features {
let key = v8::String::new(scope, feature.as_str()).unwrap();
set.add(scope, key.into());
}
Self(v8::Global::new(scope, <v8::Local<v8::Value>>::from(set)))
}
}
#[op2]
impl GPUSupportedFeatures {
#[global]
#[symbol("setlike_set")]
fn set(&self) -> v8::Global<v8::Value> {
self.0.clone()
}
#[global]
#[symbol("setlike_set")]
fn set(&self) -> v8::Global<v8::Value> {
self.0.clone()
}
}
pub struct GPUAdapterInfo {
pub info: wgpu_types::AdapterInfo,
pub subgroup_min_size: u32,
pub subgroup_max_size: u32,
pub info: wgpu_types::AdapterInfo,
pub subgroup_min_size: u32,
pub subgroup_max_size: u32,
}
impl GarbageCollected for GPUAdapterInfo {}
#[op2]
impl GPUAdapterInfo {
#[getter]
#[string]
fn vendor(&self) -> String {
self.info.vendor.to_string()
}
#[getter]
#[string]
fn vendor(&self) -> String {
self.info.vendor.to_string()
}
#[getter]
#[string]
fn architecture(&self) -> &'static str {
"" // TODO: wgpu#2170
}
#[getter]
#[string]
fn architecture(&self) -> &'static str {
"" // TODO: wgpu#2170
}
#[getter]
#[string]
fn device(&self) -> String {
self.info.device.to_string()
}
#[getter]
#[string]
fn device(&self) -> String {
self.info.device.to_string()
}
#[getter]
#[string]
fn description(&self) -> String {
self.info.name.clone()
}
#[getter]
#[string]
fn description(&self) -> String {
self.info.name.clone()
}
#[getter]
fn subgroup_min_size(&self) -> u32 {
self.subgroup_min_size
}
#[getter]
fn subgroup_min_size(&self) -> u32 {
self.subgroup_min_size
}
#[getter]
fn subgroup_max_size(&self) -> u32 {
self.subgroup_max_size
}
#[getter]
fn subgroup_max_size(&self) -> u32 {
self.subgroup_max_size
}
}

View File

@ -20,97 +20,103 @@ use crate::texture::GPUTextureView;
use crate::Instance;
pub struct GPUBindGroup {
pub instance: Instance,
pub id: wgpu_core::id::BindGroupId,
pub label: String,
pub instance: Instance,
pub id: wgpu_core::id::BindGroupId,
pub label: String,
}
impl Drop for GPUBindGroup {
fn drop(&mut self) {
self.instance.bind_group_drop(self.id);
}
fn drop(&mut self) {
self.instance.bind_group_drop(self.id);
}
}
impl WebIdlInterfaceConverter for GPUBindGroup {
const NAME: &'static str = "GPUBindGroup";
const NAME: &'static str = "GPUBindGroup";
}
impl GarbageCollected for GPUBindGroup {}
#[op2]
impl GPUBindGroup {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUBindGroupDescriptor {
#[webidl(default = String::new())]
pub label: String,
#[webidl(default = String::new())]
pub label: String,
pub layout: Ptr<super::bind_group_layout::GPUBindGroupLayout>,
pub entries: Vec<GPUBindGroupEntry>,
pub layout: Ptr<super::bind_group_layout::GPUBindGroupLayout>,
pub entries: Vec<GPUBindGroupEntry>,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUBindGroupEntry {
#[options(enforce_range = true)]
pub binding: u32,
pub resource: GPUBindingResource,
#[options(enforce_range = true)]
pub binding: u32,
pub resource: GPUBindingResource,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUBufferBinding {
pub buffer: Ptr<GPUBuffer>,
#[webidl(default = 0)]
#[options(enforce_range = true)]
pub offset: u64,
#[options(enforce_range = true)]
pub size: Option<u64>,
pub buffer: Ptr<GPUBuffer>,
#[webidl(default = 0)]
#[options(enforce_range = true)]
pub offset: u64,
#[options(enforce_range = true)]
pub size: Option<u64>,
}
pub(crate) enum GPUBindingResource {
Sampler(Ptr<GPUSampler>),
TextureView(Ptr<GPUTextureView>),
BufferBinding(GPUBufferBinding),
Sampler(Ptr<GPUSampler>),
TextureView(Ptr<GPUTextureView>),
BufferBinding(GPUBufferBinding),
}
impl<'a> WebIdlConverter<'a> for GPUBindingResource {
type Options = ();
type Options = ();
fn convert<'b>(
scope: &mut HandleScope<'a>,
value: Local<'a, Value>,
prefix: Cow<'static, str>,
context: ContextFn<'b>,
options: &Self::Options,
) -> Result<Self, WebIdlError> {
<Ptr<GPUSampler>>::convert(scope, value, prefix.clone(), context.borrowed(), options)
.map(Self::Sampler)
.or_else(|_| {
<Ptr<GPUTextureView>>::convert(
scope,
value,
prefix.clone(),
context.borrowed(),
options,
)
.map(Self::TextureView)
})
.or_else(|_| {
GPUBufferBinding::convert(scope, value, prefix, context, options)
.map(Self::BufferBinding)
})
}
fn convert<'b>(
scope: &mut HandleScope<'a>,
value: Local<'a, Value>,
prefix: Cow<'static, str>,
context: ContextFn<'b>,
options: &Self::Options,
) -> Result<Self, WebIdlError> {
<Ptr<GPUSampler>>::convert(
scope,
value,
prefix.clone(),
context.borrowed(),
options,
)
.map(Self::Sampler)
.or_else(|_| {
<Ptr<GPUTextureView>>::convert(
scope,
value,
prefix.clone(),
context.borrowed(),
options,
)
.map(Self::TextureView)
})
.or_else(|_| {
GPUBufferBinding::convert(scope, value, prefix, context, options)
.map(Self::BufferBinding)
})
}
}

View File

@ -8,169 +8,173 @@ use crate::texture::GPUTextureViewDimension;
use crate::Instance;
pub struct GPUBindGroupLayout {
pub instance: Instance,
pub id: wgpu_core::id::BindGroupLayoutId,
pub label: String,
pub instance: Instance,
pub id: wgpu_core::id::BindGroupLayoutId,
pub label: String,
}
impl Drop for GPUBindGroupLayout {
fn drop(&mut self) {
self.instance.bind_group_layout_drop(self.id);
}
fn drop(&mut self) {
self.instance.bind_group_layout_drop(self.id);
}
}
impl deno_core::webidl::WebIdlInterfaceConverter for GPUBindGroupLayout {
const NAME: &'static str = "GPUBindGroupLayout";
const NAME: &'static str = "GPUBindGroupLayout";
}
impl GarbageCollected for GPUBindGroupLayout {}
#[op2]
impl GPUBindGroupLayout {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUBindGroupLayoutDescriptor {
#[webidl(default = String::new())]
pub label: String,
pub entries: Vec<GPUBindGroupLayoutEntry>,
#[webidl(default = String::new())]
pub label: String,
pub entries: Vec<GPUBindGroupLayoutEntry>,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUBindGroupLayoutEntry {
#[options(enforce_range = true)]
pub binding: u32,
#[options(enforce_range = true)]
pub visibility: u32,
pub buffer: Option<GPUBufferBindingLayout>,
pub sampler: Option<GPUSamplerBindingLayout>,
pub texture: Option<GPUTextureBindingLayout>,
pub storage_texture: Option<GPUStorageTextureBindingLayout>,
#[options(enforce_range = true)]
pub binding: u32,
#[options(enforce_range = true)]
pub visibility: u32,
pub buffer: Option<GPUBufferBindingLayout>,
pub sampler: Option<GPUSamplerBindingLayout>,
pub texture: Option<GPUTextureBindingLayout>,
pub storage_texture: Option<GPUStorageTextureBindingLayout>,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUBufferBindingLayout {
#[webidl(default = GPUBufferBindingType::Uniform)]
pub r#type: GPUBufferBindingType,
#[webidl(default = false)]
pub has_dynamic_offset: bool,
#[webidl(default = 0)]
pub min_binding_size: u64,
#[webidl(default = GPUBufferBindingType::Uniform)]
pub r#type: GPUBufferBindingType,
#[webidl(default = false)]
pub has_dynamic_offset: bool,
#[webidl(default = 0)]
pub min_binding_size: u64,
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUBufferBindingType {
Uniform,
Storage,
ReadOnlyStorage,
Uniform,
Storage,
ReadOnlyStorage,
}
impl From<GPUBufferBindingType> for wgpu_types::BufferBindingType {
fn from(value: GPUBufferBindingType) -> Self {
match value {
GPUBufferBindingType::Uniform => Self::Uniform,
GPUBufferBindingType::Storage => Self::Storage { read_only: false },
GPUBufferBindingType::ReadOnlyStorage => Self::Storage { read_only: true },
}
fn from(value: GPUBufferBindingType) -> Self {
match value {
GPUBufferBindingType::Uniform => Self::Uniform,
GPUBufferBindingType::Storage => Self::Storage { read_only: false },
GPUBufferBindingType::ReadOnlyStorage => {
Self::Storage { read_only: true }
}
}
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUSamplerBindingLayout {
#[webidl(default = GPUSamplerBindingType::Filtering)]
pub r#type: GPUSamplerBindingType,
#[webidl(default = GPUSamplerBindingType::Filtering)]
pub r#type: GPUSamplerBindingType,
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUSamplerBindingType {
Filtering,
NonFiltering,
Comparison,
Filtering,
NonFiltering,
Comparison,
}
impl From<GPUSamplerBindingType> for wgpu_types::SamplerBindingType {
fn from(value: GPUSamplerBindingType) -> Self {
match value {
GPUSamplerBindingType::Filtering => Self::Filtering,
GPUSamplerBindingType::NonFiltering => Self::NonFiltering,
GPUSamplerBindingType::Comparison => Self::Comparison,
}
fn from(value: GPUSamplerBindingType) -> Self {
match value {
GPUSamplerBindingType::Filtering => Self::Filtering,
GPUSamplerBindingType::NonFiltering => Self::NonFiltering,
GPUSamplerBindingType::Comparison => Self::Comparison,
}
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUTextureBindingLayout {
#[webidl(default = GPUTextureSampleType::Float)]
pub sample_type: GPUTextureSampleType,
#[webidl(default = GPUTextureViewDimension::D2)]
pub view_dimension: GPUTextureViewDimension,
#[webidl(default = false)]
pub multisampled: bool,
#[webidl(default = GPUTextureSampleType::Float)]
pub sample_type: GPUTextureSampleType,
#[webidl(default = GPUTextureViewDimension::D2)]
pub view_dimension: GPUTextureViewDimension,
#[webidl(default = false)]
pub multisampled: bool,
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUTextureSampleType {
Float,
UnfilterableFloat,
Depth,
Sint,
Uint,
Float,
UnfilterableFloat,
Depth,
Sint,
Uint,
}
impl From<GPUTextureSampleType> for wgpu_types::TextureSampleType {
fn from(value: GPUTextureSampleType) -> Self {
match value {
GPUTextureSampleType::Float => Self::Float { filterable: true },
GPUTextureSampleType::UnfilterableFloat => Self::Float { filterable: false },
GPUTextureSampleType::Depth => Self::Depth,
GPUTextureSampleType::Sint => Self::Sint,
GPUTextureSampleType::Uint => Self::Uint,
}
fn from(value: GPUTextureSampleType) -> Self {
match value {
GPUTextureSampleType::Float => Self::Float { filterable: true },
GPUTextureSampleType::UnfilterableFloat => {
Self::Float { filterable: false }
}
GPUTextureSampleType::Depth => Self::Depth,
GPUTextureSampleType::Sint => Self::Sint,
GPUTextureSampleType::Uint => Self::Uint,
}
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUStorageTextureBindingLayout {
#[webidl(default = GPUStorageTextureAccess::WriteOnly)]
pub access: GPUStorageTextureAccess,
pub format: super::texture::GPUTextureFormat,
#[webidl(default = GPUTextureViewDimension::D2)]
pub view_dimension: GPUTextureViewDimension,
#[webidl(default = GPUStorageTextureAccess::WriteOnly)]
pub access: GPUStorageTextureAccess,
pub format: super::texture::GPUTextureFormat,
#[webidl(default = GPUTextureViewDimension::D2)]
pub view_dimension: GPUTextureViewDimension,
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUStorageTextureAccess {
WriteOnly,
ReadOnly,
ReadWrite,
WriteOnly,
ReadOnly,
ReadWrite,
}
impl From<GPUStorageTextureAccess> for wgpu_types::StorageTextureAccess {
fn from(value: GPUStorageTextureAccess) -> Self {
match value {
GPUStorageTextureAccess::WriteOnly => Self::WriteOnly,
GPUStorageTextureAccess::ReadOnly => Self::ReadOnly,
GPUStorageTextureAccess::ReadWrite => Self::ReadWrite,
}
fn from(value: GPUStorageTextureAccess) -> Self {
match value {
GPUStorageTextureAccess::WriteOnly => Self::WriteOnly,
GPUStorageTextureAccess::ReadOnly => Self::ReadOnly,
GPUStorageTextureAccess::ReadWrite => Self::ReadWrite,
}
}
}

View File

@ -18,240 +18,245 @@ use crate::Instance;
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUBufferDescriptor {
#[webidl(default = String::new())]
pub label: String,
#[webidl(default = String::new())]
pub label: String,
pub size: u64,
#[options(enforce_range = true)]
pub usage: u32,
#[webidl(default = false)]
pub mapped_at_creation: bool,
pub size: u64,
#[options(enforce_range = true)]
pub usage: u32,
#[webidl(default = false)]
pub mapped_at_creation: bool,
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum BufferError {
#[class(generic)]
#[error(transparent)]
Canceled(#[from] oneshot::Canceled),
#[class("DOMExceptionOperationError")]
#[error(transparent)]
Access(#[from] wgpu_core::resource::BufferAccessError),
#[class("DOMExceptionOperationError")]
#[error("{0}")]
Operation(&'static str),
#[class(inherit)]
#[error(transparent)]
Other(#[from] JsErrorBox),
#[class(generic)]
#[error(transparent)]
Canceled(#[from] oneshot::Canceled),
#[class("DOMExceptionOperationError")]
#[error(transparent)]
Access(#[from] wgpu_core::resource::BufferAccessError),
#[class("DOMExceptionOperationError")]
#[error("{0}")]
Operation(&'static str),
#[class(inherit)]
#[error(transparent)]
Other(#[from] JsErrorBox),
}
pub struct GPUBuffer {
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub id: wgpu_core::id::BufferId,
pub device: wgpu_core::id::DeviceId,
pub id: wgpu_core::id::BufferId,
pub device: wgpu_core::id::DeviceId,
pub label: String,
pub label: String,
pub size: u64,
pub usage: u32,
pub size: u64,
pub usage: u32,
pub map_state: RefCell<&'static str>,
pub map_mode: RefCell<Option<MapMode>>,
pub map_state: RefCell<&'static str>,
pub map_mode: RefCell<Option<MapMode>>,
pub mapped_js_buffers: RefCell<Vec<v8::Global<v8::ArrayBuffer>>>,
pub mapped_js_buffers: RefCell<Vec<v8::Global<v8::ArrayBuffer>>>,
}
impl Drop for GPUBuffer {
fn drop(&mut self) {
self.instance.buffer_drop(self.id);
}
fn drop(&mut self) {
self.instance.buffer_drop(self.id);
}
}
impl WebIdlInterfaceConverter for GPUBuffer {
const NAME: &'static str = "GPUBuffer";
const NAME: &'static str = "GPUBuffer";
}
impl GarbageCollected for GPUBuffer {}
#[op2]
impl GPUBuffer {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[getter]
#[number]
fn size(&self) -> u64 {
self.size
}
#[getter]
fn usage(&self) -> u32 {
self.usage
}
#[getter]
#[string]
fn map_state(&self) -> &'static str {
*self.map_state.borrow()
}
#[async_method]
async fn map_async(
&self,
#[webidl(options(enforce_range = true))] mode: u32,
#[webidl(default = 0)] offset: u64,
#[webidl] size: Option<u64>,
) -> Result<(), BufferError> {
let read_mode = (mode & 0x0001) == 0x0001;
let write_mode = (mode & 0x0002) == 0x0002;
if (read_mode && write_mode) || (!read_mode && !write_mode) {
return Err(BufferError::Operation(
"exactly one of READ or WRITE map mode must be set",
));
}
#[getter]
#[number]
fn size(&self) -> u64 {
self.size
}
#[getter]
fn usage(&self) -> u32 {
self.usage
let mode = if read_mode {
MapMode::Read
} else {
assert!(write_mode);
MapMode::Write
};
{
*self.map_state.borrow_mut() = "pending";
}
#[getter]
#[string]
fn map_state(&self) -> &'static str {
*self.map_state.borrow()
let (sender, receiver) =
oneshot::channel::<wgpu_core::resource::BufferAccessResult>();
{
let callback = Box::new(move |status| {
sender.send(status).unwrap();
});
let err = self
.instance
.buffer_map_async(
self.id,
offset,
size,
wgpu_core::resource::BufferMapOperation {
host: mode,
callback: Some(callback),
},
)
.err();
if err.is_some() {
self.error_handler.push_error(err);
return Err(BufferError::Operation("validation error occurred"));
}
}
#[async_method]
async fn map_async(
&self,
#[webidl(options(enforce_range = true))] mode: u32,
#[webidl(default = 0)] offset: u64,
#[webidl] size: Option<u64>,
) -> Result<(), BufferError> {
let read_mode = (mode & 0x0001) == 0x0001;
let write_mode = (mode & 0x0002) == 0x0002;
if (read_mode && write_mode) || (!read_mode && !write_mode) {
return Err(BufferError::Operation(
"exactly one of READ or WRITE map mode must be set",
));
}
let mode = if read_mode {
MapMode::Read
} else {
assert!(write_mode);
MapMode::Write
};
let done = Rc::new(RefCell::new(false));
let done_ = done.clone();
let device_poll_fut = async move {
while !*done.borrow() {
{
*self.map_state.borrow_mut() = "pending";
}
let (sender, receiver) = oneshot::channel::<wgpu_core::resource::BufferAccessResult>();
{
let callback = Box::new(move |status| {
sender.send(status).unwrap();
});
let err = self
.instance
.buffer_map_async(
self.id,
offset,
size,
wgpu_core::resource::BufferMapOperation {
host: mode,
callback: Some(callback),
},
)
.err();
if err.is_some() {
self.error_handler.push_error(err);
return Err(BufferError::Operation("validation error occurred"));
}
}
let done = Rc::new(RefCell::new(false));
let done_ = done.clone();
let device_poll_fut = async move {
while !*done.borrow() {
{
self.instance
.device_poll(self.device, wgpu_types::PollType::wait())
.unwrap();
}
tokio::time::sleep(Duration::from_millis(10)).await;
}
Ok::<(), BufferError>(())
};
let receiver_fut = async move {
receiver.await??;
let mut done = done_.borrow_mut();
*done = true;
Ok::<(), BufferError>(())
};
tokio::try_join!(device_poll_fut, receiver_fut)?;
*self.map_state.borrow_mut() = "mapped";
*self.map_mode.borrow_mut() = Some(mode);
Ok(())
}
fn get_mapped_range<'s>(
&self,
scope: &mut v8::HandleScope<'s>,
#[webidl(default = 0)] offset: u64,
#[webidl] size: Option<u64>,
) -> Result<v8::Local<'s, v8::ArrayBuffer>, BufferError> {
let (slice_pointer, range_size) = self
self
.instance
.buffer_get_mapped_range(self.id, offset, size)
.map_err(BufferError::Access)?;
let mode = self.map_mode.borrow();
let mode = mode.as_ref().unwrap();
let bs = if mode == &MapMode::Write {
unsafe extern "C" fn noop_deleter_callback(
_data: *mut std::ffi::c_void,
_byte_length: usize,
_deleter_data: *mut std::ffi::c_void,
) {
}
// SAFETY: creating a backing store from the pointer and length provided by wgpu
unsafe {
v8::ArrayBuffer::new_backing_store_from_ptr(
slice_pointer.as_ptr() as _,
range_size as usize,
noop_deleter_callback,
std::ptr::null_mut(),
)
}
} else {
// SAFETY: creating a vector from the pointer and length provided by wgpu
let slice =
unsafe { std::slice::from_raw_parts(slice_pointer.as_ptr(), range_size as usize) };
v8::ArrayBuffer::new_backing_store_from_vec(slice.to_vec())
};
let shared_bs = bs.make_shared();
let ab = v8::ArrayBuffer::with_backing_store(scope, &shared_bs);
if mode == &MapMode::Write {
self.mapped_js_buffers
.borrow_mut()
.push(v8::Global::new(scope, ab));
.device_poll(self.device, wgpu_types::PollType::wait())
.unwrap();
}
tokio::time::sleep(Duration::from_millis(10)).await;
}
Ok::<(), BufferError>(())
};
Ok(ab)
let receiver_fut = async move {
receiver.await??;
let mut done = done_.borrow_mut();
*done = true;
Ok::<(), BufferError>(())
};
tokio::try_join!(device_poll_fut, receiver_fut)?;
*self.map_state.borrow_mut() = "mapped";
*self.map_mode.borrow_mut() = Some(mode);
Ok(())
}
fn get_mapped_range<'s>(
&self,
scope: &mut v8::HandleScope<'s>,
#[webidl(default = 0)] offset: u64,
#[webidl] size: Option<u64>,
) -> Result<v8::Local<'s, v8::ArrayBuffer>, BufferError> {
let (slice_pointer, range_size) = self
.instance
.buffer_get_mapped_range(self.id, offset, size)
.map_err(BufferError::Access)?;
let mode = self.map_mode.borrow();
let mode = mode.as_ref().unwrap();
let bs = if mode == &MapMode::Write {
unsafe extern "C" fn noop_deleter_callback(
_data: *mut std::ffi::c_void,
_byte_length: usize,
_deleter_data: *mut std::ffi::c_void,
) {
}
// SAFETY: creating a backing store from the pointer and length provided by wgpu
unsafe {
v8::ArrayBuffer::new_backing_store_from_ptr(
slice_pointer.as_ptr() as _,
range_size as usize,
noop_deleter_callback,
std::ptr::null_mut(),
)
}
} else {
// SAFETY: creating a vector from the pointer and length provided by wgpu
let slice = unsafe {
std::slice::from_raw_parts(slice_pointer.as_ptr(), range_size as usize)
};
v8::ArrayBuffer::new_backing_store_from_vec(slice.to_vec())
};
let shared_bs = bs.make_shared();
let ab = v8::ArrayBuffer::with_backing_store(scope, &shared_bs);
if mode == &MapMode::Write {
self
.mapped_js_buffers
.borrow_mut()
.push(v8::Global::new(scope, ab));
}
#[nofast]
fn unmap(&self, scope: &mut v8::HandleScope) -> Result<(), BufferError> {
for ab in self.mapped_js_buffers.replace(vec![]) {
let ab = ab.open(scope);
ab.detach(None);
}
Ok(ab)
}
self.instance
.buffer_unmap(self.id)
.map_err(BufferError::Access)?;
*self.map_state.borrow_mut() = "unmapped";
Ok(())
#[nofast]
fn unmap(&self, scope: &mut v8::HandleScope) -> Result<(), BufferError> {
for ab in self.mapped_js_buffers.replace(vec![]) {
let ab = ab.open(scope);
ab.detach(None);
}
#[fast]
fn destroy(&self) {
self.instance.buffer_destroy(self.id);
}
self
.instance
.buffer_unmap(self.id)
.map_err(BufferError::Access)?;
*self.map_state.borrow_mut() = "unmapped";
Ok(())
}
#[fast]
fn destroy(&self) {
self.instance.buffer_destroy(self.id);
}
}

View File

@ -3,10 +3,10 @@
use std::cell::RefCell;
use std::ffi::c_void;
#[cfg(any(
target_os = "linux",
target_os = "macos",
target_os = "freebsd",
target_os = "openbsd"
target_os = "linux",
target_os = "macos",
target_os = "freebsd",
target_os = "openbsd"
))]
use std::ptr::NonNull;
@ -24,305 +24,326 @@ use crate::surface::GPUCanvasContext;
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum ByowError {
#[class(type)]
#[error("Cannot create surface outside of WebGPU context. Did you forget to call `navigator.gpu.requestAdapter()`?")]
WebGPUNotInitiated,
#[class(type)]
#[error("Invalid parameters")]
InvalidParameters,
#[class(generic)]
#[error(transparent)]
CreateSurface(wgpu_core::instance::CreateSurfaceError),
#[cfg(target_os = "windows")]
#[class(type)]
#[error("Invalid system on Windows")]
InvalidSystem,
#[cfg(target_os = "macos")]
#[class(type)]
#[error("Invalid system on macOS")]
InvalidSystem,
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))]
#[class(type)]
#[error("Invalid system on Linux/BSD")]
InvalidSystem,
#[cfg(any(
target_os = "windows",
target_os = "linux",
target_os = "freebsd",
target_os = "openbsd"
))]
#[class(type)]
#[error("window is null")]
NullWindow,
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))]
#[class(type)]
#[error("display is null")]
NullDisplay,
#[cfg(target_os = "macos")]
#[class(type)]
#[error("ns_view is null")]
NSViewDisplay,
#[class(type)]
#[error(
"Cannot create surface outside of WebGPU context. Did you forget to call `navigator.gpu.requestAdapter()`?"
)]
WebGPUNotInitiated,
#[class(type)]
#[error("Invalid parameters")]
InvalidParameters,
#[class(generic)]
#[error(transparent)]
CreateSurface(wgpu_core::instance::CreateSurfaceError),
#[cfg(target_os = "windows")]
#[class(type)]
#[error("Invalid system on Windows")]
InvalidSystem,
#[cfg(target_os = "macos")]
#[class(type)]
#[error("Invalid system on macOS")]
InvalidSystem,
#[cfg(any(
target_os = "linux",
target_os = "freebsd",
target_os = "openbsd"
))]
#[class(type)]
#[error("Invalid system on Linux/BSD")]
InvalidSystem,
#[cfg(any(
target_os = "windows",
target_os = "linux",
target_os = "freebsd",
target_os = "openbsd"
))]
#[class(type)]
#[error("window is null")]
NullWindow,
#[cfg(any(
target_os = "linux",
target_os = "freebsd",
target_os = "openbsd"
))]
#[class(type)]
#[error("display is null")]
NullDisplay,
#[cfg(target_os = "macos")]
#[class(type)]
#[error("ns_view is null")]
NSViewDisplay,
}
// TODO(@littledivy): This will extend `OffscreenCanvas` when we add it.
pub struct UnsafeWindowSurface {
pub id: wgpu_core::id::SurfaceId,
pub width: RefCell<u32>,
pub height: RefCell<u32>,
pub id: wgpu_core::id::SurfaceId,
pub width: RefCell<u32>,
pub height: RefCell<u32>,
pub context: SameObject<GPUCanvasContext>,
pub context: SameObject<GPUCanvasContext>,
}
impl GarbageCollected for UnsafeWindowSurface {}
#[op2]
impl UnsafeWindowSurface {
#[constructor]
#[cppgc]
fn new(
state: &mut OpState,
#[from_v8] options: UnsafeWindowSurfaceOptions,
) -> Result<UnsafeWindowSurface, ByowError> {
let instance = state
.try_borrow::<super::Instance>()
.ok_or(ByowError::WebGPUNotInitiated)?;
#[constructor]
#[cppgc]
fn new(
state: &mut OpState,
#[from_v8] options: UnsafeWindowSurfaceOptions,
) -> Result<UnsafeWindowSurface, ByowError> {
let instance = state
.try_borrow::<super::Instance>()
.ok_or(ByowError::WebGPUNotInitiated)?;
// Security note:
//
// The `window_handle` and `display_handle` options are pointers to
// platform-specific window handles.
//
// The code below works under the assumption that:
//
// - handles can only be created by the FFI interface which
// enforces --allow-ffi.
//
// - `*const c_void` deserizalizes null and v8::External.
//
// - Only FFI can export v8::External to user code.
if options.window_handle.is_null() {
return Err(ByowError::InvalidParameters);
}
let (win_handle, display_handle) = raw_window(
options.system,
options.window_handle,
options.display_handle,
)?;
// SAFETY: see above comment
let id = unsafe {
instance
.instance_create_surface(display_handle, win_handle, None)
.map_err(ByowError::CreateSurface)?
};
Ok(UnsafeWindowSurface {
id,
width: RefCell::new(options.width),
height: RefCell::new(options.height),
context: SameObject::new(),
})
// Security note:
//
// The `window_handle` and `display_handle` options are pointers to
// platform-specific window handles.
//
// The code below works under the assumption that:
//
// - handles can only be created by the FFI interface which
// enforces --allow-ffi.
//
// - `*const c_void` deserizalizes null and v8::External.
//
// - Only FFI can export v8::External to user code.
if options.window_handle.is_null() {
return Err(ByowError::InvalidParameters);
}
#[global]
fn get_context(
&self,
#[this] this: v8::Global<v8::Object>,
scope: &mut v8::HandleScope,
) -> v8::Global<v8::Object> {
self.context.get(scope, |_| GPUCanvasContext {
surface_id: self.id,
width: self.width.clone(),
height: self.height.clone(),
config: RefCell::new(None),
texture: RefCell::new(None),
canvas: this,
})
}
let (win_handle, display_handle) = raw_window(
options.system,
options.window_handle,
options.display_handle,
)?;
#[nofast]
fn present(&self, scope: &mut v8::HandleScope) -> Result<(), JsErrorBox> {
let Some(context) = self.context.try_unwrap(scope) else {
return Err(JsErrorBox::type_error("getContext was never called"));
};
// SAFETY: see above comment
let id = unsafe {
instance
.instance_create_surface(display_handle, win_handle, None)
.map_err(ByowError::CreateSurface)?
};
context.present().map_err(JsErrorBox::from_err)
}
Ok(UnsafeWindowSurface {
id,
width: RefCell::new(options.width),
height: RefCell::new(options.height),
context: SameObject::new(),
})
}
#[global]
fn get_context(
&self,
#[this] this: v8::Global<v8::Object>,
scope: &mut v8::HandleScope,
) -> v8::Global<v8::Object> {
self.context.get(scope, |_| GPUCanvasContext {
surface_id: self.id,
width: self.width.clone(),
height: self.height.clone(),
config: RefCell::new(None),
texture: RefCell::new(None),
canvas: this,
})
}
#[nofast]
fn present(&self, scope: &mut v8::HandleScope) -> Result<(), JsErrorBox> {
let Some(context) = self.context.try_unwrap(scope) else {
return Err(JsErrorBox::type_error("getContext was never called"));
};
context.present().map_err(JsErrorBox::from_err)
}
}
struct UnsafeWindowSurfaceOptions {
system: UnsafeWindowSurfaceSystem,
window_handle: *const c_void,
display_handle: *const c_void,
width: u32,
height: u32,
system: UnsafeWindowSurfaceSystem,
window_handle: *const c_void,
display_handle: *const c_void,
width: u32,
height: u32,
}
#[derive(Eq, PartialEq)]
enum UnsafeWindowSurfaceSystem {
Cocoa,
Win32,
X11,
Wayland,
Cocoa,
Win32,
X11,
Wayland,
}
impl<'a> FromV8<'a> for UnsafeWindowSurfaceOptions {
type Error = JsErrorBox;
type Error = JsErrorBox;
fn from_v8(
scope: &mut v8::HandleScope<'a>,
value: Local<'a, Value>,
) -> Result<Self, Self::Error> {
let obj = value
.try_cast::<v8::Object>()
.map_err(|_| JsErrorBox::type_error("is not an object"))?;
fn from_v8(
scope: &mut v8::HandleScope<'a>,
value: Local<'a, Value>,
) -> Result<Self, Self::Error> {
let obj = value
.try_cast::<v8::Object>()
.map_err(|_| JsErrorBox::type_error("is not an object"))?;
let key = v8::String::new(scope, "system").unwrap();
let val = obj
.get(scope, key.into())
.ok_or_else(|| JsErrorBox::type_error("missing field 'system'"))?;
let s = String::from_v8(scope, val).unwrap();
let system = match s.as_str() {
"cocoa" => UnsafeWindowSurfaceSystem::Cocoa,
"win32" => UnsafeWindowSurfaceSystem::Win32,
"x11" => UnsafeWindowSurfaceSystem::X11,
"wayland" => UnsafeWindowSurfaceSystem::Wayland,
_ => return Err(JsErrorBox::type_error(format!("Invalid system kind '{s}'"))),
};
let key = v8::String::new(scope, "system").unwrap();
let val = obj
.get(scope, key.into())
.ok_or_else(|| JsErrorBox::type_error("missing field 'system'"))?;
let s = String::from_v8(scope, val).unwrap();
let system = match s.as_str() {
"cocoa" => UnsafeWindowSurfaceSystem::Cocoa,
"win32" => UnsafeWindowSurfaceSystem::Win32,
"x11" => UnsafeWindowSurfaceSystem::X11,
"wayland" => UnsafeWindowSurfaceSystem::Wayland,
_ => {
return Err(JsErrorBox::type_error(format!(
"Invalid system kind '{s}'"
)));
}
};
let key = v8::String::new(scope, "windowHandle").unwrap();
let val = obj
.get(scope, key.into())
.ok_or_else(|| JsErrorBox::type_error("missing field 'windowHandle'"))?;
let Some(window_handle) = deno_core::_ops::to_external_option(&val) else {
return Err(JsErrorBox::type_error("expected external"));
};
let key = v8::String::new(scope, "windowHandle").unwrap();
let val = obj
.get(scope, key.into())
.ok_or_else(|| JsErrorBox::type_error("missing field 'windowHandle'"))?;
let Some(window_handle) = deno_core::_ops::to_external_option(&val) else {
return Err(JsErrorBox::type_error("expected external"));
};
let key = v8::String::new(scope, "displayHandle").unwrap();
let val = obj
.get(scope, key.into())
.ok_or_else(|| JsErrorBox::type_error("missing field 'displayHandle'"))?;
let Some(display_handle) = deno_core::_ops::to_external_option(&val) else {
return Err(JsErrorBox::type_error("expected external"));
};
let key = v8::String::new(scope, "displayHandle").unwrap();
let val = obj
.get(scope, key.into())
.ok_or_else(|| JsErrorBox::type_error("missing field 'displayHandle'"))?;
let Some(display_handle) = deno_core::_ops::to_external_option(&val) else {
return Err(JsErrorBox::type_error("expected external"));
};
let key = v8::String::new(scope, "width").unwrap();
let val = obj
.get(scope, key.into())
.ok_or_else(|| JsErrorBox::type_error("missing field 'width'"))?;
let width = deno_core::convert::Number::<u32>::from_v8(scope, val)?.0;
let key = v8::String::new(scope, "width").unwrap();
let val = obj
.get(scope, key.into())
.ok_or_else(|| JsErrorBox::type_error("missing field 'width'"))?;
let width = deno_core::convert::Number::<u32>::from_v8(scope, val)?.0;
let key = v8::String::new(scope, "height").unwrap();
let val = obj
.get(scope, key.into())
.ok_or_else(|| JsErrorBox::type_error("missing field 'height'"))?;
let height = deno_core::convert::Number::<u32>::from_v8(scope, val)?.0;
let key = v8::String::new(scope, "height").unwrap();
let val = obj
.get(scope, key.into())
.ok_or_else(|| JsErrorBox::type_error("missing field 'height'"))?;
let height = deno_core::convert::Number::<u32>::from_v8(scope, val)?.0;
Ok(Self {
system,
window_handle,
display_handle,
width,
height,
})
}
Ok(Self {
system,
window_handle,
display_handle,
width,
height,
})
}
}
type RawHandles = (
raw_window_handle::RawWindowHandle,
raw_window_handle::RawDisplayHandle,
raw_window_handle::RawWindowHandle,
raw_window_handle::RawDisplayHandle,
);
#[cfg(target_os = "macos")]
fn raw_window(
system: UnsafeWindowSurfaceSystem,
_ns_window: *const c_void,
ns_view: *const c_void,
system: UnsafeWindowSurfaceSystem,
_ns_window: *const c_void,
ns_view: *const c_void,
) -> Result<RawHandles, ByowError> {
if system != UnsafeWindowSurfaceSystem::Cocoa {
return Err(ByowError::InvalidSystem);
}
if system != UnsafeWindowSurfaceSystem::Cocoa {
return Err(ByowError::InvalidSystem);
}
let win_handle =
raw_window_handle::RawWindowHandle::AppKit(raw_window_handle::AppKitWindowHandle::new(
NonNull::new(ns_view as *mut c_void).ok_or(ByowError::NSViewDisplay)?,
));
let win_handle = raw_window_handle::RawWindowHandle::AppKit(
raw_window_handle::AppKitWindowHandle::new(
NonNull::new(ns_view as *mut c_void).ok_or(ByowError::NSViewDisplay)?,
),
);
let display_handle =
raw_window_handle::RawDisplayHandle::AppKit(raw_window_handle::AppKitDisplayHandle::new());
Ok((win_handle, display_handle))
let display_handle = raw_window_handle::RawDisplayHandle::AppKit(
raw_window_handle::AppKitDisplayHandle::new(),
);
Ok((win_handle, display_handle))
}
#[cfg(target_os = "windows")]
fn raw_window(
system: UnsafeWindowSurfaceSystem,
window: *const c_void,
hinstance: *const c_void,
system: UnsafeWindowSurfaceSystem,
window: *const c_void,
hinstance: *const c_void,
) -> Result<RawHandles, ByowError> {
use raw_window_handle::WindowsDisplayHandle;
if system != UnsafeWindowSurfaceSystem::Win32 {
return Err(ByowError::InvalidSystem);
}
use raw_window_handle::WindowsDisplayHandle;
if system != UnsafeWindowSurfaceSystem::Win32 {
return Err(ByowError::InvalidSystem);
}
let win_handle = {
let mut handle = raw_window_handle::Win32WindowHandle::new(
std::num::NonZeroIsize::new(window as isize).ok_or(ByowError::NullWindow)?,
);
handle.hinstance = std::num::NonZeroIsize::new(hinstance as isize);
let win_handle = {
let mut handle = raw_window_handle::Win32WindowHandle::new(
std::num::NonZeroIsize::new(window as isize)
.ok_or(ByowError::NullWindow)?,
);
handle.hinstance = std::num::NonZeroIsize::new(hinstance as isize);
raw_window_handle::RawWindowHandle::Win32(handle)
};
raw_window_handle::RawWindowHandle::Win32(handle)
};
let display_handle = raw_window_handle::RawDisplayHandle::Windows(WindowsDisplayHandle::new());
Ok((win_handle, display_handle))
let display_handle =
raw_window_handle::RawDisplayHandle::Windows(WindowsDisplayHandle::new());
Ok((win_handle, display_handle))
}
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))]
fn raw_window(
system: UnsafeWindowSurfaceSystem,
window: *const c_void,
display: *const c_void,
system: UnsafeWindowSurfaceSystem,
window: *const c_void,
display: *const c_void,
) -> Result<RawHandles, ByowError> {
let (win_handle, display_handle);
if system == UnsafeWindowSurfaceSystem::X11 {
win_handle = raw_window_handle::RawWindowHandle::Xlib(
raw_window_handle::XlibWindowHandle::new(window as *mut c_void as _),
);
let (win_handle, display_handle);
if system == UnsafeWindowSurfaceSystem::X11 {
win_handle = raw_window_handle::RawWindowHandle::Xlib(
raw_window_handle::XlibWindowHandle::new(window as *mut c_void as _),
);
display_handle = raw_window_handle::RawDisplayHandle::Xlib(
raw_window_handle::XlibDisplayHandle::new(NonNull::new(display as *mut c_void), 0),
);
} else if system == UnsafeWindowSurfaceSystem::Wayland {
win_handle = raw_window_handle::RawWindowHandle::Wayland(
raw_window_handle::WaylandWindowHandle::new(
NonNull::new(window as *mut c_void).ok_or(ByowError::NullWindow)?,
),
);
display_handle = raw_window_handle::RawDisplayHandle::Xlib(
raw_window_handle::XlibDisplayHandle::new(
NonNull::new(display as *mut c_void),
0,
),
);
} else if system == UnsafeWindowSurfaceSystem::Wayland {
win_handle = raw_window_handle::RawWindowHandle::Wayland(
raw_window_handle::WaylandWindowHandle::new(
NonNull::new(window as *mut c_void).ok_or(ByowError::NullWindow)?,
),
);
display_handle = raw_window_handle::RawDisplayHandle::Wayland(
raw_window_handle::WaylandDisplayHandle::new(
NonNull::new(display as *mut c_void).ok_or(ByowError::NullDisplay)?,
),
);
} else {
return Err(ByowError::InvalidSystem);
}
display_handle = raw_window_handle::RawDisplayHandle::Wayland(
raw_window_handle::WaylandDisplayHandle::new(
NonNull::new(display as *mut c_void).ok_or(ByowError::NullDisplay)?,
),
);
} else {
return Err(ByowError::InvalidSystem);
}
Ok((win_handle, display_handle))
Ok((win_handle, display_handle))
}
#[cfg(not(any(
target_os = "macos",
target_os = "windows",
target_os = "linux",
target_os = "freebsd",
target_os = "openbsd",
target_os = "macos",
target_os = "windows",
target_os = "linux",
target_os = "freebsd",
target_os = "openbsd",
)))]
fn raw_window(
_system: UnsafeWindowSurfaceSystem,
_window: *const c_void,
_display: *const c_void,
_system: UnsafeWindowSurfaceSystem,
_window: *const c_void,
_display: *const c_void,
) -> Result<RawHandles, deno_error::JsErrorBox> {
Err(deno_error::JsErrorBox::type_error("Unsupported platform"))
Err(deno_error::JsErrorBox::type_error("Unsupported platform"))
}

View File

@ -7,40 +7,40 @@ use deno_core::WebIDL;
use crate::Instance;
pub struct GPUCommandBuffer {
pub instance: Instance,
pub id: wgpu_core::id::CommandBufferId,
pub label: String,
pub instance: Instance,
pub id: wgpu_core::id::CommandBufferId,
pub label: String,
}
impl Drop for GPUCommandBuffer {
fn drop(&mut self) {
self.instance.command_buffer_drop(self.id);
}
fn drop(&mut self) {
self.instance.command_buffer_drop(self.id);
}
}
impl deno_core::webidl::WebIdlInterfaceConverter for GPUCommandBuffer {
const NAME: &'static str = "GPUCommandBuffer";
const NAME: &'static str = "GPUCommandBuffer";
}
impl GarbageCollected for GPUCommandBuffer {}
#[op2]
impl GPUCommandBuffer {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUCommandBufferDescriptor {
#[webidl(default = String::new())]
pub label: String,
#[webidl(default = String::new())]
pub label: String,
}

View File

@ -23,61 +23,61 @@ use crate::webidl::GPUExtent3D;
use crate::Instance;
pub struct GPUCommandEncoder {
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub id: wgpu_core::id::CommandEncoderId,
pub label: String,
pub id: wgpu_core::id::CommandEncoderId,
pub label: String,
}
impl Drop for GPUCommandEncoder {
fn drop(&mut self) {
self.instance.command_encoder_drop(self.id);
}
fn drop(&mut self) {
self.instance.command_encoder_drop(self.id);
}
}
impl GarbageCollected for GPUCommandEncoder {}
#[op2]
impl GPUCommandEncoder {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[required(1)]
#[cppgc]
fn begin_render_pass(
&self,
#[webidl] descriptor: crate::render_pass::GPURenderPassDescriptor,
) -> Result<GPURenderPassEncoder, JsErrorBox> {
let color_attachments = Cow::Owned(
descriptor
.color_attachments
.into_iter()
.map(|attachment| {
attachment.into_option().map(|attachment| {
wgpu_core::command::RenderPassColorAttachment {
view: attachment.view.id,
depth_slice: attachment.depth_slice,
resolve_target: attachment.resolve_target.map(|target| target.id),
load_op: attachment
.load_op
.with_default_value(attachment.clear_value.map(Into::into)),
store_op: attachment.store_op.into(),
}
})
})
.collect::<Vec<_>>(),
);
#[required(1)]
#[cppgc]
fn begin_render_pass(
&self,
#[webidl] descriptor: crate::render_pass::GPURenderPassDescriptor,
) -> Result<GPURenderPassEncoder, JsErrorBox> {
let color_attachments = Cow::Owned(
descriptor
.color_attachments
.into_iter()
.map(|attachment| {
attachment.into_option().map(|attachment| {
wgpu_core::command::RenderPassColorAttachment {
view: attachment.view.id,
depth_slice: attachment.depth_slice,
resolve_target: attachment.resolve_target.map(|target| target.id),
load_op: attachment
.load_op
.with_default_value(attachment.clear_value.map(Into::into)),
store_op: attachment.store_op.into(),
}
})
})
.collect::<Vec<_>>(),
);
let depth_stencil_attachment = descriptor
let depth_stencil_attachment = descriptor
.depth_stencil_attachment
.map(|attachment| {
if attachment
@ -111,359 +111,366 @@ impl GPUCommandEncoder {
})
.transpose()?;
let timestamp_writes = descriptor.timestamp_writes.map(|timestamp_writes| {
wgpu_core::command::PassTimestampWrites {
query_set: timestamp_writes.query_set.id,
beginning_of_pass_write_index: timestamp_writes.beginning_of_pass_write_index,
end_of_pass_write_index: timestamp_writes.end_of_pass_write_index,
}
});
let wgpu_descriptor = wgpu_core::command::RenderPassDescriptor {
label: crate::transform_label(descriptor.label.clone()),
color_attachments,
depth_stencil_attachment: depth_stencil_attachment.as_ref(),
timestamp_writes: timestamp_writes.as_ref(),
occlusion_query_set: descriptor.occlusion_query_set.map(|query_set| query_set.id),
};
let (render_pass, err) = self
.instance
.command_encoder_begin_render_pass(self.id, &wgpu_descriptor);
self.error_handler.push_error(err);
Ok(GPURenderPassEncoder {
instance: self.instance.clone(),
error_handler: self.error_handler.clone(),
render_pass: RefCell::new(render_pass),
label: descriptor.label,
})
}
#[cppgc]
fn begin_compute_pass(
&self,
#[webidl] descriptor: crate::compute_pass::GPUComputePassDescriptor,
) -> GPUComputePassEncoder {
let timestamp_writes = descriptor.timestamp_writes.map(|timestamp_writes| {
wgpu_core::command::PassTimestampWrites {
query_set: timestamp_writes.query_set.id,
beginning_of_pass_write_index: timestamp_writes.beginning_of_pass_write_index,
end_of_pass_write_index: timestamp_writes.end_of_pass_write_index,
}
});
let wgpu_descriptor = wgpu_core::command::ComputePassDescriptor {
label: crate::transform_label(descriptor.label.clone()),
timestamp_writes,
};
let (compute_pass, err) = self
.instance
.command_encoder_begin_compute_pass(self.id, &wgpu_descriptor);
self.error_handler.push_error(err);
GPUComputePassEncoder {
instance: self.instance.clone(),
error_handler: self.error_handler.clone(),
compute_pass: RefCell::new(compute_pass),
label: descriptor.label,
let timestamp_writes =
descriptor.timestamp_writes.map(|timestamp_writes| {
wgpu_core::command::PassTimestampWrites {
query_set: timestamp_writes.query_set.id,
beginning_of_pass_write_index: timestamp_writes
.beginning_of_pass_write_index,
end_of_pass_write_index: timestamp_writes.end_of_pass_write_index,
}
}
});
#[required(2)]
fn copy_buffer_to_buffer<'a>(
&self,
scope: &mut v8::HandleScope<'a>,
#[webidl] source: Ptr<GPUBuffer>,
arg2: v8::Local<'a, v8::Value>,
arg3: v8::Local<'a, v8::Value>,
arg4: v8::Local<'a, v8::Value>,
arg5: v8::Local<'a, v8::Value>,
) -> Result<(), WebIdlError> {
let prefix = "Failed to execute 'GPUCommandEncoder.copyBufferToBuffer'";
let int_options = IntOptions {
clamp: false,
enforce_range: true,
};
let wgpu_descriptor = wgpu_core::command::RenderPassDescriptor {
label: crate::transform_label(descriptor.label.clone()),
color_attachments,
depth_stencil_attachment: depth_stencil_attachment.as_ref(),
timestamp_writes: timestamp_writes.as_ref(),
occlusion_query_set: descriptor
.occlusion_query_set
.map(|query_set| query_set.id),
};
let source_offset: BufferAddress;
let destination: Ptr<GPUBuffer>;
let destination_offset: BufferAddress;
let size: Option<BufferAddress>;
// Note that the last argument to either overload of `copy_buffer_to_buffer`
// is optional, so `arg5.is_undefined()` would not work here.
if arg4.is_undefined() {
// 3-argument overload
source_offset = 0;
destination = Ptr::<GPUBuffer>::convert(
scope,
arg2,
Cow::Borrowed(prefix),
(|| Cow::Borrowed("destination")).into(),
&(),
)?;
destination_offset = 0;
size = <Option<u64>>::convert(
scope,
arg3,
Cow::Borrowed(prefix),
(|| Cow::Borrowed("size")).into(),
&int_options,
)?;
} else {
// 5-argument overload
source_offset = u64::convert(
scope,
arg2,
Cow::Borrowed(prefix),
(|| Cow::Borrowed("sourceOffset")).into(),
&int_options,
)?;
destination = Ptr::<GPUBuffer>::convert(
scope,
arg3,
Cow::Borrowed(prefix),
(|| Cow::Borrowed("destination")).into(),
&(),
)?;
destination_offset = u64::convert(
scope,
arg4,
Cow::Borrowed(prefix),
(|| Cow::Borrowed("destinationOffset")).into(),
&int_options,
)?;
size = <Option<u64>>::convert(
scope,
arg5,
Cow::Borrowed(prefix),
(|| Cow::Borrowed("size")).into(),
&int_options,
)?;
let (render_pass, err) = self
.instance
.command_encoder_begin_render_pass(self.id, &wgpu_descriptor);
self.error_handler.push_error(err);
Ok(GPURenderPassEncoder {
instance: self.instance.clone(),
error_handler: self.error_handler.clone(),
render_pass: RefCell::new(render_pass),
label: descriptor.label,
})
}
#[cppgc]
fn begin_compute_pass(
&self,
#[webidl] descriptor: crate::compute_pass::GPUComputePassDescriptor,
) -> GPUComputePassEncoder {
let timestamp_writes =
descriptor.timestamp_writes.map(|timestamp_writes| {
wgpu_core::command::PassTimestampWrites {
query_set: timestamp_writes.query_set.id,
beginning_of_pass_write_index: timestamp_writes
.beginning_of_pass_write_index,
end_of_pass_write_index: timestamp_writes.end_of_pass_write_index,
}
});
let err = self
.instance
.command_encoder_copy_buffer_to_buffer(
self.id,
source.id,
source_offset,
destination.id,
destination_offset,
size,
)
.err();
let wgpu_descriptor = wgpu_core::command::ComputePassDescriptor {
label: crate::transform_label(descriptor.label.clone()),
timestamp_writes,
};
self.error_handler.push_error(err);
let (compute_pass, err) = self
.instance
.command_encoder_begin_compute_pass(self.id, &wgpu_descriptor);
Ok(())
self.error_handler.push_error(err);
GPUComputePassEncoder {
instance: self.instance.clone(),
error_handler: self.error_handler.clone(),
compute_pass: RefCell::new(compute_pass),
label: descriptor.label,
}
}
#[required(2)]
fn copy_buffer_to_buffer<'a>(
&self,
scope: &mut v8::HandleScope<'a>,
#[webidl] source: Ptr<GPUBuffer>,
arg2: v8::Local<'a, v8::Value>,
arg3: v8::Local<'a, v8::Value>,
arg4: v8::Local<'a, v8::Value>,
arg5: v8::Local<'a, v8::Value>,
) -> Result<(), WebIdlError> {
let prefix = "Failed to execute 'GPUCommandEncoder.copyBufferToBuffer'";
let int_options = IntOptions {
clamp: false,
enforce_range: true,
};
let source_offset: BufferAddress;
let destination: Ptr<GPUBuffer>;
let destination_offset: BufferAddress;
let size: Option<BufferAddress>;
// Note that the last argument to either overload of `copy_buffer_to_buffer`
// is optional, so `arg5.is_undefined()` would not work here.
if arg4.is_undefined() {
// 3-argument overload
source_offset = 0;
destination = Ptr::<GPUBuffer>::convert(
scope,
arg2,
Cow::Borrowed(prefix),
(|| Cow::Borrowed("destination")).into(),
&(),
)?;
destination_offset = 0;
size = <Option<u64>>::convert(
scope,
arg3,
Cow::Borrowed(prefix),
(|| Cow::Borrowed("size")).into(),
&int_options,
)?;
} else {
// 5-argument overload
source_offset = u64::convert(
scope,
arg2,
Cow::Borrowed(prefix),
(|| Cow::Borrowed("sourceOffset")).into(),
&int_options,
)?;
destination = Ptr::<GPUBuffer>::convert(
scope,
arg3,
Cow::Borrowed(prefix),
(|| Cow::Borrowed("destination")).into(),
&(),
)?;
destination_offset = u64::convert(
scope,
arg4,
Cow::Borrowed(prefix),
(|| Cow::Borrowed("destinationOffset")).into(),
&int_options,
)?;
size = <Option<u64>>::convert(
scope,
arg5,
Cow::Borrowed(prefix),
(|| Cow::Borrowed("size")).into(),
&int_options,
)?;
}
#[required(3)]
fn copy_buffer_to_texture(
&self,
#[webidl] source: GPUTexelCopyBufferInfo,
#[webidl] destination: GPUTexelCopyTextureInfo,
#[webidl] copy_size: GPUExtent3D,
) {
let source = TexelCopyBufferInfo {
buffer: source.buffer.id,
layout: wgpu_types::TexelCopyBufferLayout {
offset: source.offset,
bytes_per_row: source.bytes_per_row,
rows_per_image: source.rows_per_image,
},
};
let destination = wgpu_types::TexelCopyTextureInfo {
texture: destination.texture.id,
mip_level: destination.mip_level,
origin: destination.origin.into(),
aspect: destination.aspect.into(),
};
let err = self
.instance
.command_encoder_copy_buffer_to_buffer(
self.id,
source.id,
source_offset,
destination.id,
destination_offset,
size,
)
.err();
let err = self
.instance
.command_encoder_copy_buffer_to_texture(
self.id,
&source,
&destination,
&copy_size.into(),
)
.err();
self.error_handler.push_error(err);
self.error_handler.push_error(err);
Ok(())
}
#[required(3)]
fn copy_buffer_to_texture(
&self,
#[webidl] source: GPUTexelCopyBufferInfo,
#[webidl] destination: GPUTexelCopyTextureInfo,
#[webidl] copy_size: GPUExtent3D,
) {
let source = TexelCopyBufferInfo {
buffer: source.buffer.id,
layout: wgpu_types::TexelCopyBufferLayout {
offset: source.offset,
bytes_per_row: source.bytes_per_row,
rows_per_image: source.rows_per_image,
},
};
let destination = wgpu_types::TexelCopyTextureInfo {
texture: destination.texture.id,
mip_level: destination.mip_level,
origin: destination.origin.into(),
aspect: destination.aspect.into(),
};
let err = self
.instance
.command_encoder_copy_buffer_to_texture(
self.id,
&source,
&destination,
&copy_size.into(),
)
.err();
self.error_handler.push_error(err);
}
#[required(3)]
fn copy_texture_to_buffer(
&self,
#[webidl] source: GPUTexelCopyTextureInfo,
#[webidl] destination: GPUTexelCopyBufferInfo,
#[webidl] copy_size: GPUExtent3D,
) {
let source = wgpu_types::TexelCopyTextureInfo {
texture: source.texture.id,
mip_level: source.mip_level,
origin: source.origin.into(),
aspect: source.aspect.into(),
};
let destination = TexelCopyBufferInfo {
buffer: destination.buffer.id,
layout: wgpu_types::TexelCopyBufferLayout {
offset: destination.offset,
bytes_per_row: destination.bytes_per_row,
rows_per_image: destination.rows_per_image,
},
};
let err = self
.instance
.command_encoder_copy_texture_to_buffer(
self.id,
&source,
&destination,
&copy_size.into(),
)
.err();
self.error_handler.push_error(err);
}
#[required(3)]
fn copy_texture_to_texture(
&self,
#[webidl] source: GPUTexelCopyTextureInfo,
#[webidl] destination: GPUTexelCopyTextureInfo,
#[webidl] copy_size: GPUExtent3D,
) {
let source = wgpu_types::TexelCopyTextureInfo {
texture: source.texture.id,
mip_level: source.mip_level,
origin: source.origin.into(),
aspect: source.aspect.into(),
};
let destination = wgpu_types::TexelCopyTextureInfo {
texture: destination.texture.id,
mip_level: destination.mip_level,
origin: destination.origin.into(),
aspect: destination.aspect.into(),
};
let err = self
.instance
.command_encoder_copy_texture_to_texture(
self.id,
&source,
&destination,
&copy_size.into(),
)
.err();
self.error_handler.push_error(err);
}
#[required(1)]
fn clear_buffer(
&self,
#[webidl] buffer: Ptr<GPUBuffer>,
#[webidl(default = 0, options(enforce_range = true))] offset: u64,
#[webidl(options(enforce_range = true))] size: Option<u64>,
) {
let err = self
.instance
.command_encoder_clear_buffer(self.id, buffer.id, offset, size)
.err();
self.error_handler.push_error(err);
}
#[required(5)]
fn resolve_query_set(
&self,
#[webidl] query_set: Ptr<super::query_set::GPUQuerySet>,
#[webidl(options(enforce_range = true))] first_query: u32,
#[webidl(options(enforce_range = true))] query_count: u32,
#[webidl] destination: Ptr<GPUBuffer>,
#[webidl(options(enforce_range = true))] destination_offset: u64,
) {
let err = self
.instance
.command_encoder_resolve_query_set(
self.id,
query_set.id,
first_query,
query_count,
destination.id,
destination_offset,
)
.err();
self.error_handler.push_error(err);
}
#[cppgc]
fn finish(
&self,
#[webidl] descriptor: crate::command_buffer::GPUCommandBufferDescriptor,
) -> GPUCommandBuffer {
let wgpu_descriptor = wgpu_types::CommandBufferDescriptor {
label: crate::transform_label(descriptor.label.clone()),
};
let (id, err) =
self
.instance
.command_encoder_finish(self.id, &wgpu_descriptor, None);
self.error_handler.push_error(err);
GPUCommandBuffer {
instance: self.instance.clone(),
id,
label: descriptor.label,
}
}
#[required(3)]
fn copy_texture_to_buffer(
&self,
#[webidl] source: GPUTexelCopyTextureInfo,
#[webidl] destination: GPUTexelCopyBufferInfo,
#[webidl] copy_size: GPUExtent3D,
) {
let source = wgpu_types::TexelCopyTextureInfo {
texture: source.texture.id,
mip_level: source.mip_level,
origin: source.origin.into(),
aspect: source.aspect.into(),
};
let destination = TexelCopyBufferInfo {
buffer: destination.buffer.id,
layout: wgpu_types::TexelCopyBufferLayout {
offset: destination.offset,
bytes_per_row: destination.bytes_per_row,
rows_per_image: destination.rows_per_image,
},
};
fn push_debug_group(&self, #[webidl] group_label: String) {
let err = self
.instance
.command_encoder_push_debug_group(self.id, &group_label)
.err();
self.error_handler.push_error(err);
}
let err = self
.instance
.command_encoder_copy_texture_to_buffer(
self.id,
&source,
&destination,
&copy_size.into(),
)
.err();
#[fast]
fn pop_debug_group(&self) {
let err = self.instance.command_encoder_pop_debug_group(self.id).err();
self.error_handler.push_error(err);
}
self.error_handler.push_error(err);
}
#[required(3)]
fn copy_texture_to_texture(
&self,
#[webidl] source: GPUTexelCopyTextureInfo,
#[webidl] destination: GPUTexelCopyTextureInfo,
#[webidl] copy_size: GPUExtent3D,
) {
let source = wgpu_types::TexelCopyTextureInfo {
texture: source.texture.id,
mip_level: source.mip_level,
origin: source.origin.into(),
aspect: source.aspect.into(),
};
let destination = wgpu_types::TexelCopyTextureInfo {
texture: destination.texture.id,
mip_level: destination.mip_level,
origin: destination.origin.into(),
aspect: destination.aspect.into(),
};
let err = self
.instance
.command_encoder_copy_texture_to_texture(
self.id,
&source,
&destination,
&copy_size.into(),
)
.err();
self.error_handler.push_error(err);
}
#[required(1)]
fn clear_buffer(
&self,
#[webidl] buffer: Ptr<GPUBuffer>,
#[webidl(default = 0, options(enforce_range = true))] offset: u64,
#[webidl(options(enforce_range = true))] size: Option<u64>,
) {
let err = self
.instance
.command_encoder_clear_buffer(self.id, buffer.id, offset, size)
.err();
self.error_handler.push_error(err);
}
#[required(5)]
fn resolve_query_set(
&self,
#[webidl] query_set: Ptr<super::query_set::GPUQuerySet>,
#[webidl(options(enforce_range = true))] first_query: u32,
#[webidl(options(enforce_range = true))] query_count: u32,
#[webidl] destination: Ptr<GPUBuffer>,
#[webidl(options(enforce_range = true))] destination_offset: u64,
) {
let err = self
.instance
.command_encoder_resolve_query_set(
self.id,
query_set.id,
first_query,
query_count,
destination.id,
destination_offset,
)
.err();
self.error_handler.push_error(err);
}
#[cppgc]
fn finish(
&self,
#[webidl] descriptor: crate::command_buffer::GPUCommandBufferDescriptor,
) -> GPUCommandBuffer {
let wgpu_descriptor = wgpu_types::CommandBufferDescriptor {
label: crate::transform_label(descriptor.label.clone()),
};
let (id, err) = self
.instance
.command_encoder_finish(self.id, &wgpu_descriptor, None);
self.error_handler.push_error(err);
GPUCommandBuffer {
instance: self.instance.clone(),
id,
label: descriptor.label,
}
}
fn push_debug_group(&self, #[webidl] group_label: String) {
let err = self
.instance
.command_encoder_push_debug_group(self.id, &group_label)
.err();
self.error_handler.push_error(err);
}
#[fast]
fn pop_debug_group(&self) {
let err = self.instance.command_encoder_pop_debug_group(self.id).err();
self.error_handler.push_error(err);
}
fn insert_debug_marker(&self, #[webidl] marker_label: String) {
let err = self
.instance
.command_encoder_insert_debug_marker(self.id, &marker_label)
.err();
self.error_handler.push_error(err);
}
fn insert_debug_marker(&self, #[webidl] marker_label: String) {
let err = self
.instance
.command_encoder_insert_debug_marker(self.id, &marker_label)
.err();
self.error_handler.push_error(err);
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUCommandEncoderDescriptor {
#[webidl(default = String::new())]
pub label: String,
#[webidl(default = String::new())]
pub label: String,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUTexelCopyBufferInfo {
pub buffer: Ptr<GPUBuffer>,
#[webidl(default = 0)]
#[options(enforce_range = true)]
offset: u64,
#[options(enforce_range = true)]
bytes_per_row: Option<u32>,
#[options(enforce_range = true)]
rows_per_image: Option<u32>,
pub buffer: Ptr<GPUBuffer>,
#[webidl(default = 0)]
#[options(enforce_range = true)]
offset: u64,
#[options(enforce_range = true)]
bytes_per_row: Option<u32>,
#[options(enforce_range = true)]
rows_per_image: Option<u32>,
}

View File

@ -16,205 +16,218 @@ use deno_core::WebIDL;
use crate::Instance;
pub struct GPUComputePassEncoder {
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub compute_pass: RefCell<wgpu_core::command::ComputePass>,
pub label: String,
pub compute_pass: RefCell<wgpu_core::command::ComputePass>,
pub label: String,
}
impl GarbageCollected for GPUComputePassEncoder {}
#[op2]
impl GPUComputePassEncoder {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
fn set_pipeline(&self, #[webidl] pipeline: Ptr<crate::compute_pipeline::GPUComputePipeline>) {
let err = self
.instance
.compute_pass_set_pipeline(&mut self.compute_pass.borrow_mut(), pipeline.id)
.err();
self.error_handler.push_error(err);
}
fn set_pipeline(
&self,
#[webidl] pipeline: Ptr<crate::compute_pipeline::GPUComputePipeline>,
) {
let err = self
.instance
.compute_pass_set_pipeline(
&mut self.compute_pass.borrow_mut(),
pipeline.id,
)
.err();
self.error_handler.push_error(err);
}
fn dispatch_workgroups(
&self,
#[webidl(options(enforce_range = true))] work_group_count_x: u32,
#[webidl(default = 1, options(enforce_range = true))] work_group_count_y: u32,
#[webidl(default = 1, options(enforce_range = true))] work_group_count_z: u32,
) {
let err = self
.instance
.compute_pass_dispatch_workgroups(
&mut self.compute_pass.borrow_mut(),
work_group_count_x,
work_group_count_y,
work_group_count_z,
)
.err();
self.error_handler.push_error(err);
}
fn dispatch_workgroups(
&self,
#[webidl(options(enforce_range = true))] work_group_count_x: u32,
#[webidl(default = 1, options(enforce_range = true))]
work_group_count_y: u32,
#[webidl(default = 1, options(enforce_range = true))]
work_group_count_z: u32,
) {
let err = self
.instance
.compute_pass_dispatch_workgroups(
&mut self.compute_pass.borrow_mut(),
work_group_count_x,
work_group_count_y,
work_group_count_z,
)
.err();
self.error_handler.push_error(err);
}
fn dispatch_workgroups_indirect(
&self,
#[webidl] indirect_buffer: Ptr<crate::buffer::GPUBuffer>,
#[webidl(options(enforce_range = true))] indirect_offset: u64,
) {
let err = self
.instance
.compute_pass_dispatch_workgroups_indirect(
&mut self.compute_pass.borrow_mut(),
indirect_buffer.id,
indirect_offset,
)
.err();
self.error_handler.push_error(err);
}
fn dispatch_workgroups_indirect(
&self,
#[webidl] indirect_buffer: Ptr<crate::buffer::GPUBuffer>,
#[webidl(options(enforce_range = true))] indirect_offset: u64,
) {
let err = self
.instance
.compute_pass_dispatch_workgroups_indirect(
&mut self.compute_pass.borrow_mut(),
indirect_buffer.id,
indirect_offset,
)
.err();
self.error_handler.push_error(err);
}
#[fast]
fn end(&self) {
let err = self
.instance
.compute_pass_end(&mut self.compute_pass.borrow_mut())
.err();
self.error_handler.push_error(err);
}
#[fast]
fn end(&self) {
let err = self
.instance
.compute_pass_end(&mut self.compute_pass.borrow_mut())
.err();
self.error_handler.push_error(err);
}
fn push_debug_group(&self, #[webidl] group_label: String) {
let err = self
.instance
.compute_pass_push_debug_group(
&mut self.compute_pass.borrow_mut(),
&group_label,
0, // wgpu#975
)
.err();
self.error_handler.push_error(err);
}
fn push_debug_group(&self, #[webidl] group_label: String) {
let err = self
.instance
.compute_pass_push_debug_group(
&mut self.compute_pass.borrow_mut(),
&group_label,
0, // wgpu#975
)
.err();
self.error_handler.push_error(err);
}
#[fast]
fn pop_debug_group(&self) {
let err = self
.instance
.compute_pass_pop_debug_group(&mut self.compute_pass.borrow_mut())
.err();
self.error_handler.push_error(err);
}
#[fast]
fn pop_debug_group(&self) {
let err = self
.instance
.compute_pass_pop_debug_group(&mut self.compute_pass.borrow_mut())
.err();
self.error_handler.push_error(err);
}
fn insert_debug_marker(&self, #[webidl] marker_label: String) {
let err = self
.instance
.compute_pass_insert_debug_marker(
&mut self.compute_pass.borrow_mut(),
&marker_label,
0, // wgpu#975
)
.err();
self.error_handler.push_error(err);
}
fn insert_debug_marker(&self, #[webidl] marker_label: String) {
let err = self
.instance
.compute_pass_insert_debug_marker(
&mut self.compute_pass.borrow_mut(),
&marker_label,
0, // wgpu#975
)
.err();
self.error_handler.push_error(err);
}
fn set_bind_group<'a>(
&self,
scope: &mut v8::HandleScope<'a>,
#[webidl(options(enforce_range = true))] index: u32,
#[webidl] bind_group: Nullable<Ptr<crate::bind_group::GPUBindGroup>>,
dynamic_offsets: v8::Local<'a, v8::Value>,
dynamic_offsets_data_start: v8::Local<'a, v8::Value>,
dynamic_offsets_data_length: v8::Local<'a, v8::Value>,
) -> Result<(), WebIdlError> {
const PREFIX: &str = "Failed to execute 'setBindGroup' on 'GPUComputePassEncoder'";
let err = if let Ok(uint_32) = dynamic_offsets.try_cast::<v8::Uint32Array>() {
let start = u64::convert(
scope,
dynamic_offsets_data_start,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 4")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)? as usize;
let len = u32::convert(
scope,
dynamic_offsets_data_length,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 5")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)? as usize;
fn set_bind_group<'a>(
&self,
scope: &mut v8::HandleScope<'a>,
#[webidl(options(enforce_range = true))] index: u32,
#[webidl] bind_group: Nullable<Ptr<crate::bind_group::GPUBindGroup>>,
dynamic_offsets: v8::Local<'a, v8::Value>,
dynamic_offsets_data_start: v8::Local<'a, v8::Value>,
dynamic_offsets_data_length: v8::Local<'a, v8::Value>,
) -> Result<(), WebIdlError> {
const PREFIX: &str =
"Failed to execute 'setBindGroup' on 'GPUComputePassEncoder'";
let err = if let Ok(uint_32) = dynamic_offsets.try_cast::<v8::Uint32Array>()
{
let start = u64::convert(
scope,
dynamic_offsets_data_start,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 4")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)? as usize;
let len = u32::convert(
scope,
dynamic_offsets_data_length,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 5")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)? as usize;
let ab = uint_32.buffer(scope).unwrap();
let ptr = ab.data().unwrap();
let ab_len = ab.byte_length() / 4;
let ab = uint_32.buffer(scope).unwrap();
let ptr = ab.data().unwrap();
let ab_len = ab.byte_length() / 4;
// SAFETY: compute_pass_set_bind_group internally calls extend_from_slice with this slice
let data = unsafe { std::slice::from_raw_parts(ptr.as_ptr() as _, ab_len) };
// SAFETY: compute_pass_set_bind_group internally calls extend_from_slice with this slice
let data =
unsafe { std::slice::from_raw_parts(ptr.as_ptr() as _, ab_len) };
let offsets = &data[start..(start + len)];
let offsets = &data[start..(start + len)];
self.instance
.compute_pass_set_bind_group(
&mut self.compute_pass.borrow_mut(),
index,
bind_group.into_option().map(|bind_group| bind_group.id),
offsets,
)
.err()
} else {
let offsets = <Option<Vec<u32>>>::convert(
scope,
dynamic_offsets,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 3")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)?
.unwrap_or_default();
self
.instance
.compute_pass_set_bind_group(
&mut self.compute_pass.borrow_mut(),
index,
bind_group.into_option().map(|bind_group| bind_group.id),
offsets,
)
.err()
} else {
let offsets = <Option<Vec<u32>>>::convert(
scope,
dynamic_offsets,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 3")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)?
.unwrap_or_default();
self.instance
.compute_pass_set_bind_group(
&mut self.compute_pass.borrow_mut(),
index,
bind_group.into_option().map(|bind_group| bind_group.id),
&offsets,
)
.err()
};
self
.instance
.compute_pass_set_bind_group(
&mut self.compute_pass.borrow_mut(),
index,
bind_group.into_option().map(|bind_group| bind_group.id),
&offsets,
)
.err()
};
self.error_handler.push_error(err);
self.error_handler.push_error(err);
Ok(())
}
Ok(())
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUComputePassDescriptor {
#[webidl(default = String::new())]
pub label: String,
#[webidl(default = String::new())]
pub label: String,
pub timestamp_writes: Option<GPUComputePassTimestampWrites>,
pub timestamp_writes: Option<GPUComputePassTimestampWrites>,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUComputePassTimestampWrites {
pub query_set: Ptr<crate::query_set::GPUQuerySet>,
#[options(enforce_range = true)]
pub beginning_of_pass_write_index: Option<u32>,
#[options(enforce_range = true)]
pub end_of_pass_write_index: Option<u32>,
pub query_set: Ptr<crate::query_set::GPUQuerySet>,
#[options(enforce_range = true)]
pub beginning_of_pass_write_index: Option<u32>,
#[options(enforce_range = true)]
pub end_of_pass_write_index: Option<u32>,
}

View File

@ -13,70 +13,70 @@ use crate::webidl::GPUPipelineLayoutOrGPUAutoLayoutMode;
use crate::Instance;
pub struct GPUComputePipeline {
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub id: wgpu_core::id::ComputePipelineId,
pub label: String,
pub id: wgpu_core::id::ComputePipelineId,
pub label: String,
}
impl Drop for GPUComputePipeline {
fn drop(&mut self) {
self.instance.compute_pipeline_drop(self.id);
}
fn drop(&mut self) {
self.instance.compute_pipeline_drop(self.id);
}
}
impl WebIdlInterfaceConverter for GPUComputePipeline {
const NAME: &'static str = "GPUComputePipeline";
const NAME: &'static str = "GPUComputePipeline";
}
impl GarbageCollected for GPUComputePipeline {}
#[op2]
impl GPUComputePipeline {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[cppgc]
fn get_bind_group_layout(&self, #[webidl] index: u32) -> GPUBindGroupLayout {
let (id, err) = self
.instance
.compute_pipeline_get_bind_group_layout(self.id, index, None);
#[cppgc]
fn get_bind_group_layout(&self, #[webidl] index: u32) -> GPUBindGroupLayout {
let (id, err) = self
.instance
.compute_pipeline_get_bind_group_layout(self.id, index, None);
self.error_handler.push_error(err);
self.error_handler.push_error(err);
// TODO(wgpu): needs to support retrieving the label
GPUBindGroupLayout {
instance: self.instance.clone(),
id,
label: "".to_string(),
}
// TODO(wgpu): needs to support retrieving the label
GPUBindGroupLayout {
instance: self.instance.clone(),
id,
label: "".to_string(),
}
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUComputePipelineDescriptor {
#[webidl(default = String::new())]
pub label: String,
#[webidl(default = String::new())]
pub label: String,
pub compute: GPUProgrammableStage,
pub layout: GPUPipelineLayoutOrGPUAutoLayoutMode,
pub compute: GPUProgrammableStage,
pub layout: GPUPipelineLayoutOrGPUAutoLayoutMode,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUProgrammableStage {
pub module: Ptr<GPUShaderModule>,
pub entry_point: Option<String>,
#[webidl(default = Default::default())]
pub constants: IndexMap<String, f64>,
pub module: Ptr<GPUShaderModule>,
pub entry_point: Option<String>,
#[webidl(default = Default::default())]
pub constants: IndexMap<String, f64>,
}

File diff suppressed because it is too large Load Diff

View File

@ -44,324 +44,331 @@ use crate::device::GPUDeviceLostReason;
pub type ErrorHandler = std::rc::Rc<DeviceErrorHandler>;
pub struct DeviceErrorHandler {
pub is_lost: OnceLock<()>,
pub scopes: Mutex<Vec<(GPUErrorFilter, Vec<GPUError>)>>,
lost_resolver: Mutex<Option<v8::Global<v8::PromiseResolver>>>,
spawner: V8TaskSpawner,
pub is_lost: OnceLock<()>,
pub scopes: Mutex<Vec<(GPUErrorFilter, Vec<GPUError>)>>,
lost_resolver: Mutex<Option<v8::Global<v8::PromiseResolver>>>,
spawner: V8TaskSpawner,
// The error handler is constructed before the device. A weak
// reference to the device is placed here with `set_device`
// after the device is constructed.
device: OnceLock<v8::Weak<v8::Object>>,
// The error handler is constructed before the device. A weak
// reference to the device is placed here with `set_device`
// after the device is constructed.
device: OnceLock<v8::Weak<v8::Object>>,
}
impl DeviceErrorHandler {
pub fn new(lost_resolver: v8::Global<v8::PromiseResolver>, spawner: V8TaskSpawner) -> Self {
Self {
is_lost: Default::default(),
scopes: Mutex::new(vec![]),
lost_resolver: Mutex::new(Some(lost_resolver)),
device: OnceLock::new(),
spawner,
}
pub fn new(
lost_resolver: v8::Global<v8::PromiseResolver>,
spawner: V8TaskSpawner,
) -> Self {
Self {
is_lost: Default::default(),
scopes: Mutex::new(vec![]),
lost_resolver: Mutex::new(Some(lost_resolver)),
device: OnceLock::new(),
spawner,
}
}
pub fn set_device(&self, device: v8::Weak<v8::Object>) {
self.device.set(device).unwrap()
}
pub fn push_error<E: Into<GPUError>>(&self, err: Option<E>) {
let Some(err) = err else {
return;
};
if self.is_lost.get().is_some() {
return;
}
pub fn set_device(&self, device: v8::Weak<v8::Object>) {
self.device.set(device).unwrap()
let err = err.into();
if let GPUError::Lost(reason) = err {
let _ = self.is_lost.set(());
if let Some(resolver) = self.lost_resolver.lock().unwrap().take() {
self.spawner.spawn(move |scope| {
let resolver = v8::Local::new(scope, resolver);
let info = make_cppgc_object(scope, GPUDeviceLostInfo { reason });
let info = v8::Local::new(scope, info);
resolver.resolve(scope, info.into());
});
}
return;
}
pub fn push_error<E: Into<GPUError>>(&self, err: Option<E>) {
let Some(err) = err else {
return;
let error_filter = match err {
GPUError::Lost(_) => unreachable!(),
GPUError::Validation(_) => GPUErrorFilter::Validation,
GPUError::OutOfMemory => GPUErrorFilter::OutOfMemory,
GPUError::Internal => GPUErrorFilter::Internal,
};
let mut scopes = self.scopes.lock().unwrap();
let scope = scopes
.iter_mut()
.rfind(|(filter, _)| filter == &error_filter);
if let Some(scope) = scope {
scope.1.push(err);
} else {
let device = self
.device
.get()
.expect("set_device was not called")
.clone();
self.spawner.spawn(move |scope| {
let state = JsRuntime::op_state_from(&*scope);
let Some(device) = device.to_local(scope) else {
// The device has already gone away, so we don't have
// anywhere to report the error.
return;
};
let key = v8::String::new(scope, "dispatchEvent").unwrap();
let val = device.get(scope, key.into()).unwrap();
let func =
v8::Global::new(scope, val.try_cast::<v8::Function>().unwrap());
let device = v8::Global::new(scope, device.cast::<v8::Value>());
let error_event_class =
state.borrow().borrow::<crate::ErrorEventClass>().0.clone();
if self.is_lost.get().is_some() {
return;
}
let error = deno_core::error::to_v8_error(scope, &err);
let err = err.into();
let error_event_class =
v8::Local::new(scope, error_event_class.clone());
let constructor =
v8::Local::<v8::Function>::try_from(error_event_class).unwrap();
let kind = v8::String::new(scope, "uncapturederror").unwrap();
if let GPUError::Lost(reason) = err {
let _ = self.is_lost.set(());
if let Some(resolver) = self.lost_resolver.lock().unwrap().take() {
self.spawner.spawn(move |scope| {
let resolver = v8::Local::new(scope, resolver);
let info = make_cppgc_object(scope, GPUDeviceLostInfo { reason });
let info = v8::Local::new(scope, info);
resolver.resolve(scope, info.into());
});
}
let obj = v8::Object::new(scope);
let key = v8::String::new(scope, "error").unwrap();
obj.set(scope, key.into(), error);
return;
}
let event = constructor
.new_instance(scope, &[kind.into(), obj.into()])
.unwrap();
let error_filter = match err {
GPUError::Lost(_) => unreachable!(),
GPUError::Validation(_) => GPUErrorFilter::Validation,
GPUError::OutOfMemory => GPUErrorFilter::OutOfMemory,
GPUError::Internal => GPUErrorFilter::Internal,
};
let mut scopes = self.scopes.lock().unwrap();
let scope = scopes
.iter_mut()
.rfind(|(filter, _)| filter == &error_filter);
if let Some(scope) = scope {
scope.1.push(err);
} else {
let device = self
.device
.get()
.expect("set_device was not called")
.clone();
self.spawner.spawn(move |scope| {
let state = JsRuntime::op_state_from(&*scope);
let Some(device) = device.to_local(scope) else {
// The device has already gone away, so we don't have
// anywhere to report the error.
return;
};
let key = v8::String::new(scope, "dispatchEvent").unwrap();
let val = device.get(scope, key.into()).unwrap();
let func = v8::Global::new(scope, val.try_cast::<v8::Function>().unwrap());
let device = v8::Global::new(scope, device.cast::<v8::Value>());
let error_event_class = state.borrow().borrow::<crate::ErrorEventClass>().0.clone();
let error = deno_core::error::to_v8_error(scope, &err);
let error_event_class = v8::Local::new(scope, error_event_class.clone());
let constructor = v8::Local::<v8::Function>::try_from(error_event_class).unwrap();
let kind = v8::String::new(scope, "uncapturederror").unwrap();
let obj = v8::Object::new(scope);
let key = v8::String::new(scope, "error").unwrap();
obj.set(scope, key.into(), error);
let event = constructor
.new_instance(scope, &[kind.into(), obj.into()])
.unwrap();
let recv = v8::Local::new(scope, device);
func.open(scope).call(scope, recv, &[event.into()]);
});
}
let recv = v8::Local::new(scope, device);
func.open(scope).call(scope, recv, &[event.into()]);
});
}
}
}
#[derive(deno_core::WebIDL, Eq, PartialEq)]
#[webidl(enum)]
pub enum GPUErrorFilter {
Validation,
OutOfMemory,
Internal,
Validation,
OutOfMemory,
Internal,
}
#[derive(Debug, deno_error::JsError)]
pub enum GPUError {
// TODO(@crowlKats): consider adding an unreachable value that uses unreachable!()
#[class("UNREACHABLE")]
Lost(GPUDeviceLostReason),
#[class("GPUValidationError")]
Validation(String),
#[class("GPUOutOfMemoryError")]
OutOfMemory,
#[class("GPUInternalError")]
Internal,
// TODO(@crowlKats): consider adding an unreachable value that uses unreachable!()
#[class("UNREACHABLE")]
Lost(GPUDeviceLostReason),
#[class("GPUValidationError")]
Validation(String),
#[class("GPUOutOfMemoryError")]
OutOfMemory,
#[class("GPUInternalError")]
Internal,
}
impl Display for GPUError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
GPUError::Lost(_) => Ok(()),
GPUError::Validation(s) => f.write_str(s),
GPUError::OutOfMemory => f.write_str("not enough memory left"),
GPUError::Internal => Ok(()),
}
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
GPUError::Lost(_) => Ok(()),
GPUError::Validation(s) => f.write_str(s),
GPUError::OutOfMemory => f.write_str("not enough memory left"),
GPUError::Internal => Ok(()),
}
}
}
impl std::error::Error for GPUError {}
impl GPUError {
fn from_webgpu(e: impl WebGpuError) -> Self {
match e.webgpu_error_type() {
ErrorType::Internal => GPUError::Internal,
ErrorType::DeviceLost => GPUError::Lost(GPUDeviceLostReason::Unknown), // TODO: this variant should be ignored, register the lost callback instead.
ErrorType::OutOfMemory => GPUError::OutOfMemory,
ErrorType::Validation => GPUError::Validation(fmt_err(&e)),
}
fn from_webgpu(e: impl WebGpuError) -> Self {
match e.webgpu_error_type() {
ErrorType::Internal => GPUError::Internal,
ErrorType::DeviceLost => GPUError::Lost(GPUDeviceLostReason::Unknown), // TODO: this variant should be ignored, register the lost callback instead.
ErrorType::OutOfMemory => GPUError::OutOfMemory,
ErrorType::Validation => GPUError::Validation(fmt_err(&e)),
}
}
}
fn fmt_err(err: &(dyn std::error::Error + 'static)) -> String {
let mut output = err.to_string();
let mut output = err.to_string();
let mut e = err.source();
while let Some(source) = e {
output.push_str(&format!(": {source}"));
e = source.source();
}
let mut e = err.source();
while let Some(source) = e {
output.push_str(&format!(": {source}"));
e = source.source();
}
if output.is_empty() {
output.push_str("validation error");
}
if output.is_empty() {
output.push_str("validation error");
}
output
output
}
impl From<EncoderStateError> for GPUError {
fn from(err: EncoderStateError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: EncoderStateError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<PassStateError> for GPUError {
fn from(err: PassStateError) -> Self {
GPUError::Validation(fmt_err(&err))
}
fn from(err: PassStateError) -> Self {
GPUError::Validation(fmt_err(&err))
}
}
impl From<CreateBufferError> for GPUError {
fn from(err: CreateBufferError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: CreateBufferError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<DeviceError> for GPUError {
fn from(err: DeviceError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: DeviceError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<BufferAccessError> for GPUError {
fn from(err: BufferAccessError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: BufferAccessError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<CreateBindGroupLayoutError> for GPUError {
fn from(err: CreateBindGroupLayoutError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: CreateBindGroupLayoutError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<CreatePipelineLayoutError> for GPUError {
fn from(err: CreatePipelineLayoutError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: CreatePipelineLayoutError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<CreateBindGroupError> for GPUError {
fn from(err: CreateBindGroupError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: CreateBindGroupError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<RenderBundleError> for GPUError {
fn from(err: RenderBundleError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: RenderBundleError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<CreateRenderBundleError> for GPUError {
fn from(err: CreateRenderBundleError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: CreateRenderBundleError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<CommandEncoderError> for GPUError {
fn from(err: CommandEncoderError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: CommandEncoderError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<QueryError> for GPUError {
fn from(err: QueryError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: QueryError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<ComputePassError> for GPUError {
fn from(err: ComputePassError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: ComputePassError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<CreateComputePipelineError> for GPUError {
fn from(err: CreateComputePipelineError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: CreateComputePipelineError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<GetBindGroupLayoutError> for GPUError {
fn from(err: GetBindGroupLayoutError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: GetBindGroupLayoutError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<CreateRenderPipelineError> for GPUError {
fn from(err: CreateRenderPipelineError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: CreateRenderPipelineError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<RenderPassError> for GPUError {
fn from(err: RenderPassError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: RenderPassError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<CreateSamplerError> for GPUError {
fn from(err: CreateSamplerError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: CreateSamplerError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<CreateShaderModuleError> for GPUError {
fn from(err: CreateShaderModuleError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: CreateShaderModuleError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<CreateTextureError> for GPUError {
fn from(err: CreateTextureError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: CreateTextureError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<CreateTextureViewError> for GPUError {
fn from(err: CreateTextureViewError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: CreateTextureViewError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<CreateQuerySetError> for GPUError {
fn from(err: CreateQuerySetError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: CreateQuerySetError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<QueueSubmitError> for GPUError {
fn from(err: QueueSubmitError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: QueueSubmitError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<QueueWriteError> for GPUError {
fn from(err: QueueWriteError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: QueueWriteError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<ClearError> for GPUError {
fn from(err: ClearError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: ClearError) -> Self {
GPUError::from_webgpu(err)
}
}
impl From<ConfigureSurfaceError> for GPUError {
fn from(err: ConfigureSurfaceError) -> Self {
GPUError::from_webgpu(err)
}
fn from(err: ConfigureSurfaceError) -> Self {
GPUError::from_webgpu(err)
}
}

View File

@ -42,85 +42,85 @@ pub const UNSTABLE_FEATURE_NAME: &str = "webgpu";
#[allow(clippy::print_stdout)]
pub fn print_linker_flags(name: &str) {
if cfg!(windows) {
// these dls load slowly, so delay loading them
let dlls = [
// webgpu
"d3dcompiler_47",
"OPENGL32",
// network related functions
"iphlpapi",
];
for dll in dlls {
println!("cargo:rustc-link-arg-bin={name}=/delayload:{dll}.dll");
}
// enable delay loading
println!("cargo:rustc-link-arg-bin={name}=delayimp.lib");
if cfg!(windows) {
// these dls load slowly, so delay loading them
let dlls = [
// webgpu
"d3dcompiler_47",
"OPENGL32",
// network related functions
"iphlpapi",
];
for dll in dlls {
println!("cargo:rustc-link-arg-bin={name}=/delayload:{dll}.dll");
}
// enable delay loading
println!("cargo:rustc-link-arg-bin={name}=delayimp.lib");
}
}
pub type Instance = Arc<wgpu_core::global::Global>;
deno_core::extension!(
deno_webgpu,
deps = [deno_webidl, deno_web],
ops = [op_create_gpu],
objects = [
GPU,
adapter::GPUAdapter,
adapter::GPUAdapterInfo,
bind_group::GPUBindGroup,
bind_group_layout::GPUBindGroupLayout,
buffer::GPUBuffer,
command_buffer::GPUCommandBuffer,
command_encoder::GPUCommandEncoder,
compute_pass::GPUComputePassEncoder,
compute_pipeline::GPUComputePipeline,
device::GPUDevice,
device::GPUDeviceLostInfo,
pipeline_layout::GPUPipelineLayout,
query_set::GPUQuerySet,
queue::GPUQueue,
render_bundle::GPURenderBundle,
render_bundle::GPURenderBundleEncoder,
render_pass::GPURenderPassEncoder,
render_pipeline::GPURenderPipeline,
sampler::GPUSampler,
shader::GPUCompilationInfo,
shader::GPUCompilationMessage,
shader::GPUShaderModule,
adapter::GPUSupportedFeatures,
adapter::GPUSupportedLimits,
texture::GPUTexture,
texture::GPUTextureView,
texture::GPUExternalTexture,
byow::UnsafeWindowSurface,
surface::GPUCanvasContext,
],
esm = ["00_init.js", "02_surface.js"],
lazy_loaded_esm = ["01_webgpu.js"],
deno_webgpu,
deps = [deno_webidl, deno_web],
ops = [op_create_gpu],
objects = [
GPU,
adapter::GPUAdapter,
adapter::GPUAdapterInfo,
bind_group::GPUBindGroup,
bind_group_layout::GPUBindGroupLayout,
buffer::GPUBuffer,
command_buffer::GPUCommandBuffer,
command_encoder::GPUCommandEncoder,
compute_pass::GPUComputePassEncoder,
compute_pipeline::GPUComputePipeline,
device::GPUDevice,
device::GPUDeviceLostInfo,
pipeline_layout::GPUPipelineLayout,
query_set::GPUQuerySet,
queue::GPUQueue,
render_bundle::GPURenderBundle,
render_bundle::GPURenderBundleEncoder,
render_pass::GPURenderPassEncoder,
render_pipeline::GPURenderPipeline,
sampler::GPUSampler,
shader::GPUCompilationInfo,
shader::GPUCompilationMessage,
shader::GPUShaderModule,
adapter::GPUSupportedFeatures,
adapter::GPUSupportedLimits,
texture::GPUTexture,
texture::GPUTextureView,
texture::GPUExternalTexture,
byow::UnsafeWindowSurface,
surface::GPUCanvasContext,
],
esm = ["00_init.js", "02_surface.js"],
lazy_loaded_esm = ["01_webgpu.js"],
);
#[op2]
#[cppgc]
pub fn op_create_gpu(
state: &mut OpState,
scope: &mut v8::HandleScope,
webidl_brand: v8::Local<v8::Value>,
set_event_target_data: v8::Local<v8::Value>,
error_event_class: v8::Local<v8::Value>,
state: &mut OpState,
scope: &mut v8::HandleScope,
webidl_brand: v8::Local<v8::Value>,
set_event_target_data: v8::Local<v8::Value>,
error_event_class: v8::Local<v8::Value>,
) -> GPU {
state.put(EventTargetSetup {
brand: v8::Global::new(scope, webidl_brand),
set_event_target_data: v8::Global::new(scope, set_event_target_data),
});
state.put(ErrorEventClass(v8::Global::new(scope, error_event_class)));
GPU
state.put(EventTargetSetup {
brand: v8::Global::new(scope, webidl_brand),
set_event_target_data: v8::Global::new(scope, set_event_target_data),
});
state.put(ErrorEventClass(v8::Global::new(scope, error_event_class)));
GPU
}
struct EventTargetSetup {
brand: v8::Global<v8::Value>,
set_event_target_data: v8::Global<v8::Value>,
brand: v8::Global<v8::Value>,
set_event_target_data: v8::Global<v8::Value>,
}
struct ErrorEventClass(v8::Global<v8::Value>);
@ -130,83 +130,83 @@ impl GarbageCollected for GPU {}
#[op2]
impl GPU {
#[async_method]
#[cppgc]
async fn request_adapter(
&self,
state: Rc<RefCell<OpState>>,
#[webidl] options: adapter::GPURequestAdapterOptions,
) -> Option<adapter::GPUAdapter> {
let mut state = state.borrow_mut();
#[async_method]
#[cppgc]
async fn request_adapter(
&self,
state: Rc<RefCell<OpState>>,
#[webidl] options: adapter::GPURequestAdapterOptions,
) -> Option<adapter::GPUAdapter> {
let mut state = state.borrow_mut();
let backends = std::env::var("DENO_WEBGPU_BACKEND").map_or_else(
|_| wgpu_types::Backends::all(),
|s| wgpu_types::Backends::from_comma_list(&s),
);
let instance = if let Some(instance) = state.try_borrow::<Instance>() {
instance
} else {
state.put(Arc::new(wgpu_core::global::Global::new(
"webgpu",
&wgpu_types::InstanceDescriptor {
backends,
flags: wgpu_types::InstanceFlags::from_build_config(),
memory_budget_thresholds: wgpu_types::MemoryBudgetThresholds {
for_resource_creation: Some(97),
for_device_loss: Some(99),
},
backend_options: wgpu_types::BackendOptions {
dx12: wgpu_types::Dx12BackendOptions {
shader_compiler: wgpu_types::Dx12Compiler::Fxc,
..Default::default()
},
gl: wgpu_types::GlBackendOptions::default(),
noop: wgpu_types::NoopBackendOptions::default(),
},
},
)));
state.borrow::<Instance>()
};
let backends = std::env::var("DENO_WEBGPU_BACKEND").map_or_else(
|_| wgpu_types::Backends::all(),
|s| wgpu_types::Backends::from_comma_list(&s),
);
let instance = if let Some(instance) = state.try_borrow::<Instance>() {
instance
} else {
state.put(Arc::new(wgpu_core::global::Global::new(
"webgpu",
&wgpu_types::InstanceDescriptor {
backends,
flags: wgpu_types::InstanceFlags::from_build_config(),
memory_budget_thresholds: wgpu_types::MemoryBudgetThresholds {
for_resource_creation: Some(97),
for_device_loss: Some(99),
},
backend_options: wgpu_types::BackendOptions {
dx12: wgpu_types::Dx12BackendOptions {
shader_compiler: wgpu_types::Dx12Compiler::Fxc,
..Default::default()
},
gl: wgpu_types::GlBackendOptions::default(),
noop: wgpu_types::NoopBackendOptions::default(),
},
},
)));
state.borrow::<Instance>()
};
let descriptor = wgpu_core::instance::RequestAdapterOptions {
power_preference: options
.power_preference
.map(|pp| match pp {
adapter::GPUPowerPreference::LowPower => PowerPreference::LowPower,
adapter::GPUPowerPreference::HighPerformance => {
PowerPreference::HighPerformance
}
})
.unwrap_or_default(),
force_fallback_adapter: options.force_fallback_adapter,
compatible_surface: None, // windowless
};
let id = instance.request_adapter(&descriptor, backends, None).ok()?;
Some(adapter::GPUAdapter {
instance: instance.clone(),
features: SameObject::new(),
limits: SameObject::new(),
info: Rc::new(SameObject::new()),
id,
let descriptor = wgpu_core::instance::RequestAdapterOptions {
power_preference: options
.power_preference
.map(|pp| match pp {
adapter::GPUPowerPreference::LowPower => PowerPreference::LowPower,
adapter::GPUPowerPreference::HighPerformance => {
PowerPreference::HighPerformance
}
})
}
.unwrap_or_default(),
force_fallback_adapter: options.force_fallback_adapter,
compatible_surface: None, // windowless
};
let id = instance.request_adapter(&descriptor, backends, None).ok()?;
#[string]
fn getPreferredCanvasFormat(&self) -> &'static str {
// https://github.com/mozilla/gecko-dev/blob/b75080bb8b11844d18cb5f9ac6e68a866ef8e243/dom/webgpu/Instance.h#L42-L47
if cfg!(target_os = "android") {
texture::GPUTextureFormat::Rgba8unorm.as_str()
} else {
texture::GPUTextureFormat::Bgra8unorm.as_str()
}
Some(adapter::GPUAdapter {
instance: instance.clone(),
features: SameObject::new(),
limits: SameObject::new(),
info: Rc::new(SameObject::new()),
id,
})
}
#[string]
fn getPreferredCanvasFormat(&self) -> &'static str {
// https://github.com/mozilla/gecko-dev/blob/b75080bb8b11844d18cb5f9ac6e68a866ef8e243/dom/webgpu/Instance.h#L42-L47
if cfg!(target_os = "android") {
texture::GPUTextureFormat::Rgba8unorm.as_str()
} else {
texture::GPUTextureFormat::Bgra8unorm.as_str()
}
}
}
fn transform_label<'a>(label: String) -> Option<std::borrow::Cow<'a, str>> {
if label.is_empty() {
None
} else {
Some(std::borrow::Cow::Owned(label))
}
if label.is_empty() {
None
} else {
Some(std::borrow::Cow::Owned(label))
}
}

View File

@ -9,42 +9,43 @@ use deno_core::WebIDL;
use crate::Instance;
pub struct GPUPipelineLayout {
pub instance: Instance,
pub id: wgpu_core::id::PipelineLayoutId,
pub label: String,
pub instance: Instance,
pub id: wgpu_core::id::PipelineLayoutId,
pub label: String,
}
impl Drop for GPUPipelineLayout {
fn drop(&mut self) {
self.instance.pipeline_layout_drop(self.id);
}
fn drop(&mut self) {
self.instance.pipeline_layout_drop(self.id);
}
}
impl WebIdlInterfaceConverter for GPUPipelineLayout {
const NAME: &'static str = "GPUPipelineLayout";
const NAME: &'static str = "GPUPipelineLayout";
}
impl GarbageCollected for GPUPipelineLayout {}
#[op2]
impl GPUPipelineLayout {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUPipelineLayoutDescriptor {
#[webidl(default = String::new())]
pub label: String,
#[webidl(default = String::new())]
pub label: String,
pub bind_group_layouts: Vec<Ptr<super::bind_group_layout::GPUBindGroupLayout>>,
pub bind_group_layouts:
Vec<Ptr<super::bind_group_layout::GPUBindGroupLayout>>,
}

View File

@ -9,82 +9,82 @@ use deno_error::JsErrorBox;
use crate::Instance;
pub struct GPUQuerySet {
pub instance: Instance,
pub id: wgpu_core::id::QuerySetId,
pub r#type: GPUQueryType,
pub count: u32,
pub label: String,
pub instance: Instance,
pub id: wgpu_core::id::QuerySetId,
pub r#type: GPUQueryType,
pub count: u32,
pub label: String,
}
impl Drop for GPUQuerySet {
fn drop(&mut self) {
self.instance.query_set_drop(self.id);
}
fn drop(&mut self) {
self.instance.query_set_drop(self.id);
}
}
impl WebIdlInterfaceConverter for GPUQuerySet {
const NAME: &'static str = "GPUQuerySet";
const NAME: &'static str = "GPUQuerySet";
}
impl GarbageCollected for GPUQuerySet {}
#[op2]
impl GPUQuerySet {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[fast]
fn destroy(&self) -> Result<(), JsErrorBox> {
// TODO(https://github.com/gfx-rs/wgpu/issues/6495): Destroy the query
// set. Until that is supported, it is okay to do nothing here, the
// query set will be garbage collected and dropped eventually.
Ok(())
}
#[fast]
fn destroy(&self) -> Result<(), JsErrorBox> {
// TODO(https://github.com/gfx-rs/wgpu/issues/6495): Destroy the query
// set. Until that is supported, it is okay to do nothing here, the
// query set will be garbage collected and dropped eventually.
Ok(())
}
// Naming this `type` or `r#type` does not work.
// https://github.com/gfx-rs/wgpu/issues/7778
#[getter]
#[string]
fn ty(&self) -> &'static str {
self.r#type.as_str()
}
// Naming this `type` or `r#type` does not work.
// https://github.com/gfx-rs/wgpu/issues/7778
#[getter]
#[string]
fn ty(&self) -> &'static str {
self.r#type.as_str()
}
#[getter]
fn count(&self) -> u32 {
self.count
}
#[getter]
fn count(&self) -> u32 {
self.count
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUQuerySetDescriptor {
#[webidl(default = String::new())]
pub label: String,
#[webidl(default = String::new())]
pub label: String,
pub r#type: GPUQueryType,
#[options(enforce_range = true)]
pub count: u32,
pub r#type: GPUQueryType,
#[options(enforce_range = true)]
pub count: u32,
}
#[derive(WebIDL, Clone)]
#[webidl(enum)]
pub(crate) enum GPUQueryType {
Occlusion,
Timestamp,
Occlusion,
Timestamp,
}
impl From<GPUQueryType> for wgpu_types::QueryType {
fn from(value: GPUQueryType) -> Self {
match value {
GPUQueryType::Occlusion => Self::Occlusion,
GPUQueryType::Timestamp => Self::Timestamp,
}
fn from(value: GPUQueryType) -> Self {
match value {
GPUQueryType::Occlusion => Self::Occlusion,
GPUQueryType::Timestamp => Self::Timestamp,
}
}
}

View File

@ -21,168 +21,178 @@ use crate::webidl::GPUOrigin3D;
use crate::Instance;
pub struct GPUQueue {
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub label: String,
pub label: String,
pub id: wgpu_core::id::QueueId,
pub device: wgpu_core::id::DeviceId,
pub id: wgpu_core::id::QueueId,
pub device: wgpu_core::id::DeviceId,
}
impl Drop for GPUQueue {
fn drop(&mut self) {
self.instance.queue_drop(self.id);
}
fn drop(&mut self) {
self.instance.queue_drop(self.id);
}
}
impl GarbageCollected for GPUQueue {}
#[op2]
impl GPUQueue {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[required(1)]
fn submit(
&self,
scope: &mut v8::HandleScope,
#[webidl] command_buffers: Vec<Ptr<GPUCommandBuffer>>,
) -> Result<v8::Local<v8::Value>, JsErrorBox> {
let ids = command_buffers
.into_iter()
.map(|cb| cb.id)
.collect::<Vec<_>>();
let err = self.instance.queue_submit(self.id, &ids).err();
if let Some((_, err)) = err {
self.error_handler.push_error(Some(err));
}
#[required(1)]
fn submit(
&self,
scope: &mut v8::HandleScope,
#[webidl] command_buffers: Vec<Ptr<GPUCommandBuffer>>,
) -> Result<v8::Local<v8::Value>, JsErrorBox> {
let ids = command_buffers
.into_iter()
.map(|cb| cb.id)
.collect::<Vec<_>>();
Ok(v8::undefined(scope).into())
}
let err = self.instance.queue_submit(self.id, &ids).err();
#[async_method]
async fn on_submitted_work_done(&self) -> Result<(), JsErrorBox> {
let (sender, receiver) = oneshot::channel::<()>();
if let Some((_, err)) = err {
self.error_handler.push_error(Some(err));
let callback = Box::new(move || {
sender.send(()).unwrap();
});
self
.instance
.queue_on_submitted_work_done(self.id, callback);
let done = Rc::new(RefCell::new(false));
let done_ = done.clone();
let device_poll_fut = async move {
while !*done.borrow() {
{
self
.instance
.device_poll(self.device, wgpu_types::PollType::wait())
.unwrap();
}
tokio::time::sleep(Duration::from_millis(10)).await;
}
Ok::<(), JsErrorBox>(())
};
Ok(v8::undefined(scope).into())
}
let receiver_fut = async move {
receiver
.await
.map_err(|e| JsErrorBox::generic(e.to_string()))?;
let mut done = done_.borrow_mut();
*done = true;
Ok::<(), JsErrorBox>(())
};
#[async_method]
async fn on_submitted_work_done(&self) -> Result<(), JsErrorBox> {
let (sender, receiver) = oneshot::channel::<()>();
tokio::try_join!(device_poll_fut, receiver_fut)?;
let callback = Box::new(move || {
sender.send(()).unwrap();
});
Ok(())
}
self.instance
.queue_on_submitted_work_done(self.id, callback);
#[required(3)]
fn write_buffer(
&self,
#[webidl] buffer: Ptr<GPUBuffer>,
#[webidl(options(enforce_range = true))] buffer_offset: u64,
#[anybuffer] buf: &[u8],
#[webidl(default = 0, options(enforce_range = true))] data_offset: u64,
#[webidl(options(enforce_range = true))] size: Option<u64>,
) {
let data = match size {
Some(size) => {
&buf[(data_offset as usize)..((data_offset + size) as usize)]
}
None => &buf[(data_offset as usize)..],
};
let done = Rc::new(RefCell::new(false));
let done_ = done.clone();
let device_poll_fut = async move {
while !*done.borrow() {
{
self.instance
.device_poll(self.device, wgpu_types::PollType::wait())
.unwrap();
}
tokio::time::sleep(Duration::from_millis(10)).await;
}
Ok::<(), JsErrorBox>(())
};
let err = self
.instance
.queue_write_buffer(self.id, buffer.id, buffer_offset, data)
.err();
let receiver_fut = async move {
receiver
.await
.map_err(|e| JsErrorBox::generic(e.to_string()))?;
let mut done = done_.borrow_mut();
*done = true;
Ok::<(), JsErrorBox>(())
};
self.error_handler.push_error(err);
}
tokio::try_join!(device_poll_fut, receiver_fut)?;
#[required(4)]
fn write_texture(
&self,
#[webidl] destination: GPUTexelCopyTextureInfo,
#[anybuffer] buf: &[u8],
#[webidl] data_layout: GPUTexelCopyBufferLayout,
#[webidl] size: GPUExtent3D,
) {
let destination = wgpu_types::TexelCopyTextureInfo {
texture: destination.texture.id,
mip_level: destination.mip_level,
origin: destination.origin.into(),
aspect: destination.aspect.into(),
};
Ok(())
}
let data_layout = wgpu_types::TexelCopyBufferLayout {
offset: data_layout.offset,
bytes_per_row: data_layout.bytes_per_row,
rows_per_image: data_layout.rows_per_image,
};
#[required(3)]
fn write_buffer(
&self,
#[webidl] buffer: Ptr<GPUBuffer>,
#[webidl(options(enforce_range = true))] buffer_offset: u64,
#[anybuffer] buf: &[u8],
#[webidl(default = 0, options(enforce_range = true))] data_offset: u64,
#[webidl(options(enforce_range = true))] size: Option<u64>,
) {
let data = match size {
Some(size) => &buf[(data_offset as usize)..((data_offset + size) as usize)],
None => &buf[(data_offset as usize)..],
};
let err = self
.instance
.queue_write_texture(
self.id,
&destination,
buf,
&data_layout,
&size.into(),
)
.err();
let err = self
.instance
.queue_write_buffer(self.id, buffer.id, buffer_offset, data)
.err();
self.error_handler.push_error(err);
}
#[required(4)]
fn write_texture(
&self,
#[webidl] destination: GPUTexelCopyTextureInfo,
#[anybuffer] buf: &[u8],
#[webidl] data_layout: GPUTexelCopyBufferLayout,
#[webidl] size: GPUExtent3D,
) {
let destination = wgpu_types::TexelCopyTextureInfo {
texture: destination.texture.id,
mip_level: destination.mip_level,
origin: destination.origin.into(),
aspect: destination.aspect.into(),
};
let data_layout = wgpu_types::TexelCopyBufferLayout {
offset: data_layout.offset,
bytes_per_row: data_layout.bytes_per_row,
rows_per_image: data_layout.rows_per_image,
};
let err = self
.instance
.queue_write_texture(self.id, &destination, buf, &data_layout, &size.into())
.err();
self.error_handler.push_error(err);
}
self.error_handler.push_error(err);
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUTexelCopyTextureInfo {
pub texture: Ptr<GPUTexture>,
#[webidl(default = 0)]
#[options(enforce_range = true)]
pub mip_level: u32,
#[webidl(default = Default::default())]
pub origin: GPUOrigin3D,
#[webidl(default = GPUTextureAspect::All)]
pub aspect: GPUTextureAspect,
pub texture: Ptr<GPUTexture>,
#[webidl(default = 0)]
#[options(enforce_range = true)]
pub mip_level: u32,
#[webidl(default = Default::default())]
pub origin: GPUOrigin3D,
#[webidl(default = GPUTextureAspect::All)]
pub aspect: GPUTextureAspect,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
struct GPUTexelCopyBufferLayout {
#[webidl(default = 0)]
#[options(enforce_range = true)]
offset: u64,
#[options(enforce_range = true)]
bytes_per_row: Option<u32>,
#[options(enforce_range = true)]
rows_per_image: Option<u32>,
#[webidl(default = 0)]
#[options(enforce_range = true)]
offset: u64,
#[options(enforce_range = true)]
bytes_per_row: Option<u32>,
#[options(enforce_range = true)]
rows_per_image: Option<u32>,
}

View File

@ -20,396 +20,412 @@ use crate::buffer::GPUBuffer;
use crate::texture::GPUTextureFormat;
use crate::Instance;
fn c_string_truncated_at_first_nul<T: Into<Vec<u8>>>(src: T) -> std::ffi::CString {
std::ffi::CString::new(src).unwrap_or_else(|err| {
let nul_pos = err.nul_position();
std::ffi::CString::new(err.into_vec().split_at(nul_pos).0).unwrap()
})
fn c_string_truncated_at_first_nul<T: Into<Vec<u8>>>(
src: T,
) -> std::ffi::CString {
std::ffi::CString::new(src).unwrap_or_else(|err| {
let nul_pos = err.nul_position();
std::ffi::CString::new(err.into_vec().split_at(nul_pos).0).unwrap()
})
}
pub struct GPURenderBundleEncoder {
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub encoder: RefCell<Option<wgpu_core::command::RenderBundleEncoder>>,
pub label: String,
pub encoder: RefCell<Option<wgpu_core::command::RenderBundleEncoder>>,
pub label: String,
}
impl GarbageCollected for GPURenderBundleEncoder {}
#[op2]
impl GPURenderBundleEncoder {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[cppgc]
fn finish(
&self,
#[webidl] descriptor: GPURenderBundleDescriptor,
) -> GPURenderBundle {
let wgpu_descriptor = wgpu_core::command::RenderBundleDescriptor {
label: crate::transform_label(descriptor.label.clone()),
};
let (id, err) = self.instance.render_bundle_encoder_finish(
self.encoder.borrow_mut().take().unwrap(),
&wgpu_descriptor,
None,
);
self.error_handler.push_error(err);
GPURenderBundle {
instance: self.instance.clone(),
id,
label: descriptor.label.clone(),
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
fn push_debug_group(
&self,
#[webidl] group_label: String,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder.as_mut().ok_or_else(|| {
JsErrorBox::generic("Encoder has already been finished")
})?;
let label = c_string_truncated_at_first_nul(group_label);
// SAFETY: the string the raw pointer points to lives longer than the below
// function invocation.
unsafe {
wgpu_core::command::bundle_ffi::wgpu_render_bundle_push_debug_group(
encoder,
label.as_ptr(),
);
}
#[cppgc]
fn finish(&self, #[webidl] descriptor: GPURenderBundleDescriptor) -> GPURenderBundle {
let wgpu_descriptor = wgpu_core::command::RenderBundleDescriptor {
label: crate::transform_label(descriptor.label.clone()),
};
Ok(())
}
let (id, err) = self.instance.render_bundle_encoder_finish(
self.encoder.borrow_mut().take().unwrap(),
&wgpu_descriptor,
None,
#[fast]
fn pop_debug_group(&self) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder.as_mut().ok_or_else(|| {
JsErrorBox::generic("Encoder has already been finished")
})?;
wgpu_core::command::bundle_ffi::wgpu_render_bundle_pop_debug_group(encoder);
Ok(())
}
fn insert_debug_marker(
&self,
#[webidl] marker_label: String,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder.as_mut().ok_or_else(|| {
JsErrorBox::generic("Encoder has already been finished")
})?;
let label = c_string_truncated_at_first_nul(marker_label);
// SAFETY: the string the raw pointer points to lives longer than the below
// function invocation.
unsafe {
wgpu_core::command::bundle_ffi::wgpu_render_bundle_insert_debug_marker(
encoder,
label.as_ptr(),
);
}
Ok(())
}
fn set_bind_group<'a>(
&self,
scope: &mut v8::HandleScope<'a>,
#[webidl(options(enforce_range = true))] index: u32,
#[webidl] bind_group: Nullable<Ptr<crate::bind_group::GPUBindGroup>>,
dynamic_offsets: v8::Local<'a, v8::Value>,
dynamic_offsets_data_start: v8::Local<'a, v8::Value>,
dynamic_offsets_data_length: v8::Local<'a, v8::Value>,
) -> Result<(), SetBindGroupError> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder.as_mut().ok_or_else(|| {
JsErrorBox::generic("Encoder has already been finished")
})?;
const PREFIX: &str =
"Failed to execute 'setBindGroup' on 'GPUComputePassEncoder'";
if let Ok(uint_32) = dynamic_offsets.try_cast::<v8::Uint32Array>() {
let start = u64::convert(
scope,
dynamic_offsets_data_start,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 4")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)? as usize;
let len = u32::convert(
scope,
dynamic_offsets_data_length,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 5")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)? as usize;
let ab = uint_32.buffer(scope).unwrap();
let ptr = ab.data().unwrap();
let ab_len = ab.byte_length() / 4;
// SAFETY: created from an array buffer, slice is dropped at end of function call
let data =
unsafe { std::slice::from_raw_parts(ptr.as_ptr() as _, ab_len) };
let offsets = &data[start..(start + len)];
// SAFETY: wgpu FFI call
unsafe {
wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group(
encoder,
index,
bind_group.into_option().map(|bind_group| bind_group.id),
offsets.as_ptr(),
offsets.len(),
);
}
} else {
let offsets = <Option<Vec<u32>>>::convert(
scope,
dynamic_offsets,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 3")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)?
.unwrap_or_default();
self.error_handler.push_error(err);
GPURenderBundle {
instance: self.instance.clone(),
id,
label: descriptor.label.clone(),
}
}
fn push_debug_group(&self, #[webidl] group_label: String) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder
.as_mut()
.ok_or_else(|| JsErrorBox::generic("Encoder has already been finished"))?;
let label = c_string_truncated_at_first_nul(group_label);
// SAFETY: the string the raw pointer points to lives longer than the below
// function invocation.
unsafe {
wgpu_core::command::bundle_ffi::wgpu_render_bundle_push_debug_group(
encoder,
label.as_ptr(),
);
}
Ok(())
}
#[fast]
fn pop_debug_group(&self) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder
.as_mut()
.ok_or_else(|| JsErrorBox::generic("Encoder has already been finished"))?;
wgpu_core::command::bundle_ffi::wgpu_render_bundle_pop_debug_group(encoder);
Ok(())
}
fn insert_debug_marker(&self, #[webidl] marker_label: String) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder
.as_mut()
.ok_or_else(|| JsErrorBox::generic("Encoder has already been finished"))?;
let label = c_string_truncated_at_first_nul(marker_label);
// SAFETY: the string the raw pointer points to lives longer than the below
// function invocation.
unsafe {
wgpu_core::command::bundle_ffi::wgpu_render_bundle_insert_debug_marker(
encoder,
label.as_ptr(),
);
}
Ok(())
}
fn set_bind_group<'a>(
&self,
scope: &mut v8::HandleScope<'a>,
#[webidl(options(enforce_range = true))] index: u32,
#[webidl] bind_group: Nullable<Ptr<crate::bind_group::GPUBindGroup>>,
dynamic_offsets: v8::Local<'a, v8::Value>,
dynamic_offsets_data_start: v8::Local<'a, v8::Value>,
dynamic_offsets_data_length: v8::Local<'a, v8::Value>,
) -> Result<(), SetBindGroupError> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder
.as_mut()
.ok_or_else(|| JsErrorBox::generic("Encoder has already been finished"))?;
const PREFIX: &str = "Failed to execute 'setBindGroup' on 'GPUComputePassEncoder'";
if let Ok(uint_32) = dynamic_offsets.try_cast::<v8::Uint32Array>() {
let start = u64::convert(
scope,
dynamic_offsets_data_start,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 4")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)? as usize;
let len = u32::convert(
scope,
dynamic_offsets_data_length,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 5")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)? as usize;
let ab = uint_32.buffer(scope).unwrap();
let ptr = ab.data().unwrap();
let ab_len = ab.byte_length() / 4;
// SAFETY: created from an array buffer, slice is dropped at end of function call
let data = unsafe { std::slice::from_raw_parts(ptr.as_ptr() as _, ab_len) };
let offsets = &data[start..(start + len)];
// SAFETY: wgpu FFI call
unsafe {
wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group(
encoder,
index,
bind_group.into_option().map(|bind_group| bind_group.id),
offsets.as_ptr(),
offsets.len(),
);
}
} else {
let offsets = <Option<Vec<u32>>>::convert(
scope,
dynamic_offsets,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 3")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)?
.unwrap_or_default();
// SAFETY: wgpu FFI call
unsafe {
wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group(
encoder,
index,
bind_group.into_option().map(|bind_group| bind_group.id),
offsets.as_ptr(),
offsets.len(),
);
}
}
Ok(())
}
fn set_pipeline(
&self,
#[webidl] pipeline: Ptr<crate::render_pipeline::GPURenderPipeline>,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder
.as_mut()
.ok_or_else(|| JsErrorBox::generic("Encoder has already been finished"))?;
wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_pipeline(encoder, pipeline.id);
Ok(())
}
#[required(2)]
fn set_index_buffer(
&self,
#[webidl] buffer: Ptr<GPUBuffer>,
#[webidl] index_format: crate::render_pipeline::GPUIndexFormat,
#[webidl(default = 0, options(enforce_range = true))] offset: u64,
#[webidl(options(enforce_range = true))] size: Option<u64>,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder
.as_mut()
.ok_or_else(|| JsErrorBox::generic("Encoder has already been finished"))?;
encoder.set_index_buffer(
buffer.id,
index_format.into(),
offset,
size.and_then(NonZeroU64::new),
// SAFETY: wgpu FFI call
unsafe {
wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group(
encoder,
index,
bind_group.into_option().map(|bind_group| bind_group.id),
offsets.as_ptr(),
offsets.len(),
);
Ok(())
}
}
#[required(2)]
fn set_vertex_buffer(
&self,
#[webidl(options(enforce_range = true))] slot: u32,
#[webidl] buffer: Ptr<GPUBuffer>, // TODO(wgpu): support nullable buffer
#[webidl(default = 0, options(enforce_range = true))] offset: u64,
#[webidl(options(enforce_range = true))] size: Option<u64>,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder
.as_mut()
.ok_or_else(|| JsErrorBox::generic("Encoder has already been finished"))?;
Ok(())
}
wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_vertex_buffer(
encoder,
slot,
buffer.id,
offset,
size.and_then(NonZeroU64::new),
);
Ok(())
}
fn set_pipeline(
&self,
#[webidl] pipeline: Ptr<crate::render_pipeline::GPURenderPipeline>,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder.as_mut().ok_or_else(|| {
JsErrorBox::generic("Encoder has already been finished")
})?;
#[required(1)]
fn draw(
&self,
#[webidl(options(enforce_range = true))] vertex_count: u32,
#[webidl(default = 1, options(enforce_range = true))] instance_count: u32,
#[webidl(default = 0, options(enforce_range = true))] first_vertex: u32,
#[webidl(default = 0, options(enforce_range = true))] first_instance: u32,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder
.as_mut()
.ok_or_else(|| JsErrorBox::generic("Encoder has already been finished"))?;
wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_pipeline(
encoder,
pipeline.id,
);
Ok(())
}
wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw(
encoder,
vertex_count,
instance_count,
first_vertex,
first_instance,
);
Ok(())
}
#[required(2)]
fn set_index_buffer(
&self,
#[webidl] buffer: Ptr<GPUBuffer>,
#[webidl] index_format: crate::render_pipeline::GPUIndexFormat,
#[webidl(default = 0, options(enforce_range = true))] offset: u64,
#[webidl(options(enforce_range = true))] size: Option<u64>,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder.as_mut().ok_or_else(|| {
JsErrorBox::generic("Encoder has already been finished")
})?;
#[required(1)]
fn draw_indexed(
&self,
#[webidl(options(enforce_range = true))] index_count: u32,
#[webidl(default = 1, options(enforce_range = true))] instance_count: u32,
#[webidl(default = 0, options(enforce_range = true))] first_index: u32,
#[webidl(default = 0, options(enforce_range = true))] base_vertex: i32,
#[webidl(default = 0, options(enforce_range = true))] first_instance: u32,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder
.as_mut()
.ok_or_else(|| JsErrorBox::generic("Encoder has already been finished"))?;
encoder.set_index_buffer(
buffer.id,
index_format.into(),
offset,
size.and_then(NonZeroU64::new),
);
Ok(())
}
wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indexed(
encoder,
index_count,
instance_count,
first_index,
base_vertex,
first_instance,
);
Ok(())
}
#[required(2)]
fn set_vertex_buffer(
&self,
#[webidl(options(enforce_range = true))] slot: u32,
#[webidl] buffer: Ptr<GPUBuffer>, // TODO(wgpu): support nullable buffer
#[webidl(default = 0, options(enforce_range = true))] offset: u64,
#[webidl(options(enforce_range = true))] size: Option<u64>,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder.as_mut().ok_or_else(|| {
JsErrorBox::generic("Encoder has already been finished")
})?;
#[required(2)]
fn draw_indirect(
&self,
#[webidl] indirect_buffer: Ptr<GPUBuffer>,
#[webidl(options(enforce_range = true))] indirect_offset: u64,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder
.as_mut()
.ok_or_else(|| JsErrorBox::generic("Encoder has already been finished"))?;
wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_vertex_buffer(
encoder,
slot,
buffer.id,
offset,
size.and_then(NonZeroU64::new),
);
Ok(())
}
wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indirect(
encoder,
indirect_buffer.id,
indirect_offset,
);
Ok(())
}
#[required(1)]
fn draw(
&self,
#[webidl(options(enforce_range = true))] vertex_count: u32,
#[webidl(default = 1, options(enforce_range = true))] instance_count: u32,
#[webidl(default = 0, options(enforce_range = true))] first_vertex: u32,
#[webidl(default = 0, options(enforce_range = true))] first_instance: u32,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder.as_mut().ok_or_else(|| {
JsErrorBox::generic("Encoder has already been finished")
})?;
#[required(2)]
fn draw_indexed_indirect(
&self,
#[webidl] indirect_buffer: Ptr<GPUBuffer>,
#[webidl(options(enforce_range = true))] indirect_offset: u64,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder
.as_mut()
.ok_or_else(|| JsErrorBox::generic("Encoder has already been finished"))?;
wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw(
encoder,
vertex_count,
instance_count,
first_vertex,
first_instance,
);
Ok(())
}
wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indexed_indirect(
encoder,
indirect_buffer.id,
indirect_offset,
);
Ok(())
}
#[required(1)]
fn draw_indexed(
&self,
#[webidl(options(enforce_range = true))] index_count: u32,
#[webidl(default = 1, options(enforce_range = true))] instance_count: u32,
#[webidl(default = 0, options(enforce_range = true))] first_index: u32,
#[webidl(default = 0, options(enforce_range = true))] base_vertex: i32,
#[webidl(default = 0, options(enforce_range = true))] first_instance: u32,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder.as_mut().ok_or_else(|| {
JsErrorBox::generic("Encoder has already been finished")
})?;
wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indexed(
encoder,
index_count,
instance_count,
first_index,
base_vertex,
first_instance,
);
Ok(())
}
#[required(2)]
fn draw_indirect(
&self,
#[webidl] indirect_buffer: Ptr<GPUBuffer>,
#[webidl(options(enforce_range = true))] indirect_offset: u64,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder.as_mut().ok_or_else(|| {
JsErrorBox::generic("Encoder has already been finished")
})?;
wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indirect(
encoder,
indirect_buffer.id,
indirect_offset,
);
Ok(())
}
#[required(2)]
fn draw_indexed_indirect(
&self,
#[webidl] indirect_buffer: Ptr<GPUBuffer>,
#[webidl(options(enforce_range = true))] indirect_offset: u64,
) -> Result<(), JsErrorBox> {
let mut encoder = self.encoder.borrow_mut();
let encoder = encoder.as_mut().ok_or_else(|| {
JsErrorBox::generic("Encoder has already been finished")
})?;
wgpu_core::command::bundle_ffi::wgpu_render_bundle_draw_indexed_indirect(
encoder,
indirect_buffer.id,
indirect_offset,
);
Ok(())
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPURenderBundleEncoderDescriptor {
#[webidl(default = String::new())]
pub label: String,
#[webidl(default = String::new())]
pub label: String,
pub color_formats: Vec<Nullable<GPUTextureFormat>>,
pub depth_stencil_format: Option<GPUTextureFormat>,
#[webidl(default = 1)]
#[options(enforce_range = true)]
pub sample_count: u32,
pub color_formats: Vec<Nullable<GPUTextureFormat>>,
pub depth_stencil_format: Option<GPUTextureFormat>,
#[webidl(default = 1)]
#[options(enforce_range = true)]
pub sample_count: u32,
#[webidl(default = false)]
pub depth_read_only: bool,
#[webidl(default = false)]
pub stencil_read_only: bool,
#[webidl(default = false)]
pub depth_read_only: bool,
#[webidl(default = false)]
pub stencil_read_only: bool,
}
#[derive(Debug, thiserror::Error, deno_error::JsError)]
enum SetBindGroupError {
#[class(inherit)]
#[error(transparent)]
WebIDL(#[from] WebIdlError),
#[class(inherit)]
#[error(transparent)]
Other(#[from] JsErrorBox),
#[class(inherit)]
#[error(transparent)]
WebIDL(#[from] WebIdlError),
#[class(inherit)]
#[error(transparent)]
Other(#[from] JsErrorBox),
}
pub struct GPURenderBundle {
pub instance: Instance,
pub id: wgpu_core::id::RenderBundleId,
pub label: String,
pub instance: Instance,
pub id: wgpu_core::id::RenderBundleId,
pub label: String,
}
impl Drop for GPURenderBundle {
fn drop(&mut self) {
self.instance.render_bundle_drop(self.id);
}
fn drop(&mut self) {
self.instance.render_bundle_drop(self.id);
}
}
impl WebIdlInterfaceConverter for GPURenderBundle {
const NAME: &'static str = "GPURenderBundle";
const NAME: &'static str = "GPURenderBundle";
}
impl GarbageCollected for GPURenderBundle {}
#[op2]
impl GPURenderBundle {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPURenderBundleDescriptor {
#[webidl(default = String::new())]
pub label: String,
#[webidl(default = String::new())]
pub label: String,
}

View File

@ -21,456 +21,490 @@ use crate::webidl::GPUColor;
use crate::Instance;
pub struct GPURenderPassEncoder {
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub render_pass: RefCell<wgpu_core::command::RenderPass>,
pub label: String,
pub render_pass: RefCell<wgpu_core::command::RenderPass>,
pub label: String,
}
impl GarbageCollected for GPURenderPassEncoder {}
#[op2]
impl GPURenderPassEncoder {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[required(6)]
fn set_viewport(
&self,
#[webidl] x: f32,
#[webidl] y: f32,
#[webidl] width: f32,
#[webidl] height: f32,
#[webidl] min_depth: f32,
#[webidl] max_depth: f32,
) {
let err = self
.instance
.render_pass_set_viewport(
&mut self.render_pass.borrow_mut(),
x,
y,
width,
height,
min_depth,
max_depth,
)
.err();
self.error_handler.push_error(err);
}
#[required(6)]
fn set_viewport(
&self,
#[webidl] x: f32,
#[webidl] y: f32,
#[webidl] width: f32,
#[webidl] height: f32,
#[webidl] min_depth: f32,
#[webidl] max_depth: f32,
) {
let err = self
.instance
.render_pass_set_viewport(
&mut self.render_pass.borrow_mut(),
x,
y,
width,
height,
min_depth,
max_depth,
)
.err();
self.error_handler.push_error(err);
}
#[required(4)]
fn set_scissor_rect(
&self,
#[webidl(options(enforce_range = true))] x: u32,
#[webidl(options(enforce_range = true))] y: u32,
#[webidl(options(enforce_range = true))] width: u32,
#[webidl(options(enforce_range = true))] height: u32,
) {
let err = self
.instance
.render_pass_set_scissor_rect(&mut self.render_pass.borrow_mut(), x, y, width, height)
.err();
self.error_handler.push_error(err);
}
#[required(4)]
fn set_scissor_rect(
&self,
#[webidl(options(enforce_range = true))] x: u32,
#[webidl(options(enforce_range = true))] y: u32,
#[webidl(options(enforce_range = true))] width: u32,
#[webidl(options(enforce_range = true))] height: u32,
) {
let err = self
.instance
.render_pass_set_scissor_rect(
&mut self.render_pass.borrow_mut(),
x,
y,
width,
height,
)
.err();
self.error_handler.push_error(err);
}
#[required(1)]
fn set_blend_constant(&self, #[webidl] color: GPUColor) {
let err = self
.instance
.render_pass_set_blend_constant(&mut self.render_pass.borrow_mut(), color.into())
.err();
self.error_handler.push_error(err);
}
#[required(1)]
fn set_blend_constant(&self, #[webidl] color: GPUColor) {
let err = self
.instance
.render_pass_set_blend_constant(
&mut self.render_pass.borrow_mut(),
color.into(),
)
.err();
self.error_handler.push_error(err);
}
#[required(1)]
fn set_stencil_reference(&self, #[webidl(options(enforce_range = true))] reference: u32) {
let err = self
.instance
.render_pass_set_stencil_reference(&mut self.render_pass.borrow_mut(), reference)
.err();
self.error_handler.push_error(err);
}
#[required(1)]
fn set_stencil_reference(
&self,
#[webidl(options(enforce_range = true))] reference: u32,
) {
let err = self
.instance
.render_pass_set_stencil_reference(
&mut self.render_pass.borrow_mut(),
reference,
)
.err();
self.error_handler.push_error(err);
}
#[required(1)]
fn begin_occlusion_query(&self, #[webidl(options(enforce_range = true))] query_index: u32) {
let err = self
.instance
.render_pass_begin_occlusion_query(&mut self.render_pass.borrow_mut(), query_index)
.err();
self.error_handler.push_error(err);
}
#[required(1)]
fn begin_occlusion_query(
&self,
#[webidl(options(enforce_range = true))] query_index: u32,
) {
let err = self
.instance
.render_pass_begin_occlusion_query(
&mut self.render_pass.borrow_mut(),
query_index,
)
.err();
self.error_handler.push_error(err);
}
#[fast]
fn end_occlusion_query(&self) {
let err = self
.instance
.render_pass_end_occlusion_query(&mut self.render_pass.borrow_mut())
.err();
self.error_handler.push_error(err);
}
#[fast]
fn end_occlusion_query(&self) {
let err = self
.instance
.render_pass_end_occlusion_query(&mut self.render_pass.borrow_mut())
.err();
self.error_handler.push_error(err);
}
#[required(1)]
fn execute_bundles(&self, #[webidl] bundles: Vec<Ptr<GPURenderBundle>>) {
let err = self
.instance
.render_pass_execute_bundles(
&mut self.render_pass.borrow_mut(),
&bundles
.into_iter()
.map(|bundle| bundle.id)
.collect::<Vec<_>>(),
)
.err();
self.error_handler.push_error(err);
}
#[required(1)]
fn execute_bundles(&self, #[webidl] bundles: Vec<Ptr<GPURenderBundle>>) {
let err = self
.instance
.render_pass_execute_bundles(
&mut self.render_pass.borrow_mut(),
&bundles
.into_iter()
.map(|bundle| bundle.id)
.collect::<Vec<_>>(),
)
.err();
self.error_handler.push_error(err);
}
#[fast]
fn end(&self) {
let err = self
.instance
.render_pass_end(&mut self.render_pass.borrow_mut())
.err();
self.error_handler.push_error(err);
}
#[fast]
fn end(&self) {
let err = self
.instance
.render_pass_end(&mut self.render_pass.borrow_mut())
.err();
self.error_handler.push_error(err);
}
fn push_debug_group(&self, #[webidl] group_label: String) {
let err = self
.instance
.render_pass_push_debug_group(
&mut self.render_pass.borrow_mut(),
&group_label,
0, // wgpu#975
)
.err();
self.error_handler.push_error(err);
}
fn push_debug_group(&self, #[webidl] group_label: String) {
let err = self
.instance
.render_pass_push_debug_group(
&mut self.render_pass.borrow_mut(),
&group_label,
0, // wgpu#975
)
.err();
self.error_handler.push_error(err);
}
#[fast]
fn pop_debug_group(&self) {
let err = self
.instance
.render_pass_pop_debug_group(&mut self.render_pass.borrow_mut())
.err();
self.error_handler.push_error(err);
}
#[fast]
fn pop_debug_group(&self) {
let err = self
.instance
.render_pass_pop_debug_group(&mut self.render_pass.borrow_mut())
.err();
self.error_handler.push_error(err);
}
fn insert_debug_marker(&self, #[webidl] marker_label: String) {
let err = self
.instance
.render_pass_insert_debug_marker(
&mut self.render_pass.borrow_mut(),
&marker_label,
0, // wgpu#975
)
.err();
self.error_handler.push_error(err);
}
fn insert_debug_marker(&self, #[webidl] marker_label: String) {
let err = self
.instance
.render_pass_insert_debug_marker(
&mut self.render_pass.borrow_mut(),
&marker_label,
0, // wgpu#975
)
.err();
self.error_handler.push_error(err);
}
fn set_bind_group<'a>(
&self,
scope: &mut v8::HandleScope<'a>,
#[webidl(options(enforce_range = true))] index: u32,
#[webidl] bind_group: Nullable<Ptr<crate::bind_group::GPUBindGroup>>,
dynamic_offsets: v8::Local<'a, v8::Value>,
dynamic_offsets_data_start: v8::Local<'a, v8::Value>,
dynamic_offsets_data_length: v8::Local<'a, v8::Value>,
) -> Result<(), WebIdlError> {
const PREFIX: &str = "Failed to execute 'setBindGroup' on 'GPUComputePassEncoder'";
fn set_bind_group<'a>(
&self,
scope: &mut v8::HandleScope<'a>,
#[webidl(options(enforce_range = true))] index: u32,
#[webidl] bind_group: Nullable<Ptr<crate::bind_group::GPUBindGroup>>,
dynamic_offsets: v8::Local<'a, v8::Value>,
dynamic_offsets_data_start: v8::Local<'a, v8::Value>,
dynamic_offsets_data_length: v8::Local<'a, v8::Value>,
) -> Result<(), WebIdlError> {
const PREFIX: &str =
"Failed to execute 'setBindGroup' on 'GPUComputePassEncoder'";
let err = if let Ok(uint_32) = dynamic_offsets.try_cast::<v8::Uint32Array>() {
let start = u64::convert(
scope,
dynamic_offsets_data_start,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 4")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)? as usize;
let len = u32::convert(
scope,
dynamic_offsets_data_length,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 5")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)? as usize;
let err = if let Ok(uint_32) = dynamic_offsets.try_cast::<v8::Uint32Array>()
{
let start = u64::convert(
scope,
dynamic_offsets_data_start,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 4")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)? as usize;
let len = u32::convert(
scope,
dynamic_offsets_data_length,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 5")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)? as usize;
let ab = uint_32.buffer(scope).unwrap();
let ptr = ab.data().unwrap();
let ab_len = ab.byte_length() / 4;
let ab = uint_32.buffer(scope).unwrap();
let ptr = ab.data().unwrap();
let ab_len = ab.byte_length() / 4;
// SAFETY: created from an array buffer, slice is dropped at end of function call
let data = unsafe { std::slice::from_raw_parts(ptr.as_ptr() as _, ab_len) };
// SAFETY: created from an array buffer, slice is dropped at end of function call
let data =
unsafe { std::slice::from_raw_parts(ptr.as_ptr() as _, ab_len) };
let offsets = &data[start..(start + len)];
let offsets = &data[start..(start + len)];
self.instance
.render_pass_set_bind_group(
&mut self.render_pass.borrow_mut(),
index,
bind_group.into_option().map(|bind_group| bind_group.id),
offsets,
)
.err()
} else {
let offsets = <Option<Vec<u32>>>::convert(
scope,
dynamic_offsets,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 3")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)?
.unwrap_or_default();
self
.instance
.render_pass_set_bind_group(
&mut self.render_pass.borrow_mut(),
index,
bind_group.into_option().map(|bind_group| bind_group.id),
offsets,
)
.err()
} else {
let offsets = <Option<Vec<u32>>>::convert(
scope,
dynamic_offsets,
Cow::Borrowed(PREFIX),
(|| Cow::Borrowed("Argument 3")).into(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)?
.unwrap_or_default();
self.instance
.render_pass_set_bind_group(
&mut self.render_pass.borrow_mut(),
index,
bind_group.into_option().map(|bind_group| bind_group.id),
&offsets,
)
.err()
};
self
.instance
.render_pass_set_bind_group(
&mut self.render_pass.borrow_mut(),
index,
bind_group.into_option().map(|bind_group| bind_group.id),
&offsets,
)
.err()
};
self.error_handler.push_error(err);
self.error_handler.push_error(err);
Ok(())
}
Ok(())
}
fn set_pipeline(&self, #[webidl] pipeline: Ptr<crate::render_pipeline::GPURenderPipeline>) {
let err = self
.instance
.render_pass_set_pipeline(&mut self.render_pass.borrow_mut(), pipeline.id)
.err();
self.error_handler.push_error(err);
}
fn set_pipeline(
&self,
#[webidl] pipeline: Ptr<crate::render_pipeline::GPURenderPipeline>,
) {
let err = self
.instance
.render_pass_set_pipeline(&mut self.render_pass.borrow_mut(), pipeline.id)
.err();
self.error_handler.push_error(err);
}
#[required(2)]
fn set_index_buffer(
&self,
#[webidl] buffer: Ptr<GPUBuffer>,
#[webidl] index_format: crate::render_pipeline::GPUIndexFormat,
#[webidl(default = 0, options(enforce_range = true))] offset: u64,
#[webidl(options(enforce_range = true))] size: Option<u64>,
) {
let err = self
.instance
.render_pass_set_index_buffer(
&mut self.render_pass.borrow_mut(),
buffer.id,
index_format.into(),
offset,
size.and_then(NonZeroU64::new),
)
.err();
self.error_handler.push_error(err);
}
#[required(2)]
fn set_index_buffer(
&self,
#[webidl] buffer: Ptr<GPUBuffer>,
#[webidl] index_format: crate::render_pipeline::GPUIndexFormat,
#[webidl(default = 0, options(enforce_range = true))] offset: u64,
#[webidl(options(enforce_range = true))] size: Option<u64>,
) {
let err = self
.instance
.render_pass_set_index_buffer(
&mut self.render_pass.borrow_mut(),
buffer.id,
index_format.into(),
offset,
size.and_then(NonZeroU64::new),
)
.err();
self.error_handler.push_error(err);
}
#[required(2)]
fn set_vertex_buffer(
&self,
#[webidl(options(enforce_range = true))] slot: u32,
#[webidl] buffer: Ptr<GPUBuffer>, // TODO(wgpu): support nullable buffer
#[webidl(default = 0, options(enforce_range = true))] offset: u64,
#[webidl(options(enforce_range = true))] size: Option<u64>,
) {
let err = self
.instance
.render_pass_set_vertex_buffer(
&mut self.render_pass.borrow_mut(),
slot,
buffer.id,
offset,
size.and_then(NonZeroU64::new),
)
.err();
self.error_handler.push_error(err);
}
#[required(2)]
fn set_vertex_buffer(
&self,
#[webidl(options(enforce_range = true))] slot: u32,
#[webidl] buffer: Ptr<GPUBuffer>, // TODO(wgpu): support nullable buffer
#[webidl(default = 0, options(enforce_range = true))] offset: u64,
#[webidl(options(enforce_range = true))] size: Option<u64>,
) {
let err = self
.instance
.render_pass_set_vertex_buffer(
&mut self.render_pass.borrow_mut(),
slot,
buffer.id,
offset,
size.and_then(NonZeroU64::new),
)
.err();
self.error_handler.push_error(err);
}
#[required(1)]
fn draw(
&self,
#[webidl(options(enforce_range = true))] vertex_count: u32,
#[webidl(default = 1, options(enforce_range = true))] instance_count: u32,
#[webidl(default = 0, options(enforce_range = true))] first_vertex: u32,
#[webidl(default = 0, options(enforce_range = true))] first_instance: u32,
) {
let err = self
.instance
.render_pass_draw(
&mut self.render_pass.borrow_mut(),
vertex_count,
instance_count,
first_vertex,
first_instance,
)
.err();
self.error_handler.push_error(err);
}
#[required(1)]
fn draw(
&self,
#[webidl(options(enforce_range = true))] vertex_count: u32,
#[webidl(default = 1, options(enforce_range = true))] instance_count: u32,
#[webidl(default = 0, options(enforce_range = true))] first_vertex: u32,
#[webidl(default = 0, options(enforce_range = true))] first_instance: u32,
) {
let err = self
.instance
.render_pass_draw(
&mut self.render_pass.borrow_mut(),
vertex_count,
instance_count,
first_vertex,
first_instance,
)
.err();
self.error_handler.push_error(err);
}
#[required(1)]
fn draw_indexed(
&self,
#[webidl(options(enforce_range = true))] index_count: u32,
#[webidl(default = 1, options(enforce_range = true))] instance_count: u32,
#[webidl(default = 0, options(enforce_range = true))] first_index: u32,
#[webidl(default = 0, options(enforce_range = true))] base_vertex: i32,
#[webidl(default = 0, options(enforce_range = true))] first_instance: u32,
) {
let err = self
.instance
.render_pass_draw_indexed(
&mut self.render_pass.borrow_mut(),
index_count,
instance_count,
first_index,
base_vertex,
first_instance,
)
.err();
self.error_handler.push_error(err);
}
#[required(1)]
fn draw_indexed(
&self,
#[webidl(options(enforce_range = true))] index_count: u32,
#[webidl(default = 1, options(enforce_range = true))] instance_count: u32,
#[webidl(default = 0, options(enforce_range = true))] first_index: u32,
#[webidl(default = 0, options(enforce_range = true))] base_vertex: i32,
#[webidl(default = 0, options(enforce_range = true))] first_instance: u32,
) {
let err = self
.instance
.render_pass_draw_indexed(
&mut self.render_pass.borrow_mut(),
index_count,
instance_count,
first_index,
base_vertex,
first_instance,
)
.err();
self.error_handler.push_error(err);
}
#[required(2)]
fn draw_indirect(
&self,
#[webidl] indirect_buffer: Ptr<GPUBuffer>,
#[webidl(options(enforce_range = true))] indirect_offset: u64,
) {
let err = self
.instance
.render_pass_draw_indirect(
&mut self.render_pass.borrow_mut(),
indirect_buffer.id,
indirect_offset,
)
.err();
self.error_handler.push_error(err);
}
#[required(2)]
fn draw_indirect(
&self,
#[webidl] indirect_buffer: Ptr<GPUBuffer>,
#[webidl(options(enforce_range = true))] indirect_offset: u64,
) {
let err = self
.instance
.render_pass_draw_indirect(
&mut self.render_pass.borrow_mut(),
indirect_buffer.id,
indirect_offset,
)
.err();
self.error_handler.push_error(err);
}
#[required(2)]
fn draw_indexed_indirect(
&self,
#[webidl] indirect_buffer: Ptr<GPUBuffer>,
#[webidl(options(enforce_range = true))] indirect_offset: u64,
) {
let err = self
.instance
.render_pass_draw_indexed_indirect(
&mut self.render_pass.borrow_mut(),
indirect_buffer.id,
indirect_offset,
)
.err();
self.error_handler.push_error(err);
}
#[required(2)]
fn draw_indexed_indirect(
&self,
#[webidl] indirect_buffer: Ptr<GPUBuffer>,
#[webidl(options(enforce_range = true))] indirect_offset: u64,
) {
let err = self
.instance
.render_pass_draw_indexed_indirect(
&mut self.render_pass.borrow_mut(),
indirect_buffer.id,
indirect_offset,
)
.err();
self.error_handler.push_error(err);
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPURenderPassDescriptor {
#[webidl(default = String::new())]
pub label: String,
#[webidl(default = String::new())]
pub label: String,
pub color_attachments: Vec<Nullable<GPURenderPassColorAttachment>>,
pub depth_stencil_attachment: Option<GPURenderPassDepthStencilAttachment>,
pub occlusion_query_set: Option<Ptr<crate::query_set::GPUQuerySet>>,
pub timestamp_writes: Option<GPURenderPassTimestampWrites>,
/*#[webidl(default = 50000000)]
#[options(enforce_range = true)]
pub max_draw_count: u64,*/
pub color_attachments: Vec<Nullable<GPURenderPassColorAttachment>>,
pub depth_stencil_attachment: Option<GPURenderPassDepthStencilAttachment>,
pub occlusion_query_set: Option<Ptr<crate::query_set::GPUQuerySet>>,
pub timestamp_writes: Option<GPURenderPassTimestampWrites>,
/*#[webidl(default = 50000000)]
#[options(enforce_range = true)]
pub max_draw_count: u64,*/
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPURenderPassColorAttachment {
pub view: Ptr<GPUTextureView>,
#[options(enforce_range = true)]
pub depth_slice: Option<u32>,
pub resolve_target: Option<Ptr<GPUTextureView>>,
pub clear_value: Option<GPUColor>,
pub load_op: GPULoadOp,
pub store_op: GPUStoreOp,
pub view: Ptr<GPUTextureView>,
#[options(enforce_range = true)]
pub depth_slice: Option<u32>,
pub resolve_target: Option<Ptr<GPUTextureView>>,
pub clear_value: Option<GPUColor>,
pub load_op: GPULoadOp,
pub store_op: GPUStoreOp,
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPULoadOp {
Load,
Clear,
Load,
Clear,
}
impl GPULoadOp {
pub fn with_default_value<V: Default>(self, val: Option<V>) -> wgpu_core::command::LoadOp<V> {
match self {
GPULoadOp::Load => wgpu_core::command::LoadOp::Load,
GPULoadOp::Clear => wgpu_core::command::LoadOp::Clear(val.unwrap_or_default()),
}
pub fn with_default_value<V: Default>(
self,
val: Option<V>,
) -> wgpu_core::command::LoadOp<V> {
match self {
GPULoadOp::Load => wgpu_core::command::LoadOp::Load,
GPULoadOp::Clear => {
wgpu_core::command::LoadOp::Clear(val.unwrap_or_default())
}
}
}
pub fn with_value<V>(self, val: V) -> wgpu_core::command::LoadOp<V> {
match self {
GPULoadOp::Load => wgpu_core::command::LoadOp::Load,
GPULoadOp::Clear => wgpu_core::command::LoadOp::Clear(val),
}
pub fn with_value<V>(self, val: V) -> wgpu_core::command::LoadOp<V> {
match self {
GPULoadOp::Load => wgpu_core::command::LoadOp::Load,
GPULoadOp::Clear => wgpu_core::command::LoadOp::Clear(val),
}
}
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUStoreOp {
Store,
Discard,
Store,
Discard,
}
impl From<GPUStoreOp> for wgpu_core::command::StoreOp {
fn from(value: GPUStoreOp) -> Self {
match value {
GPUStoreOp::Store => Self::Store,
GPUStoreOp::Discard => Self::Discard,
}
fn from(value: GPUStoreOp) -> Self {
match value {
GPUStoreOp::Store => Self::Store,
GPUStoreOp::Discard => Self::Discard,
}
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPURenderPassDepthStencilAttachment {
pub view: Ptr<GPUTextureView>,
pub depth_clear_value: Option<f32>,
pub depth_load_op: Option<GPULoadOp>,
pub depth_store_op: Option<GPUStoreOp>,
#[webidl(default = false)]
pub depth_read_only: bool,
#[webidl(default = 0)]
#[options(enforce_range = true)]
pub stencil_clear_value: u32,
pub stencil_load_op: Option<GPULoadOp>,
pub stencil_store_op: Option<GPUStoreOp>,
#[webidl(default = false)]
pub stencil_read_only: bool,
pub view: Ptr<GPUTextureView>,
pub depth_clear_value: Option<f32>,
pub depth_load_op: Option<GPULoadOp>,
pub depth_store_op: Option<GPUStoreOp>,
#[webidl(default = false)]
pub depth_read_only: bool,
#[webidl(default = 0)]
#[options(enforce_range = true)]
pub stencil_clear_value: u32,
pub stencil_load_op: Option<GPULoadOp>,
pub stencil_store_op: Option<GPUStoreOp>,
#[webidl(default = false)]
pub stencil_read_only: bool,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPURenderPassTimestampWrites {
pub query_set: Ptr<crate::query_set::GPUQuerySet>,
#[options(enforce_range = true)]
pub beginning_of_pass_write_index: Option<u32>,
#[options(enforce_range = true)]
pub end_of_pass_write_index: Option<u32>,
pub query_set: Ptr<crate::query_set::GPUQuerySet>,
#[options(enforce_range = true)]
pub beginning_of_pass_write_index: Option<u32>,
#[options(enforce_range = true)]
pub end_of_pass_write_index: Option<u32>,
}

View File

@ -16,535 +16,535 @@ use crate::webidl::GPUPipelineLayoutOrGPUAutoLayoutMode;
use crate::Instance;
pub struct GPURenderPipeline {
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub instance: Instance,
pub error_handler: super::error::ErrorHandler,
pub id: wgpu_core::id::RenderPipelineId,
pub label: String,
pub id: wgpu_core::id::RenderPipelineId,
pub label: String,
}
impl Drop for GPURenderPipeline {
fn drop(&mut self) {
self.instance.render_pipeline_drop(self.id);
}
fn drop(&mut self) {
self.instance.render_pipeline_drop(self.id);
}
}
impl WebIdlInterfaceConverter for GPURenderPipeline {
const NAME: &'static str = "GPURenderPipeline";
const NAME: &'static str = "GPURenderPipeline";
}
impl GarbageCollected for GPURenderPipeline {}
#[op2]
impl GPURenderPipeline {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[cppgc]
fn get_bind_group_layout(&self, #[webidl] index: u32) -> GPUBindGroupLayout {
let (id, err) = self
.instance
.render_pipeline_get_bind_group_layout(self.id, index, None);
#[cppgc]
fn get_bind_group_layout(&self, #[webidl] index: u32) -> GPUBindGroupLayout {
let (id, err) = self
.instance
.render_pipeline_get_bind_group_layout(self.id, index, None);
self.error_handler.push_error(err);
self.error_handler.push_error(err);
// TODO(wgpu): needs to add a way to retrieve the label
GPUBindGroupLayout {
instance: self.instance.clone(),
id,
label: "".to_string(),
}
// TODO(wgpu): needs to add a way to retrieve the label
GPUBindGroupLayout {
instance: self.instance.clone(),
id,
label: "".to_string(),
}
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPURenderPipelineDescriptor {
#[webidl(default = String::new())]
pub label: String,
#[webidl(default = String::new())]
pub label: String,
pub layout: GPUPipelineLayoutOrGPUAutoLayoutMode,
pub vertex: GPUVertexState,
pub primitive: GPUPrimitiveState,
pub depth_stencil: Option<GPUDepthStencilState>,
pub multisample: GPUMultisampleState,
pub fragment: Option<GPUFragmentState>,
pub layout: GPUPipelineLayoutOrGPUAutoLayoutMode,
pub vertex: GPUVertexState,
pub primitive: GPUPrimitiveState,
pub depth_stencil: Option<GPUDepthStencilState>,
pub multisample: GPUMultisampleState,
pub fragment: Option<GPUFragmentState>,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUMultisampleState {
#[webidl(default = 1)]
#[options(enforce_range = true)]
pub count: u32,
#[webidl(default = 0xFFFFFFFF)]
#[options(enforce_range = true)]
pub mask: u32,
#[webidl(default = false)]
pub alpha_to_coverage_enabled: bool,
#[webidl(default = 1)]
#[options(enforce_range = true)]
pub count: u32,
#[webidl(default = 0xFFFFFFFF)]
#[options(enforce_range = true)]
pub mask: u32,
#[webidl(default = false)]
pub alpha_to_coverage_enabled: bool,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUDepthStencilState {
pub format: GPUTextureFormat,
pub depth_write_enabled: Option<bool>,
pub depth_compare: Option<GPUCompareFunction>,
pub stencil_front: GPUStencilFaceState,
pub stencil_back: GPUStencilFaceState,
#[webidl(default = 0xFFFFFFFF)]
#[options(enforce_range = true)]
pub stencil_read_mask: u32,
#[webidl(default = 0xFFFFFFFF)]
#[options(enforce_range = true)]
pub stencil_write_mask: u32,
#[webidl(default = 0)]
#[options(enforce_range = true)]
pub depth_bias: i32,
#[webidl(default = 0.0)]
pub depth_bias_slope_scale: f32,
#[webidl(default = 0.0)]
pub depth_bias_clamp: f32,
pub format: GPUTextureFormat,
pub depth_write_enabled: Option<bool>,
pub depth_compare: Option<GPUCompareFunction>,
pub stencil_front: GPUStencilFaceState,
pub stencil_back: GPUStencilFaceState,
#[webidl(default = 0xFFFFFFFF)]
#[options(enforce_range = true)]
pub stencil_read_mask: u32,
#[webidl(default = 0xFFFFFFFF)]
#[options(enforce_range = true)]
pub stencil_write_mask: u32,
#[webidl(default = 0)]
#[options(enforce_range = true)]
pub depth_bias: i32,
#[webidl(default = 0.0)]
pub depth_bias_slope_scale: f32,
#[webidl(default = 0.0)]
pub depth_bias_clamp: f32,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUStencilFaceState {
#[webidl(default = GPUCompareFunction::Always)]
pub compare: GPUCompareFunction,
#[webidl(default = GPUStencilOperation::Keep)]
pub fail_op: GPUStencilOperation,
#[webidl(default = GPUStencilOperation::Keep)]
pub depth_fail_op: GPUStencilOperation,
#[webidl(default = GPUStencilOperation::Keep)]
pub pass_op: GPUStencilOperation,
#[webidl(default = GPUCompareFunction::Always)]
pub compare: GPUCompareFunction,
#[webidl(default = GPUStencilOperation::Keep)]
pub fail_op: GPUStencilOperation,
#[webidl(default = GPUStencilOperation::Keep)]
pub depth_fail_op: GPUStencilOperation,
#[webidl(default = GPUStencilOperation::Keep)]
pub pass_op: GPUStencilOperation,
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUStencilOperation {
Keep,
Zero,
Replace,
Invert,
IncrementClamp,
DecrementClamp,
IncrementWrap,
DecrementWrap,
Keep,
Zero,
Replace,
Invert,
IncrementClamp,
DecrementClamp,
IncrementWrap,
DecrementWrap,
}
impl From<GPUStencilOperation> for wgpu_types::StencilOperation {
fn from(value: GPUStencilOperation) -> Self {
match value {
GPUStencilOperation::Keep => Self::Keep,
GPUStencilOperation::Zero => Self::Zero,
GPUStencilOperation::Replace => Self::Replace,
GPUStencilOperation::Invert => Self::Invert,
GPUStencilOperation::IncrementClamp => Self::IncrementClamp,
GPUStencilOperation::DecrementClamp => Self::DecrementClamp,
GPUStencilOperation::IncrementWrap => Self::IncrementWrap,
GPUStencilOperation::DecrementWrap => Self::DecrementWrap,
}
fn from(value: GPUStencilOperation) -> Self {
match value {
GPUStencilOperation::Keep => Self::Keep,
GPUStencilOperation::Zero => Self::Zero,
GPUStencilOperation::Replace => Self::Replace,
GPUStencilOperation::Invert => Self::Invert,
GPUStencilOperation::IncrementClamp => Self::IncrementClamp,
GPUStencilOperation::DecrementClamp => Self::DecrementClamp,
GPUStencilOperation::IncrementWrap => Self::IncrementWrap,
GPUStencilOperation::DecrementWrap => Self::DecrementWrap,
}
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUVertexState {
pub module: Ptr<GPUShaderModule>,
pub entry_point: Option<String>,
#[webidl(default = Default::default())]
pub constants: IndexMap<String, f64>,
#[webidl(default = vec![])]
pub buffers: Vec<Nullable<GPUVertexBufferLayout>>,
pub module: Ptr<GPUShaderModule>,
pub entry_point: Option<String>,
#[webidl(default = Default::default())]
pub constants: IndexMap<String, f64>,
#[webidl(default = vec![])]
pub buffers: Vec<Nullable<GPUVertexBufferLayout>>,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUFragmentState {
pub module: Ptr<GPUShaderModule>,
pub entry_point: Option<String>,
#[webidl(default = Default::default())]
pub constants: IndexMap<String, f64>,
pub targets: Vec<Nullable<GPUColorTargetState>>,
pub module: Ptr<GPUShaderModule>,
pub entry_point: Option<String>,
#[webidl(default = Default::default())]
pub constants: IndexMap<String, f64>,
pub targets: Vec<Nullable<GPUColorTargetState>>,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUColorTargetState {
pub format: GPUTextureFormat,
pub blend: Option<GPUBlendState>,
#[webidl(default = 0xF)]
#[options(enforce_range = true)]
pub write_mask: u32,
pub format: GPUTextureFormat,
pub blend: Option<GPUBlendState>,
#[webidl(default = 0xF)]
#[options(enforce_range = true)]
pub write_mask: u32,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUBlendState {
pub color: GPUBlendComponent,
pub alpha: GPUBlendComponent,
pub color: GPUBlendComponent,
pub alpha: GPUBlendComponent,
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUBlendComponent {
#[webidl(default = GPUBlendOperation::Add)]
pub operation: GPUBlendOperation,
#[webidl(default = GPUBlendFactor::One)]
pub src_factor: GPUBlendFactor,
#[webidl(default = GPUBlendFactor::Zero)]
pub dst_factor: GPUBlendFactor,
#[webidl(default = GPUBlendOperation::Add)]
pub operation: GPUBlendOperation,
#[webidl(default = GPUBlendFactor::One)]
pub src_factor: GPUBlendFactor,
#[webidl(default = GPUBlendFactor::Zero)]
pub dst_factor: GPUBlendFactor,
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUBlendOperation {
Add,
Subtract,
ReverseSubtract,
Min,
Max,
Add,
Subtract,
ReverseSubtract,
Min,
Max,
}
impl From<GPUBlendOperation> for wgpu_types::BlendOperation {
fn from(value: GPUBlendOperation) -> Self {
match value {
GPUBlendOperation::Add => Self::Add,
GPUBlendOperation::Subtract => Self::Subtract,
GPUBlendOperation::ReverseSubtract => Self::ReverseSubtract,
GPUBlendOperation::Min => Self::Min,
GPUBlendOperation::Max => Self::Max,
}
fn from(value: GPUBlendOperation) -> Self {
match value {
GPUBlendOperation::Add => Self::Add,
GPUBlendOperation::Subtract => Self::Subtract,
GPUBlendOperation::ReverseSubtract => Self::ReverseSubtract,
GPUBlendOperation::Min => Self::Min,
GPUBlendOperation::Max => Self::Max,
}
}
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUBlendFactor {
#[webidl(rename = "zero")]
Zero,
#[webidl(rename = "one")]
One,
#[webidl(rename = "src")]
Src,
#[webidl(rename = "one-minus-src")]
OneMinusSrc,
#[webidl(rename = "src-alpha")]
SrcAlpha,
#[webidl(rename = "one-minus-src-alpha")]
OneMinusSrcAlpha,
#[webidl(rename = "dst")]
Dst,
#[webidl(rename = "one-minus-dst")]
OneMinusDst,
#[webidl(rename = "dst-alpha")]
DstAlpha,
#[webidl(rename = "one-minus-dst-alpha")]
OneMinusDstAlpha,
#[webidl(rename = "src-alpha-saturated")]
SrcAlphaSaturated,
#[webidl(rename = "constant")]
Constant,
#[webidl(rename = "one-minus-constant")]
OneMinusConstant,
#[webidl(rename = "src1")]
Src1,
#[webidl(rename = "one-minus-src1")]
OneMinusSrc1,
#[webidl(rename = "src1-alpha")]
Src1Alpha,
#[webidl(rename = "one-minus-src1-alpha")]
OneMinusSrc1Alpha,
#[webidl(rename = "zero")]
Zero,
#[webidl(rename = "one")]
One,
#[webidl(rename = "src")]
Src,
#[webidl(rename = "one-minus-src")]
OneMinusSrc,
#[webidl(rename = "src-alpha")]
SrcAlpha,
#[webidl(rename = "one-minus-src-alpha")]
OneMinusSrcAlpha,
#[webidl(rename = "dst")]
Dst,
#[webidl(rename = "one-minus-dst")]
OneMinusDst,
#[webidl(rename = "dst-alpha")]
DstAlpha,
#[webidl(rename = "one-minus-dst-alpha")]
OneMinusDstAlpha,
#[webidl(rename = "src-alpha-saturated")]
SrcAlphaSaturated,
#[webidl(rename = "constant")]
Constant,
#[webidl(rename = "one-minus-constant")]
OneMinusConstant,
#[webidl(rename = "src1")]
Src1,
#[webidl(rename = "one-minus-src1")]
OneMinusSrc1,
#[webidl(rename = "src1-alpha")]
Src1Alpha,
#[webidl(rename = "one-minus-src1-alpha")]
OneMinusSrc1Alpha,
}
impl From<GPUBlendFactor> for wgpu_types::BlendFactor {
fn from(value: GPUBlendFactor) -> Self {
match value {
GPUBlendFactor::Zero => Self::Zero,
GPUBlendFactor::One => Self::One,
GPUBlendFactor::Src => Self::Src,
GPUBlendFactor::OneMinusSrc => Self::OneMinusSrc,
GPUBlendFactor::SrcAlpha => Self::SrcAlpha,
GPUBlendFactor::OneMinusSrcAlpha => Self::OneMinusSrcAlpha,
GPUBlendFactor::Dst => Self::Dst,
GPUBlendFactor::OneMinusDst => Self::OneMinusDst,
GPUBlendFactor::DstAlpha => Self::DstAlpha,
GPUBlendFactor::OneMinusDstAlpha => Self::OneMinusDstAlpha,
GPUBlendFactor::SrcAlphaSaturated => Self::SrcAlphaSaturated,
GPUBlendFactor::Constant => Self::Constant,
GPUBlendFactor::OneMinusConstant => Self::OneMinusConstant,
GPUBlendFactor::Src1 => Self::Src1,
GPUBlendFactor::OneMinusSrc1 => Self::OneMinusSrc1,
GPUBlendFactor::Src1Alpha => Self::Src1Alpha,
GPUBlendFactor::OneMinusSrc1Alpha => Self::OneMinusSrc1Alpha,
}
fn from(value: GPUBlendFactor) -> Self {
match value {
GPUBlendFactor::Zero => Self::Zero,
GPUBlendFactor::One => Self::One,
GPUBlendFactor::Src => Self::Src,
GPUBlendFactor::OneMinusSrc => Self::OneMinusSrc,
GPUBlendFactor::SrcAlpha => Self::SrcAlpha,
GPUBlendFactor::OneMinusSrcAlpha => Self::OneMinusSrcAlpha,
GPUBlendFactor::Dst => Self::Dst,
GPUBlendFactor::OneMinusDst => Self::OneMinusDst,
GPUBlendFactor::DstAlpha => Self::DstAlpha,
GPUBlendFactor::OneMinusDstAlpha => Self::OneMinusDstAlpha,
GPUBlendFactor::SrcAlphaSaturated => Self::SrcAlphaSaturated,
GPUBlendFactor::Constant => Self::Constant,
GPUBlendFactor::OneMinusConstant => Self::OneMinusConstant,
GPUBlendFactor::Src1 => Self::Src1,
GPUBlendFactor::OneMinusSrc1 => Self::OneMinusSrc1,
GPUBlendFactor::Src1Alpha => Self::Src1Alpha,
GPUBlendFactor::OneMinusSrc1Alpha => Self::OneMinusSrc1Alpha,
}
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUPrimitiveState {
#[webidl(default = GPUPrimitiveTopology::TriangleList)]
pub topology: GPUPrimitiveTopology,
pub strip_index_format: Option<GPUIndexFormat>,
#[webidl(default = GPUFrontFace::Ccw)]
pub front_face: GPUFrontFace,
#[webidl(default = GPUCullMode::None)]
pub cull_mode: GPUCullMode,
#[webidl(default = false)]
pub unclipped_depth: bool,
#[webidl(default = GPUPrimitiveTopology::TriangleList)]
pub topology: GPUPrimitiveTopology,
pub strip_index_format: Option<GPUIndexFormat>,
#[webidl(default = GPUFrontFace::Ccw)]
pub front_face: GPUFrontFace,
#[webidl(default = GPUCullMode::None)]
pub cull_mode: GPUCullMode,
#[webidl(default = false)]
pub unclipped_depth: bool,
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUPrimitiveTopology {
PointList,
LineList,
LineStrip,
TriangleList,
TriangleStrip,
PointList,
LineList,
LineStrip,
TriangleList,
TriangleStrip,
}
impl From<GPUPrimitiveTopology> for wgpu_types::PrimitiveTopology {
fn from(value: GPUPrimitiveTopology) -> Self {
match value {
GPUPrimitiveTopology::PointList => Self::PointList,
GPUPrimitiveTopology::LineList => Self::LineList,
GPUPrimitiveTopology::LineStrip => Self::LineStrip,
GPUPrimitiveTopology::TriangleList => Self::TriangleList,
GPUPrimitiveTopology::TriangleStrip => Self::TriangleStrip,
}
fn from(value: GPUPrimitiveTopology) -> Self {
match value {
GPUPrimitiveTopology::PointList => Self::PointList,
GPUPrimitiveTopology::LineList => Self::LineList,
GPUPrimitiveTopology::LineStrip => Self::LineStrip,
GPUPrimitiveTopology::TriangleList => Self::TriangleList,
GPUPrimitiveTopology::TriangleStrip => Self::TriangleStrip,
}
}
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUIndexFormat {
#[webidl(rename = "uint16")]
Uint16,
#[webidl(rename = "uint32")]
Uint32,
#[webidl(rename = "uint16")]
Uint16,
#[webidl(rename = "uint32")]
Uint32,
}
impl From<GPUIndexFormat> for wgpu_types::IndexFormat {
fn from(value: GPUIndexFormat) -> Self {
match value {
GPUIndexFormat::Uint16 => Self::Uint16,
GPUIndexFormat::Uint32 => Self::Uint32,
}
fn from(value: GPUIndexFormat) -> Self {
match value {
GPUIndexFormat::Uint16 => Self::Uint16,
GPUIndexFormat::Uint32 => Self::Uint32,
}
}
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUFrontFace {
Ccw,
Cw,
Ccw,
Cw,
}
impl From<GPUFrontFace> for wgpu_types::FrontFace {
fn from(value: GPUFrontFace) -> Self {
match value {
GPUFrontFace::Ccw => Self::Ccw,
GPUFrontFace::Cw => Self::Cw,
}
fn from(value: GPUFrontFace) -> Self {
match value {
GPUFrontFace::Ccw => Self::Ccw,
GPUFrontFace::Cw => Self::Cw,
}
}
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUCullMode {
None,
Front,
Back,
None,
Front,
Back,
}
impl From<GPUCullMode> for Option<wgpu_types::Face> {
fn from(value: GPUCullMode) -> Self {
match value {
GPUCullMode::None => None,
GPUCullMode::Front => Some(wgpu_types::Face::Front),
GPUCullMode::Back => Some(wgpu_types::Face::Back),
}
fn from(value: GPUCullMode) -> Self {
match value {
GPUCullMode::None => None,
GPUCullMode::Front => Some(wgpu_types::Face::Front),
GPUCullMode::Back => Some(wgpu_types::Face::Back),
}
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUVertexBufferLayout {
#[options(enforce_range = true)]
pub array_stride: u64,
#[webidl(default = GPUVertexStepMode::Vertex)]
pub step_mode: GPUVertexStepMode,
pub attributes: Vec<GPUVertexAttribute>,
#[options(enforce_range = true)]
pub array_stride: u64,
#[webidl(default = GPUVertexStepMode::Vertex)]
pub step_mode: GPUVertexStepMode,
pub attributes: Vec<GPUVertexAttribute>,
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUVertexStepMode {
Vertex,
Instance,
Vertex,
Instance,
}
impl From<GPUVertexStepMode> for wgpu_types::VertexStepMode {
fn from(value: GPUVertexStepMode) -> Self {
match value {
GPUVertexStepMode::Vertex => Self::Vertex,
GPUVertexStepMode::Instance => Self::Instance,
}
fn from(value: GPUVertexStepMode) -> Self {
match value {
GPUVertexStepMode::Vertex => Self::Vertex,
GPUVertexStepMode::Instance => Self::Instance,
}
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUVertexAttribute {
pub format: GPUVertexFormat,
#[options(enforce_range = true)]
pub offset: u64,
#[options(enforce_range = true)]
pub shader_location: u32,
pub format: GPUVertexFormat,
#[options(enforce_range = true)]
pub offset: u64,
#[options(enforce_range = true)]
pub shader_location: u32,
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUVertexFormat {
#[webidl(rename = "uint8")]
Uint8,
#[webidl(rename = "uint8x2")]
Uint8x2,
#[webidl(rename = "uint8x4")]
Uint8x4,
#[webidl(rename = "sint8")]
Sint8,
#[webidl(rename = "sint8x2")]
Sint8x2,
#[webidl(rename = "sint8x4")]
Sint8x4,
#[webidl(rename = "unorm8")]
Unorm8,
#[webidl(rename = "unorm8x2")]
Unorm8x2,
#[webidl(rename = "unorm8x4")]
Unorm8x4,
#[webidl(rename = "snorm8")]
Snorm8,
#[webidl(rename = "snorm8x2")]
Snorm8x2,
#[webidl(rename = "snorm8x4")]
Snorm8x4,
#[webidl(rename = "uint16")]
Uint16,
#[webidl(rename = "uint16x2")]
Uint16x2,
#[webidl(rename = "uint16x4")]
Uint16x4,
#[webidl(rename = "sint16")]
Sint16,
#[webidl(rename = "sint16x2")]
Sint16x2,
#[webidl(rename = "sint16x4")]
Sint16x4,
#[webidl(rename = "unorm16")]
Unorm16,
#[webidl(rename = "unorm16x2")]
Unorm16x2,
#[webidl(rename = "unorm16x4")]
Unorm16x4,
#[webidl(rename = "snorm16")]
Snorm16,
#[webidl(rename = "snorm16x2")]
Snorm16x2,
#[webidl(rename = "snorm16x4")]
Snorm16x4,
#[webidl(rename = "float16")]
Float16,
#[webidl(rename = "float16x2")]
Float16x2,
#[webidl(rename = "float16x4")]
Float16x4,
#[webidl(rename = "float32")]
Float32,
#[webidl(rename = "float32x2")]
Float32x2,
#[webidl(rename = "float32x3")]
Float32x3,
#[webidl(rename = "float32x4")]
Float32x4,
#[webidl(rename = "uint32")]
Uint32,
#[webidl(rename = "uint32x2")]
Uint32x2,
#[webidl(rename = "uint32x3")]
Uint32x3,
#[webidl(rename = "uint32x4")]
Uint32x4,
#[webidl(rename = "sint32")]
Sint32,
#[webidl(rename = "sint32x2")]
Sint32x2,
#[webidl(rename = "sint32x3")]
Sint32x3,
#[webidl(rename = "sint32x4")]
Sint32x4,
#[webidl(rename = "unorm10-10-10-2")]
Unorm1010102,
#[webidl(rename = "unorm8x4-bgra")]
Unorm8x4Bgra,
#[webidl(rename = "uint8")]
Uint8,
#[webidl(rename = "uint8x2")]
Uint8x2,
#[webidl(rename = "uint8x4")]
Uint8x4,
#[webidl(rename = "sint8")]
Sint8,
#[webidl(rename = "sint8x2")]
Sint8x2,
#[webidl(rename = "sint8x4")]
Sint8x4,
#[webidl(rename = "unorm8")]
Unorm8,
#[webidl(rename = "unorm8x2")]
Unorm8x2,
#[webidl(rename = "unorm8x4")]
Unorm8x4,
#[webidl(rename = "snorm8")]
Snorm8,
#[webidl(rename = "snorm8x2")]
Snorm8x2,
#[webidl(rename = "snorm8x4")]
Snorm8x4,
#[webidl(rename = "uint16")]
Uint16,
#[webidl(rename = "uint16x2")]
Uint16x2,
#[webidl(rename = "uint16x4")]
Uint16x4,
#[webidl(rename = "sint16")]
Sint16,
#[webidl(rename = "sint16x2")]
Sint16x2,
#[webidl(rename = "sint16x4")]
Sint16x4,
#[webidl(rename = "unorm16")]
Unorm16,
#[webidl(rename = "unorm16x2")]
Unorm16x2,
#[webidl(rename = "unorm16x4")]
Unorm16x4,
#[webidl(rename = "snorm16")]
Snorm16,
#[webidl(rename = "snorm16x2")]
Snorm16x2,
#[webidl(rename = "snorm16x4")]
Snorm16x4,
#[webidl(rename = "float16")]
Float16,
#[webidl(rename = "float16x2")]
Float16x2,
#[webidl(rename = "float16x4")]
Float16x4,
#[webidl(rename = "float32")]
Float32,
#[webidl(rename = "float32x2")]
Float32x2,
#[webidl(rename = "float32x3")]
Float32x3,
#[webidl(rename = "float32x4")]
Float32x4,
#[webidl(rename = "uint32")]
Uint32,
#[webidl(rename = "uint32x2")]
Uint32x2,
#[webidl(rename = "uint32x3")]
Uint32x3,
#[webidl(rename = "uint32x4")]
Uint32x4,
#[webidl(rename = "sint32")]
Sint32,
#[webidl(rename = "sint32x2")]
Sint32x2,
#[webidl(rename = "sint32x3")]
Sint32x3,
#[webidl(rename = "sint32x4")]
Sint32x4,
#[webidl(rename = "unorm10-10-10-2")]
Unorm1010102,
#[webidl(rename = "unorm8x4-bgra")]
Unorm8x4Bgra,
}
impl From<GPUVertexFormat> for wgpu_types::VertexFormat {
fn from(value: GPUVertexFormat) -> Self {
match value {
GPUVertexFormat::Uint8 => Self::Uint8,
GPUVertexFormat::Uint8x2 => Self::Uint8x2,
GPUVertexFormat::Uint8x4 => Self::Uint8x4,
GPUVertexFormat::Sint8 => Self::Sint8,
GPUVertexFormat::Sint8x2 => Self::Sint8x2,
GPUVertexFormat::Sint8x4 => Self::Sint8x4,
GPUVertexFormat::Unorm8 => Self::Unorm8,
GPUVertexFormat::Unorm8x2 => Self::Unorm8x2,
GPUVertexFormat::Unorm8x4 => Self::Unorm8x4,
GPUVertexFormat::Snorm8 => Self::Snorm8,
GPUVertexFormat::Snorm8x2 => Self::Snorm8x2,
GPUVertexFormat::Snorm8x4 => Self::Snorm8x4,
GPUVertexFormat::Uint16 => Self::Uint16,
GPUVertexFormat::Uint16x2 => Self::Uint16x2,
GPUVertexFormat::Uint16x4 => Self::Uint16x4,
GPUVertexFormat::Sint16 => Self::Sint16,
GPUVertexFormat::Sint16x2 => Self::Sint16x2,
GPUVertexFormat::Sint16x4 => Self::Sint16x4,
GPUVertexFormat::Unorm16 => Self::Unorm16,
GPUVertexFormat::Unorm16x2 => Self::Unorm16x2,
GPUVertexFormat::Unorm16x4 => Self::Unorm16x4,
GPUVertexFormat::Snorm16 => Self::Snorm16,
GPUVertexFormat::Snorm16x2 => Self::Snorm16x2,
GPUVertexFormat::Snorm16x4 => Self::Snorm16x4,
GPUVertexFormat::Float16 => Self::Float16,
GPUVertexFormat::Float16x2 => Self::Float16x2,
GPUVertexFormat::Float16x4 => Self::Float16x4,
GPUVertexFormat::Float32 => Self::Float32,
GPUVertexFormat::Float32x2 => Self::Float32x2,
GPUVertexFormat::Float32x3 => Self::Float32x3,
GPUVertexFormat::Float32x4 => Self::Float32x4,
GPUVertexFormat::Uint32 => Self::Uint32,
GPUVertexFormat::Uint32x2 => Self::Uint32x2,
GPUVertexFormat::Uint32x3 => Self::Uint32x3,
GPUVertexFormat::Uint32x4 => Self::Uint32x4,
GPUVertexFormat::Sint32 => Self::Sint32,
GPUVertexFormat::Sint32x2 => Self::Sint32x2,
GPUVertexFormat::Sint32x3 => Self::Sint32x3,
GPUVertexFormat::Sint32x4 => Self::Sint32x4,
GPUVertexFormat::Unorm1010102 => Self::Unorm10_10_10_2,
GPUVertexFormat::Unorm8x4Bgra => Self::Unorm8x4Bgra,
}
fn from(value: GPUVertexFormat) -> Self {
match value {
GPUVertexFormat::Uint8 => Self::Uint8,
GPUVertexFormat::Uint8x2 => Self::Uint8x2,
GPUVertexFormat::Uint8x4 => Self::Uint8x4,
GPUVertexFormat::Sint8 => Self::Sint8,
GPUVertexFormat::Sint8x2 => Self::Sint8x2,
GPUVertexFormat::Sint8x4 => Self::Sint8x4,
GPUVertexFormat::Unorm8 => Self::Unorm8,
GPUVertexFormat::Unorm8x2 => Self::Unorm8x2,
GPUVertexFormat::Unorm8x4 => Self::Unorm8x4,
GPUVertexFormat::Snorm8 => Self::Snorm8,
GPUVertexFormat::Snorm8x2 => Self::Snorm8x2,
GPUVertexFormat::Snorm8x4 => Self::Snorm8x4,
GPUVertexFormat::Uint16 => Self::Uint16,
GPUVertexFormat::Uint16x2 => Self::Uint16x2,
GPUVertexFormat::Uint16x4 => Self::Uint16x4,
GPUVertexFormat::Sint16 => Self::Sint16,
GPUVertexFormat::Sint16x2 => Self::Sint16x2,
GPUVertexFormat::Sint16x4 => Self::Sint16x4,
GPUVertexFormat::Unorm16 => Self::Unorm16,
GPUVertexFormat::Unorm16x2 => Self::Unorm16x2,
GPUVertexFormat::Unorm16x4 => Self::Unorm16x4,
GPUVertexFormat::Snorm16 => Self::Snorm16,
GPUVertexFormat::Snorm16x2 => Self::Snorm16x2,
GPUVertexFormat::Snorm16x4 => Self::Snorm16x4,
GPUVertexFormat::Float16 => Self::Float16,
GPUVertexFormat::Float16x2 => Self::Float16x2,
GPUVertexFormat::Float16x4 => Self::Float16x4,
GPUVertexFormat::Float32 => Self::Float32,
GPUVertexFormat::Float32x2 => Self::Float32x2,
GPUVertexFormat::Float32x3 => Self::Float32x3,
GPUVertexFormat::Float32x4 => Self::Float32x4,
GPUVertexFormat::Uint32 => Self::Uint32,
GPUVertexFormat::Uint32x2 => Self::Uint32x2,
GPUVertexFormat::Uint32x3 => Self::Uint32x3,
GPUVertexFormat::Uint32x4 => Self::Uint32x4,
GPUVertexFormat::Sint32 => Self::Sint32,
GPUVertexFormat::Sint32x2 => Self::Sint32x2,
GPUVertexFormat::Sint32x3 => Self::Sint32x3,
GPUVertexFormat::Sint32x4 => Self::Sint32x4,
GPUVertexFormat::Unorm1010102 => Self::Unorm10_10_10_2,
GPUVertexFormat::Unorm8x4Bgra => Self::Unorm8x4Bgra,
}
}
}

3
deno_webgpu/rustfmt.toml Normal file
View File

@ -0,0 +1,3 @@
max_width = 80
tab_spaces = 2
edition = "2021"

View File

@ -8,127 +8,127 @@ use deno_core::WebIDL;
use crate::Instance;
pub struct GPUSampler {
pub instance: Instance,
pub id: wgpu_core::id::SamplerId,
pub label: String,
pub instance: Instance,
pub id: wgpu_core::id::SamplerId,
pub label: String,
}
impl Drop for GPUSampler {
fn drop(&mut self) {
self.instance.sampler_drop(self.id);
}
fn drop(&mut self) {
self.instance.sampler_drop(self.id);
}
}
impl WebIdlInterfaceConverter for GPUSampler {
const NAME: &'static str = "GPUSampler";
const NAME: &'static str = "GPUSampler";
}
impl GarbageCollected for GPUSampler {}
#[op2]
impl GPUSampler {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(super) struct GPUSamplerDescriptor {
#[webidl(default = String::new())]
pub label: String,
#[webidl(default = String::new())]
pub label: String,
#[webidl(default = GPUAddressMode::ClampToEdge)]
pub address_mode_u: GPUAddressMode,
#[webidl(default = GPUAddressMode::ClampToEdge)]
pub address_mode_v: GPUAddressMode,
#[webidl(default = GPUAddressMode::ClampToEdge)]
pub address_mode_w: GPUAddressMode,
#[webidl(default = GPUFilterMode::Nearest)]
pub mag_filter: GPUFilterMode,
#[webidl(default = GPUFilterMode::Nearest)]
pub min_filter: GPUFilterMode,
#[webidl(default = GPUFilterMode::Nearest)]
pub mipmap_filter: GPUFilterMode,
#[webidl(default = GPUAddressMode::ClampToEdge)]
pub address_mode_u: GPUAddressMode,
#[webidl(default = GPUAddressMode::ClampToEdge)]
pub address_mode_v: GPUAddressMode,
#[webidl(default = GPUAddressMode::ClampToEdge)]
pub address_mode_w: GPUAddressMode,
#[webidl(default = GPUFilterMode::Nearest)]
pub mag_filter: GPUFilterMode,
#[webidl(default = GPUFilterMode::Nearest)]
pub min_filter: GPUFilterMode,
#[webidl(default = GPUFilterMode::Nearest)]
pub mipmap_filter: GPUFilterMode,
#[webidl(default = 0.0)]
pub lod_min_clamp: f32,
#[webidl(default = 32.0)]
pub lod_max_clamp: f32,
#[webidl(default = 0.0)]
pub lod_min_clamp: f32,
#[webidl(default = 32.0)]
pub lod_max_clamp: f32,
pub compare: Option<GPUCompareFunction>,
pub compare: Option<GPUCompareFunction>,
#[webidl(default = 1)]
#[options(clamp = true)]
pub max_anisotropy: u16,
#[webidl(default = 1)]
#[options(clamp = true)]
pub max_anisotropy: u16,
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUAddressMode {
ClampToEdge,
Repeat,
MirrorRepeat,
ClampToEdge,
Repeat,
MirrorRepeat,
}
impl From<GPUAddressMode> for wgpu_types::AddressMode {
fn from(value: GPUAddressMode) -> Self {
match value {
GPUAddressMode::ClampToEdge => Self::ClampToEdge,
GPUAddressMode::Repeat => Self::Repeat,
GPUAddressMode::MirrorRepeat => Self::MirrorRepeat,
}
fn from(value: GPUAddressMode) -> Self {
match value {
GPUAddressMode::ClampToEdge => Self::ClampToEdge,
GPUAddressMode::Repeat => Self::Repeat,
GPUAddressMode::MirrorRepeat => Self::MirrorRepeat,
}
}
}
// Same as GPUMipmapFilterMode
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUFilterMode {
Nearest,
Linear,
Nearest,
Linear,
}
impl From<GPUFilterMode> for wgpu_types::FilterMode {
fn from(value: GPUFilterMode) -> Self {
match value {
GPUFilterMode::Nearest => Self::Nearest,
GPUFilterMode::Linear => Self::Linear,
}
fn from(value: GPUFilterMode) -> Self {
match value {
GPUFilterMode::Nearest => Self::Nearest,
GPUFilterMode::Linear => Self::Linear,
}
}
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUCompareFunction {
Never,
Less,
Equal,
LessEqual,
Greater,
NotEqual,
GreaterEqual,
Always,
Never,
Less,
Equal,
LessEqual,
Greater,
NotEqual,
GreaterEqual,
Always,
}
impl From<GPUCompareFunction> for wgpu_types::CompareFunction {
fn from(value: GPUCompareFunction) -> Self {
match value {
GPUCompareFunction::Never => Self::Never,
GPUCompareFunction::Less => Self::Less,
GPUCompareFunction::Equal => Self::Equal,
GPUCompareFunction::LessEqual => Self::LessEqual,
GPUCompareFunction::Greater => Self::Greater,
GPUCompareFunction::NotEqual => Self::NotEqual,
GPUCompareFunction::GreaterEqual => Self::GreaterEqual,
GPUCompareFunction::Always => Self::Always,
}
fn from(value: GPUCompareFunction) -> Self {
match value {
GPUCompareFunction::Never => Self::Never,
GPUCompareFunction::Less => Self::Less,
GPUCompareFunction::Equal => Self::Equal,
GPUCompareFunction::LessEqual => Self::LessEqual,
GPUCompareFunction::Greater => Self::Greater,
GPUCompareFunction::NotEqual => Self::NotEqual,
GPUCompareFunction::GreaterEqual => Self::GreaterEqual,
GPUCompareFunction::Always => Self::Always,
}
}
}

View File

@ -11,193 +11,198 @@ use wgpu_core::pipeline;
use crate::Instance;
pub struct GPUShaderModule {
pub instance: Instance,
pub id: wgpu_core::id::ShaderModuleId,
pub label: String,
pub compilation_info: v8::Global<v8::Object>,
pub instance: Instance,
pub id: wgpu_core::id::ShaderModuleId,
pub label: String,
pub compilation_info: v8::Global<v8::Object>,
}
impl Drop for GPUShaderModule {
fn drop(&mut self) {
self.instance.shader_module_drop(self.id);
}
fn drop(&mut self) {
self.instance.shader_module_drop(self.id);
}
}
impl WebIdlInterfaceConverter for GPUShaderModule {
const NAME: &'static str = "GPUShaderModule";
const NAME: &'static str = "GPUShaderModule";
}
impl GarbageCollected for GPUShaderModule {}
#[op2]
impl GPUShaderModule {
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
#[getter]
#[string]
fn label(&self) -> String {
self.label.clone()
}
#[setter]
#[string]
fn label(&self, #[webidl] _label: String) {
// TODO(@crowlKats): no-op, needs wpgu to implement changing the label
}
fn get_compilation_info<'a>(
&self,
scope: &mut v8::HandleScope<'a>,
) -> v8::Local<'a, v8::Promise> {
let resolver = v8::PromiseResolver::new(scope).unwrap();
let info = v8::Local::new(scope, self.compilation_info.clone());
resolver.resolve(scope, info.into()).unwrap();
resolver.get_promise(scope)
}
fn get_compilation_info<'a>(
&self,
scope: &mut v8::HandleScope<'a>,
) -> v8::Local<'a, v8::Promise> {
let resolver = v8::PromiseResolver::new(scope).unwrap();
let info = v8::Local::new(scope, self.compilation_info.clone());
resolver.resolve(scope, info.into()).unwrap();
resolver.get_promise(scope)
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUShaderModuleDescriptor {
#[webidl(default = String::new())]
pub label: String,
#[webidl(default = String::new())]
pub label: String,
pub code: String,
pub code: String,
}
pub struct GPUCompilationMessage {
message: String,
r#type: GPUCompilationMessageType,
line_num: u64,
line_pos: u64,
offset: u64,
length: u64,
message: String,
r#type: GPUCompilationMessageType,
line_num: u64,
line_pos: u64,
offset: u64,
length: u64,
}
impl GarbageCollected for GPUCompilationMessage {}
#[op2]
impl GPUCompilationMessage {
#[getter]
#[string]
fn message(&self) -> String {
self.message.clone()
}
#[getter]
#[string]
fn message(&self) -> String {
self.message.clone()
}
// Naming this `type` or `r#type` does not work.
// https://github.com/gfx-rs/wgpu/issues/7778
#[getter]
#[string]
fn ty(&self) -> &'static str {
self.r#type.as_str()
}
// Naming this `type` or `r#type` does not work.
// https://github.com/gfx-rs/wgpu/issues/7778
#[getter]
#[string]
fn ty(&self) -> &'static str {
self.r#type.as_str()
}
#[getter]
#[number]
fn line_num(&self) -> u64 {
self.line_num
}
#[getter]
#[number]
fn line_num(&self) -> u64 {
self.line_num
}
#[getter]
#[number]
fn line_pos(&self) -> u64 {
self.line_pos
}
#[getter]
#[number]
fn line_pos(&self) -> u64 {
self.line_pos
}
#[getter]
#[number]
fn offset(&self) -> u64 {
self.offset
}
#[getter]
#[number]
fn offset(&self) -> u64 {
self.offset
}
#[getter]
#[number]
fn length(&self) -> u64 {
self.length
}
#[getter]
#[number]
fn length(&self) -> u64 {
self.length
}
}
impl GPUCompilationMessage {
fn new(error: &pipeline::CreateShaderModuleError, source: &str) -> Self {
let message = error.to_string();
fn new(error: &pipeline::CreateShaderModuleError, source: &str) -> Self {
let message = error.to_string();
let loc = match error {
pipeline::CreateShaderModuleError::Parsing(e) => e.inner.location(source),
pipeline::CreateShaderModuleError::Validation(e) => e.inner.location(source),
_ => None,
};
let loc = match error {
pipeline::CreateShaderModuleError::Parsing(e) => e.inner.location(source),
pipeline::CreateShaderModuleError::Validation(e) => {
e.inner.location(source)
}
_ => None,
};
match loc {
Some(loc) => {
let len_utf16 = |s: &str| s.chars().map(|c| c.len_utf16() as u64).sum();
match loc {
Some(loc) => {
let len_utf16 = |s: &str| s.chars().map(|c| c.len_utf16() as u64).sum();
let start = loc.offset as usize;
let start = loc.offset as usize;
// Naga reports a `line_pos` using UTF-8 bytes, so we cannot use it.
let line_start = source[0..start].rfind('\n').map(|pos| pos + 1).unwrap_or(0);
let line_pos = len_utf16(&source[line_start..start]) + 1;
// Naga reports a `line_pos` using UTF-8 bytes, so we cannot use it.
let line_start =
source[0..start].rfind('\n').map(|pos| pos + 1).unwrap_or(0);
let line_pos = len_utf16(&source[line_start..start]) + 1;
Self {
message,
r#type: GPUCompilationMessageType::Error,
line_num: loc.line_number.into(),
line_pos,
offset: len_utf16(&source[0..start]),
length: len_utf16(&source[start..start + loc.length as usize]),
}
}
_ => Self {
message,
r#type: GPUCompilationMessageType::Error,
line_num: 0,
line_pos: 0,
offset: 0,
length: 0,
},
Self {
message,
r#type: GPUCompilationMessageType::Error,
line_num: loc.line_number.into(),
line_pos,
offset: len_utf16(&source[0..start]),
length: len_utf16(&source[start..start + loc.length as usize]),
}
}
_ => Self {
message,
r#type: GPUCompilationMessageType::Error,
line_num: 0,
line_pos: 0,
offset: 0,
length: 0,
},
}
}
}
pub struct GPUCompilationInfo {
messages: v8::Global<v8::Object>,
messages: v8::Global<v8::Object>,
}
impl GarbageCollected for GPUCompilationInfo {}
#[op2]
impl GPUCompilationInfo {
#[getter]
#[global]
fn messages(&self) -> v8::Global<v8::Object> {
self.messages.clone()
}
#[getter]
#[global]
fn messages(&self) -> v8::Global<v8::Object> {
self.messages.clone()
}
}
impl GPUCompilationInfo {
pub fn new<'args, 'scope>(
scope: &mut v8::HandleScope<'scope>,
messages: impl ExactSizeIterator<Item = &'args pipeline::CreateShaderModuleError>,
source: &'args str,
) -> Self {
let array = v8::Array::new(scope, messages.len().try_into().unwrap());
for (i, message) in messages.enumerate() {
let message_object =
make_cppgc_object(scope, GPUCompilationMessage::new(message, source));
array.set_index(scope, i.try_into().unwrap(), message_object.into());
}
let object: v8::Local<v8::Object> = array.into();
object
.set_integrity_level(scope, v8::IntegrityLevel::Frozen)
.unwrap();
Self {
messages: v8::Global::new(scope, object),
}
pub fn new<'args, 'scope>(
scope: &mut v8::HandleScope<'scope>,
messages: impl ExactSizeIterator<
Item = &'args pipeline::CreateShaderModuleError,
>,
source: &'args str,
) -> Self {
let array = v8::Array::new(scope, messages.len().try_into().unwrap());
for (i, message) in messages.enumerate() {
let message_object =
make_cppgc_object(scope, GPUCompilationMessage::new(message, source));
array.set_index(scope, i.try_into().unwrap(), message_object.into());
}
let object: v8::Local<v8::Object> = array.into();
object
.set_integrity_level(scope, v8::IntegrityLevel::Frozen)
.unwrap();
Self {
messages: v8::Global::new(scope, object),
}
}
}
#[derive(WebIDL, Clone)]
#[webidl(enum)]
pub(crate) enum GPUCompilationMessageType {
Error,
Warning,
Info,
Error,
Warning,
Info,
}

View File

@ -2,12 +2,12 @@
use std::cell::RefCell;
use deno_core::op2;
use deno_core::v8;
use deno_core::GarbageCollected;
use deno_core::WebIDL;
use deno_core::_ops::make_cppgc_object;
use deno_core::cppgc::Ptr;
use deno_core::op2;
use deno_core::v8;
use deno_error::JsErrorBox;
use wgpu_types::SurfaceStatus;
@ -17,213 +17,217 @@ use crate::texture::GPUTextureFormat;
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum SurfaceError {
#[class("DOMExceptionInvalidStateError")]
#[error("Context is not configured")]
UnconfiguredContext,
#[class(generic)]
#[error("Invalid Surface Status")]
InvalidStatus,
#[class(generic)]
#[error(transparent)]
Surface(#[from] wgpu_core::present::SurfaceError),
#[class("DOMExceptionInvalidStateError")]
#[error("Context is not configured")]
UnconfiguredContext,
#[class(generic)]
#[error("Invalid Surface Status")]
InvalidStatus,
#[class(generic)]
#[error(transparent)]
Surface(#[from] wgpu_core::present::SurfaceError),
}
pub struct Configuration {
pub device: Ptr<GPUDevice>,
pub usage: u32,
pub format: GPUTextureFormat,
pub device: Ptr<GPUDevice>,
pub usage: u32,
pub format: GPUTextureFormat,
}
pub struct GPUCanvasContext {
pub surface_id: wgpu_core::id::SurfaceId,
pub width: RefCell<u32>,
pub height: RefCell<u32>,
pub surface_id: wgpu_core::id::SurfaceId,
pub width: RefCell<u32>,
pub height: RefCell<u32>,
pub config: RefCell<Option<Configuration>>,
pub texture: RefCell<Option<v8::Global<v8::Object>>>,
pub config: RefCell<Option<Configuration>>,
pub texture: RefCell<Option<v8::Global<v8::Object>>>,
pub canvas: v8::Global<v8::Object>,
pub canvas: v8::Global<v8::Object>,
}
impl GarbageCollected for GPUCanvasContext {}
#[op2]
impl GPUCanvasContext {
#[getter]
#[global]
fn canvas(&self) -> v8::Global<v8::Object> {
self.canvas.clone()
#[getter]
#[global]
fn canvas(&self) -> v8::Global<v8::Object> {
self.canvas.clone()
}
fn configure(
&self,
#[webidl] configuration: GPUCanvasConfiguration,
) -> Result<(), JsErrorBox> {
let usage = wgpu_types::TextureUsages::from_bits(configuration.usage)
.ok_or_else(|| JsErrorBox::type_error("usage is not valid"))?;
let format = configuration.format.clone().into();
let conf = wgpu_types::SurfaceConfiguration {
usage,
format,
width: *self.width.borrow(),
height: *self.height.borrow(),
present_mode: configuration
.present_mode
.map(Into::into)
.unwrap_or_default(),
alpha_mode: configuration.alpha_mode.into(),
view_formats: configuration
.view_formats
.into_iter()
.map(Into::into)
.collect(),
desired_maximum_frame_latency: 2,
};
let device = configuration.device;
let err =
device
.instance
.surface_configure(self.surface_id, device.id, &conf);
device.error_handler.push_error(err);
self.config.borrow_mut().replace(Configuration {
device,
usage: configuration.usage,
format: configuration.format,
});
Ok(())
}
#[fast]
fn unconfigure(&self) {
*self.config.borrow_mut() = None;
}
#[global]
fn get_current_texture(
&self,
scope: &mut v8::HandleScope,
) -> Result<v8::Global<v8::Object>, SurfaceError> {
let config = self.config.borrow();
let Some(config) = config.as_ref() else {
return Err(SurfaceError::UnconfiguredContext);
};
{
if let Some(obj) = self.texture.borrow().as_ref() {
return Ok(obj.clone());
}
}
fn configure(&self, #[webidl] configuration: GPUCanvasConfiguration) -> Result<(), JsErrorBox> {
let usage = wgpu_types::TextureUsages::from_bits(configuration.usage)
.ok_or_else(|| JsErrorBox::type_error("usage is not valid"))?;
let format = configuration.format.clone().into();
let conf = wgpu_types::SurfaceConfiguration {
usage,
format,
let output = config
.device
.instance
.surface_get_current_texture(self.surface_id, None)?;
match output.status {
SurfaceStatus::Good | SurfaceStatus::Suboptimal => {
let id = output.texture.unwrap();
let texture = GPUTexture {
instance: config.device.instance.clone(),
error_handler: config.device.error_handler.clone(),
id,
label: "".to_string(),
size: wgpu_types::Extent3d {
width: *self.width.borrow(),
height: *self.height.borrow(),
present_mode: configuration
.present_mode
.map(Into::into)
.unwrap_or_default(),
alpha_mode: configuration.alpha_mode.into(),
view_formats: configuration
.view_formats
.into_iter()
.map(Into::into)
.collect(),
desired_maximum_frame_latency: 2,
depth_or_array_layers: 1,
},
mip_level_count: 0,
sample_count: 0,
dimension: crate::texture::GPUTextureDimension::D2,
format: config.format.clone(),
usage: config.usage,
};
let obj = make_cppgc_object(scope, texture);
let obj = v8::Global::new(scope, obj);
*self.texture.borrow_mut() = Some(obj.clone());
let device = configuration.device;
let err = device
.instance
.surface_configure(self.surface_id, device.id, &conf);
device.error_handler.push_error(err);
self.config.borrow_mut().replace(Configuration {
device,
usage: configuration.usage,
format: configuration.format,
});
Ok(())
}
#[fast]
fn unconfigure(&self) {
*self.config.borrow_mut() = None;
}
#[global]
fn get_current_texture(
&self,
scope: &mut v8::HandleScope,
) -> Result<v8::Global<v8::Object>, SurfaceError> {
let config = self.config.borrow();
let Some(config) = config.as_ref() else {
return Err(SurfaceError::UnconfiguredContext);
};
{
if let Some(obj) = self.texture.borrow().as_ref() {
return Ok(obj.clone());
}
}
let output = config
.device
.instance
.surface_get_current_texture(self.surface_id, None)?;
match output.status {
SurfaceStatus::Good | SurfaceStatus::Suboptimal => {
let id = output.texture.unwrap();
let texture = GPUTexture {
instance: config.device.instance.clone(),
error_handler: config.device.error_handler.clone(),
id,
label: "".to_string(),
size: wgpu_types::Extent3d {
width: *self.width.borrow(),
height: *self.height.borrow(),
depth_or_array_layers: 1,
},
mip_level_count: 0,
sample_count: 0,
dimension: crate::texture::GPUTextureDimension::D2,
format: config.format.clone(),
usage: config.usage,
};
let obj = make_cppgc_object(scope, texture);
let obj = v8::Global::new(scope, obj);
*self.texture.borrow_mut() = Some(obj.clone());
Ok(obj)
}
_ => Err(SurfaceError::InvalidStatus),
}
Ok(obj)
}
_ => Err(SurfaceError::InvalidStatus),
}
}
}
impl GPUCanvasContext {
pub fn present(&self) -> Result<(), SurfaceError> {
let config = self.config.borrow();
let Some(config) = config.as_ref() else {
return Err(SurfaceError::UnconfiguredContext);
};
pub fn present(&self) -> Result<(), SurfaceError> {
let config = self.config.borrow();
let Some(config) = config.as_ref() else {
return Err(SurfaceError::UnconfiguredContext);
};
config.device.instance.surface_present(self.surface_id)?;
config.device.instance.surface_present(self.surface_id)?;
Ok(())
}
Ok(())
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
struct GPUCanvasConfiguration {
device: Ptr<GPUDevice>,
format: GPUTextureFormat,
#[webidl(default = wgpu_types::TextureUsages::RENDER_ATTACHMENT.bits())]
#[options(enforce_range = true)]
usage: u32,
#[webidl(default = GPUCanvasAlphaMode::Opaque)]
alpha_mode: GPUCanvasAlphaMode,
device: Ptr<GPUDevice>,
format: GPUTextureFormat,
#[webidl(default = wgpu_types::TextureUsages::RENDER_ATTACHMENT.bits())]
#[options(enforce_range = true)]
usage: u32,
#[webidl(default = GPUCanvasAlphaMode::Opaque)]
alpha_mode: GPUCanvasAlphaMode,
// Extended from spec
present_mode: Option<GPUPresentMode>,
#[webidl(default = vec![])]
view_formats: Vec<GPUTextureFormat>,
// Extended from spec
present_mode: Option<GPUPresentMode>,
#[webidl(default = vec![])]
view_formats: Vec<GPUTextureFormat>,
}
#[derive(WebIDL)]
#[webidl(enum)]
enum GPUCanvasAlphaMode {
Opaque,
Premultiplied,
Opaque,
Premultiplied,
}
impl From<GPUCanvasAlphaMode> for wgpu_types::CompositeAlphaMode {
fn from(value: GPUCanvasAlphaMode) -> Self {
match value {
GPUCanvasAlphaMode::Opaque => Self::Opaque,
GPUCanvasAlphaMode::Premultiplied => Self::PreMultiplied,
}
fn from(value: GPUCanvasAlphaMode) -> Self {
match value {
GPUCanvasAlphaMode::Opaque => Self::Opaque,
GPUCanvasAlphaMode::Premultiplied => Self::PreMultiplied,
}
}
}
// Extended from spec
#[derive(WebIDL)]
#[webidl(enum)]
enum GPUPresentMode {
#[webidl(rename = "autoVsync")]
AutoVsync,
#[webidl(rename = "autoNoVsync")]
AutoNoVsync,
#[webidl(rename = "fifo")]
Fifo,
#[webidl(rename = "fifoRelaxed")]
FifoRelaxed,
#[webidl(rename = "immediate")]
Immediate,
#[webidl(rename = "mailbox")]
Mailbox,
#[webidl(rename = "autoVsync")]
AutoVsync,
#[webidl(rename = "autoNoVsync")]
AutoNoVsync,
#[webidl(rename = "fifo")]
Fifo,
#[webidl(rename = "fifoRelaxed")]
FifoRelaxed,
#[webidl(rename = "immediate")]
Immediate,
#[webidl(rename = "mailbox")]
Mailbox,
}
impl From<GPUPresentMode> for wgpu_types::PresentMode {
fn from(value: GPUPresentMode) -> Self {
match value {
GPUPresentMode::AutoVsync => Self::AutoVsync,
GPUPresentMode::AutoNoVsync => Self::AutoNoVsync,
GPUPresentMode::Fifo => Self::Fifo,
GPUPresentMode::FifoRelaxed => Self::FifoRelaxed,
GPUPresentMode::Immediate => Self::Immediate,
GPUPresentMode::Mailbox => Self::Mailbox,
}
fn from(value: GPUPresentMode) -> Self {
match value {
GPUPresentMode::AutoVsync => Self::AutoVsync,
GPUPresentMode::AutoNoVsync => Self::AutoNoVsync,
GPUPresentMode::Fifo => Self::Fifo,
GPUPresentMode::FifoRelaxed => Self::FifoRelaxed,
GPUPresentMode::Immediate => Self::Immediate,
GPUPresentMode::Mailbox => Self::Mailbox,
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff