mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
[deno] Format with Deno's rustfmt config
This commit is contained in:
parent
099a95ba64
commit
e714cb0339
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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"))
|
||||
}
|
||||
|
||||
@ -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,
|
||||
}
|
||||
|
||||
@ -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,
|
||||
©_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,
|
||||
©_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,
|
||||
©_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,
|
||||
©_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,
|
||||
©_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,
|
||||
©_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>,
|
||||
}
|
||||
|
||||
@ -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>,
|
||||
}
|
||||
|
||||
@ -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
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@ -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>>,
|
||||
}
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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>,
|
||||
}
|
||||
|
||||
@ -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,
|
||||
}
|
||||
|
||||
@ -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>,
|
||||
}
|
||||
|
||||
@ -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
3
deno_webgpu/rustfmt.toml
Normal file
@ -0,0 +1,3 @@
|
||||
max_width = 80
|
||||
tab_spaces = 2
|
||||
edition = "2021"
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
}
|
||||
|
||||
@ -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
Loading…
x
Reference in New Issue
Block a user