mirror of
https://github.com/servo/servo.git
synced 2025-07-23 23:33:43 +01:00
Move script gpu files into webgpu folder (#34415)
Signed-off-by: atbrakhi <atbrakhi@igalia.com>
This commit is contained in:
parent
a37ccc3e64
commit
d2d3407501
44 changed files with 108 additions and 118 deletions
180
components/script/dom/webgpu/gpu.rs
Normal file
180
components/script/dom/webgpu/gpu.rs
Normal file
|
@ -0,0 +1,180 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use ipc_channel::router::ROUTER;
|
||||
use js::jsapi::Heap;
|
||||
use script_traits::ScriptMsg;
|
||||
use webgpu::wgt::PowerPreference;
|
||||
use webgpu::{wgc, WebGPUResponse};
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUMethods, GPUPowerPreference, GPURequestAdapterOptions, GPUTextureFormat,
|
||||
};
|
||||
use crate::dom::bindings::error::Error;
|
||||
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpuadapter::GPUAdapter;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::realms::InRealm;
|
||||
use crate::script_runtime::CanGc;
|
||||
use crate::task_source::{TaskSource, TaskSourceName};
|
||||
|
||||
#[dom_struct]
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub struct GPU {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl GPU {
|
||||
pub fn new_inherited() -> GPU {
|
||||
GPU {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope) -> DomRoot<GPU> {
|
||||
reflect_dom_object(Box::new(GPU::new_inherited()), global)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AsyncWGPUListener {
|
||||
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>, can_gc: CanGc);
|
||||
}
|
||||
|
||||
struct WGPUResponse<T: AsyncWGPUListener + DomObject> {
|
||||
trusted: TrustedPromise,
|
||||
receiver: Trusted<T>,
|
||||
}
|
||||
|
||||
impl<T: AsyncWGPUListener + DomObject> WGPUResponse<T> {
|
||||
#[allow(crown::unrooted_must_root)]
|
||||
fn response(self, response: WebGPUResponse, can_gc: CanGc) {
|
||||
let promise = self.trusted.root();
|
||||
self.receiver
|
||||
.root()
|
||||
.handle_response(response, &promise, can_gc);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn response_async<T: AsyncWGPUListener + DomObject + 'static>(
|
||||
promise: &Rc<Promise>,
|
||||
receiver: &T,
|
||||
) -> IpcSender<WebGPUResponse> {
|
||||
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
||||
let task_source = receiver.global().dom_manipulation_task_source();
|
||||
let canceller = receiver
|
||||
.global()
|
||||
.task_canceller(TaskSourceName::DOMManipulation);
|
||||
let mut trusted: Option<TrustedPromise> = Some(TrustedPromise::new(promise.clone()));
|
||||
let trusted_receiver = Trusted::new(receiver);
|
||||
ROUTER.add_typed_route(
|
||||
action_receiver,
|
||||
Box::new(move |message| {
|
||||
let trusted = if let Some(trusted) = trusted.take() {
|
||||
trusted
|
||||
} else {
|
||||
error!("WebGPU callback called twice!");
|
||||
return;
|
||||
};
|
||||
|
||||
let context = WGPUResponse {
|
||||
trusted,
|
||||
receiver: trusted_receiver.clone(),
|
||||
};
|
||||
let result = task_source.queue_with_canceller(
|
||||
task!(process_webgpu_task: move|| {
|
||||
context.response(message.unwrap(), CanGc::note());
|
||||
}),
|
||||
&canceller,
|
||||
);
|
||||
if let Err(err) = result {
|
||||
error!("Failed to queue GPU listener-task: {:?}", err);
|
||||
}
|
||||
}),
|
||||
);
|
||||
action_sender
|
||||
}
|
||||
|
||||
impl GPUMethods<crate::DomTypeHolder> for GPU {
|
||||
// https://gpuweb.github.io/gpuweb/#dom-gpu-requestadapter
|
||||
fn RequestAdapter(
|
||||
&self,
|
||||
options: &GPURequestAdapterOptions,
|
||||
comp: InRealm,
|
||||
can_gc: CanGc,
|
||||
) -> Rc<Promise> {
|
||||
let global = &self.global();
|
||||
let promise = Promise::new_in_current_realm(comp, can_gc);
|
||||
let sender = response_async(&promise, self);
|
||||
let power_preference = match options.powerPreference {
|
||||
Some(GPUPowerPreference::Low_power) => PowerPreference::LowPower,
|
||||
Some(GPUPowerPreference::High_performance) => PowerPreference::HighPerformance,
|
||||
None => PowerPreference::default(),
|
||||
};
|
||||
let ids = global.wgpu_id_hub().create_adapter_id();
|
||||
|
||||
let script_to_constellation_chan = global.script_to_constellation_chan();
|
||||
if script_to_constellation_chan
|
||||
.send(ScriptMsg::RequestAdapter(
|
||||
sender,
|
||||
wgc::instance::RequestAdapterOptions {
|
||||
power_preference,
|
||||
compatible_surface: None,
|
||||
force_fallback_adapter: options.forceFallbackAdapter,
|
||||
},
|
||||
ids,
|
||||
))
|
||||
.is_err()
|
||||
{
|
||||
promise.reject_error(Error::Operation);
|
||||
}
|
||||
promise
|
||||
}
|
||||
|
||||
// https://gpuweb.github.io/gpuweb/#dom-gpu-getpreferredcanvasformat
|
||||
fn GetPreferredCanvasFormat(&self) -> GPUTextureFormat {
|
||||
// TODO: real implementation
|
||||
GPUTextureFormat::Rgba8unorm
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncWGPUListener for GPU {
|
||||
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>, can_gc: CanGc) {
|
||||
match response {
|
||||
WebGPUResponse::Adapter(Ok(adapter)) => {
|
||||
let adapter = GPUAdapter::new(
|
||||
&self.global(),
|
||||
adapter.channel,
|
||||
DOMString::from(format!(
|
||||
"{} ({:?})",
|
||||
adapter.adapter_info.name, adapter.adapter_id.0
|
||||
)),
|
||||
Heap::default(),
|
||||
adapter.features,
|
||||
adapter.limits,
|
||||
adapter.adapter_info,
|
||||
adapter.adapter_id,
|
||||
can_gc,
|
||||
);
|
||||
promise.resolve_native(&adapter);
|
||||
},
|
||||
WebGPUResponse::Adapter(Err(e)) => {
|
||||
warn!("Could not get GPUAdapter ({:?})", e);
|
||||
promise.resolve_native(&None::<GPUAdapter>);
|
||||
},
|
||||
WebGPUResponse::None => {
|
||||
warn!("Couldn't get a response, because WebGPU is disabled");
|
||||
promise.resolve_native(&None::<GPUAdapter>);
|
||||
},
|
||||
_ => unreachable!("GPU received wrong WebGPUResponse"),
|
||||
}
|
||||
}
|
||||
}
|
254
components/script/dom/webgpu/gpuadapter.rs
Normal file
254
components/script/dom/webgpu/gpuadapter.rs
Normal file
|
@ -0,0 +1,254 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use js::jsapi::{Heap, JSObject};
|
||||
use webgpu::wgc::instance::RequestDeviceError;
|
||||
use webgpu::wgt::MemoryHints;
|
||||
use webgpu::{wgt, WebGPU, WebGPUAdapter, WebGPURequest, WebGPUResponse};
|
||||
|
||||
use super::gpusupportedfeatures::GPUSupportedFeatures;
|
||||
use super::gpusupportedlimits::set_limit;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUAdapterMethods, GPUDeviceDescriptor, GPUDeviceLostReason,
|
||||
};
|
||||
use crate::dom::bindings::error::Error;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpudevice::GPUDevice;
|
||||
use crate::dom::gpusupportedfeatures::gpu_to_wgt_feature;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::dom::types::{GPUAdapterInfo, GPUSupportedLimits};
|
||||
use crate::dom::webgpu::gpu::{response_async, AsyncWGPUListener};
|
||||
use crate::realms::InRealm;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUAdapter {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
name: DOMString,
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
extensions: Heap<*mut JSObject>,
|
||||
features: Dom<GPUSupportedFeatures>,
|
||||
limits: Dom<GPUSupportedLimits>,
|
||||
info: Dom<GPUAdapterInfo>,
|
||||
#[no_trace]
|
||||
adapter: WebGPUAdapter,
|
||||
}
|
||||
|
||||
impl GPUAdapter {
|
||||
fn new_inherited(
|
||||
channel: WebGPU,
|
||||
name: DOMString,
|
||||
extensions: Heap<*mut JSObject>,
|
||||
features: &GPUSupportedFeatures,
|
||||
limits: &GPUSupportedLimits,
|
||||
info: &GPUAdapterInfo,
|
||||
adapter: WebGPUAdapter,
|
||||
) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
channel,
|
||||
name,
|
||||
extensions,
|
||||
features: Dom::from_ref(features),
|
||||
limits: Dom::from_ref(limits),
|
||||
info: Dom::from_ref(info),
|
||||
adapter,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
channel: WebGPU,
|
||||
name: DOMString,
|
||||
extensions: Heap<*mut JSObject>,
|
||||
features: wgt::Features,
|
||||
limits: wgt::Limits,
|
||||
info: wgt::AdapterInfo,
|
||||
adapter: WebGPUAdapter,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
let features = GPUSupportedFeatures::Constructor(global, None, features, can_gc).unwrap();
|
||||
let limits = GPUSupportedLimits::new(global, limits);
|
||||
let info = GPUAdapterInfo::new(global, info);
|
||||
reflect_dom_object(
|
||||
Box::new(GPUAdapter::new_inherited(
|
||||
channel, name, extensions, &features, &limits, &info, adapter,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPUAdapter {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DropAdapter(self.adapter.0))
|
||||
{
|
||||
warn!(
|
||||
"Failed to send WebGPURequest::DropAdapter({:?}) ({})",
|
||||
self.adapter.0, e
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUAdapterMethods<crate::DomTypeHolder> for GPUAdapter {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuadapter-requestdevice>
|
||||
fn RequestDevice(
|
||||
&self,
|
||||
descriptor: &GPUDeviceDescriptor,
|
||||
comp: InRealm,
|
||||
can_gc: CanGc,
|
||||
) -> Rc<Promise> {
|
||||
// Step 2
|
||||
let promise = Promise::new_in_current_realm(comp, can_gc);
|
||||
let sender = response_async(&promise, self);
|
||||
let mut required_features = wgt::Features::empty();
|
||||
for &ext in descriptor.requiredFeatures.iter() {
|
||||
if let Some(feature) = gpu_to_wgt_feature(ext) {
|
||||
required_features.insert(feature);
|
||||
} else {
|
||||
promise.reject_error(Error::Type(format!(
|
||||
"{} is not supported feature",
|
||||
ext.as_str()
|
||||
)));
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
|
||||
let mut required_limits = wgt::Limits::default();
|
||||
if let Some(limits) = &descriptor.requiredLimits {
|
||||
for (limit, value) in (*limits).iter() {
|
||||
if !set_limit(&mut required_limits, limit.as_ref(), *value) {
|
||||
warn!("Unknown GPUDevice limit: {limit}");
|
||||
promise.reject_error(Error::Operation);
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let desc = wgt::DeviceDescriptor {
|
||||
required_features,
|
||||
required_limits,
|
||||
label: Some(descriptor.parent.label.to_string()),
|
||||
memory_hints: MemoryHints::MemoryUsage,
|
||||
};
|
||||
let device_id = self.global().wgpu_id_hub().create_device_id();
|
||||
let queue_id = self.global().wgpu_id_hub().create_queue_id();
|
||||
let pipeline_id = self.global().pipeline_id();
|
||||
if self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::RequestDevice {
|
||||
sender,
|
||||
adapter_id: self.adapter,
|
||||
descriptor: desc,
|
||||
device_id,
|
||||
queue_id,
|
||||
pipeline_id,
|
||||
})
|
||||
.is_err()
|
||||
{
|
||||
promise.reject_error(Error::Operation);
|
||||
}
|
||||
// Step 5
|
||||
promise
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuadapter-isfallbackadapter>
|
||||
fn IsFallbackAdapter(&self) -> bool {
|
||||
//TODO
|
||||
false
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuadapter-requestadapterinfo>
|
||||
fn RequestAdapterInfo(
|
||||
&self,
|
||||
unmask_hints: Vec<DOMString>,
|
||||
comp: InRealm,
|
||||
can_gc: CanGc,
|
||||
) -> Rc<Promise> {
|
||||
// XXX: Adapter info should be generated here ...
|
||||
// Step 1
|
||||
let promise = Promise::new_in_current_realm(comp, can_gc);
|
||||
// Step 4
|
||||
if !unmask_hints.is_empty() {
|
||||
todo!("unmaskHints on RequestAdapterInfo");
|
||||
}
|
||||
promise.resolve_native(&*self.info);
|
||||
// Step 5
|
||||
promise
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuadapter-features>
|
||||
fn Features(&self) -> DomRoot<GPUSupportedFeatures> {
|
||||
DomRoot::from_ref(&self.features)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuadapter-limits>
|
||||
fn Limits(&self) -> DomRoot<GPUSupportedLimits> {
|
||||
DomRoot::from_ref(&self.limits)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncWGPUListener for GPUAdapter {
|
||||
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>, can_gc: CanGc) {
|
||||
match response {
|
||||
WebGPUResponse::Device((device_id, queue_id, Ok(descriptor))) => {
|
||||
let device = GPUDevice::new(
|
||||
&self.global(),
|
||||
self.channel.clone(),
|
||||
self,
|
||||
Heap::default(),
|
||||
descriptor.required_features,
|
||||
descriptor.required_limits,
|
||||
device_id,
|
||||
queue_id,
|
||||
descriptor.label.unwrap_or_default(),
|
||||
can_gc,
|
||||
);
|
||||
self.global().add_gpu_device(&device);
|
||||
promise.resolve_native(&device);
|
||||
},
|
||||
WebGPUResponse::Device((_, _, Err(RequestDeviceError::UnsupportedFeature(f)))) => {
|
||||
promise.reject_error(Error::Type(
|
||||
RequestDeviceError::UnsupportedFeature(f).to_string(),
|
||||
))
|
||||
},
|
||||
WebGPUResponse::Device((_, _, Err(RequestDeviceError::LimitsExceeded(_)))) => {
|
||||
promise.reject_error(Error::Operation)
|
||||
},
|
||||
WebGPUResponse::Device((device_id, queue_id, Err(e))) => {
|
||||
let device = GPUDevice::new(
|
||||
&self.global(),
|
||||
self.channel.clone(),
|
||||
self,
|
||||
Heap::default(),
|
||||
wgt::Features::default(),
|
||||
wgt::Limits::default(),
|
||||
device_id,
|
||||
queue_id,
|
||||
String::new(),
|
||||
can_gc,
|
||||
);
|
||||
device.lose(GPUDeviceLostReason::Unknown, e.to_string());
|
||||
promise.resolve_native(&device);
|
||||
},
|
||||
WebGPUResponse::None => unreachable!("Failed to get a response for RequestDevice"),
|
||||
_ => unreachable!("GPUAdapter received wrong WebGPUResponse"),
|
||||
}
|
||||
}
|
||||
}
|
56
components/script/dom/webgpu/gpuadapterinfo.rs
Normal file
56
components/script/dom/webgpu/gpuadapterinfo.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use webgpu::wgt::AdapterInfo;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUAdapterInfoMethods;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::test::DOMString;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUAdapterInfo {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "defined in wgpu-types"]
|
||||
#[no_trace]
|
||||
info: AdapterInfo,
|
||||
}
|
||||
|
||||
impl GPUAdapterInfo {
|
||||
fn new_inherited(info: AdapterInfo) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
info,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope, info: AdapterInfo) -> DomRoot<Self> {
|
||||
reflect_dom_object(Box::new(Self::new_inherited(info)), global)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: wgpu does not expose right fields right now
|
||||
impl GPUAdapterInfoMethods<crate::DomTypeHolder> for GPUAdapterInfo {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuadapterinfo-vendor>
|
||||
fn Vendor(&self) -> DOMString {
|
||||
DOMString::new()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuadapterinfo-architecture>
|
||||
fn Architecture(&self) -> DOMString {
|
||||
DOMString::new()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuadapterinfo-device>
|
||||
fn Device(&self) -> DOMString {
|
||||
DOMString::new()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuadapterinfo-description>
|
||||
fn Description(&self) -> DOMString {
|
||||
DOMString::from_string(self.info.driver_info.clone())
|
||||
}
|
||||
}
|
142
components/script/dom/webgpu/gpubindgroup.rs
Normal file
142
components/script/dom/webgpu/gpubindgroup.rs
Normal file
|
@ -0,0 +1,142 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use webgpu::wgc::binding_model::BindGroupDescriptor;
|
||||
use webgpu::{WebGPU, WebGPUBindGroup, WebGPUDevice, WebGPURequest};
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUBindGroupDescriptor, GPUBindGroupMethods,
|
||||
};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpubindgrouplayout::GPUBindGroupLayout;
|
||||
use crate::dom::gpudevice::GPUDevice;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUBindGroup {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
label: DomRefCell<USVString>,
|
||||
#[no_trace]
|
||||
bind_group: WebGPUBindGroup,
|
||||
#[no_trace]
|
||||
device: WebGPUDevice,
|
||||
layout: Dom<GPUBindGroupLayout>,
|
||||
}
|
||||
|
||||
impl GPUBindGroup {
|
||||
fn new_inherited(
|
||||
channel: WebGPU,
|
||||
bind_group: WebGPUBindGroup,
|
||||
device: WebGPUDevice,
|
||||
layout: &GPUBindGroupLayout,
|
||||
label: USVString,
|
||||
) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
channel,
|
||||
label: DomRefCell::new(label),
|
||||
bind_group,
|
||||
device,
|
||||
layout: Dom::from_ref(layout),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
channel: WebGPU,
|
||||
bind_group: WebGPUBindGroup,
|
||||
device: WebGPUDevice,
|
||||
layout: &GPUBindGroupLayout,
|
||||
label: USVString,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPUBindGroup::new_inherited(
|
||||
channel, bind_group, device, layout, label,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUBindGroup {
|
||||
pub fn id(&self) -> &WebGPUBindGroup {
|
||||
&self.bind_group
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbindgroup>
|
||||
pub fn create(
|
||||
device: &GPUDevice,
|
||||
descriptor: &GPUBindGroupDescriptor,
|
||||
) -> DomRoot<GPUBindGroup> {
|
||||
let entries = descriptor
|
||||
.entries
|
||||
.iter()
|
||||
.map(|bind| bind.into())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let desc = BindGroupDescriptor {
|
||||
label: (&descriptor.parent).into(),
|
||||
layout: descriptor.layout.id().0,
|
||||
entries: Cow::Owned(entries),
|
||||
};
|
||||
|
||||
let bind_group_id = device.global().wgpu_id_hub().create_bind_group_id();
|
||||
device
|
||||
.channel()
|
||||
.0
|
||||
.send(WebGPURequest::CreateBindGroup {
|
||||
device_id: device.id().0,
|
||||
bind_group_id,
|
||||
descriptor: desc,
|
||||
})
|
||||
.expect("Failed to create WebGPU BindGroup");
|
||||
|
||||
let bind_group = WebGPUBindGroup(bind_group_id);
|
||||
|
||||
GPUBindGroup::new(
|
||||
&device.global(),
|
||||
device.channel().clone(),
|
||||
bind_group,
|
||||
device.id(),
|
||||
&descriptor.layout,
|
||||
descriptor.parent.label.clone(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPUBindGroup {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DropBindGroup(self.bind_group.0))
|
||||
{
|
||||
warn!(
|
||||
"Failed to send WebGPURequest::DropBindGroup({:?}) ({})",
|
||||
self.bind_group.0, e
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUBindGroupMethods<crate::DomTypeHolder> for GPUBindGroup {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
}
|
139
components/script/dom/webgpu/gpubindgrouplayout.rs
Normal file
139
components/script/dom/webgpu/gpubindgrouplayout.rs
Normal file
|
@ -0,0 +1,139 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use webgpu::wgc::binding_model::BindGroupLayoutDescriptor;
|
||||
use webgpu::{WebGPU, WebGPUBindGroupLayout, WebGPURequest};
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUBindGroupLayoutDescriptor, GPUBindGroupLayoutMethods,
|
||||
};
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpuconvert::convert_bind_group_layout_entry;
|
||||
use crate::dom::gpudevice::GPUDevice;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUBindGroupLayout {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
label: DomRefCell<USVString>,
|
||||
#[no_trace]
|
||||
bind_group_layout: WebGPUBindGroupLayout,
|
||||
}
|
||||
|
||||
impl GPUBindGroupLayout {
|
||||
fn new_inherited(
|
||||
channel: WebGPU,
|
||||
bind_group_layout: WebGPUBindGroupLayout,
|
||||
label: USVString,
|
||||
) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
channel,
|
||||
label: DomRefCell::new(label),
|
||||
bind_group_layout,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
channel: WebGPU,
|
||||
bind_group_layout: WebGPUBindGroupLayout,
|
||||
label: USVString,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPUBindGroupLayout::new_inherited(
|
||||
channel,
|
||||
bind_group_layout,
|
||||
label,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUBindGroupLayout {
|
||||
pub fn id(&self) -> WebGPUBindGroupLayout {
|
||||
self.bind_group_layout
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#GPUDevice-createBindGroupLayout>
|
||||
pub fn create(
|
||||
device: &GPUDevice,
|
||||
descriptor: &GPUBindGroupLayoutDescriptor,
|
||||
) -> Fallible<DomRoot<GPUBindGroupLayout>> {
|
||||
let entries = descriptor
|
||||
.entries
|
||||
.iter()
|
||||
.map(|bgle| convert_bind_group_layout_entry(bgle, device))
|
||||
.collect::<Fallible<Result<Vec<_>, _>>>()?;
|
||||
|
||||
let desc = match entries {
|
||||
Ok(entries) => Some(BindGroupLayoutDescriptor {
|
||||
label: (&descriptor.parent).into(),
|
||||
entries: Cow::Owned(entries),
|
||||
}),
|
||||
Err(error) => {
|
||||
device.dispatch_error(error);
|
||||
None
|
||||
},
|
||||
};
|
||||
|
||||
let bind_group_layout_id = device.global().wgpu_id_hub().create_bind_group_layout_id();
|
||||
device
|
||||
.channel()
|
||||
.0
|
||||
.send(WebGPURequest::CreateBindGroupLayout {
|
||||
device_id: device.id().0,
|
||||
bind_group_layout_id,
|
||||
descriptor: desc,
|
||||
})
|
||||
.expect("Failed to create WebGPU BindGroupLayout");
|
||||
|
||||
let bgl = WebGPUBindGroupLayout(bind_group_layout_id);
|
||||
|
||||
Ok(GPUBindGroupLayout::new(
|
||||
&device.global(),
|
||||
device.channel().clone(),
|
||||
bgl,
|
||||
descriptor.parent.label.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPUBindGroupLayout {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DropBindGroupLayout(self.bind_group_layout.0))
|
||||
{
|
||||
warn!(
|
||||
"Failed to send WebGPURequest::DropBindGroupLayout({:?}) ({})",
|
||||
self.bind_group_layout.0, e
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUBindGroupLayoutMethods<crate::DomTypeHolder> for GPUBindGroupLayout {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
}
|
425
components/script/dom/webgpu/gpubuffer.rs
Normal file
425
components/script/dom/webgpu/gpubuffer.rs
Normal file
|
@ -0,0 +1,425 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::ops::Range;
|
||||
use std::rc::Rc;
|
||||
use std::string::String;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use ipc_channel::ipc::IpcSharedMemory;
|
||||
use js::typedarray::ArrayBuffer;
|
||||
use webgpu::wgc::device::HostMap;
|
||||
use webgpu::{wgt, Mapping, WebGPU, WebGPUBuffer, WebGPURequest, WebGPUResponse};
|
||||
|
||||
use crate::dom::bindings::buffer_source::DataBlock;
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUBufferDescriptor, GPUBufferMapState, GPUBufferMethods, GPUFlagsConstant,
|
||||
GPUMapModeConstants, GPUMapModeFlags, GPUSize64,
|
||||
};
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpudevice::GPUDevice;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::dom::webgpu::gpu::{response_async, AsyncWGPUListener};
|
||||
use crate::realms::InRealm;
|
||||
use crate::script_runtime::{CanGc, JSContext};
|
||||
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
pub struct ActiveBufferMapping {
|
||||
// TODO(sagudev): Use IpcSharedMemory when https://github.com/servo/ipc-channel/pull/356 lands
|
||||
/// <https://gpuweb.github.io/gpuweb/#active-buffer-mapping-data>
|
||||
/// <https://gpuweb.github.io/gpuweb/#active-buffer-mapping-views>
|
||||
pub data: DataBlock,
|
||||
/// <https://gpuweb.github.io/gpuweb/#active-buffer-mapping-mode>
|
||||
mode: GPUMapModeFlags,
|
||||
/// <https://gpuweb.github.io/gpuweb/#active-buffer-mapping-range>
|
||||
range: Range<u64>,
|
||||
}
|
||||
|
||||
impl ActiveBufferMapping {
|
||||
/// <https://gpuweb.github.io/gpuweb/#abstract-opdef-initialize-an-active-buffer-mapping>
|
||||
pub fn new(mode: GPUMapModeFlags, range: Range<u64>) -> Fallible<Self> {
|
||||
// Step 1
|
||||
let size = range.end - range.start;
|
||||
// Step 2
|
||||
if size > (1 << 53) - 1 {
|
||||
return Err(Error::Range("Over MAX_SAFE_INTEGER".to_string()));
|
||||
}
|
||||
let size: usize = size
|
||||
.try_into()
|
||||
.map_err(|_| Error::Range("Over usize".to_string()))?;
|
||||
Ok(Self {
|
||||
data: DataBlock::new_zeroed(size),
|
||||
mode,
|
||||
range,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUBuffer {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "defined in webgpu"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
label: DomRefCell<USVString>,
|
||||
#[no_trace]
|
||||
buffer: WebGPUBuffer,
|
||||
device: Dom<GPUDevice>,
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-size>
|
||||
size: GPUSize64,
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-usage>
|
||||
usage: GPUFlagsConstant,
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-pending_map-slot>
|
||||
#[ignore_malloc_size_of = "promises are hard"]
|
||||
pending_map: DomRefCell<Option<Rc<Promise>>>,
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-mapping-slot>
|
||||
mapping: DomRefCell<Option<ActiveBufferMapping>>,
|
||||
}
|
||||
|
||||
impl GPUBuffer {
|
||||
fn new_inherited(
|
||||
channel: WebGPU,
|
||||
buffer: WebGPUBuffer,
|
||||
device: &GPUDevice,
|
||||
size: GPUSize64,
|
||||
usage: GPUFlagsConstant,
|
||||
mapping: Option<ActiveBufferMapping>,
|
||||
label: USVString,
|
||||
) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
channel,
|
||||
label: DomRefCell::new(label),
|
||||
device: Dom::from_ref(device),
|
||||
buffer,
|
||||
pending_map: DomRefCell::new(None),
|
||||
size,
|
||||
usage,
|
||||
mapping: DomRefCell::new(mapping),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
channel: WebGPU,
|
||||
buffer: WebGPUBuffer,
|
||||
device: &GPUDevice,
|
||||
size: GPUSize64,
|
||||
usage: GPUFlagsConstant,
|
||||
mapping: Option<ActiveBufferMapping>,
|
||||
label: USVString,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPUBuffer::new_inherited(
|
||||
channel, buffer, device, size, usage, mapping, label,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUBuffer {
|
||||
pub fn id(&self) -> WebGPUBuffer {
|
||||
self.buffer
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbuffer>
|
||||
pub fn create(
|
||||
device: &GPUDevice,
|
||||
descriptor: &GPUBufferDescriptor,
|
||||
) -> Fallible<DomRoot<GPUBuffer>> {
|
||||
let desc = wgt::BufferDescriptor {
|
||||
label: (&descriptor.parent).into(),
|
||||
size: descriptor.size as wgt::BufferAddress,
|
||||
usage: wgt::BufferUsages::from_bits_retain(descriptor.usage),
|
||||
mapped_at_creation: descriptor.mappedAtCreation,
|
||||
};
|
||||
let id = device.global().wgpu_id_hub().create_buffer_id();
|
||||
|
||||
device
|
||||
.channel()
|
||||
.0
|
||||
.send(WebGPURequest::CreateBuffer {
|
||||
device_id: device.id().0,
|
||||
buffer_id: id,
|
||||
descriptor: desc,
|
||||
})
|
||||
.expect("Failed to create WebGPU buffer");
|
||||
|
||||
let buffer = WebGPUBuffer(id);
|
||||
let mapping = if descriptor.mappedAtCreation {
|
||||
Some(ActiveBufferMapping::new(
|
||||
GPUMapModeConstants::WRITE,
|
||||
0..descriptor.size,
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(GPUBuffer::new(
|
||||
&device.global(),
|
||||
device.channel().clone(),
|
||||
buffer,
|
||||
device,
|
||||
descriptor.size,
|
||||
descriptor.usage,
|
||||
mapping,
|
||||
descriptor.parent.label.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPUBuffer {
|
||||
fn drop(&mut self) {
|
||||
self.Destroy()
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUBufferMethods<crate::DomTypeHolder> for GPUBuffer {
|
||||
#[allow(unsafe_code)]
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-unmap>
|
||||
fn Unmap(&self) {
|
||||
// Step 1
|
||||
if let Some(promise) = self.pending_map.borrow_mut().take() {
|
||||
promise.reject_error(Error::Abort);
|
||||
}
|
||||
// Step 2
|
||||
let mut mapping = self.mapping.borrow_mut().take();
|
||||
let mapping = if let Some(mapping) = mapping.as_mut() {
|
||||
mapping
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Step 3
|
||||
mapping.data.clear_views();
|
||||
// Step 5&7
|
||||
if let Err(e) = self.channel.0.send(WebGPURequest::UnmapBuffer {
|
||||
buffer_id: self.id().0,
|
||||
mapping: if mapping.mode >= GPUMapModeConstants::WRITE {
|
||||
Some(Mapping {
|
||||
data: IpcSharedMemory::from_bytes(mapping.data.data()),
|
||||
range: mapping.range.clone(),
|
||||
mode: HostMap::Write,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}) {
|
||||
warn!("Failed to send Buffer unmap ({:?}) ({})", self.buffer.0, e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-destroy>
|
||||
fn Destroy(&self) {
|
||||
// Step 1
|
||||
self.Unmap();
|
||||
// Step 2
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DestroyBuffer(self.buffer.0))
|
||||
{
|
||||
warn!(
|
||||
"Failed to send WebGPURequest::DestroyBuffer({:?}) ({})",
|
||||
self.buffer.0, e
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-mapasync>
|
||||
fn MapAsync(
|
||||
&self,
|
||||
mode: u32,
|
||||
offset: GPUSize64,
|
||||
size: Option<GPUSize64>,
|
||||
comp: InRealm,
|
||||
can_gc: CanGc,
|
||||
) -> Rc<Promise> {
|
||||
let promise = Promise::new_in_current_realm(comp, can_gc);
|
||||
// Step 2
|
||||
if self.pending_map.borrow().is_some() {
|
||||
promise.reject_error(Error::Operation);
|
||||
return promise;
|
||||
}
|
||||
// Step 4
|
||||
*self.pending_map.borrow_mut() = Some(promise.clone());
|
||||
// Step 5
|
||||
let host_map = match mode {
|
||||
GPUMapModeConstants::READ => HostMap::Read,
|
||||
GPUMapModeConstants::WRITE => HostMap::Write,
|
||||
_ => {
|
||||
self.device
|
||||
.dispatch_error(webgpu::Error::Validation(String::from(
|
||||
"Invalid MapModeFlags",
|
||||
)));
|
||||
self.map_failure(&promise);
|
||||
return promise;
|
||||
},
|
||||
};
|
||||
|
||||
let sender = response_async(&promise, self);
|
||||
if let Err(e) = self.channel.0.send(WebGPURequest::BufferMapAsync {
|
||||
sender,
|
||||
buffer_id: self.buffer.0,
|
||||
device_id: self.device.id().0,
|
||||
host_map,
|
||||
offset,
|
||||
size,
|
||||
}) {
|
||||
warn!(
|
||||
"Failed to send BufferMapAsync ({:?}) ({})",
|
||||
self.buffer.0, e
|
||||
);
|
||||
self.map_failure(&promise);
|
||||
return promise;
|
||||
}
|
||||
// Step 6
|
||||
promise
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-getmappedrange>
|
||||
#[allow(unsafe_code)]
|
||||
fn GetMappedRange(
|
||||
&self,
|
||||
_cx: JSContext,
|
||||
offset: GPUSize64,
|
||||
size: Option<GPUSize64>,
|
||||
) -> Fallible<ArrayBuffer> {
|
||||
let range_size = if let Some(s) = size {
|
||||
s
|
||||
} else {
|
||||
self.size.saturating_sub(offset)
|
||||
};
|
||||
// Step 2: validation
|
||||
let mut mapping = self.mapping.borrow_mut();
|
||||
let mapping = mapping.as_mut().ok_or(Error::Operation)?;
|
||||
|
||||
let valid = offset % wgt::MAP_ALIGNMENT == 0 &&
|
||||
range_size % wgt::COPY_BUFFER_ALIGNMENT == 0 &&
|
||||
offset >= mapping.range.start &&
|
||||
offset + range_size <= mapping.range.end;
|
||||
if !valid {
|
||||
return Err(Error::Operation);
|
||||
}
|
||||
|
||||
// Step 4
|
||||
// only mapping.range is mapped with mapping.range.start at 0
|
||||
// so we need to rebase range to mapped.range
|
||||
let rebased_offset = (offset - mapping.range.start) as usize;
|
||||
mapping
|
||||
.data
|
||||
.view(rebased_offset..rebased_offset + range_size as usize)
|
||||
.map(|view| view.array_buffer())
|
||||
.map_err(|()| Error::Operation)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-size>
|
||||
fn Size(&self) -> GPUSize64 {
|
||||
self.size
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-usage>
|
||||
fn Usage(&self) -> GPUFlagsConstant {
|
||||
self.usage
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-mapstate>
|
||||
fn MapState(&self) -> GPUBufferMapState {
|
||||
// Step 1&2&3
|
||||
if self.mapping.borrow().is_some() {
|
||||
GPUBufferMapState::Mapped
|
||||
} else if self.pending_map.borrow().is_some() {
|
||||
GPUBufferMapState::Pending
|
||||
} else {
|
||||
GPUBufferMapState::Unmapped
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUBuffer {
|
||||
fn map_failure(&self, p: &Rc<Promise>) {
|
||||
let mut pending_map = self.pending_map.borrow_mut();
|
||||
// Step 1
|
||||
if pending_map.as_ref() != Some(p) {
|
||||
assert!(p.is_rejected());
|
||||
return;
|
||||
}
|
||||
// Step 2
|
||||
assert!(p.is_pending());
|
||||
// Step 3
|
||||
pending_map.take();
|
||||
// Step 4
|
||||
if self.device.is_lost() {
|
||||
p.reject_error(Error::Abort);
|
||||
} else {
|
||||
p.reject_error(Error::Operation);
|
||||
}
|
||||
}
|
||||
|
||||
fn map_success(&self, p: &Rc<Promise>, wgpu_mapping: Mapping) {
|
||||
let mut pending_map = self.pending_map.borrow_mut();
|
||||
|
||||
// Step 1
|
||||
if pending_map.as_ref() != Some(p) {
|
||||
assert!(p.is_rejected());
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2
|
||||
assert!(p.is_pending());
|
||||
|
||||
// Step 4
|
||||
let mapping = ActiveBufferMapping::new(
|
||||
match wgpu_mapping.mode {
|
||||
HostMap::Read => GPUMapModeConstants::READ,
|
||||
HostMap::Write => GPUMapModeConstants::WRITE,
|
||||
},
|
||||
wgpu_mapping.range,
|
||||
);
|
||||
|
||||
match mapping {
|
||||
Err(error) => {
|
||||
*pending_map = None;
|
||||
p.reject_error(error.clone());
|
||||
},
|
||||
Ok(mut mapping) => {
|
||||
// Step 5
|
||||
mapping.data.load(&wgpu_mapping.data);
|
||||
// Step 6
|
||||
self.mapping.borrow_mut().replace(mapping);
|
||||
// Step 7
|
||||
pending_map.take();
|
||||
p.resolve_native(&());
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncWGPUListener for GPUBuffer {
|
||||
#[allow(unsafe_code)]
|
||||
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>, _can_gc: CanGc) {
|
||||
match response {
|
||||
WebGPUResponse::BufferMapAsync(Ok(mapping)) => self.map_success(promise, mapping),
|
||||
WebGPUResponse::BufferMapAsync(Err(_)) => self.map_failure(promise),
|
||||
_ => unreachable!("Wrong response received on AsyncWGPUListener for GPUBuffer"),
|
||||
}
|
||||
}
|
||||
}
|
12
components/script/dom/webgpu/gpubufferusage.rs
Normal file
12
components/script/dom/webgpu/gpubufferusage.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::reflector::Reflector;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUBufferUsage {
|
||||
reflector_: Reflector,
|
||||
}
|
386
components/script/dom/webgpu/gpucanvascontext.rs
Normal file
386
components/script/dom/webgpu/gpucanvascontext.rs
Normal file
|
@ -0,0 +1,386 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use dom_struct::dom_struct;
|
||||
use euclid::default::Size2D;
|
||||
use ipc_channel::ipc;
|
||||
use script_layout_interface::HTMLCanvasDataSource;
|
||||
use webgpu::swapchain::WebGPUContextId;
|
||||
use webgpu::wgc::id;
|
||||
use webgpu::{
|
||||
ContextConfiguration, WebGPU, WebGPURequest, WebGPUTexture, PRESENTATION_BUFFER_COUNT,
|
||||
};
|
||||
use webrender_api::units::DeviceIntSize;
|
||||
use webrender_api::ImageKey;
|
||||
|
||||
use super::gpuconvert::convert_texture_descriptor;
|
||||
use super::gputexture::GPUTexture;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUTexture_Binding::GPUTextureMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUCanvasAlphaMode, GPUCanvasConfiguration, GPUCanvasContextMethods, GPUDeviceMethods,
|
||||
GPUExtent3D, GPUExtent3DDict, GPUObjectDescriptorBase, GPUTextureDescriptor,
|
||||
GPUTextureDimension, GPUTextureFormat, GPUTextureUsageConstants,
|
||||
};
|
||||
use crate::dom::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanvas;
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::htmlcanvaselement::{HTMLCanvasElement, LayoutCanvasRenderingContextHelpers};
|
||||
use crate::dom::node::{document_from_node, Node, NodeDamage};
|
||||
|
||||
impl HTMLCanvasElementOrOffscreenCanvas {
|
||||
fn size(&self) -> Size2D<u64> {
|
||||
match self {
|
||||
HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(canvas) => {
|
||||
canvas.get_size().cast()
|
||||
},
|
||||
HTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(canvas) => canvas.get_size(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#supported-context-formats>
|
||||
fn supported_context_format(format: GPUTextureFormat) -> bool {
|
||||
// TODO: GPUTextureFormat::Rgba16float
|
||||
matches!(
|
||||
format,
|
||||
GPUTextureFormat::Bgra8unorm | GPUTextureFormat::Rgba8unorm
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, JSTraceable, MallocSizeOf)]
|
||||
/// Helps observe changes on swapchain
|
||||
struct DrawingBuffer {
|
||||
#[no_trace]
|
||||
size: DeviceIntSize,
|
||||
/// image is transparent black
|
||||
cleared: bool,
|
||||
#[ignore_malloc_size_of = "Defined in wgpu"]
|
||||
#[no_trace]
|
||||
config: Option<ContextConfiguration>,
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUCanvasContext {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-canvas>
|
||||
canvas: HTMLCanvasElementOrOffscreenCanvas,
|
||||
// TODO: can we have wgpu surface that is hw accelerated inside wr ...
|
||||
#[ignore_malloc_size_of = "Defined in webrender"]
|
||||
#[no_trace]
|
||||
webrender_image: ImageKey,
|
||||
#[no_trace]
|
||||
context_id: WebGPUContextId,
|
||||
#[ignore_malloc_size_of = "manual writing is hard"]
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-configuration-slot>
|
||||
configuration: RefCell<Option<GPUCanvasConfiguration>>,
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-texturedescriptor-slot>
|
||||
texture_descriptor: RefCell<Option<GPUTextureDescriptor>>,
|
||||
/// Conceptually <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-drawingbuffer-slot>
|
||||
drawing_buffer: RefCell<DrawingBuffer>,
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-currenttexture-slot>
|
||||
current_texture: MutNullableDom<GPUTexture>,
|
||||
}
|
||||
|
||||
impl GPUCanvasContext {
|
||||
fn new_inherited(
|
||||
global: &GlobalScope,
|
||||
canvas: HTMLCanvasElementOrOffscreenCanvas,
|
||||
channel: WebGPU,
|
||||
) -> Self {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
let size = canvas.size().cast().cast_unit();
|
||||
let mut buffer_ids = ArrayVec::<id::BufferId, PRESENTATION_BUFFER_COUNT>::new();
|
||||
for _ in 0..PRESENTATION_BUFFER_COUNT {
|
||||
buffer_ids.push(global.wgpu_id_hub().create_buffer_id());
|
||||
}
|
||||
if let Err(e) = channel.0.send(WebGPURequest::CreateContext {
|
||||
buffer_ids,
|
||||
size,
|
||||
sender,
|
||||
}) {
|
||||
warn!("Failed to send CreateContext ({:?})", e);
|
||||
}
|
||||
let (external_id, webrender_image) = receiver.recv().unwrap();
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
channel,
|
||||
canvas,
|
||||
webrender_image,
|
||||
context_id: WebGPUContextId(external_id.0),
|
||||
drawing_buffer: RefCell::new(DrawingBuffer {
|
||||
size,
|
||||
cleared: true,
|
||||
..Default::default()
|
||||
}),
|
||||
configuration: RefCell::new(None),
|
||||
texture_descriptor: RefCell::new(None),
|
||||
current_texture: MutNullableDom::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope, canvas: &HTMLCanvasElement, channel: WebGPU) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPUCanvasContext::new_inherited(
|
||||
global,
|
||||
HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(DomRoot::from_ref(canvas)),
|
||||
channel,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Abstract ops from spec
|
||||
impl GPUCanvasContext {
|
||||
/// <https://gpuweb.github.io/gpuweb/#abstract-opdef-gputexturedescriptor-for-the-canvas-and-configuration>
|
||||
fn texture_descriptor_for_canvas(
|
||||
&self,
|
||||
configuration: &GPUCanvasConfiguration,
|
||||
) -> GPUTextureDescriptor {
|
||||
let size = self.size();
|
||||
GPUTextureDescriptor {
|
||||
format: configuration.format,
|
||||
// We need to add `COPY_SRC` so we can copy texture to presentation buffer
|
||||
// causes FAIL on webgpu:web_platform,canvas,configure:usage:*
|
||||
usage: configuration.usage | GPUTextureUsageConstants::COPY_SRC,
|
||||
size: GPUExtent3D::GPUExtent3DDict(GPUExtent3DDict {
|
||||
width: size.width as u32,
|
||||
height: size.height as u32,
|
||||
depthOrArrayLayers: 1,
|
||||
}),
|
||||
viewFormats: configuration.viewFormats.clone(),
|
||||
// other members to default
|
||||
mipLevelCount: 1,
|
||||
sampleCount: 1,
|
||||
parent: GPUObjectDescriptorBase {
|
||||
label: USVString::default(),
|
||||
},
|
||||
dimension: GPUTextureDimension::_2d,
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#abstract-opdef-expire-the-current-texture>
|
||||
fn expire_current_texture(&self) {
|
||||
if let Some(current_texture) = self.current_texture.take() {
|
||||
// Make copy of texture content
|
||||
self.send_swap_chain_present(current_texture.id());
|
||||
// Step 1
|
||||
current_texture.Destroy()
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#abstract-opdef-replace-the-drawing-buffer>
|
||||
fn replace_drawing_buffer(&self) {
|
||||
// Step 1
|
||||
self.expire_current_texture();
|
||||
// Step 2
|
||||
let configuration = self.configuration.borrow();
|
||||
// Step 3
|
||||
let mut drawing_buffer = self.drawing_buffer.borrow_mut();
|
||||
drawing_buffer.size = self.size().cast().cast_unit();
|
||||
drawing_buffer.cleared = true;
|
||||
if let Some(configuration) = configuration.as_ref() {
|
||||
drawing_buffer.config = Some(ContextConfiguration {
|
||||
device_id: configuration.device.id().0,
|
||||
queue_id: configuration.device.queue_id().0,
|
||||
format: configuration.format.into(),
|
||||
is_opaque: matches!(configuration.alphaMode, GPUCanvasAlphaMode::Opaque),
|
||||
});
|
||||
} else {
|
||||
drawing_buffer.config.take();
|
||||
};
|
||||
// TODO: send less
|
||||
self.channel
|
||||
.0
|
||||
.send(WebGPURequest::UpdateContext {
|
||||
context_id: self.context_id,
|
||||
size: drawing_buffer.size,
|
||||
configuration: drawing_buffer.config,
|
||||
})
|
||||
.expect("Failed to update webgpu context");
|
||||
}
|
||||
}
|
||||
|
||||
// Internal helper methods
|
||||
impl GPUCanvasContext {
|
||||
fn layout_handle(&self) -> HTMLCanvasDataSource {
|
||||
if self.drawing_buffer.borrow().cleared {
|
||||
HTMLCanvasDataSource::Empty
|
||||
} else {
|
||||
HTMLCanvasDataSource::WebGPU(self.webrender_image)
|
||||
}
|
||||
}
|
||||
|
||||
fn send_swap_chain_present(&self, texture_id: WebGPUTexture) {
|
||||
self.drawing_buffer.borrow_mut().cleared = false;
|
||||
let encoder_id = self.global().wgpu_id_hub().create_command_encoder_id();
|
||||
if let Err(e) = self.channel.0.send(WebGPURequest::SwapChainPresent {
|
||||
context_id: self.context_id,
|
||||
texture_id: texture_id.0,
|
||||
encoder_id,
|
||||
}) {
|
||||
warn!(
|
||||
"Failed to send UpdateWebrenderData({:?}) ({})",
|
||||
self.context_id, e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn size(&self) -> Size2D<u64> {
|
||||
self.canvas.size()
|
||||
}
|
||||
}
|
||||
|
||||
// public methods for canvas handling
|
||||
// these methods should probably be behind trait for all canvases
|
||||
impl GPUCanvasContext {
|
||||
pub(crate) fn context_id(&self) -> WebGPUContextId {
|
||||
self.context_id
|
||||
}
|
||||
|
||||
pub(crate) fn mark_as_dirty(&self) {
|
||||
if let HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(canvas) = &self.canvas {
|
||||
canvas.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||
let document = document_from_node(&**canvas);
|
||||
document.add_dirty_webgpu_canvas(self);
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#abstract-opdef-updating-the-rendering-of-a-webgpu-canvas>
|
||||
pub(crate) fn update_rendering_of_webgpu_canvas(&self) {
|
||||
// Step 1
|
||||
self.expire_current_texture();
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#abstract-opdef-update-the-canvas-size>
|
||||
pub(crate) fn resize(&self) {
|
||||
// Step 1
|
||||
self.replace_drawing_buffer();
|
||||
// Step 2
|
||||
let configuration = self.configuration.borrow();
|
||||
// Step 3
|
||||
if let Some(configuration) = configuration.as_ref() {
|
||||
self.texture_descriptor
|
||||
.replace(Some(self.texture_descriptor_for_canvas(configuration)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, GPUCanvasContext> {
|
||||
fn canvas_data_source(self) -> HTMLCanvasDataSource {
|
||||
(*self.unsafe_get()).layout_handle()
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUCanvasContextMethods<crate::DomTypeHolder> for GPUCanvasContext {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-canvas>
|
||||
fn Canvas(&self) -> HTMLCanvasElementOrOffscreenCanvas {
|
||||
self.canvas.clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-configure>
|
||||
fn Configure(&self, configuration: &GPUCanvasConfiguration) -> Fallible<()> {
|
||||
// Step 1: Let device be configuration.device
|
||||
let device = &configuration.device;
|
||||
|
||||
// Step 5: Let descriptor be the GPUTextureDescriptor for the canvas and configuration.
|
||||
let descriptor = self.texture_descriptor_for_canvas(configuration);
|
||||
|
||||
// Step 2&3: Validate texture format required features
|
||||
let (mut desc, _) = convert_texture_descriptor(&descriptor, device)?;
|
||||
desc.label = Some(Cow::Borrowed(
|
||||
"dummy texture for texture descriptor validation",
|
||||
));
|
||||
|
||||
// Step 4: If Supported context formats does not contain configuration.format, throw a TypeError
|
||||
if !supported_context_format(configuration.format) {
|
||||
return Err(Error::Type(format!(
|
||||
"Unsupported context format: {:?}",
|
||||
configuration.format
|
||||
)));
|
||||
}
|
||||
|
||||
// Step 5
|
||||
self.configuration.replace(Some(configuration.clone()));
|
||||
|
||||
// Step 6
|
||||
self.texture_descriptor.replace(Some(descriptor));
|
||||
|
||||
// Step 7
|
||||
self.replace_drawing_buffer();
|
||||
|
||||
// Step 8: Validate texture descriptor
|
||||
let texture_id = self.global().wgpu_id_hub().create_texture_id();
|
||||
self.channel
|
||||
.0
|
||||
.send(WebGPURequest::ValidateTextureDescriptor {
|
||||
device_id: device.id().0,
|
||||
texture_id,
|
||||
descriptor: desc,
|
||||
})
|
||||
.expect("Failed to create WebGPU SwapChain");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-unconfigure>
|
||||
fn Unconfigure(&self) {
|
||||
// Step 1
|
||||
self.configuration.take();
|
||||
// Step 2
|
||||
self.current_texture.take();
|
||||
// Step 3
|
||||
self.replace_drawing_buffer();
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-getcurrenttexture>
|
||||
fn GetCurrentTexture(&self) -> Fallible<DomRoot<GPUTexture>> {
|
||||
// Step 1
|
||||
let configuration = self.configuration.borrow();
|
||||
let Some(configuration) = configuration.as_ref() else {
|
||||
return Err(Error::InvalidState);
|
||||
};
|
||||
// Step 2
|
||||
let texture_descriptor = self.texture_descriptor.borrow();
|
||||
let texture_descriptor = texture_descriptor.as_ref().unwrap();
|
||||
// Step 6
|
||||
let current_texture = if let Some(current_texture) = self.current_texture.get() {
|
||||
current_texture
|
||||
} else {
|
||||
// Step 3&4
|
||||
self.replace_drawing_buffer();
|
||||
let current_texture = configuration.device.CreateTexture(texture_descriptor)?;
|
||||
self.current_texture.set(Some(¤t_texture));
|
||||
current_texture
|
||||
};
|
||||
// Step 5
|
||||
self.mark_as_dirty();
|
||||
// Step 6
|
||||
Ok(current_texture)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPUCanvasContext {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self.channel.0.send(WebGPURequest::DestroyContext {
|
||||
context_id: self.context_id,
|
||||
}) {
|
||||
warn!(
|
||||
"Failed to send DestroySwapChain-ImageKey({:?}) ({})",
|
||||
self.webrender_image, e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
12
components/script/dom/webgpu/gpucolorwrite.rs
Normal file
12
components/script/dom/webgpu/gpucolorwrite.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::reflector::Reflector;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUColorWrite {
|
||||
reflector_: Reflector,
|
||||
}
|
88
components/script/dom/webgpu/gpucommandbuffer.rs
Normal file
88
components/script/dom/webgpu/gpucommandbuffer.rs
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use webgpu::{WebGPU, WebGPUCommandBuffer, WebGPURequest};
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUCommandBufferMethods;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUCommandBuffer {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "defined in webgpu"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
label: DomRefCell<USVString>,
|
||||
#[no_trace]
|
||||
command_buffer: WebGPUCommandBuffer,
|
||||
}
|
||||
|
||||
impl GPUCommandBuffer {
|
||||
fn new_inherited(
|
||||
channel: WebGPU,
|
||||
command_buffer: WebGPUCommandBuffer,
|
||||
label: USVString,
|
||||
) -> Self {
|
||||
Self {
|
||||
channel,
|
||||
reflector_: Reflector::new(),
|
||||
label: DomRefCell::new(label),
|
||||
command_buffer,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
channel: WebGPU,
|
||||
command_buffer: WebGPUCommandBuffer,
|
||||
label: USVString,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPUCommandBuffer::new_inherited(
|
||||
channel,
|
||||
command_buffer,
|
||||
label,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPUCommandBuffer {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DropCommandBuffer(self.command_buffer.0))
|
||||
{
|
||||
warn!(
|
||||
"Failed to send DropCommandBuffer({:?}) ({})",
|
||||
self.command_buffer.0, e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUCommandBuffer {
|
||||
pub fn id(&self) -> WebGPUCommandBuffer {
|
||||
self.command_buffer
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUCommandBufferMethods<crate::DomTypeHolder> for GPUCommandBuffer {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
}
|
319
components/script/dom/webgpu/gpucommandencoder.rs
Normal file
319
components/script/dom/webgpu/gpucommandencoder.rs
Normal file
|
@ -0,0 +1,319 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use webgpu::wgc::command as wgpu_com;
|
||||
use webgpu::{
|
||||
wgt, WebGPU, WebGPUCommandBuffer, WebGPUCommandEncoder, WebGPUComputePass, WebGPUDevice,
|
||||
WebGPURenderPass, WebGPURequest,
|
||||
};
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUCommandBufferDescriptor, GPUCommandEncoderDescriptor, GPUCommandEncoderMethods,
|
||||
GPUComputePassDescriptor, GPUExtent3D, GPUImageCopyBuffer, GPUImageCopyTexture,
|
||||
GPURenderPassDescriptor, GPUSize64,
|
||||
};
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpubuffer::GPUBuffer;
|
||||
use crate::dom::gpucommandbuffer::GPUCommandBuffer;
|
||||
use crate::dom::gpucomputepassencoder::GPUComputePassEncoder;
|
||||
use crate::dom::gpuconvert::{convert_load_op, convert_store_op};
|
||||
use crate::dom::gpudevice::GPUDevice;
|
||||
use crate::dom::gpurenderpassencoder::GPURenderPassEncoder;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUCommandEncoder {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "defined in webgpu"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
label: DomRefCell<USVString>,
|
||||
#[no_trace]
|
||||
encoder: WebGPUCommandEncoder,
|
||||
device: Dom<GPUDevice>,
|
||||
}
|
||||
|
||||
impl GPUCommandEncoder {
|
||||
pub fn new_inherited(
|
||||
channel: WebGPU,
|
||||
device: &GPUDevice,
|
||||
encoder: WebGPUCommandEncoder,
|
||||
label: USVString,
|
||||
) -> Self {
|
||||
Self {
|
||||
channel,
|
||||
reflector_: Reflector::new(),
|
||||
label: DomRefCell::new(label),
|
||||
device: Dom::from_ref(device),
|
||||
encoder,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
channel: WebGPU,
|
||||
device: &GPUDevice,
|
||||
encoder: WebGPUCommandEncoder,
|
||||
label: USVString,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPUCommandEncoder::new_inherited(
|
||||
channel, device, encoder, label,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUCommandEncoder {
|
||||
pub fn id(&self) -> WebGPUCommandEncoder {
|
||||
self.encoder
|
||||
}
|
||||
|
||||
pub fn device_id(&self) -> WebGPUDevice {
|
||||
self.device.id()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createcommandencoder>
|
||||
pub fn create(
|
||||
device: &GPUDevice,
|
||||
descriptor: &GPUCommandEncoderDescriptor,
|
||||
) -> DomRoot<GPUCommandEncoder> {
|
||||
let command_encoder_id = device.global().wgpu_id_hub().create_command_encoder_id();
|
||||
device
|
||||
.channel()
|
||||
.0
|
||||
.send(WebGPURequest::CreateCommandEncoder {
|
||||
device_id: device.id().0,
|
||||
command_encoder_id,
|
||||
desc: wgt::CommandEncoderDescriptor {
|
||||
label: (&descriptor.parent).into(),
|
||||
},
|
||||
})
|
||||
.expect("Failed to create WebGPU command encoder");
|
||||
|
||||
let encoder = WebGPUCommandEncoder(command_encoder_id);
|
||||
|
||||
GPUCommandEncoder::new(
|
||||
&device.global(),
|
||||
device.channel().clone(),
|
||||
device,
|
||||
encoder,
|
||||
descriptor.parent.label.clone(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUCommandEncoderMethods<crate::DomTypeHolder> for GPUCommandEncoder {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-begincomputepass>
|
||||
fn BeginComputePass(
|
||||
&self,
|
||||
descriptor: &GPUComputePassDescriptor,
|
||||
) -> DomRoot<GPUComputePassEncoder> {
|
||||
let compute_pass_id = self.global().wgpu_id_hub().create_compute_pass_id();
|
||||
|
||||
if let Err(e) = self.channel.0.send(WebGPURequest::BeginComputePass {
|
||||
command_encoder_id: self.id().0,
|
||||
compute_pass_id,
|
||||
label: (&descriptor.parent).into(),
|
||||
device_id: self.device.id().0,
|
||||
}) {
|
||||
warn!("Failed to send WebGPURequest::BeginComputePass {e:?}");
|
||||
}
|
||||
|
||||
GPUComputePassEncoder::new(
|
||||
&self.global(),
|
||||
self.channel.clone(),
|
||||
self,
|
||||
WebGPUComputePass(compute_pass_id),
|
||||
descriptor.parent.label.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-beginrenderpass>
|
||||
fn BeginRenderPass(
|
||||
&self,
|
||||
descriptor: &GPURenderPassDescriptor,
|
||||
) -> Fallible<DomRoot<GPURenderPassEncoder>> {
|
||||
let depth_stencil_attachment = descriptor.depthStencilAttachment.as_ref().map(|depth| {
|
||||
wgpu_com::RenderPassDepthStencilAttachment {
|
||||
depth: wgpu_com::PassChannel {
|
||||
load_op: convert_load_op(depth.depthLoadOp),
|
||||
store_op: convert_store_op(depth.depthStoreOp),
|
||||
clear_value: *depth.depthClearValue.unwrap_or_default(),
|
||||
read_only: depth.depthReadOnly,
|
||||
},
|
||||
stencil: wgpu_com::PassChannel {
|
||||
load_op: convert_load_op(depth.stencilLoadOp),
|
||||
store_op: convert_store_op(depth.stencilStoreOp),
|
||||
clear_value: depth.stencilClearValue,
|
||||
read_only: depth.stencilReadOnly,
|
||||
},
|
||||
view: depth.view.id().0,
|
||||
}
|
||||
});
|
||||
|
||||
let color_attachments = descriptor
|
||||
.colorAttachments
|
||||
.iter()
|
||||
.map(|color| -> Fallible<_> {
|
||||
let channel = wgpu_com::PassChannel {
|
||||
load_op: convert_load_op(Some(color.loadOp)),
|
||||
store_op: convert_store_op(Some(color.storeOp)),
|
||||
clear_value: color
|
||||
.clearValue
|
||||
.as_ref()
|
||||
.map(|color| (color).try_into())
|
||||
.transpose()?
|
||||
.unwrap_or_default(),
|
||||
read_only: false,
|
||||
};
|
||||
Ok(Some(wgpu_com::RenderPassColorAttachment {
|
||||
resolve_target: color.resolveTarget.as_ref().map(|t| t.id().0),
|
||||
channel,
|
||||
view: color.view.id().0,
|
||||
}))
|
||||
})
|
||||
.collect::<Fallible<Vec<_>>>()?;
|
||||
let render_pass_id = self.global().wgpu_id_hub().create_render_pass_id();
|
||||
|
||||
if let Err(e) = self.channel.0.send(WebGPURequest::BeginRenderPass {
|
||||
command_encoder_id: self.id().0,
|
||||
render_pass_id,
|
||||
label: (&descriptor.parent).into(),
|
||||
depth_stencil_attachment,
|
||||
color_attachments,
|
||||
device_id: self.device.id().0,
|
||||
}) {
|
||||
warn!("Failed to send WebGPURequest::BeginRenderPass {e:?}");
|
||||
}
|
||||
|
||||
Ok(GPURenderPassEncoder::new(
|
||||
&self.global(),
|
||||
self.channel.clone(),
|
||||
WebGPURenderPass(render_pass_id),
|
||||
self,
|
||||
descriptor.parent.label.clone(),
|
||||
))
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-copybuffertobuffer>
|
||||
fn CopyBufferToBuffer(
|
||||
&self,
|
||||
source: &GPUBuffer,
|
||||
source_offset: GPUSize64,
|
||||
destination: &GPUBuffer,
|
||||
destination_offset: GPUSize64,
|
||||
size: GPUSize64,
|
||||
) {
|
||||
self.channel
|
||||
.0
|
||||
.send(WebGPURequest::CopyBufferToBuffer {
|
||||
command_encoder_id: self.encoder.0,
|
||||
source_id: source.id().0,
|
||||
source_offset,
|
||||
destination_id: destination.id().0,
|
||||
destination_offset,
|
||||
size,
|
||||
})
|
||||
.expect("Failed to send CopyBufferToBuffer");
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-copybuffertotexture>
|
||||
fn CopyBufferToTexture(
|
||||
&self,
|
||||
source: &GPUImageCopyBuffer,
|
||||
destination: &GPUImageCopyTexture,
|
||||
copy_size: GPUExtent3D,
|
||||
) -> Fallible<()> {
|
||||
self.channel
|
||||
.0
|
||||
.send(WebGPURequest::CopyBufferToTexture {
|
||||
command_encoder_id: self.encoder.0,
|
||||
source: source.into(),
|
||||
destination: destination.try_into()?,
|
||||
copy_size: (©_size).try_into()?,
|
||||
})
|
||||
.expect("Failed to send CopyBufferToTexture");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-copybuffertotexture>
|
||||
fn CopyTextureToBuffer(
|
||||
&self,
|
||||
source: &GPUImageCopyTexture,
|
||||
destination: &GPUImageCopyBuffer,
|
||||
copy_size: GPUExtent3D,
|
||||
) -> Fallible<()> {
|
||||
self.channel
|
||||
.0
|
||||
.send(WebGPURequest::CopyTextureToBuffer {
|
||||
command_encoder_id: self.encoder.0,
|
||||
source: source.try_into()?,
|
||||
destination: destination.into(),
|
||||
copy_size: (©_size).try_into()?,
|
||||
})
|
||||
.expect("Failed to send CopyTextureToBuffer");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#GPUCommandEncoder-copyTextureToTexture>
|
||||
fn CopyTextureToTexture(
|
||||
&self,
|
||||
source: &GPUImageCopyTexture,
|
||||
destination: &GPUImageCopyTexture,
|
||||
copy_size: GPUExtent3D,
|
||||
) -> Fallible<()> {
|
||||
self.channel
|
||||
.0
|
||||
.send(WebGPURequest::CopyTextureToTexture {
|
||||
command_encoder_id: self.encoder.0,
|
||||
source: source.try_into()?,
|
||||
destination: destination.try_into()?,
|
||||
copy_size: (©_size).try_into()?,
|
||||
})
|
||||
.expect("Failed to send CopyTextureToTexture");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-finish>
|
||||
fn Finish(&self, descriptor: &GPUCommandBufferDescriptor) -> DomRoot<GPUCommandBuffer> {
|
||||
self.channel
|
||||
.0
|
||||
.send(WebGPURequest::CommandEncoderFinish {
|
||||
command_encoder_id: self.encoder.0,
|
||||
device_id: self.device.id().0,
|
||||
desc: wgt::CommandBufferDescriptor {
|
||||
label: (&descriptor.parent).into(),
|
||||
},
|
||||
})
|
||||
.expect("Failed to send Finish");
|
||||
|
||||
let buffer = WebGPUCommandBuffer(self.encoder.0.into_command_buffer_id());
|
||||
GPUCommandBuffer::new(
|
||||
&self.global(),
|
||||
self.channel.clone(),
|
||||
buffer,
|
||||
descriptor.parent.label.clone(),
|
||||
)
|
||||
}
|
||||
}
|
63
components/script/dom/webgpu/gpucompilationinfo.rs
Normal file
63
components/script/dom/webgpu/gpucompilationinfo.rs
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use js::rust::MutableHandleValue;
|
||||
use webgpu::ShaderCompilationInfo;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUCompilationInfoMethods;
|
||||
use crate::dom::bindings::import::module::DomRoot;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, Reflector};
|
||||
use crate::dom::bindings::utils::to_frozen_array;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::types::GPUCompilationMessage;
|
||||
use crate::script_runtime::{CanGc, JSContext};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUCompilationInfo {
|
||||
reflector_: Reflector,
|
||||
// currently we only get one message from wgpu
|
||||
msg: Vec<DomRoot<GPUCompilationMessage>>,
|
||||
}
|
||||
|
||||
impl GPUCompilationInfo {
|
||||
pub fn new_inherited(msg: Vec<DomRoot<GPUCompilationMessage>>) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
msg,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
msg: Vec<DomRoot<GPUCompilationMessage>>,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object_with_proto(Box::new(Self::new_inherited(msg)), global, None, can_gc)
|
||||
}
|
||||
|
||||
pub fn from(
|
||||
global: &GlobalScope,
|
||||
error: Option<ShaderCompilationInfo>,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
Self::new(
|
||||
global,
|
||||
if let Some(error) = error {
|
||||
vec![GPUCompilationMessage::from(global, error)]
|
||||
} else {
|
||||
Vec::new()
|
||||
},
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUCompilationInfoMethods<crate::DomTypeHolder> for GPUCompilationInfo {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucompilationinfo-messages>
|
||||
fn Messages(&self, cx: JSContext, retval: MutableHandleValue) {
|
||||
to_frozen_array(self.msg.as_slice(), cx, retval)
|
||||
}
|
||||
}
|
110
components/script/dom/webgpu/gpucompilationmessage.rs
Normal file
110
components/script/dom/webgpu/gpucompilationmessage.rs
Normal file
|
@ -0,0 +1,110 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#![allow(dead_code)] // this file is stub as wgpu does not provide info
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use webgpu::ShaderCompilationInfo;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUCompilationMessageMethods, GPUCompilationMessageType,
|
||||
};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::types::GlobalScope;
|
||||
use crate::test::DOMString;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUCompilationMessage {
|
||||
reflector_: Reflector,
|
||||
// #[ignore_malloc_size_of = "defined in wgpu-types"]
|
||||
message: DOMString,
|
||||
mtype: GPUCompilationMessageType,
|
||||
line_num: u64,
|
||||
line_pos: u64,
|
||||
offset: u64,
|
||||
length: u64,
|
||||
}
|
||||
|
||||
impl GPUCompilationMessage {
|
||||
fn new_inherited(
|
||||
message: DOMString,
|
||||
mtype: GPUCompilationMessageType,
|
||||
line_num: u64,
|
||||
line_pos: u64,
|
||||
offset: u64,
|
||||
length: u64,
|
||||
) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
message,
|
||||
mtype,
|
||||
line_num,
|
||||
line_pos,
|
||||
offset,
|
||||
length,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
message: DOMString,
|
||||
mtype: GPUCompilationMessageType,
|
||||
line_num: u64,
|
||||
line_pos: u64,
|
||||
offset: u64,
|
||||
length: u64,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(Self::new_inherited(
|
||||
message, mtype, line_num, line_pos, offset, length,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn from(global: &GlobalScope, info: ShaderCompilationInfo) -> DomRoot<Self> {
|
||||
GPUCompilationMessage::new(
|
||||
global,
|
||||
info.message.into(),
|
||||
GPUCompilationMessageType::Error,
|
||||
info.line_number,
|
||||
info.line_pos,
|
||||
info.offset,
|
||||
info.length,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUCompilationMessageMethods<crate::DomTypeHolder> for GPUCompilationMessage {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucompilationmessage-message>
|
||||
fn Message(&self) -> DOMString {
|
||||
self.message.to_owned()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucompilationmessage-type>
|
||||
fn Type(&self) -> GPUCompilationMessageType {
|
||||
self.mtype
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucompilationmessage-linenum>
|
||||
fn LineNum(&self) -> u64 {
|
||||
self.line_num
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucompilationmessage-linepos>
|
||||
fn LinePos(&self) -> u64 {
|
||||
self.line_pos
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucompilationmessage-offset>
|
||||
fn Offset(&self) -> u64 {
|
||||
self.offset
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucompilationmessage-length>
|
||||
fn Length(&self) -> u64 {
|
||||
self.length
|
||||
}
|
||||
}
|
156
components/script/dom/webgpu/gpucomputepassencoder.rs
Normal file
156
components/script/dom/webgpu/gpucomputepassencoder.rs
Normal file
|
@ -0,0 +1,156 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use webgpu::{WebGPU, WebGPUComputePass, WebGPURequest};
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUComputePassEncoderMethods;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpubindgroup::GPUBindGroup;
|
||||
use crate::dom::gpubuffer::GPUBuffer;
|
||||
use crate::dom::gpucommandencoder::GPUCommandEncoder;
|
||||
use crate::dom::gpucomputepipeline::GPUComputePipeline;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUComputePassEncoder {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "defined in webgpu"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
label: DomRefCell<USVString>,
|
||||
#[no_trace]
|
||||
compute_pass: WebGPUComputePass,
|
||||
command_encoder: Dom<GPUCommandEncoder>,
|
||||
}
|
||||
|
||||
impl GPUComputePassEncoder {
|
||||
fn new_inherited(
|
||||
channel: WebGPU,
|
||||
parent: &GPUCommandEncoder,
|
||||
compute_pass: WebGPUComputePass,
|
||||
label: USVString,
|
||||
) -> Self {
|
||||
Self {
|
||||
channel,
|
||||
reflector_: Reflector::new(),
|
||||
label: DomRefCell::new(label),
|
||||
compute_pass,
|
||||
command_encoder: Dom::from_ref(parent),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
channel: WebGPU,
|
||||
parent: &GPUCommandEncoder,
|
||||
compute_pass: WebGPUComputePass,
|
||||
label: USVString,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPUComputePassEncoder::new_inherited(
|
||||
channel,
|
||||
parent,
|
||||
compute_pass,
|
||||
label,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUComputePassEncoderMethods<crate::DomTypeHolder> for GPUComputePassEncoder {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucomputepassencoder-dispatchworkgroups>
|
||||
fn DispatchWorkgroups(&self, x: u32, y: u32, z: u32) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::ComputePassDispatchWorkgroups {
|
||||
compute_pass_id: self.compute_pass.0,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
device_id: self.command_encoder.device_id().0,
|
||||
})
|
||||
{
|
||||
warn!("Error sending WebGPURequest::ComputePassDispatchWorkgroups: {e:?}")
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucomputepassencoder-dispatchworkgroupsindirect>
|
||||
fn DispatchWorkgroupsIndirect(&self, buffer: &GPUBuffer, offset: u64) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::ComputePassDispatchWorkgroupsIndirect {
|
||||
compute_pass_id: self.compute_pass.0,
|
||||
buffer_id: buffer.id().0,
|
||||
offset,
|
||||
device_id: self.command_encoder.device_id().0,
|
||||
})
|
||||
{
|
||||
warn!("Error sending WebGPURequest::ComputePassDispatchWorkgroupsIndirect: {e:?}")
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-endpass>
|
||||
fn End(&self) {
|
||||
if let Err(e) = self.channel.0.send(WebGPURequest::EndComputePass {
|
||||
compute_pass_id: self.compute_pass.0,
|
||||
device_id: self.command_encoder.device_id().0,
|
||||
command_encoder_id: self.command_encoder.id().0,
|
||||
}) {
|
||||
warn!("Failed to send WebGPURequest::EndComputePass: {e:?}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuprogrammablepassencoder-setbindgroup>
|
||||
fn SetBindGroup(&self, index: u32, bind_group: &GPUBindGroup, offsets: Vec<u32>) {
|
||||
if let Err(e) = self.channel.0.send(WebGPURequest::ComputePassSetBindGroup {
|
||||
compute_pass_id: self.compute_pass.0,
|
||||
index,
|
||||
bind_group_id: bind_group.id().0,
|
||||
offsets,
|
||||
device_id: self.command_encoder.device_id().0,
|
||||
}) {
|
||||
warn!("Error sending WebGPURequest::ComputePassSetBindGroup: {e:?}")
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucomputepassencoder-setpipeline>
|
||||
fn SetPipeline(&self, pipeline: &GPUComputePipeline) {
|
||||
if let Err(e) = self.channel.0.send(WebGPURequest::ComputePassSetPipeline {
|
||||
compute_pass_id: self.compute_pass.0,
|
||||
pipeline_id: pipeline.id().0,
|
||||
device_id: self.command_encoder.device_id().0,
|
||||
}) {
|
||||
warn!("Error sending WebGPURequest::ComputePassSetPipeline: {e:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPUComputePassEncoder {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DropComputePass(self.compute_pass.0))
|
||||
{
|
||||
warn!("Failed to send WebGPURequest::DropComputePass with {e:?}");
|
||||
}
|
||||
}
|
||||
}
|
154
components/script/dom/webgpu/gpucomputepipeline.rs
Normal file
154
components/script/dom/webgpu/gpucomputepipeline.rs
Normal file
|
@ -0,0 +1,154 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use webgpu::wgc::pipeline::ComputePipelineDescriptor;
|
||||
use webgpu::{WebGPU, WebGPUBindGroupLayout, WebGPUComputePipeline, WebGPURequest, WebGPUResponse};
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUComputePipelineDescriptor, GPUComputePipelineMethods,
|
||||
};
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpubindgrouplayout::GPUBindGroupLayout;
|
||||
use crate::dom::gpudevice::GPUDevice;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUComputePipeline {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
label: DomRefCell<USVString>,
|
||||
#[no_trace]
|
||||
compute_pipeline: WebGPUComputePipeline,
|
||||
device: Dom<GPUDevice>,
|
||||
}
|
||||
|
||||
impl GPUComputePipeline {
|
||||
fn new_inherited(
|
||||
compute_pipeline: WebGPUComputePipeline,
|
||||
label: USVString,
|
||||
device: &GPUDevice,
|
||||
) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
channel: device.channel(),
|
||||
label: DomRefCell::new(label),
|
||||
compute_pipeline,
|
||||
device: Dom::from_ref(device),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
compute_pipeline: WebGPUComputePipeline,
|
||||
label: USVString,
|
||||
device: &GPUDevice,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPUComputePipeline::new_inherited(
|
||||
compute_pipeline,
|
||||
label,
|
||||
device,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUComputePipeline {
|
||||
pub fn id(&self) -> &WebGPUComputePipeline {
|
||||
&self.compute_pipeline
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createcomputepipeline>
|
||||
pub fn create(
|
||||
device: &GPUDevice,
|
||||
descriptor: &GPUComputePipelineDescriptor,
|
||||
async_sender: Option<IpcSender<WebGPUResponse>>,
|
||||
) -> WebGPUComputePipeline {
|
||||
let compute_pipeline_id = device.global().wgpu_id_hub().create_compute_pipeline_id();
|
||||
|
||||
let pipeline_layout = device.get_pipeline_layout_data(&descriptor.parent.layout);
|
||||
|
||||
let desc = ComputePipelineDescriptor {
|
||||
label: (&descriptor.parent.parent).into(),
|
||||
layout: pipeline_layout.explicit(),
|
||||
stage: (&descriptor.compute).into(),
|
||||
cache: None,
|
||||
};
|
||||
|
||||
device
|
||||
.channel()
|
||||
.0
|
||||
.send(WebGPURequest::CreateComputePipeline {
|
||||
device_id: device.id().0,
|
||||
compute_pipeline_id,
|
||||
descriptor: desc,
|
||||
implicit_ids: pipeline_layout.implicit(),
|
||||
async_sender,
|
||||
})
|
||||
.expect("Failed to create WebGPU ComputePipeline");
|
||||
|
||||
WebGPUComputePipeline(compute_pipeline_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUComputePipelineMethods<crate::DomTypeHolder> for GPUComputePipeline {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpupipelinebase-getbindgrouplayout>
|
||||
fn GetBindGroupLayout(&self, index: u32) -> Fallible<DomRoot<GPUBindGroupLayout>> {
|
||||
let id = self.global().wgpu_id_hub().create_bind_group_layout_id();
|
||||
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::ComputeGetBindGroupLayout {
|
||||
device_id: self.device.id().0,
|
||||
pipeline_id: self.compute_pipeline.0,
|
||||
index,
|
||||
id,
|
||||
})
|
||||
{
|
||||
warn!("Failed to send WebGPURequest::ComputeGetBindGroupLayout {e:?}");
|
||||
}
|
||||
|
||||
Ok(GPUBindGroupLayout::new(
|
||||
&self.global(),
|
||||
self.channel.clone(),
|
||||
WebGPUBindGroupLayout(id),
|
||||
USVString::default(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPUComputePipeline {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DropComputePipeline(self.compute_pipeline.0))
|
||||
{
|
||||
warn!(
|
||||
"Failed to send WebGPURequest::DropComputePipeline({:?}) ({})",
|
||||
self.compute_pipeline.0, e
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
680
components/script/dom/webgpu/gpuconvert.rs
Normal file
680
components/script/dom/webgpu/gpuconvert.rs
Normal file
|
@ -0,0 +1,680 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::num::NonZeroU64;
|
||||
|
||||
use webgpu::wgc::binding_model::{BindGroupEntry, BindingResource, BufferBinding};
|
||||
use webgpu::wgc::command as wgpu_com;
|
||||
use webgpu::wgc::pipeline::ProgrammableStageDescriptor;
|
||||
use webgpu::wgc::resource::TextureDescriptor;
|
||||
use webgpu::wgt::{self, AstcBlock, AstcChannel};
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUAddressMode, GPUBindGroupEntry, GPUBindGroupLayoutEntry, GPUBindingResource,
|
||||
GPUBlendComponent, GPUBlendFactor, GPUBlendOperation, GPUBufferBindingType, GPUColor,
|
||||
GPUCompareFunction, GPUCullMode, GPUExtent3D, GPUFilterMode, GPUFrontFace, GPUImageCopyBuffer,
|
||||
GPUImageCopyTexture, GPUImageDataLayout, GPUIndexFormat, GPULoadOp, GPUObjectDescriptorBase,
|
||||
GPUOrigin3D, GPUPrimitiveState, GPUPrimitiveTopology, GPUProgrammableStage,
|
||||
GPUSamplerBindingType, GPUStencilOperation, GPUStorageTextureAccess, GPUStoreOp,
|
||||
GPUTextureAspect, GPUTextureDescriptor, GPUTextureDimension, GPUTextureFormat,
|
||||
GPUTextureSampleType, GPUTextureViewDimension, GPUVertexFormat,
|
||||
};
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::types::GPUDevice;
|
||||
|
||||
impl From<GPUTextureFormat> for wgt::TextureFormat {
|
||||
fn from(format: GPUTextureFormat) -> Self {
|
||||
match format {
|
||||
GPUTextureFormat::R8unorm => wgt::TextureFormat::R8Unorm,
|
||||
GPUTextureFormat::R8snorm => wgt::TextureFormat::R8Snorm,
|
||||
GPUTextureFormat::R8uint => wgt::TextureFormat::R8Uint,
|
||||
GPUTextureFormat::R8sint => wgt::TextureFormat::R8Sint,
|
||||
GPUTextureFormat::R16uint => wgt::TextureFormat::R16Uint,
|
||||
GPUTextureFormat::R16sint => wgt::TextureFormat::R16Sint,
|
||||
GPUTextureFormat::R16float => wgt::TextureFormat::R16Float,
|
||||
GPUTextureFormat::Rg8unorm => wgt::TextureFormat::Rg8Unorm,
|
||||
GPUTextureFormat::Rg8snorm => wgt::TextureFormat::Rg8Snorm,
|
||||
GPUTextureFormat::Rg8uint => wgt::TextureFormat::Rg8Uint,
|
||||
GPUTextureFormat::Rg8sint => wgt::TextureFormat::Rg8Sint,
|
||||
GPUTextureFormat::R32uint => wgt::TextureFormat::R32Uint,
|
||||
GPUTextureFormat::R32sint => wgt::TextureFormat::R32Sint,
|
||||
GPUTextureFormat::R32float => wgt::TextureFormat::R32Float,
|
||||
GPUTextureFormat::Rg16uint => wgt::TextureFormat::Rg16Uint,
|
||||
GPUTextureFormat::Rg16sint => wgt::TextureFormat::Rg16Sint,
|
||||
GPUTextureFormat::Rg16float => wgt::TextureFormat::Rg16Float,
|
||||
GPUTextureFormat::Rgba8unorm => wgt::TextureFormat::Rgba8Unorm,
|
||||
GPUTextureFormat::Rgba8unorm_srgb => wgt::TextureFormat::Rgba8UnormSrgb,
|
||||
GPUTextureFormat::Rgba8snorm => wgt::TextureFormat::Rgba8Snorm,
|
||||
GPUTextureFormat::Rgba8uint => wgt::TextureFormat::Rgba8Uint,
|
||||
GPUTextureFormat::Rgba8sint => wgt::TextureFormat::Rgba8Sint,
|
||||
GPUTextureFormat::Bgra8unorm => wgt::TextureFormat::Bgra8Unorm,
|
||||
GPUTextureFormat::Bgra8unorm_srgb => wgt::TextureFormat::Bgra8UnormSrgb,
|
||||
GPUTextureFormat::Rgb10a2unorm => wgt::TextureFormat::Rgb10a2Unorm,
|
||||
GPUTextureFormat::Rg32uint => wgt::TextureFormat::Rg32Uint,
|
||||
GPUTextureFormat::Rg32sint => wgt::TextureFormat::Rg32Sint,
|
||||
GPUTextureFormat::Rg32float => wgt::TextureFormat::Rg32Float,
|
||||
GPUTextureFormat::Rgba16uint => wgt::TextureFormat::Rgba16Uint,
|
||||
GPUTextureFormat::Rgba16sint => wgt::TextureFormat::Rgba16Sint,
|
||||
GPUTextureFormat::Rgba16float => wgt::TextureFormat::Rgba16Float,
|
||||
GPUTextureFormat::Rgba32uint => wgt::TextureFormat::Rgba32Uint,
|
||||
GPUTextureFormat::Rgba32sint => wgt::TextureFormat::Rgba32Sint,
|
||||
GPUTextureFormat::Rgba32float => wgt::TextureFormat::Rgba32Float,
|
||||
GPUTextureFormat::Depth32float => wgt::TextureFormat::Depth32Float,
|
||||
GPUTextureFormat::Depth24plus => wgt::TextureFormat::Depth24Plus,
|
||||
GPUTextureFormat::Depth24plus_stencil8 => wgt::TextureFormat::Depth24PlusStencil8,
|
||||
GPUTextureFormat::Bc1_rgba_unorm => wgt::TextureFormat::Bc1RgbaUnorm,
|
||||
GPUTextureFormat::Bc1_rgba_unorm_srgb => wgt::TextureFormat::Bc1RgbaUnormSrgb,
|
||||
GPUTextureFormat::Bc2_rgba_unorm => wgt::TextureFormat::Bc2RgbaUnorm,
|
||||
GPUTextureFormat::Bc2_rgba_unorm_srgb => wgt::TextureFormat::Bc2RgbaUnormSrgb,
|
||||
GPUTextureFormat::Bc3_rgba_unorm => wgt::TextureFormat::Bc3RgbaUnorm,
|
||||
GPUTextureFormat::Bc3_rgba_unorm_srgb => wgt::TextureFormat::Bc3RgbaUnormSrgb,
|
||||
GPUTextureFormat::Bc4_r_unorm => wgt::TextureFormat::Bc4RUnorm,
|
||||
GPUTextureFormat::Bc4_r_snorm => wgt::TextureFormat::Bc4RSnorm,
|
||||
GPUTextureFormat::Bc5_rg_unorm => wgt::TextureFormat::Bc5RgUnorm,
|
||||
GPUTextureFormat::Bc5_rg_snorm => wgt::TextureFormat::Bc5RgSnorm,
|
||||
GPUTextureFormat::Bc6h_rgb_ufloat => wgt::TextureFormat::Bc6hRgbUfloat,
|
||||
GPUTextureFormat::Bc7_rgba_unorm => wgt::TextureFormat::Bc7RgbaUnorm,
|
||||
GPUTextureFormat::Bc7_rgba_unorm_srgb => wgt::TextureFormat::Bc7RgbaUnormSrgb,
|
||||
GPUTextureFormat::Bc6h_rgb_float => wgt::TextureFormat::Bc6hRgbFloat,
|
||||
GPUTextureFormat::Rgb9e5ufloat => wgt::TextureFormat::Rgb9e5Ufloat,
|
||||
GPUTextureFormat::Rgb10a2uint => wgt::TextureFormat::Rgb10a2Uint,
|
||||
GPUTextureFormat::Rg11b10ufloat => wgt::TextureFormat::Rg11b10Ufloat,
|
||||
GPUTextureFormat::Stencil8 => wgt::TextureFormat::Stencil8,
|
||||
GPUTextureFormat::Depth16unorm => wgt::TextureFormat::Depth16Unorm,
|
||||
GPUTextureFormat::Depth32float_stencil8 => wgt::TextureFormat::Depth32FloatStencil8,
|
||||
GPUTextureFormat::Etc2_rgb8unorm => wgt::TextureFormat::Etc2Rgb8Unorm,
|
||||
GPUTextureFormat::Etc2_rgb8unorm_srgb => wgt::TextureFormat::Etc2Rgb8UnormSrgb,
|
||||
GPUTextureFormat::Etc2_rgb8a1unorm => wgt::TextureFormat::Etc2Rgb8A1Unorm,
|
||||
GPUTextureFormat::Etc2_rgb8a1unorm_srgb => wgt::TextureFormat::Etc2Rgb8A1UnormSrgb,
|
||||
GPUTextureFormat::Etc2_rgba8unorm => wgt::TextureFormat::Etc2Rgba8Unorm,
|
||||
GPUTextureFormat::Etc2_rgba8unorm_srgb => wgt::TextureFormat::Etc2Rgba8UnormSrgb,
|
||||
GPUTextureFormat::Eac_r11unorm => wgt::TextureFormat::EacR11Unorm,
|
||||
GPUTextureFormat::Eac_r11snorm => wgt::TextureFormat::EacR11Snorm,
|
||||
GPUTextureFormat::Eac_rg11unorm => wgt::TextureFormat::EacRg11Unorm,
|
||||
GPUTextureFormat::Eac_rg11snorm => wgt::TextureFormat::EacRg11Snorm,
|
||||
GPUTextureFormat::Astc_4x4_unorm => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B4x4,
|
||||
channel: AstcChannel::Unorm,
|
||||
},
|
||||
GPUTextureFormat::Astc_4x4_unorm_srgb => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B4x4,
|
||||
channel: AstcChannel::UnormSrgb,
|
||||
},
|
||||
GPUTextureFormat::Astc_5x4_unorm => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B5x4,
|
||||
channel: AstcChannel::Unorm,
|
||||
},
|
||||
GPUTextureFormat::Astc_5x4_unorm_srgb => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B5x4,
|
||||
channel: AstcChannel::UnormSrgb,
|
||||
},
|
||||
GPUTextureFormat::Astc_5x5_unorm => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B5x5,
|
||||
channel: AstcChannel::Unorm,
|
||||
},
|
||||
GPUTextureFormat::Astc_5x5_unorm_srgb => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B5x5,
|
||||
channel: AstcChannel::UnormSrgb,
|
||||
},
|
||||
GPUTextureFormat::Astc_6x5_unorm => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B6x5,
|
||||
channel: AstcChannel::Unorm,
|
||||
},
|
||||
GPUTextureFormat::Astc_6x5_unorm_srgb => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B6x5,
|
||||
channel: AstcChannel::UnormSrgb,
|
||||
},
|
||||
GPUTextureFormat::Astc_6x6_unorm => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B6x6,
|
||||
channel: AstcChannel::Unorm,
|
||||
},
|
||||
GPUTextureFormat::Astc_6x6_unorm_srgb => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B6x6,
|
||||
channel: AstcChannel::UnormSrgb,
|
||||
},
|
||||
GPUTextureFormat::Astc_8x5_unorm => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B8x5,
|
||||
channel: AstcChannel::Unorm,
|
||||
},
|
||||
GPUTextureFormat::Astc_8x5_unorm_srgb => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B8x5,
|
||||
channel: AstcChannel::UnormSrgb,
|
||||
},
|
||||
GPUTextureFormat::Astc_8x6_unorm => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B8x6,
|
||||
channel: AstcChannel::Unorm,
|
||||
},
|
||||
GPUTextureFormat::Astc_8x6_unorm_srgb => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B8x6,
|
||||
channel: AstcChannel::UnormSrgb,
|
||||
},
|
||||
GPUTextureFormat::Astc_8x8_unorm => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B8x8,
|
||||
channel: AstcChannel::Unorm,
|
||||
},
|
||||
GPUTextureFormat::Astc_8x8_unorm_srgb => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B8x8,
|
||||
channel: AstcChannel::UnormSrgb,
|
||||
},
|
||||
GPUTextureFormat::Astc_10x5_unorm => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B10x5,
|
||||
channel: AstcChannel::Unorm,
|
||||
},
|
||||
GPUTextureFormat::Astc_10x5_unorm_srgb => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B10x5,
|
||||
channel: AstcChannel::UnormSrgb,
|
||||
},
|
||||
GPUTextureFormat::Astc_10x6_unorm => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B10x6,
|
||||
channel: AstcChannel::Unorm,
|
||||
},
|
||||
GPUTextureFormat::Astc_10x6_unorm_srgb => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B10x6,
|
||||
channel: AstcChannel::UnormSrgb,
|
||||
},
|
||||
GPUTextureFormat::Astc_10x8_unorm => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B10x8,
|
||||
channel: AstcChannel::Unorm,
|
||||
},
|
||||
GPUTextureFormat::Astc_10x8_unorm_srgb => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B10x8,
|
||||
channel: AstcChannel::UnormSrgb,
|
||||
},
|
||||
GPUTextureFormat::Astc_10x10_unorm => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B10x10,
|
||||
channel: AstcChannel::Unorm,
|
||||
},
|
||||
GPUTextureFormat::Astc_10x10_unorm_srgb => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B10x10,
|
||||
channel: AstcChannel::UnormSrgb,
|
||||
},
|
||||
GPUTextureFormat::Astc_12x10_unorm => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B12x10,
|
||||
channel: AstcChannel::Unorm,
|
||||
},
|
||||
GPUTextureFormat::Astc_12x10_unorm_srgb => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B12x10,
|
||||
channel: AstcChannel::UnormSrgb,
|
||||
},
|
||||
GPUTextureFormat::Astc_12x12_unorm => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B12x12,
|
||||
channel: AstcChannel::Unorm,
|
||||
},
|
||||
GPUTextureFormat::Astc_12x12_unorm_srgb => wgt::TextureFormat::Astc {
|
||||
block: AstcBlock::B12x12,
|
||||
channel: AstcChannel::UnormSrgb,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&GPUExtent3D> for wgt::Extent3d {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(size: &GPUExtent3D) -> Result<Self, Self::Error> {
|
||||
match *size {
|
||||
GPUExtent3D::GPUExtent3DDict(ref dict) => Ok(wgt::Extent3d {
|
||||
width: dict.width,
|
||||
height: dict.height,
|
||||
depth_or_array_layers: dict.depthOrArrayLayers,
|
||||
}),
|
||||
GPUExtent3D::RangeEnforcedUnsignedLongSequence(ref v) => {
|
||||
// https://gpuweb.github.io/gpuweb/#abstract-opdef-validate-gpuextent3d-shape
|
||||
if v.is_empty() || v.len() > 3 {
|
||||
Err(Error::Type(
|
||||
"GPUExtent3D size must be between 1 and 3 (inclusive)".to_string(),
|
||||
))
|
||||
} else {
|
||||
Ok(wgt::Extent3d {
|
||||
width: v[0],
|
||||
height: v.get(1).copied().unwrap_or(1),
|
||||
depth_or_array_layers: v.get(2).copied().unwrap_or(1),
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&GPUImageDataLayout> for wgt::ImageDataLayout {
|
||||
fn from(data_layout: &GPUImageDataLayout) -> Self {
|
||||
wgt::ImageDataLayout {
|
||||
offset: data_layout.offset as wgt::BufferAddress,
|
||||
bytes_per_row: data_layout.bytesPerRow,
|
||||
rows_per_image: data_layout.rowsPerImage,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GPUVertexFormat> for wgt::VertexFormat {
|
||||
fn from(format: GPUVertexFormat) -> Self {
|
||||
match format {
|
||||
GPUVertexFormat::Uint8x2 => wgt::VertexFormat::Uint8x2,
|
||||
GPUVertexFormat::Uint8x4 => wgt::VertexFormat::Uint8x4,
|
||||
GPUVertexFormat::Sint8x2 => wgt::VertexFormat::Sint8x2,
|
||||
GPUVertexFormat::Sint8x4 => wgt::VertexFormat::Sint8x4,
|
||||
GPUVertexFormat::Unorm8x2 => wgt::VertexFormat::Unorm8x2,
|
||||
GPUVertexFormat::Unorm8x4 => wgt::VertexFormat::Unorm8x4,
|
||||
GPUVertexFormat::Snorm8x2 => wgt::VertexFormat::Unorm8x2,
|
||||
GPUVertexFormat::Snorm8x4 => wgt::VertexFormat::Unorm8x4,
|
||||
GPUVertexFormat::Uint16x2 => wgt::VertexFormat::Uint16x2,
|
||||
GPUVertexFormat::Uint16x4 => wgt::VertexFormat::Uint16x4,
|
||||
GPUVertexFormat::Sint16x2 => wgt::VertexFormat::Sint16x2,
|
||||
GPUVertexFormat::Sint16x4 => wgt::VertexFormat::Sint16x4,
|
||||
GPUVertexFormat::Unorm16x2 => wgt::VertexFormat::Unorm16x2,
|
||||
GPUVertexFormat::Unorm16x4 => wgt::VertexFormat::Unorm16x4,
|
||||
GPUVertexFormat::Snorm16x2 => wgt::VertexFormat::Snorm16x2,
|
||||
GPUVertexFormat::Snorm16x4 => wgt::VertexFormat::Snorm16x4,
|
||||
GPUVertexFormat::Float16x2 => wgt::VertexFormat::Float16x2,
|
||||
GPUVertexFormat::Float16x4 => wgt::VertexFormat::Float16x4,
|
||||
GPUVertexFormat::Float32 => wgt::VertexFormat::Float32,
|
||||
GPUVertexFormat::Float32x2 => wgt::VertexFormat::Float32x2,
|
||||
GPUVertexFormat::Float32x3 => wgt::VertexFormat::Float32x3,
|
||||
GPUVertexFormat::Float32x4 => wgt::VertexFormat::Float32x4,
|
||||
GPUVertexFormat::Uint32 => wgt::VertexFormat::Uint32,
|
||||
GPUVertexFormat::Uint32x2 => wgt::VertexFormat::Uint32x2,
|
||||
GPUVertexFormat::Uint32x3 => wgt::VertexFormat::Uint32x3,
|
||||
GPUVertexFormat::Uint32x4 => wgt::VertexFormat::Uint32x4,
|
||||
GPUVertexFormat::Sint32 => wgt::VertexFormat::Sint32,
|
||||
GPUVertexFormat::Sint32x2 => wgt::VertexFormat::Sint32x2,
|
||||
GPUVertexFormat::Sint32x3 => wgt::VertexFormat::Sint32x3,
|
||||
GPUVertexFormat::Sint32x4 => wgt::VertexFormat::Sint32x4,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&GPUPrimitiveState> for wgt::PrimitiveState {
|
||||
fn from(primitive_state: &GPUPrimitiveState) -> Self {
|
||||
wgt::PrimitiveState {
|
||||
topology: wgt::PrimitiveTopology::from(&primitive_state.topology),
|
||||
strip_index_format: primitive_state.stripIndexFormat.map(|index_format| {
|
||||
match index_format {
|
||||
GPUIndexFormat::Uint16 => wgt::IndexFormat::Uint16,
|
||||
GPUIndexFormat::Uint32 => wgt::IndexFormat::Uint32,
|
||||
}
|
||||
}),
|
||||
front_face: match primitive_state.frontFace {
|
||||
GPUFrontFace::Ccw => wgt::FrontFace::Ccw,
|
||||
GPUFrontFace::Cw => wgt::FrontFace::Cw,
|
||||
},
|
||||
cull_mode: match primitive_state.cullMode {
|
||||
GPUCullMode::None => None,
|
||||
GPUCullMode::Front => Some(wgt::Face::Front),
|
||||
GPUCullMode::Back => Some(wgt::Face::Back),
|
||||
},
|
||||
unclipped_depth: primitive_state.clampDepth,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&GPUPrimitiveTopology> for wgt::PrimitiveTopology {
|
||||
fn from(primitive_topology: &GPUPrimitiveTopology) -> Self {
|
||||
match primitive_topology {
|
||||
GPUPrimitiveTopology::Point_list => wgt::PrimitiveTopology::PointList,
|
||||
GPUPrimitiveTopology::Line_list => wgt::PrimitiveTopology::LineList,
|
||||
GPUPrimitiveTopology::Line_strip => wgt::PrimitiveTopology::LineStrip,
|
||||
GPUPrimitiveTopology::Triangle_list => wgt::PrimitiveTopology::TriangleList,
|
||||
GPUPrimitiveTopology::Triangle_strip => wgt::PrimitiveTopology::TriangleStrip,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GPUAddressMode> for wgt::AddressMode {
|
||||
fn from(address_mode: GPUAddressMode) -> Self {
|
||||
match address_mode {
|
||||
GPUAddressMode::Clamp_to_edge => wgt::AddressMode::ClampToEdge,
|
||||
GPUAddressMode::Repeat => wgt::AddressMode::Repeat,
|
||||
GPUAddressMode::Mirror_repeat => wgt::AddressMode::MirrorRepeat,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GPUFilterMode> for wgt::FilterMode {
|
||||
fn from(filter_mode: GPUFilterMode) -> Self {
|
||||
match filter_mode {
|
||||
GPUFilterMode::Nearest => wgt::FilterMode::Nearest,
|
||||
GPUFilterMode::Linear => wgt::FilterMode::Linear,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GPUTextureViewDimension> for wgt::TextureViewDimension {
|
||||
fn from(view_dimension: GPUTextureViewDimension) -> Self {
|
||||
match view_dimension {
|
||||
GPUTextureViewDimension::_1d => wgt::TextureViewDimension::D1,
|
||||
GPUTextureViewDimension::_2d => wgt::TextureViewDimension::D2,
|
||||
GPUTextureViewDimension::_2d_array => wgt::TextureViewDimension::D2Array,
|
||||
GPUTextureViewDimension::Cube => wgt::TextureViewDimension::Cube,
|
||||
GPUTextureViewDimension::Cube_array => wgt::TextureViewDimension::CubeArray,
|
||||
GPUTextureViewDimension::_3d => wgt::TextureViewDimension::D3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GPUCompareFunction> for wgt::CompareFunction {
|
||||
fn from(compare: GPUCompareFunction) -> Self {
|
||||
match compare {
|
||||
GPUCompareFunction::Never => wgt::CompareFunction::Never,
|
||||
GPUCompareFunction::Less => wgt::CompareFunction::Less,
|
||||
GPUCompareFunction::Equal => wgt::CompareFunction::Equal,
|
||||
GPUCompareFunction::Less_equal => wgt::CompareFunction::LessEqual,
|
||||
GPUCompareFunction::Greater => wgt::CompareFunction::Greater,
|
||||
GPUCompareFunction::Not_equal => wgt::CompareFunction::NotEqual,
|
||||
GPUCompareFunction::Greater_equal => wgt::CompareFunction::GreaterEqual,
|
||||
GPUCompareFunction::Always => wgt::CompareFunction::Always,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&GPUBlendFactor> for wgt::BlendFactor {
|
||||
fn from(factor: &GPUBlendFactor) -> Self {
|
||||
match factor {
|
||||
GPUBlendFactor::Zero => wgt::BlendFactor::Zero,
|
||||
GPUBlendFactor::One => wgt::BlendFactor::One,
|
||||
GPUBlendFactor::Src => wgt::BlendFactor::Src,
|
||||
GPUBlendFactor::One_minus_src => wgt::BlendFactor::OneMinusSrc,
|
||||
GPUBlendFactor::Src_alpha => wgt::BlendFactor::SrcAlpha,
|
||||
GPUBlendFactor::One_minus_src_alpha => wgt::BlendFactor::OneMinusSrcAlpha,
|
||||
GPUBlendFactor::Dst => wgt::BlendFactor::Dst,
|
||||
GPUBlendFactor::One_minus_dst => wgt::BlendFactor::OneMinusDst,
|
||||
GPUBlendFactor::Dst_alpha => wgt::BlendFactor::DstAlpha,
|
||||
GPUBlendFactor::One_minus_dst_alpha => wgt::BlendFactor::OneMinusDstAlpha,
|
||||
GPUBlendFactor::Src_alpha_saturated => wgt::BlendFactor::SrcAlphaSaturated,
|
||||
GPUBlendFactor::Constant => wgt::BlendFactor::Constant,
|
||||
GPUBlendFactor::One_minus_constant => wgt::BlendFactor::OneMinusConstant,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&GPUBlendComponent> for wgt::BlendComponent {
|
||||
fn from(blend_component: &GPUBlendComponent) -> Self {
|
||||
wgt::BlendComponent {
|
||||
src_factor: wgt::BlendFactor::from(&blend_component.srcFactor),
|
||||
dst_factor: wgt::BlendFactor::from(&blend_component.dstFactor),
|
||||
operation: match blend_component.operation {
|
||||
GPUBlendOperation::Add => wgt::BlendOperation::Add,
|
||||
GPUBlendOperation::Subtract => wgt::BlendOperation::Subtract,
|
||||
GPUBlendOperation::Reverse_subtract => wgt::BlendOperation::ReverseSubtract,
|
||||
GPUBlendOperation::Min => wgt::BlendOperation::Min,
|
||||
GPUBlendOperation::Max => wgt::BlendOperation::Max,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_load_op(op: Option<GPULoadOp>) -> wgpu_com::LoadOp {
|
||||
match op {
|
||||
Some(GPULoadOp::Load) => wgpu_com::LoadOp::Load,
|
||||
Some(GPULoadOp::Clear) => wgpu_com::LoadOp::Clear,
|
||||
None => wgpu_com::LoadOp::Clear,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_store_op(op: Option<GPUStoreOp>) -> wgpu_com::StoreOp {
|
||||
match op {
|
||||
Some(GPUStoreOp::Store) => wgpu_com::StoreOp::Store,
|
||||
Some(GPUStoreOp::Discard) => wgpu_com::StoreOp::Discard,
|
||||
None => wgpu_com::StoreOp::Discard,
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GPUStencilOperation> for wgt::StencilOperation {
|
||||
fn from(operation: GPUStencilOperation) -> Self {
|
||||
match operation {
|
||||
GPUStencilOperation::Keep => wgt::StencilOperation::Keep,
|
||||
GPUStencilOperation::Zero => wgt::StencilOperation::Zero,
|
||||
GPUStencilOperation::Replace => wgt::StencilOperation::Replace,
|
||||
GPUStencilOperation::Invert => wgt::StencilOperation::Invert,
|
||||
GPUStencilOperation::Increment_clamp => wgt::StencilOperation::IncrementClamp,
|
||||
GPUStencilOperation::Decrement_clamp => wgt::StencilOperation::DecrementClamp,
|
||||
GPUStencilOperation::Increment_wrap => wgt::StencilOperation::IncrementWrap,
|
||||
GPUStencilOperation::Decrement_wrap => wgt::StencilOperation::DecrementWrap,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&GPUImageCopyBuffer> for wgpu_com::ImageCopyBuffer {
|
||||
fn from(ic_buffer: &GPUImageCopyBuffer) -> Self {
|
||||
wgpu_com::ImageCopyBuffer {
|
||||
buffer: ic_buffer.buffer.id().0,
|
||||
layout: wgt::ImageDataLayout::from(&ic_buffer.parent),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&GPUOrigin3D> for wgt::Origin3d {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(origin: &GPUOrigin3D) -> Result<Self, Self::Error> {
|
||||
match origin {
|
||||
GPUOrigin3D::RangeEnforcedUnsignedLongSequence(v) => {
|
||||
// https://gpuweb.github.io/gpuweb/#abstract-opdef-validate-gpuorigin3d-shape
|
||||
if v.len() > 3 {
|
||||
Err(Error::Type(
|
||||
"sequence is too long for GPUOrigin3D".to_string(),
|
||||
))
|
||||
} else {
|
||||
Ok(wgt::Origin3d {
|
||||
x: v.first().copied().unwrap_or(0),
|
||||
y: v.get(1).copied().unwrap_or(0),
|
||||
z: v.get(2).copied().unwrap_or(0),
|
||||
})
|
||||
}
|
||||
},
|
||||
GPUOrigin3D::GPUOrigin3DDict(d) => Ok(wgt::Origin3d {
|
||||
x: d.x,
|
||||
y: d.y,
|
||||
z: d.z,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&GPUImageCopyTexture> for wgpu_com::ImageCopyTexture {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(ic_texture: &GPUImageCopyTexture) -> Result<Self, Self::Error> {
|
||||
Ok(wgpu_com::ImageCopyTexture {
|
||||
texture: ic_texture.texture.id().0,
|
||||
mip_level: ic_texture.mipLevel,
|
||||
origin: ic_texture
|
||||
.origin
|
||||
.as_ref()
|
||||
.map(wgt::Origin3d::try_from)
|
||||
.transpose()?
|
||||
.unwrap_or_default(),
|
||||
aspect: match ic_texture.aspect {
|
||||
GPUTextureAspect::All => wgt::TextureAspect::All,
|
||||
GPUTextureAspect::Stencil_only => wgt::TextureAspect::StencilOnly,
|
||||
GPUTextureAspect::Depth_only => wgt::TextureAspect::DepthOnly,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&GPUObjectDescriptorBase> for Option<Cow<'a, str>> {
|
||||
fn from(val: &GPUObjectDescriptorBase) -> Self {
|
||||
if val.label.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Cow::Owned(val.label.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_bind_group_layout_entry(
|
||||
bgle: &GPUBindGroupLayoutEntry,
|
||||
device: &GPUDevice,
|
||||
) -> Fallible<Result<wgt::BindGroupLayoutEntry, webgpu::Error>> {
|
||||
let number_of_provided_bindings = bgle.buffer.is_some() as u8 +
|
||||
bgle.sampler.is_some() as u8 +
|
||||
bgle.storageTexture.is_some() as u8 +
|
||||
bgle.texture.is_some() as u8;
|
||||
let ty = if let Some(buffer) = &bgle.buffer {
|
||||
Some(wgt::BindingType::Buffer {
|
||||
ty: match buffer.type_ {
|
||||
GPUBufferBindingType::Uniform => wgt::BufferBindingType::Uniform,
|
||||
GPUBufferBindingType::Storage => {
|
||||
wgt::BufferBindingType::Storage { read_only: false }
|
||||
},
|
||||
GPUBufferBindingType::Read_only_storage => {
|
||||
wgt::BufferBindingType::Storage { read_only: true }
|
||||
},
|
||||
},
|
||||
has_dynamic_offset: buffer.hasDynamicOffset,
|
||||
min_binding_size: NonZeroU64::new(buffer.minBindingSize),
|
||||
})
|
||||
} else if let Some(sampler) = &bgle.sampler {
|
||||
Some(wgt::BindingType::Sampler(match sampler.type_ {
|
||||
GPUSamplerBindingType::Filtering => wgt::SamplerBindingType::Filtering,
|
||||
GPUSamplerBindingType::Non_filtering => wgt::SamplerBindingType::NonFiltering,
|
||||
GPUSamplerBindingType::Comparison => wgt::SamplerBindingType::Comparison,
|
||||
}))
|
||||
} else if let Some(storage) = &bgle.storageTexture {
|
||||
Some(wgt::BindingType::StorageTexture {
|
||||
access: match storage.access {
|
||||
GPUStorageTextureAccess::Write_only => wgt::StorageTextureAccess::WriteOnly,
|
||||
GPUStorageTextureAccess::Read_only => wgt::StorageTextureAccess::ReadOnly,
|
||||
GPUStorageTextureAccess::Read_write => wgt::StorageTextureAccess::ReadWrite,
|
||||
},
|
||||
format: device.validate_texture_format_required_features(&storage.format)?,
|
||||
view_dimension: storage.viewDimension.into(),
|
||||
})
|
||||
} else if let Some(texture) = &bgle.texture {
|
||||
Some(wgt::BindingType::Texture {
|
||||
sample_type: match texture.sampleType {
|
||||
GPUTextureSampleType::Float => wgt::TextureSampleType::Float { filterable: true },
|
||||
GPUTextureSampleType::Unfilterable_float => {
|
||||
wgt::TextureSampleType::Float { filterable: false }
|
||||
},
|
||||
GPUTextureSampleType::Depth => wgt::TextureSampleType::Depth,
|
||||
GPUTextureSampleType::Sint => wgt::TextureSampleType::Sint,
|
||||
GPUTextureSampleType::Uint => wgt::TextureSampleType::Uint,
|
||||
},
|
||||
view_dimension: texture.viewDimension.into(),
|
||||
multisampled: texture.multisampled,
|
||||
})
|
||||
} else {
|
||||
assert_eq!(number_of_provided_bindings, 0);
|
||||
None
|
||||
};
|
||||
// Check for number of bindings should actually be done in device-timeline,
|
||||
// but we do it last on content-timeline to have some visible effect
|
||||
let ty = if number_of_provided_bindings != 1 {
|
||||
None
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
.ok_or(webgpu::Error::Validation(
|
||||
"Exactly on entry type must be provided".to_string(),
|
||||
));
|
||||
|
||||
Ok(ty.map(|ty| wgt::BindGroupLayoutEntry {
|
||||
binding: bgle.binding,
|
||||
visibility: wgt::ShaderStages::from_bits_retain(bgle.visibility),
|
||||
ty,
|
||||
count: None,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn convert_texture_descriptor(
|
||||
descriptor: &GPUTextureDescriptor,
|
||||
device: &GPUDevice,
|
||||
) -> Fallible<(TextureDescriptor<'static>, wgt::Extent3d)> {
|
||||
let size = (&descriptor.size).try_into()?;
|
||||
let desc = TextureDescriptor {
|
||||
label: (&descriptor.parent).into(),
|
||||
size,
|
||||
mip_level_count: descriptor.mipLevelCount,
|
||||
sample_count: descriptor.sampleCount,
|
||||
dimension: descriptor.dimension.into(),
|
||||
format: device.validate_texture_format_required_features(&descriptor.format)?,
|
||||
usage: wgt::TextureUsages::from_bits_retain(descriptor.usage),
|
||||
view_formats: descriptor
|
||||
.viewFormats
|
||||
.iter()
|
||||
.map(|tf| device.validate_texture_format_required_features(tf))
|
||||
.collect::<Fallible<_>>()?,
|
||||
};
|
||||
Ok((desc, size))
|
||||
}
|
||||
|
||||
impl TryFrom<&GPUColor> for wgt::Color {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(color: &GPUColor) -> Result<Self, Self::Error> {
|
||||
match color {
|
||||
GPUColor::DoubleSequence(s) => {
|
||||
// https://gpuweb.github.io/gpuweb/#abstract-opdef-validate-gpucolor-shape
|
||||
if s.len() != 4 {
|
||||
Err(Error::Type("GPUColor sequence must be len 4".to_string()))
|
||||
} else {
|
||||
Ok(wgt::Color {
|
||||
r: *s[0],
|
||||
g: *s[1],
|
||||
b: *s[2],
|
||||
a: *s[3],
|
||||
})
|
||||
}
|
||||
},
|
||||
GPUColor::GPUColorDict(d) => Ok(wgt::Color {
|
||||
r: *d.r,
|
||||
g: *d.g,
|
||||
b: *d.b,
|
||||
a: *d.a,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&GPUProgrammableStage> for ProgrammableStageDescriptor<'a> {
|
||||
fn from(stage: &GPUProgrammableStage) -> Self {
|
||||
Self {
|
||||
module: stage.module.id().0,
|
||||
entry_point: stage
|
||||
.entryPoint
|
||||
.as_ref()
|
||||
.map(|ep| Cow::Owned(ep.to_string())),
|
||||
constants: Cow::Owned(
|
||||
stage
|
||||
.constants
|
||||
.as_ref()
|
||||
.map(|records| records.iter().map(|(k, v)| (k.0.clone(), **v)).collect())
|
||||
.unwrap_or_default(),
|
||||
),
|
||||
zero_initialize_workgroup_memory: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&GPUBindGroupEntry> for BindGroupEntry<'_> {
|
||||
fn from(entry: &GPUBindGroupEntry) -> Self {
|
||||
Self {
|
||||
binding: entry.binding,
|
||||
resource: match entry.resource {
|
||||
GPUBindingResource::GPUSampler(ref s) => BindingResource::Sampler(s.id().0),
|
||||
GPUBindingResource::GPUTextureView(ref t) => BindingResource::TextureView(t.id().0),
|
||||
GPUBindingResource::GPUBufferBinding(ref b) => {
|
||||
BindingResource::Buffer(BufferBinding {
|
||||
buffer_id: b.buffer.id().0,
|
||||
offset: b.offset,
|
||||
size: b.size.and_then(wgt::BufferSize::new),
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GPUTextureDimension> for wgt::TextureDimension {
|
||||
fn from(dimension: GPUTextureDimension) -> Self {
|
||||
match dimension {
|
||||
GPUTextureDimension::_1d => wgt::TextureDimension::D1,
|
||||
GPUTextureDimension::_2d => wgt::TextureDimension::D2,
|
||||
GPUTextureDimension::_3d => wgt::TextureDimension::D3,
|
||||
}
|
||||
}
|
||||
}
|
652
components/script/dom/webgpu/gpudevice.rs
Normal file
652
components/script/dom/webgpu/gpudevice.rs
Normal file
|
@ -0,0 +1,652 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use js::jsapi::{Heap, JSObject};
|
||||
use webgpu::wgc::id::{BindGroupLayoutId, PipelineLayoutId};
|
||||
use webgpu::wgc::pipeline as wgpu_pipe;
|
||||
use webgpu::wgc::pipeline::RenderPipelineDescriptor;
|
||||
use webgpu::wgt::TextureFormat;
|
||||
use webgpu::{
|
||||
wgt, PopError, WebGPU, WebGPUComputePipeline, WebGPURenderPipeline, WebGPURequest,
|
||||
WebGPUResponse,
|
||||
};
|
||||
|
||||
use super::gpu::AsyncWGPUListener;
|
||||
use super::gpudevicelostinfo::GPUDeviceLostInfo;
|
||||
use super::gpupipelineerror::GPUPipelineError;
|
||||
use super::gpusupportedlimits::GPUSupportedLimits;
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::EventBinding::EventInit;
|
||||
use crate::dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUBindGroupDescriptor, GPUBindGroupLayoutDescriptor, GPUBufferDescriptor,
|
||||
GPUCommandEncoderDescriptor, GPUComputePipelineDescriptor, GPUDeviceLostReason,
|
||||
GPUDeviceMethods, GPUErrorFilter, GPUPipelineErrorReason, GPUPipelineLayoutDescriptor,
|
||||
GPURenderBundleEncoderDescriptor, GPURenderPipelineDescriptor, GPUSamplerDescriptor,
|
||||
GPUShaderModuleDescriptor, GPUSupportedLimitsMethods, GPUTextureDescriptor, GPUTextureFormat,
|
||||
GPUUncapturedErrorEventInit, GPUVertexStepMode,
|
||||
};
|
||||
use crate::dom::bindings::codegen::UnionTypes::GPUPipelineLayoutOrGPUAutoLayoutMode;
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::{DOMString, USVString};
|
||||
use crate::dom::bindings::trace::RootedTraceableBox;
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpuadapter::GPUAdapter;
|
||||
use crate::dom::gpubindgroup::GPUBindGroup;
|
||||
use crate::dom::gpubindgrouplayout::GPUBindGroupLayout;
|
||||
use crate::dom::gpubuffer::GPUBuffer;
|
||||
use crate::dom::gpucommandencoder::GPUCommandEncoder;
|
||||
use crate::dom::gpucomputepipeline::GPUComputePipeline;
|
||||
use crate::dom::gpupipelinelayout::GPUPipelineLayout;
|
||||
use crate::dom::gpuqueue::GPUQueue;
|
||||
use crate::dom::gpurenderbundleencoder::GPURenderBundleEncoder;
|
||||
use crate::dom::gpurenderpipeline::GPURenderPipeline;
|
||||
use crate::dom::gpusampler::GPUSampler;
|
||||
use crate::dom::gpushadermodule::GPUShaderModule;
|
||||
use crate::dom::gpusupportedfeatures::GPUSupportedFeatures;
|
||||
use crate::dom::gputexture::GPUTexture;
|
||||
use crate::dom::gpuuncapturederrorevent::GPUUncapturedErrorEvent;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::dom::types::GPUError;
|
||||
use crate::dom::webgpu::gpu::response_async;
|
||||
use crate::realms::InRealm;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUDevice {
|
||||
eventtarget: EventTarget,
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
adapter: Dom<GPUAdapter>,
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
extensions: Heap<*mut JSObject>,
|
||||
features: Dom<GPUSupportedFeatures>,
|
||||
limits: Dom<GPUSupportedLimits>,
|
||||
label: DomRefCell<USVString>,
|
||||
#[no_trace]
|
||||
device: webgpu::WebGPUDevice,
|
||||
default_queue: Dom<GPUQueue>,
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-lost>
|
||||
#[ignore_malloc_size_of = "promises are hard"]
|
||||
lost_promise: DomRefCell<Rc<Promise>>,
|
||||
valid: Cell<bool>,
|
||||
}
|
||||
|
||||
pub enum PipelineLayout {
|
||||
Implicit(PipelineLayoutId, Vec<BindGroupLayoutId>),
|
||||
Explicit(PipelineLayoutId),
|
||||
}
|
||||
|
||||
impl PipelineLayout {
|
||||
pub fn explicit(&self) -> Option<PipelineLayoutId> {
|
||||
match self {
|
||||
PipelineLayout::Explicit(layout_id) => Some(*layout_id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn implicit(self) -> Option<(PipelineLayoutId, Vec<BindGroupLayoutId>)> {
|
||||
match self {
|
||||
PipelineLayout::Implicit(layout_id, bind_group_layout_ids) => {
|
||||
Some((layout_id, bind_group_layout_ids))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUDevice {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn new_inherited(
|
||||
channel: WebGPU,
|
||||
adapter: &GPUAdapter,
|
||||
extensions: Heap<*mut JSObject>,
|
||||
features: &GPUSupportedFeatures,
|
||||
limits: &GPUSupportedLimits,
|
||||
device: webgpu::WebGPUDevice,
|
||||
queue: &GPUQueue,
|
||||
label: String,
|
||||
lost_promise: Rc<Promise>,
|
||||
) -> Self {
|
||||
Self {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
channel,
|
||||
adapter: Dom::from_ref(adapter),
|
||||
extensions,
|
||||
features: Dom::from_ref(features),
|
||||
limits: Dom::from_ref(limits),
|
||||
label: DomRefCell::new(USVString::from(label)),
|
||||
device,
|
||||
default_queue: Dom::from_ref(queue),
|
||||
lost_promise: DomRefCell::new(lost_promise),
|
||||
valid: Cell::new(true),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
channel: WebGPU,
|
||||
adapter: &GPUAdapter,
|
||||
extensions: Heap<*mut JSObject>,
|
||||
features: wgt::Features,
|
||||
limits: wgt::Limits,
|
||||
device: webgpu::WebGPUDevice,
|
||||
queue: webgpu::WebGPUQueue,
|
||||
label: String,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
let queue = GPUQueue::new(global, channel.clone(), queue);
|
||||
let limits = GPUSupportedLimits::new(global, limits);
|
||||
let features = GPUSupportedFeatures::Constructor(global, None, features, can_gc).unwrap();
|
||||
let lost_promise = Promise::new(global, can_gc);
|
||||
let device = reflect_dom_object(
|
||||
Box::new(GPUDevice::new_inherited(
|
||||
channel,
|
||||
adapter,
|
||||
extensions,
|
||||
&features,
|
||||
&limits,
|
||||
device,
|
||||
&queue,
|
||||
label,
|
||||
lost_promise,
|
||||
)),
|
||||
global,
|
||||
);
|
||||
queue.set_device(&device);
|
||||
device
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUDevice {
|
||||
pub fn id(&self) -> webgpu::WebGPUDevice {
|
||||
self.device
|
||||
}
|
||||
|
||||
pub fn queue_id(&self) -> webgpu::WebGPUQueue {
|
||||
self.default_queue.id()
|
||||
}
|
||||
|
||||
pub fn channel(&self) -> WebGPU {
|
||||
self.channel.clone()
|
||||
}
|
||||
|
||||
pub fn dispatch_error(&self, error: webgpu::Error) {
|
||||
if let Err(e) = self.channel.0.send(WebGPURequest::DispatchError {
|
||||
device_id: self.device.0,
|
||||
error,
|
||||
}) {
|
||||
warn!("Failed to send WebGPURequest::DispatchError due to {e:?}");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fire_uncaptured_error(&self, error: webgpu::Error, can_gc: CanGc) {
|
||||
let error = GPUError::from_error(&self.global(), error, can_gc);
|
||||
let ev = GPUUncapturedErrorEvent::new(
|
||||
&self.global(),
|
||||
DOMString::from("uncapturederror"),
|
||||
&GPUUncapturedErrorEventInit {
|
||||
error,
|
||||
parent: EventInit::empty(),
|
||||
},
|
||||
can_gc,
|
||||
);
|
||||
let _ = self.eventtarget.DispatchEvent(ev.event(), can_gc);
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#abstract-opdef-validate-texture-format-required-features>
|
||||
///
|
||||
/// Validates that the device suppports required features,
|
||||
/// and if so returns an ok containing wgpu's `TextureFormat`
|
||||
pub fn validate_texture_format_required_features(
|
||||
&self,
|
||||
format: &GPUTextureFormat,
|
||||
) -> Fallible<TextureFormat> {
|
||||
let texture_format: TextureFormat = (*format).into();
|
||||
if self
|
||||
.features
|
||||
.wgpu_features()
|
||||
.contains(texture_format.required_features())
|
||||
{
|
||||
Ok(texture_format)
|
||||
} else {
|
||||
Err(Error::Type(format!(
|
||||
"{texture_format:?} is not supported by this GPUDevice"
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_lost(&self) -> bool {
|
||||
self.lost_promise.borrow().is_fulfilled()
|
||||
}
|
||||
|
||||
pub fn get_pipeline_layout_data(
|
||||
&self,
|
||||
layout: &GPUPipelineLayoutOrGPUAutoLayoutMode,
|
||||
) -> PipelineLayout {
|
||||
if let GPUPipelineLayoutOrGPUAutoLayoutMode::GPUPipelineLayout(ref layout) = layout {
|
||||
PipelineLayout::Explicit(layout.id().0)
|
||||
} else {
|
||||
let layout_id = self.global().wgpu_id_hub().create_pipeline_layout_id();
|
||||
let max_bind_grps = self.limits.MaxBindGroups();
|
||||
let mut bgl_ids = Vec::with_capacity(max_bind_grps as usize);
|
||||
for _ in 0..max_bind_grps {
|
||||
let bgl = self.global().wgpu_id_hub().create_bind_group_layout_id();
|
||||
bgl_ids.push(bgl);
|
||||
}
|
||||
PipelineLayout::Implicit(layout_id, bgl_ids)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_render_pipeline<'a>(
|
||||
&self,
|
||||
descriptor: &GPURenderPipelineDescriptor,
|
||||
) -> Fallible<(PipelineLayout, RenderPipelineDescriptor<'a>)> {
|
||||
let pipeline_layout = self.get_pipeline_layout_data(&descriptor.parent.layout);
|
||||
|
||||
let desc = wgpu_pipe::RenderPipelineDescriptor {
|
||||
label: (&descriptor.parent.parent).into(),
|
||||
layout: pipeline_layout.explicit(),
|
||||
cache: None,
|
||||
vertex: wgpu_pipe::VertexState {
|
||||
stage: (&descriptor.vertex.parent).into(),
|
||||
buffers: Cow::Owned(
|
||||
descriptor
|
||||
.vertex
|
||||
.buffers
|
||||
.iter()
|
||||
.map(|buffer| wgpu_pipe::VertexBufferLayout {
|
||||
array_stride: buffer.arrayStride,
|
||||
step_mode: match buffer.stepMode {
|
||||
GPUVertexStepMode::Vertex => wgt::VertexStepMode::Vertex,
|
||||
GPUVertexStepMode::Instance => wgt::VertexStepMode::Instance,
|
||||
},
|
||||
attributes: Cow::Owned(
|
||||
buffer
|
||||
.attributes
|
||||
.iter()
|
||||
.map(|att| wgt::VertexAttribute {
|
||||
format: att.format.into(),
|
||||
offset: att.offset,
|
||||
shader_location: att.shaderLocation,
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
},
|
||||
fragment: descriptor
|
||||
.fragment
|
||||
.as_ref()
|
||||
.map(|stage| -> Fallible<wgpu_pipe::FragmentState> {
|
||||
Ok(wgpu_pipe::FragmentState {
|
||||
stage: (&stage.parent).into(),
|
||||
targets: Cow::Owned(
|
||||
stage
|
||||
.targets
|
||||
.iter()
|
||||
.map(|state| {
|
||||
self.validate_texture_format_required_features(&state.format)
|
||||
.map(|format| {
|
||||
Some(wgt::ColorTargetState {
|
||||
format,
|
||||
write_mask: wgt::ColorWrites::from_bits_retain(
|
||||
state.writeMask,
|
||||
),
|
||||
blend: state.blend.as_ref().map(|blend| {
|
||||
wgt::BlendState {
|
||||
color: (&blend.color).into(),
|
||||
alpha: (&blend.alpha).into(),
|
||||
}
|
||||
}),
|
||||
})
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
),
|
||||
})
|
||||
})
|
||||
.transpose()?,
|
||||
primitive: (&descriptor.primitive).into(),
|
||||
depth_stencil: descriptor
|
||||
.depthStencil
|
||||
.as_ref()
|
||||
.map(|dss_desc| {
|
||||
self.validate_texture_format_required_features(&dss_desc.format)
|
||||
.map(|format| wgt::DepthStencilState {
|
||||
format,
|
||||
depth_write_enabled: dss_desc.depthWriteEnabled,
|
||||
depth_compare: dss_desc.depthCompare.into(),
|
||||
stencil: wgt::StencilState {
|
||||
front: wgt::StencilFaceState {
|
||||
compare: dss_desc.stencilFront.compare.into(),
|
||||
|
||||
fail_op: dss_desc.stencilFront.failOp.into(),
|
||||
depth_fail_op: dss_desc.stencilFront.depthFailOp.into(),
|
||||
pass_op: dss_desc.stencilFront.passOp.into(),
|
||||
},
|
||||
back: wgt::StencilFaceState {
|
||||
compare: dss_desc.stencilBack.compare.into(),
|
||||
fail_op: dss_desc.stencilBack.failOp.into(),
|
||||
depth_fail_op: dss_desc.stencilBack.depthFailOp.into(),
|
||||
pass_op: dss_desc.stencilBack.passOp.into(),
|
||||
},
|
||||
read_mask: dss_desc.stencilReadMask,
|
||||
write_mask: dss_desc.stencilWriteMask,
|
||||
},
|
||||
bias: wgt::DepthBiasState {
|
||||
constant: dss_desc.depthBias,
|
||||
slope_scale: *dss_desc.depthBiasSlopeScale,
|
||||
clamp: *dss_desc.depthBiasClamp,
|
||||
},
|
||||
})
|
||||
})
|
||||
.transpose()?,
|
||||
multisample: wgt::MultisampleState {
|
||||
count: descriptor.multisample.count,
|
||||
mask: descriptor.multisample.mask as u64,
|
||||
alpha_to_coverage_enabled: descriptor.multisample.alphaToCoverageEnabled,
|
||||
},
|
||||
multiview: None,
|
||||
};
|
||||
Ok((pipeline_layout, desc))
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#lose-the-device>
|
||||
pub fn lose(&self, reason: GPUDeviceLostReason, msg: String) {
|
||||
let lost_promise = &(*self.lost_promise.borrow());
|
||||
let global = &self.global();
|
||||
let lost = GPUDeviceLostInfo::new(global, msg.into(), reason);
|
||||
lost_promise.resolve_native(&*lost);
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUDeviceMethods<crate::DomTypeHolder> for GPUDevice {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-features>
|
||||
fn Features(&self) -> DomRoot<GPUSupportedFeatures> {
|
||||
DomRoot::from_ref(&self.features)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-limits>
|
||||
fn Limits(&self) -> DomRoot<GPUSupportedLimits> {
|
||||
DomRoot::from_ref(&self.limits)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-queue>
|
||||
fn GetQueue(&self) -> DomRoot<GPUQueue> {
|
||||
DomRoot::from_ref(&self.default_queue)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-lost>
|
||||
fn Lost(&self) -> Rc<Promise> {
|
||||
self.lost_promise.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbuffer>
|
||||
fn CreateBuffer(&self, descriptor: &GPUBufferDescriptor) -> Fallible<DomRoot<GPUBuffer>> {
|
||||
GPUBuffer::create(self, descriptor)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#GPUDevice-createBindGroupLayout>
|
||||
#[allow(non_snake_case)]
|
||||
fn CreateBindGroupLayout(
|
||||
&self,
|
||||
descriptor: &GPUBindGroupLayoutDescriptor,
|
||||
) -> Fallible<DomRoot<GPUBindGroupLayout>> {
|
||||
GPUBindGroupLayout::create(self, descriptor)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createpipelinelayout>
|
||||
fn CreatePipelineLayout(
|
||||
&self,
|
||||
descriptor: &GPUPipelineLayoutDescriptor,
|
||||
) -> DomRoot<GPUPipelineLayout> {
|
||||
GPUPipelineLayout::create(self, descriptor)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbindgroup>
|
||||
fn CreateBindGroup(&self, descriptor: &GPUBindGroupDescriptor) -> DomRoot<GPUBindGroup> {
|
||||
GPUBindGroup::create(self, descriptor)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createshadermodule>
|
||||
fn CreateShaderModule(
|
||||
&self,
|
||||
descriptor: RootedTraceableBox<GPUShaderModuleDescriptor>,
|
||||
comp: InRealm,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<GPUShaderModule> {
|
||||
GPUShaderModule::create(self, descriptor, comp, can_gc)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createcomputepipeline>
|
||||
fn CreateComputePipeline(
|
||||
&self,
|
||||
descriptor: &GPUComputePipelineDescriptor,
|
||||
) -> DomRoot<GPUComputePipeline> {
|
||||
let compute_pipeline = GPUComputePipeline::create(self, descriptor, None);
|
||||
GPUComputePipeline::new(
|
||||
&self.global(),
|
||||
compute_pipeline,
|
||||
descriptor.parent.parent.label.clone(),
|
||||
self,
|
||||
)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createcomputepipelineasync>
|
||||
fn CreateComputePipelineAsync(
|
||||
&self,
|
||||
descriptor: &GPUComputePipelineDescriptor,
|
||||
comp: InRealm,
|
||||
can_gc: CanGc,
|
||||
) -> Rc<Promise> {
|
||||
let promise = Promise::new_in_current_realm(comp, can_gc);
|
||||
let sender = response_async(&promise, self);
|
||||
GPUComputePipeline::create(self, descriptor, Some(sender));
|
||||
promise
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createcommandencoder>
|
||||
fn CreateCommandEncoder(
|
||||
&self,
|
||||
descriptor: &GPUCommandEncoderDescriptor,
|
||||
) -> DomRoot<GPUCommandEncoder> {
|
||||
GPUCommandEncoder::create(self, descriptor)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createtexture>
|
||||
fn CreateTexture(&self, descriptor: &GPUTextureDescriptor) -> Fallible<DomRoot<GPUTexture>> {
|
||||
GPUTexture::create(self, descriptor)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createsampler>
|
||||
fn CreateSampler(&self, descriptor: &GPUSamplerDescriptor) -> DomRoot<GPUSampler> {
|
||||
GPUSampler::create(self, descriptor)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createrenderpipeline>
|
||||
fn CreateRenderPipeline(
|
||||
&self,
|
||||
descriptor: &GPURenderPipelineDescriptor,
|
||||
) -> Fallible<DomRoot<GPURenderPipeline>> {
|
||||
let (pipeline_layout, desc) = self.parse_render_pipeline(descriptor)?;
|
||||
let render_pipeline = GPURenderPipeline::create(self, pipeline_layout, desc, None)?;
|
||||
Ok(GPURenderPipeline::new(
|
||||
&self.global(),
|
||||
render_pipeline,
|
||||
descriptor.parent.parent.label.clone(),
|
||||
self,
|
||||
))
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createrenderpipelineasync>
|
||||
fn CreateRenderPipelineAsync(
|
||||
&self,
|
||||
descriptor: &GPURenderPipelineDescriptor,
|
||||
comp: InRealm,
|
||||
can_gc: CanGc,
|
||||
) -> Fallible<Rc<Promise>> {
|
||||
let (implicit_ids, desc) = self.parse_render_pipeline(descriptor)?;
|
||||
let promise = Promise::new_in_current_realm(comp, can_gc);
|
||||
let sender = response_async(&promise, self);
|
||||
GPURenderPipeline::create(self, implicit_ids, desc, Some(sender))?;
|
||||
Ok(promise)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createrenderbundleencoder>
|
||||
fn CreateRenderBundleEncoder(
|
||||
&self,
|
||||
descriptor: &GPURenderBundleEncoderDescriptor,
|
||||
) -> Fallible<DomRoot<GPURenderBundleEncoder>> {
|
||||
GPURenderBundleEncoder::create(self, descriptor)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-pusherrorscope>
|
||||
fn PushErrorScope(&self, filter: GPUErrorFilter) {
|
||||
if self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::PushErrorScope {
|
||||
device_id: self.device.0,
|
||||
filter: filter.as_webgpu(),
|
||||
})
|
||||
.is_err()
|
||||
{
|
||||
warn!("Failed sending WebGPURequest::PushErrorScope");
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-poperrorscope>
|
||||
fn PopErrorScope(&self, comp: InRealm, can_gc: CanGc) -> Rc<Promise> {
|
||||
let promise = Promise::new_in_current_realm(comp, can_gc);
|
||||
let sender = response_async(&promise, self);
|
||||
if self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::PopErrorScope {
|
||||
device_id: self.device.0,
|
||||
sender,
|
||||
})
|
||||
.is_err()
|
||||
{
|
||||
warn!("Error when sending WebGPURequest::PopErrorScope");
|
||||
}
|
||||
promise
|
||||
}
|
||||
|
||||
// https://gpuweb.github.io/gpuweb/#dom-gpudevice-onuncapturederror
|
||||
event_handler!(uncapturederror, GetOnuncapturederror, SetOnuncapturederror);
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-destroy>
|
||||
fn Destroy(&self) {
|
||||
if self.valid.get() {
|
||||
self.valid.set(false);
|
||||
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DestroyDevice(self.device.0))
|
||||
{
|
||||
warn!("Failed to send DestroyDevice ({:?}) ({})", self.device.0, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncWGPUListener for GPUDevice {
|
||||
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>, can_gc: CanGc) {
|
||||
match response {
|
||||
WebGPUResponse::PoppedErrorScope(result) => match result {
|
||||
Ok(None) | Err(PopError::Lost) => promise.resolve_native(&None::<Option<GPUError>>),
|
||||
Err(PopError::Empty) => promise.reject_error(Error::Operation),
|
||||
Ok(Some(error)) => {
|
||||
let error = GPUError::from_error(&self.global(), error, can_gc);
|
||||
promise.resolve_native(&error);
|
||||
},
|
||||
},
|
||||
WebGPUResponse::ComputePipeline(result) => match result {
|
||||
Ok(pipeline) => promise.resolve_native(&GPUComputePipeline::new(
|
||||
&self.global(),
|
||||
WebGPUComputePipeline(pipeline.id),
|
||||
pipeline.label.into(),
|
||||
self,
|
||||
)),
|
||||
Err(webgpu::Error::Validation(msg)) => {
|
||||
promise.reject_native(&GPUPipelineError::new(
|
||||
&self.global(),
|
||||
msg.into(),
|
||||
GPUPipelineErrorReason::Validation,
|
||||
can_gc,
|
||||
))
|
||||
},
|
||||
Err(webgpu::Error::OutOfMemory(msg) | webgpu::Error::Internal(msg)) => promise
|
||||
.reject_native(&GPUPipelineError::new(
|
||||
&self.global(),
|
||||
msg.into(),
|
||||
GPUPipelineErrorReason::Internal,
|
||||
can_gc,
|
||||
)),
|
||||
},
|
||||
WebGPUResponse::RenderPipeline(result) => match result {
|
||||
Ok(pipeline) => promise.resolve_native(&GPURenderPipeline::new(
|
||||
&self.global(),
|
||||
WebGPURenderPipeline(pipeline.id),
|
||||
pipeline.label.into(),
|
||||
self,
|
||||
)),
|
||||
Err(webgpu::Error::Validation(msg)) => {
|
||||
promise.reject_native(&GPUPipelineError::new(
|
||||
&self.global(),
|
||||
msg.into(),
|
||||
GPUPipelineErrorReason::Validation,
|
||||
can_gc,
|
||||
))
|
||||
},
|
||||
Err(webgpu::Error::OutOfMemory(msg) | webgpu::Error::Internal(msg)) => promise
|
||||
.reject_native(&GPUPipelineError::new(
|
||||
&self.global(),
|
||||
msg.into(),
|
||||
GPUPipelineErrorReason::Internal,
|
||||
can_gc,
|
||||
)),
|
||||
},
|
||||
_ => unreachable!("Wrong response received on AsyncWGPUListener for GPUDevice"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPUDevice {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DropDevice(self.device.0))
|
||||
{
|
||||
warn!("Failed to send DropDevice ({:?}) ({})", self.device.0, e);
|
||||
}
|
||||
}
|
||||
}
|
55
components/script/dom/webgpu/gpudevicelostinfo.rs
Normal file
55
components/script/dom/webgpu/gpudevicelostinfo.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUDeviceLostInfoMethods, GPUDeviceLostReason,
|
||||
};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUDeviceLostInfo {
|
||||
reflector_: Reflector,
|
||||
message: DOMString,
|
||||
reason: GPUDeviceLostReason,
|
||||
}
|
||||
|
||||
impl GPUDeviceLostInfo {
|
||||
fn new_inherited(message: DOMString, reason: GPUDeviceLostReason) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
message,
|
||||
reason,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
message: DOMString,
|
||||
reason: GPUDeviceLostReason,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPUDeviceLostInfo::new_inherited(message, reason)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUDeviceLostInfoMethods<crate::DomTypeHolder> for GPUDeviceLostInfo {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevicelostinfo-message>
|
||||
fn Message(&self) -> DOMString {
|
||||
self.message.clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevicelostinfo-reason>
|
||||
fn Reason(&self) -> GPUDeviceLostReason {
|
||||
self.reason
|
||||
}
|
||||
}
|
100
components/script/dom/webgpu/gpuerror.rs
Normal file
100
components/script/dom/webgpu/gpuerror.rs
Normal file
|
@ -0,0 +1,100 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
use webgpu::{Error, ErrorFilter};
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{GPUErrorFilter, GPUErrorMethods};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::types::{GPUInternalError, GPUOutOfMemoryError, GPUValidationError};
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUError {
|
||||
reflector_: Reflector,
|
||||
message: DOMString,
|
||||
}
|
||||
|
||||
impl GPUError {
|
||||
pub fn new_inherited(message: DOMString) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
message,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn new(global: &GlobalScope, message: DOMString, can_gc: CanGc) -> DomRoot<Self> {
|
||||
Self::new_with_proto(global, None, message, can_gc)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn new_with_proto(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
message: DOMString,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object_with_proto(
|
||||
Box::new(GPUError::new_inherited(message)),
|
||||
global,
|
||||
proto,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn from_error(global: &GlobalScope, error: Error, can_gc: CanGc) -> DomRoot<Self> {
|
||||
match error {
|
||||
Error::Validation(msg) => DomRoot::upcast(GPUValidationError::new_with_proto(
|
||||
global,
|
||||
None,
|
||||
DOMString::from_string(msg),
|
||||
can_gc,
|
||||
)),
|
||||
Error::OutOfMemory(msg) => DomRoot::upcast(GPUOutOfMemoryError::new_with_proto(
|
||||
global,
|
||||
None,
|
||||
DOMString::from_string(msg),
|
||||
can_gc,
|
||||
)),
|
||||
Error::Internal(msg) => DomRoot::upcast(GPUInternalError::new_with_proto(
|
||||
global,
|
||||
None,
|
||||
DOMString::from_string(msg),
|
||||
can_gc,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUErrorMethods<crate::DomTypeHolder> for GPUError {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuerror-message>
|
||||
fn Message(&self) -> DOMString {
|
||||
self.message.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ErrorFilter> for GPUErrorFilter {
|
||||
fn from(filter: ErrorFilter) -> Self {
|
||||
match filter {
|
||||
ErrorFilter::Validation => GPUErrorFilter::Validation,
|
||||
ErrorFilter::OutOfMemory => GPUErrorFilter::Out_of_memory,
|
||||
ErrorFilter::Internal => GPUErrorFilter::Internal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUErrorFilter {
|
||||
pub fn as_webgpu(&self) -> ErrorFilter {
|
||||
match self {
|
||||
GPUErrorFilter::Validation => ErrorFilter::Validation,
|
||||
GPUErrorFilter::Out_of_memory => ErrorFilter::OutOfMemory,
|
||||
GPUErrorFilter::Internal => ErrorFilter::Internal,
|
||||
}
|
||||
}
|
||||
}
|
53
components/script/dom/webgpu/gpuinternalerror.rs
Normal file
53
components/script/dom/webgpu/gpuinternalerror.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUInternalError_Binding::GPUInternalErrorMethods;
|
||||
use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::types::GPUError;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUInternalError {
|
||||
gpu_error: GPUError,
|
||||
}
|
||||
|
||||
impl GPUInternalError {
|
||||
fn new_inherited(message: DOMString) -> Self {
|
||||
Self {
|
||||
gpu_error: GPUError::new_inherited(message),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_proto(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
message: DOMString,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object_with_proto(
|
||||
Box::new(Self::new_inherited(message)),
|
||||
global,
|
||||
proto,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUInternalErrorMethods<crate::DomTypeHolder> for GPUInternalError {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-GPUInternalError-GPUInternalError>
|
||||
fn Constructor(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
message: DOMString,
|
||||
) -> DomRoot<Self> {
|
||||
Self::new_with_proto(global, proto, message, can_gc)
|
||||
}
|
||||
}
|
12
components/script/dom/webgpu/gpumapmode.rs
Normal file
12
components/script/dom/webgpu/gpumapmode.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::reflector::Reflector;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUMapMode {
|
||||
reflector_: Reflector,
|
||||
}
|
53
components/script/dom/webgpu/gpuoutofmemoryerror.rs
Normal file
53
components/script/dom/webgpu/gpuoutofmemoryerror.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUOutOfMemoryError_Binding::GPUOutOfMemoryErrorMethods;
|
||||
use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::types::GPUError;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUOutOfMemoryError {
|
||||
gpu_error: GPUError,
|
||||
}
|
||||
|
||||
impl GPUOutOfMemoryError {
|
||||
fn new_inherited(message: DOMString) -> Self {
|
||||
Self {
|
||||
gpu_error: GPUError::new_inherited(message),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_proto(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
message: DOMString,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object_with_proto(
|
||||
Box::new(Self::new_inherited(message)),
|
||||
global,
|
||||
proto,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUOutOfMemoryErrorMethods<crate::DomTypeHolder> for GPUOutOfMemoryError {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-GPUOutOfMemoryError-GPUOutOfMemoryError>
|
||||
fn Constructor(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
message: DOMString,
|
||||
) -> DomRoot<Self> {
|
||||
Self::new_with_proto(global, proto, message, can_gc)
|
||||
}
|
||||
}
|
74
components/script/dom/webgpu/gpupipelineerror.rs
Normal file
74
components/script/dom/webgpu/gpupipelineerror.rs
Normal file
|
@ -0,0 +1,74 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUPipelineErrorInit, GPUPipelineErrorMethods, GPUPipelineErrorReason,
|
||||
};
|
||||
use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::domexception::DOMException;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#gpupipelineerror>
|
||||
#[dom_struct]
|
||||
pub struct GPUPipelineError {
|
||||
exception: DOMException,
|
||||
reason: GPUPipelineErrorReason,
|
||||
}
|
||||
|
||||
impl GPUPipelineError {
|
||||
fn new_inherited(message: DOMString, reason: GPUPipelineErrorReason) -> Self {
|
||||
Self {
|
||||
exception: DOMException::new_inherited(message, "GPUPipelineError".into()),
|
||||
reason,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_proto(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
message: DOMString,
|
||||
reason: GPUPipelineErrorReason,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object_with_proto(
|
||||
Box::new(Self::new_inherited(message, reason)),
|
||||
global,
|
||||
proto,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
message: DOMString,
|
||||
reason: GPUPipelineErrorReason,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
Self::new_with_proto(global, None, message, reason, can_gc)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUPipelineErrorMethods<crate::DomTypeHolder> for GPUPipelineError {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpupipelineerror-constructor>
|
||||
fn Constructor(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
message: DOMString,
|
||||
options: &GPUPipelineErrorInit,
|
||||
) -> DomRoot<Self> {
|
||||
Self::new_with_proto(global, proto, message, options.reason, can_gc)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpupipelineerror-reason>
|
||||
fn Reason(&self) -> GPUPipelineErrorReason {
|
||||
self.reason
|
||||
}
|
||||
}
|
142
components/script/dom/webgpu/gpupipelinelayout.rs
Normal file
142
components/script/dom/webgpu/gpupipelinelayout.rs
Normal file
|
@ -0,0 +1,142 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use webgpu::wgc::binding_model::PipelineLayoutDescriptor;
|
||||
use webgpu::{WebGPU, WebGPUBindGroupLayout, WebGPUPipelineLayout, WebGPURequest};
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUPipelineLayoutDescriptor, GPUPipelineLayoutMethods,
|
||||
};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpudevice::GPUDevice;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUPipelineLayout {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "defined in webgpu"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
label: DomRefCell<USVString>,
|
||||
#[no_trace]
|
||||
pipeline_layout: WebGPUPipelineLayout,
|
||||
#[no_trace]
|
||||
bind_group_layouts: Vec<WebGPUBindGroupLayout>,
|
||||
}
|
||||
|
||||
impl GPUPipelineLayout {
|
||||
fn new_inherited(
|
||||
channel: WebGPU,
|
||||
pipeline_layout: WebGPUPipelineLayout,
|
||||
label: USVString,
|
||||
bgls: Vec<WebGPUBindGroupLayout>,
|
||||
) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
channel,
|
||||
label: DomRefCell::new(label),
|
||||
pipeline_layout,
|
||||
bind_group_layouts: bgls,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
channel: WebGPU,
|
||||
pipeline_layout: WebGPUPipelineLayout,
|
||||
label: USVString,
|
||||
bgls: Vec<WebGPUBindGroupLayout>,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPUPipelineLayout::new_inherited(
|
||||
channel,
|
||||
pipeline_layout,
|
||||
label,
|
||||
bgls,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUPipelineLayout {
|
||||
pub fn id(&self) -> WebGPUPipelineLayout {
|
||||
self.pipeline_layout
|
||||
}
|
||||
|
||||
pub fn bind_group_layouts(&self) -> Vec<WebGPUBindGroupLayout> {
|
||||
self.bind_group_layouts.clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createpipelinelayout>
|
||||
pub fn create(
|
||||
device: &GPUDevice,
|
||||
descriptor: &GPUPipelineLayoutDescriptor,
|
||||
) -> DomRoot<GPUPipelineLayout> {
|
||||
let bgls = descriptor
|
||||
.bindGroupLayouts
|
||||
.iter()
|
||||
.map(|each| each.id())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let desc = PipelineLayoutDescriptor {
|
||||
label: (&descriptor.parent).into(),
|
||||
bind_group_layouts: Cow::Owned(bgls.iter().map(|l| l.0).collect::<Vec<_>>()),
|
||||
push_constant_ranges: Cow::Owned(vec![]),
|
||||
};
|
||||
|
||||
let pipeline_layout_id = device.global().wgpu_id_hub().create_pipeline_layout_id();
|
||||
device
|
||||
.channel()
|
||||
.0
|
||||
.send(WebGPURequest::CreatePipelineLayout {
|
||||
device_id: device.id().0,
|
||||
pipeline_layout_id,
|
||||
descriptor: desc,
|
||||
})
|
||||
.expect("Failed to create WebGPU PipelineLayout");
|
||||
|
||||
let pipeline_layout = WebGPUPipelineLayout(pipeline_layout_id);
|
||||
GPUPipelineLayout::new(
|
||||
&device.global(),
|
||||
device.channel().clone(),
|
||||
pipeline_layout,
|
||||
descriptor.parent.label.clone(),
|
||||
bgls,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUPipelineLayoutMethods<crate::DomTypeHolder> for GPUPipelineLayout {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPUPipelineLayout {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DropPipelineLayout(self.pipeline_layout.0))
|
||||
{
|
||||
warn!(
|
||||
"Failed to send DropPipelineLayout ({:?}) ({})",
|
||||
self.pipeline_layout.0, e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
35
components/script/dom/webgpu/gpuqueryset.rs
Normal file
35
components/script/dom/webgpu/gpuqueryset.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#![allow(dead_code)] // this file is stub
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUQuerySetMethods;
|
||||
use crate::dom::bindings::reflector::Reflector;
|
||||
use crate::dom::bindings::str::USVString;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUQuerySet {
|
||||
reflector_: Reflector,
|
||||
// #[ignore_malloc_size_of = "defined in wgpu-types"]
|
||||
}
|
||||
|
||||
// TODO: wgpu does not expose right fields right now
|
||||
impl GPUQuerySetMethods<crate::DomTypeHolder> for GPUQuerySet {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuqueryset-destroy>
|
||||
fn Destroy(&self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, _value: USVString) {
|
||||
todo!()
|
||||
}
|
||||
}
|
225
components/script/dom/webgpu/gpuqueue.rs
Normal file
225
components/script/dom/webgpu/gpuqueue.rs
Normal file
|
@ -0,0 +1,225 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use ipc_channel::ipc::IpcSharedMemory;
|
||||
use webgpu::{wgt, WebGPU, WebGPUQueue, WebGPURequest, WebGPUResponse};
|
||||
|
||||
use super::gpu::{response_async, AsyncWGPUListener};
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUExtent3D, GPUImageCopyTexture, GPUImageDataLayout, GPUQueueMethods, GPUSize64,
|
||||
};
|
||||
use crate::dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer as BufferSource;
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpubuffer::GPUBuffer;
|
||||
use crate::dom::gpucommandbuffer::GPUCommandBuffer;
|
||||
use crate::dom::gpudevice::GPUDevice;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUQueue {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "defined in webgpu"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
device: DomRefCell<Option<Dom<GPUDevice>>>,
|
||||
label: DomRefCell<USVString>,
|
||||
#[no_trace]
|
||||
queue: WebGPUQueue,
|
||||
}
|
||||
|
||||
impl GPUQueue {
|
||||
fn new_inherited(channel: WebGPU, queue: WebGPUQueue) -> Self {
|
||||
GPUQueue {
|
||||
channel,
|
||||
reflector_: Reflector::new(),
|
||||
device: DomRefCell::new(None),
|
||||
label: DomRefCell::new(USVString::default()),
|
||||
queue,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope, channel: WebGPU, queue: WebGPUQueue) -> DomRoot<Self> {
|
||||
reflect_dom_object(Box::new(GPUQueue::new_inherited(channel, queue)), global)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUQueue {
|
||||
pub fn set_device(&self, device: &GPUDevice) {
|
||||
*self.device.borrow_mut() = Some(Dom::from_ref(device));
|
||||
}
|
||||
|
||||
pub fn id(&self) -> WebGPUQueue {
|
||||
self.queue
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUQueueMethods<crate::DomTypeHolder> for GPUQueue {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuqueue-submit>
|
||||
fn Submit(&self, command_buffers: Vec<DomRoot<GPUCommandBuffer>>) {
|
||||
let command_buffers = command_buffers.iter().map(|cb| cb.id().0).collect();
|
||||
self.channel
|
||||
.0
|
||||
.send(WebGPURequest::Submit {
|
||||
device_id: self.device.borrow().as_ref().unwrap().id().0,
|
||||
queue_id: self.queue.0,
|
||||
command_buffers,
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuqueue-writebuffer>
|
||||
#[allow(unsafe_code)]
|
||||
fn WriteBuffer(
|
||||
&self,
|
||||
buffer: &GPUBuffer,
|
||||
buffer_offset: GPUSize64,
|
||||
data: BufferSource,
|
||||
data_offset: GPUSize64,
|
||||
size: Option<GPUSize64>,
|
||||
) -> Fallible<()> {
|
||||
// Step 1
|
||||
let sizeof_element: usize = match data {
|
||||
BufferSource::ArrayBufferView(ref d) => d.get_array_type().byte_size().unwrap_or(1),
|
||||
BufferSource::ArrayBuffer(_) => 1,
|
||||
};
|
||||
let data = match data {
|
||||
BufferSource::ArrayBufferView(d) => d.to_vec(),
|
||||
BufferSource::ArrayBuffer(d) => d.to_vec(),
|
||||
};
|
||||
// Step 2
|
||||
let data_size: usize = data.len() / sizeof_element;
|
||||
debug_assert_eq!(data.len() % sizeof_element, 0);
|
||||
// Step 3
|
||||
let content_size = if let Some(s) = size {
|
||||
s
|
||||
} else {
|
||||
(data_size as GPUSize64)
|
||||
.checked_sub(data_offset)
|
||||
.ok_or(Error::Operation)?
|
||||
};
|
||||
|
||||
// Step 4
|
||||
let valid = data_offset + content_size <= data_size as u64 &&
|
||||
content_size * sizeof_element as u64 % wgt::COPY_BUFFER_ALIGNMENT == 0;
|
||||
if !valid {
|
||||
return Err(Error::Operation);
|
||||
}
|
||||
|
||||
// Step 5&6
|
||||
let contents = IpcSharedMemory::from_bytes(
|
||||
&data[(data_offset as usize) * sizeof_element..
|
||||
((data_offset + content_size) as usize) * sizeof_element],
|
||||
);
|
||||
if let Err(e) = self.channel.0.send(WebGPURequest::WriteBuffer {
|
||||
device_id: self.device.borrow().as_ref().unwrap().id().0,
|
||||
queue_id: self.queue.0,
|
||||
buffer_id: buffer.id().0,
|
||||
buffer_offset,
|
||||
data: contents,
|
||||
}) {
|
||||
warn!("Failed to send WriteBuffer({:?}) ({})", buffer.id(), e);
|
||||
return Err(Error::Operation);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuqueue-writetexture>
|
||||
fn WriteTexture(
|
||||
&self,
|
||||
destination: &GPUImageCopyTexture,
|
||||
data: BufferSource,
|
||||
data_layout: &GPUImageDataLayout,
|
||||
size: GPUExtent3D,
|
||||
) -> Fallible<()> {
|
||||
let (bytes, len) = match data {
|
||||
BufferSource::ArrayBufferView(d) => (d.to_vec(), d.len() as u64),
|
||||
BufferSource::ArrayBuffer(d) => (d.to_vec(), d.len() as u64),
|
||||
};
|
||||
let valid = data_layout.offset <= len;
|
||||
|
||||
if !valid {
|
||||
return Err(Error::Operation);
|
||||
}
|
||||
|
||||
let texture_cv = destination.try_into()?;
|
||||
let texture_layout = data_layout.into();
|
||||
let write_size = (&size).try_into()?;
|
||||
let final_data = IpcSharedMemory::from_bytes(&bytes);
|
||||
|
||||
if let Err(e) = self.channel.0.send(WebGPURequest::WriteTexture {
|
||||
device_id: self.device.borrow().as_ref().unwrap().id().0,
|
||||
queue_id: self.queue.0,
|
||||
texture_cv,
|
||||
data_layout: texture_layout,
|
||||
size: write_size,
|
||||
data: final_data,
|
||||
}) {
|
||||
warn!(
|
||||
"Failed to send WriteTexture({:?}) ({})",
|
||||
destination.texture.id().0,
|
||||
e
|
||||
);
|
||||
return Err(Error::Operation);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuqueue-onsubmittedworkdone>
|
||||
fn OnSubmittedWorkDone(&self, can_gc: CanGc) -> Rc<Promise> {
|
||||
let global = self.global();
|
||||
let promise = Promise::new(&global, can_gc);
|
||||
let sender = response_async(&promise, self);
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::QueueOnSubmittedWorkDone {
|
||||
sender,
|
||||
queue_id: self.queue.0,
|
||||
})
|
||||
{
|
||||
warn!("QueueOnSubmittedWorkDone failed with {e}")
|
||||
}
|
||||
promise
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncWGPUListener for GPUQueue {
|
||||
fn handle_response(
|
||||
&self,
|
||||
response: webgpu::WebGPUResponse,
|
||||
promise: &Rc<Promise>,
|
||||
_can_gc: CanGc,
|
||||
) {
|
||||
match response {
|
||||
WebGPUResponse::SubmittedWorkDone => {
|
||||
promise.resolve_native(&());
|
||||
},
|
||||
_ => {
|
||||
warn!("GPUQueue received wrong WebGPUResponse");
|
||||
promise.reject_error(Error::Operation);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
94
components/script/dom/webgpu/gpurenderbundle.rs
Normal file
94
components/script/dom/webgpu/gpurenderbundle.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use webgpu::{WebGPU, WebGPUDevice, WebGPURenderBundle, WebGPURequest};
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPURenderBundleMethods;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPURenderBundle {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
#[no_trace]
|
||||
device: WebGPUDevice,
|
||||
#[no_trace]
|
||||
render_bundle: WebGPURenderBundle,
|
||||
label: DomRefCell<USVString>,
|
||||
}
|
||||
|
||||
impl GPURenderBundle {
|
||||
fn new_inherited(
|
||||
render_bundle: WebGPURenderBundle,
|
||||
device: WebGPUDevice,
|
||||
channel: WebGPU,
|
||||
label: USVString,
|
||||
) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
render_bundle,
|
||||
device,
|
||||
channel,
|
||||
label: DomRefCell::new(label),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
render_bundle: WebGPURenderBundle,
|
||||
device: WebGPUDevice,
|
||||
channel: WebGPU,
|
||||
label: USVString,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPURenderBundle::new_inherited(
|
||||
render_bundle,
|
||||
device,
|
||||
channel,
|
||||
label,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPURenderBundle {
|
||||
pub fn id(&self) -> WebGPURenderBundle {
|
||||
self.render_bundle
|
||||
}
|
||||
}
|
||||
|
||||
impl GPURenderBundleMethods<crate::DomTypeHolder> for GPURenderBundle {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPURenderBundle {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DropRenderBundle(self.render_bundle.0))
|
||||
{
|
||||
warn!(
|
||||
"Failed to send DropRenderBundle ({:?}) ({})",
|
||||
self.render_bundle.0, e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
279
components/script/dom/webgpu/gpurenderbundleencoder.rs
Normal file
279
components/script/dom/webgpu/gpurenderbundleencoder.rs
Normal file
|
@ -0,0 +1,279 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use webgpu::wgc::command::{
|
||||
bundle_ffi as wgpu_bundle, RenderBundleEncoder, RenderBundleEncoderDescriptor,
|
||||
};
|
||||
use webgpu::{wgt, WebGPU, WebGPURenderBundle, WebGPURequest};
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUIndexFormat, GPURenderBundleDescriptor, GPURenderBundleEncoderDescriptor,
|
||||
GPURenderBundleEncoderMethods,
|
||||
};
|
||||
use crate::dom::bindings::import::module::Fallible;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpubindgroup::GPUBindGroup;
|
||||
use crate::dom::gpubuffer::GPUBuffer;
|
||||
use crate::dom::gpudevice::GPUDevice;
|
||||
use crate::dom::gpurenderbundle::GPURenderBundle;
|
||||
use crate::dom::gpurenderpipeline::GPURenderPipeline;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPURenderBundleEncoder {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
device: Dom<GPUDevice>,
|
||||
#[ignore_malloc_size_of = "defined in wgpu-core"]
|
||||
#[no_trace]
|
||||
render_bundle_encoder: DomRefCell<Option<RenderBundleEncoder>>,
|
||||
label: DomRefCell<USVString>,
|
||||
}
|
||||
|
||||
impl GPURenderBundleEncoder {
|
||||
fn new_inherited(
|
||||
render_bundle_encoder: RenderBundleEncoder,
|
||||
device: &GPUDevice,
|
||||
channel: WebGPU,
|
||||
label: USVString,
|
||||
) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
render_bundle_encoder: DomRefCell::new(Some(render_bundle_encoder)),
|
||||
device: Dom::from_ref(device),
|
||||
channel,
|
||||
label: DomRefCell::new(label),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
render_bundle_encoder: RenderBundleEncoder,
|
||||
device: &GPUDevice,
|
||||
channel: WebGPU,
|
||||
label: USVString,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPURenderBundleEncoder::new_inherited(
|
||||
render_bundle_encoder,
|
||||
device,
|
||||
channel,
|
||||
label,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPURenderBundleEncoder {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createrenderbundleencoder>
|
||||
pub fn create(
|
||||
device: &GPUDevice,
|
||||
descriptor: &GPURenderBundleEncoderDescriptor,
|
||||
) -> Fallible<DomRoot<GPURenderBundleEncoder>> {
|
||||
let desc = RenderBundleEncoderDescriptor {
|
||||
label: (&descriptor.parent.parent).into(),
|
||||
color_formats: Cow::Owned(
|
||||
descriptor
|
||||
.parent
|
||||
.colorFormats
|
||||
.iter()
|
||||
.map(|format| {
|
||||
device
|
||||
.validate_texture_format_required_features(format)
|
||||
.map(Some)
|
||||
})
|
||||
.collect::<Fallible<Vec<_>>>()?,
|
||||
),
|
||||
depth_stencil: descriptor
|
||||
.parent
|
||||
.depthStencilFormat
|
||||
.map(|dsf| {
|
||||
device
|
||||
.validate_texture_format_required_features(&dsf)
|
||||
.map(|format| wgt::RenderBundleDepthStencil {
|
||||
format,
|
||||
depth_read_only: descriptor.depthReadOnly,
|
||||
stencil_read_only: descriptor.stencilReadOnly,
|
||||
})
|
||||
})
|
||||
.transpose()?,
|
||||
sample_count: descriptor.parent.sampleCount,
|
||||
multiview: None,
|
||||
};
|
||||
|
||||
// Handle error gracefully
|
||||
let render_bundle_encoder = RenderBundleEncoder::new(&desc, device.id().0, None).unwrap();
|
||||
|
||||
Ok(GPURenderBundleEncoder::new(
|
||||
&device.global(),
|
||||
render_bundle_encoder,
|
||||
device,
|
||||
device.channel().clone(),
|
||||
descriptor.parent.parent.label.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl GPURenderBundleEncoderMethods<crate::DomTypeHolder> for GPURenderBundleEncoder {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuprogrammablepassencoder-setbindgroup>
|
||||
#[allow(unsafe_code)]
|
||||
fn SetBindGroup(&self, index: u32, bind_group: &GPUBindGroup, dynamic_offsets: Vec<u32>) {
|
||||
if let Some(encoder) = self.render_bundle_encoder.borrow_mut().as_mut() {
|
||||
unsafe {
|
||||
wgpu_bundle::wgpu_render_bundle_set_bind_group(
|
||||
encoder,
|
||||
index,
|
||||
Some(bind_group.id().0),
|
||||
dynamic_offsets.as_ptr(),
|
||||
dynamic_offsets.len(),
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-setpipeline>
|
||||
fn SetPipeline(&self, pipeline: &GPURenderPipeline) {
|
||||
if let Some(encoder) = self.render_bundle_encoder.borrow_mut().as_mut() {
|
||||
wgpu_bundle::wgpu_render_bundle_set_pipeline(encoder, pipeline.id().0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-setindexbuffer>
|
||||
fn SetIndexBuffer(
|
||||
&self,
|
||||
buffer: &GPUBuffer,
|
||||
index_format: GPUIndexFormat,
|
||||
offset: u64,
|
||||
size: u64,
|
||||
) {
|
||||
if let Some(encoder) = self.render_bundle_encoder.borrow_mut().as_mut() {
|
||||
wgpu_bundle::wgpu_render_bundle_set_index_buffer(
|
||||
encoder,
|
||||
buffer.id().0,
|
||||
match index_format {
|
||||
GPUIndexFormat::Uint16 => wgt::IndexFormat::Uint16,
|
||||
GPUIndexFormat::Uint32 => wgt::IndexFormat::Uint32,
|
||||
},
|
||||
offset,
|
||||
wgt::BufferSize::new(size),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-setvertexbuffer>
|
||||
fn SetVertexBuffer(&self, slot: u32, buffer: &GPUBuffer, offset: u64, size: u64) {
|
||||
if let Some(encoder) = self.render_bundle_encoder.borrow_mut().as_mut() {
|
||||
wgpu_bundle::wgpu_render_bundle_set_vertex_buffer(
|
||||
encoder,
|
||||
slot,
|
||||
buffer.id().0,
|
||||
offset,
|
||||
wgt::BufferSize::new(size),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-draw>
|
||||
fn Draw(&self, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32) {
|
||||
if let Some(encoder) = self.render_bundle_encoder.borrow_mut().as_mut() {
|
||||
wgpu_bundle::wgpu_render_bundle_draw(
|
||||
encoder,
|
||||
vertex_count,
|
||||
instance_count,
|
||||
first_vertex,
|
||||
first_instance,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-drawindexed>
|
||||
fn DrawIndexed(
|
||||
&self,
|
||||
index_count: u32,
|
||||
instance_count: u32,
|
||||
first_index: u32,
|
||||
base_vertex: i32,
|
||||
first_instance: u32,
|
||||
) {
|
||||
if let Some(encoder) = self.render_bundle_encoder.borrow_mut().as_mut() {
|
||||
wgpu_bundle::wgpu_render_bundle_draw_indexed(
|
||||
encoder,
|
||||
index_count,
|
||||
instance_count,
|
||||
first_index,
|
||||
base_vertex,
|
||||
first_instance,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-drawindirect>
|
||||
fn DrawIndirect(&self, indirect_buffer: &GPUBuffer, indirect_offset: u64) {
|
||||
if let Some(encoder) = self.render_bundle_encoder.borrow_mut().as_mut() {
|
||||
wgpu_bundle::wgpu_render_bundle_draw_indirect(
|
||||
encoder,
|
||||
indirect_buffer.id().0,
|
||||
indirect_offset,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-drawindexedindirect>
|
||||
fn DrawIndexedIndirect(&self, indirect_buffer: &GPUBuffer, indirect_offset: u64) {
|
||||
if let Some(encoder) = self.render_bundle_encoder.borrow_mut().as_mut() {
|
||||
wgpu_bundle::wgpu_render_bundle_draw_indexed_indirect(
|
||||
encoder,
|
||||
indirect_buffer.id().0,
|
||||
indirect_offset,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderbundleencoder-finish>
|
||||
fn Finish(&self, descriptor: &GPURenderBundleDescriptor) -> DomRoot<GPURenderBundle> {
|
||||
let desc = wgt::RenderBundleDescriptor {
|
||||
label: (&descriptor.parent).into(),
|
||||
};
|
||||
let encoder = self.render_bundle_encoder.borrow_mut().take().unwrap();
|
||||
let render_bundle_id = self.global().wgpu_id_hub().create_render_bundle_id();
|
||||
|
||||
self.channel
|
||||
.0
|
||||
.send(WebGPURequest::RenderBundleEncoderFinish {
|
||||
render_bundle_encoder: encoder,
|
||||
descriptor: desc,
|
||||
render_bundle_id,
|
||||
device_id: self.device.id().0,
|
||||
})
|
||||
.expect("Failed to send RenderBundleEncoderFinish");
|
||||
|
||||
let render_bundle = WebGPURenderBundle(render_bundle_id);
|
||||
GPURenderBundle::new(
|
||||
&self.global(),
|
||||
render_bundle,
|
||||
self.device.id(),
|
||||
self.channel.clone(),
|
||||
descriptor.parent.label.clone(),
|
||||
)
|
||||
}
|
||||
}
|
249
components/script/dom/webgpu/gpurenderpassencoder.rs
Normal file
249
components/script/dom/webgpu/gpurenderpassencoder.rs
Normal file
|
@ -0,0 +1,249 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use webgpu::{wgt, RenderCommand, WebGPU, WebGPURenderPass, WebGPURequest};
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUColor, GPUIndexFormat, GPURenderPassEncoderMethods,
|
||||
};
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpubindgroup::GPUBindGroup;
|
||||
use crate::dom::gpubuffer::GPUBuffer;
|
||||
use crate::dom::gpucommandencoder::GPUCommandEncoder;
|
||||
use crate::dom::gpurenderbundle::GPURenderBundle;
|
||||
use crate::dom::gpurenderpipeline::GPURenderPipeline;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPURenderPassEncoder {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "defined in webgpu"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
label: DomRefCell<USVString>,
|
||||
#[no_trace]
|
||||
render_pass: WebGPURenderPass,
|
||||
command_encoder: Dom<GPUCommandEncoder>,
|
||||
}
|
||||
|
||||
impl GPURenderPassEncoder {
|
||||
fn new_inherited(
|
||||
channel: WebGPU,
|
||||
render_pass: WebGPURenderPass,
|
||||
parent: &GPUCommandEncoder,
|
||||
label: USVString,
|
||||
) -> Self {
|
||||
Self {
|
||||
channel,
|
||||
reflector_: Reflector::new(),
|
||||
label: DomRefCell::new(label),
|
||||
render_pass,
|
||||
command_encoder: Dom::from_ref(parent),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
channel: WebGPU,
|
||||
render_pass: WebGPURenderPass,
|
||||
parent: &GPUCommandEncoder,
|
||||
label: USVString,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPURenderPassEncoder::new_inherited(
|
||||
channel,
|
||||
render_pass,
|
||||
parent,
|
||||
label,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
|
||||
fn send_render_command(&self, render_command: RenderCommand) {
|
||||
if let Err(e) = self.channel.0.send(WebGPURequest::RenderPassCommand {
|
||||
render_pass_id: self.render_pass.0,
|
||||
render_command,
|
||||
device_id: self.command_encoder.device_id().0,
|
||||
}) {
|
||||
warn!("Error sending WebGPURequest::RenderPassCommand: {e:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GPURenderPassEncoderMethods<crate::DomTypeHolder> for GPURenderPassEncoder {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuprogrammablepassencoder-setbindgroup>
|
||||
fn SetBindGroup(&self, index: u32, bind_group: &GPUBindGroup, offsets: Vec<u32>) {
|
||||
self.send_render_command(RenderCommand::SetBindGroup {
|
||||
index,
|
||||
bind_group_id: bind_group.id().0,
|
||||
offsets,
|
||||
})
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setviewport>
|
||||
fn SetViewport(
|
||||
&self,
|
||||
x: Finite<f32>,
|
||||
y: Finite<f32>,
|
||||
width: Finite<f32>,
|
||||
height: Finite<f32>,
|
||||
min_depth: Finite<f32>,
|
||||
max_depth: Finite<f32>,
|
||||
) {
|
||||
self.send_render_command(RenderCommand::SetViewport {
|
||||
x: *x,
|
||||
y: *y,
|
||||
width: *width,
|
||||
height: *height,
|
||||
min_depth: *min_depth,
|
||||
max_depth: *max_depth,
|
||||
})
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setscissorrect>
|
||||
fn SetScissorRect(&self, x: u32, y: u32, width: u32, height: u32) {
|
||||
self.send_render_command(RenderCommand::SetScissorRect {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
})
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setblendcolor>
|
||||
fn SetBlendConstant(&self, color: GPUColor) -> Fallible<()> {
|
||||
self.send_render_command(RenderCommand::SetBlendConstant((&color).try_into()?));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setstencilreference>
|
||||
fn SetStencilReference(&self, reference: u32) {
|
||||
self.send_render_command(RenderCommand::SetStencilReference(reference))
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-end>
|
||||
fn End(&self) {
|
||||
if let Err(e) = self.channel.0.send(WebGPURequest::EndRenderPass {
|
||||
render_pass_id: self.render_pass.0,
|
||||
device_id: self.command_encoder.device_id().0,
|
||||
command_encoder_id: self.command_encoder.id().0,
|
||||
}) {
|
||||
warn!("Failed to send WebGPURequest::EndRenderPass: {e:?}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-setpipeline>
|
||||
fn SetPipeline(&self, pipeline: &GPURenderPipeline) {
|
||||
self.send_render_command(RenderCommand::SetPipeline(pipeline.id().0))
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurendercommandsmixin-setindexbuffer>
|
||||
fn SetIndexBuffer(
|
||||
&self,
|
||||
buffer: &GPUBuffer,
|
||||
index_format: GPUIndexFormat,
|
||||
offset: u64,
|
||||
size: u64,
|
||||
) {
|
||||
self.send_render_command(RenderCommand::SetIndexBuffer {
|
||||
buffer_id: buffer.id().0,
|
||||
index_format: match index_format {
|
||||
GPUIndexFormat::Uint16 => wgt::IndexFormat::Uint16,
|
||||
GPUIndexFormat::Uint32 => wgt::IndexFormat::Uint32,
|
||||
},
|
||||
offset,
|
||||
size: wgt::BufferSize::new(size),
|
||||
})
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-setvertexbuffer>
|
||||
fn SetVertexBuffer(&self, slot: u32, buffer: &GPUBuffer, offset: u64, size: u64) {
|
||||
self.send_render_command(RenderCommand::SetVertexBuffer {
|
||||
slot,
|
||||
buffer_id: buffer.id().0,
|
||||
offset,
|
||||
size: wgt::BufferSize::new(size),
|
||||
})
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-draw>
|
||||
fn Draw(&self, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32) {
|
||||
self.send_render_command(RenderCommand::Draw {
|
||||
vertex_count,
|
||||
instance_count,
|
||||
first_vertex,
|
||||
first_instance,
|
||||
})
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-drawindexed>
|
||||
fn DrawIndexed(
|
||||
&self,
|
||||
index_count: u32,
|
||||
instance_count: u32,
|
||||
first_index: u32,
|
||||
base_vertex: i32,
|
||||
first_instance: u32,
|
||||
) {
|
||||
self.send_render_command(RenderCommand::DrawIndexed {
|
||||
index_count,
|
||||
instance_count,
|
||||
first_index,
|
||||
base_vertex,
|
||||
first_instance,
|
||||
})
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-drawindirect>
|
||||
fn DrawIndirect(&self, buffer: &GPUBuffer, offset: u64) {
|
||||
self.send_render_command(RenderCommand::DrawIndirect {
|
||||
buffer_id: buffer.id().0,
|
||||
offset,
|
||||
})
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-drawindexedindirect>
|
||||
fn DrawIndexedIndirect(&self, buffer: &GPUBuffer, offset: u64) {
|
||||
self.send_render_command(RenderCommand::DrawIndexedIndirect {
|
||||
buffer_id: buffer.id().0,
|
||||
offset,
|
||||
})
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-executebundles>
|
||||
#[allow(unsafe_code)]
|
||||
fn ExecuteBundles(&self, bundles: Vec<DomRoot<GPURenderBundle>>) {
|
||||
let bundle_ids: Vec<_> = bundles.iter().map(|b| b.id().0).collect();
|
||||
self.send_render_command(RenderCommand::ExecuteBundles(bundle_ids))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPURenderPassEncoder {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DropRenderPass(self.render_pass.0))
|
||||
{
|
||||
warn!("Failed to send WebGPURequest::DropRenderPass with {e:?}");
|
||||
}
|
||||
}
|
||||
}
|
144
components/script/dom/webgpu/gpurenderpipeline.rs
Normal file
144
components/script/dom/webgpu/gpurenderpipeline.rs
Normal file
|
@ -0,0 +1,144 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use webgpu::wgc::pipeline::RenderPipelineDescriptor;
|
||||
use webgpu::{WebGPU, WebGPUBindGroupLayout, WebGPURenderPipeline, WebGPURequest, WebGPUResponse};
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPURenderPipelineMethods;
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpubindgrouplayout::GPUBindGroupLayout;
|
||||
use crate::dom::gpudevice::{GPUDevice, PipelineLayout};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPURenderPipeline {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
label: DomRefCell<USVString>,
|
||||
#[no_trace]
|
||||
render_pipeline: WebGPURenderPipeline,
|
||||
device: Dom<GPUDevice>,
|
||||
}
|
||||
|
||||
impl GPURenderPipeline {
|
||||
fn new_inherited(
|
||||
render_pipeline: WebGPURenderPipeline,
|
||||
label: USVString,
|
||||
device: &GPUDevice,
|
||||
) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
channel: device.channel(),
|
||||
label: DomRefCell::new(label),
|
||||
render_pipeline,
|
||||
device: Dom::from_ref(device),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
render_pipeline: WebGPURenderPipeline,
|
||||
label: USVString,
|
||||
device: &GPUDevice,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPURenderPipeline::new_inherited(
|
||||
render_pipeline,
|
||||
label,
|
||||
device,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPURenderPipeline {
|
||||
pub fn id(&self) -> WebGPURenderPipeline {
|
||||
self.render_pipeline
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createrenderpipeline>
|
||||
pub fn create(
|
||||
device: &GPUDevice,
|
||||
pipeline_layout: PipelineLayout,
|
||||
descriptor: RenderPipelineDescriptor<'static>,
|
||||
async_sender: Option<IpcSender<WebGPUResponse>>,
|
||||
) -> Fallible<WebGPURenderPipeline> {
|
||||
let render_pipeline_id = device.global().wgpu_id_hub().create_render_pipeline_id();
|
||||
|
||||
device
|
||||
.channel()
|
||||
.0
|
||||
.send(WebGPURequest::CreateRenderPipeline {
|
||||
device_id: device.id().0,
|
||||
render_pipeline_id,
|
||||
descriptor,
|
||||
implicit_ids: pipeline_layout.implicit(),
|
||||
async_sender,
|
||||
})
|
||||
.expect("Failed to create WebGPU render pipeline");
|
||||
|
||||
Ok(WebGPURenderPipeline(render_pipeline_id))
|
||||
}
|
||||
}
|
||||
|
||||
impl GPURenderPipelineMethods<crate::DomTypeHolder> for GPURenderPipeline {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpupipelinebase-getbindgrouplayout>
|
||||
fn GetBindGroupLayout(&self, index: u32) -> Fallible<DomRoot<GPUBindGroupLayout>> {
|
||||
let id = self.global().wgpu_id_hub().create_bind_group_layout_id();
|
||||
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::RenderGetBindGroupLayout {
|
||||
device_id: self.device.id().0,
|
||||
pipeline_id: self.render_pipeline.0,
|
||||
index,
|
||||
id,
|
||||
})
|
||||
{
|
||||
warn!("Failed to send WebGPURequest::RenderGetBindGroupLayout {e:?}");
|
||||
}
|
||||
|
||||
Ok(GPUBindGroupLayout::new(
|
||||
&self.global(),
|
||||
self.channel.clone(),
|
||||
WebGPUBindGroupLayout(id),
|
||||
USVString::default(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPURenderPipeline {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DropRenderPipeline(self.render_pipeline.0))
|
||||
{
|
||||
warn!(
|
||||
"Failed to send WebGPURequest::DropRenderPipeline({:?}) ({})",
|
||||
self.render_pipeline.0, e
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
143
components/script/dom/webgpu/gpusampler.rs
Normal file
143
components/script/dom/webgpu/gpusampler.rs
Normal file
|
@ -0,0 +1,143 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use webgpu::wgc::resource::SamplerDescriptor;
|
||||
use webgpu::{WebGPU, WebGPUDevice, WebGPURequest, WebGPUSampler};
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUSamplerDescriptor, GPUSamplerMethods,
|
||||
};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpudevice::GPUDevice;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUSampler {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "defined in webgpu"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
label: DomRefCell<USVString>,
|
||||
#[no_trace]
|
||||
device: WebGPUDevice,
|
||||
compare_enable: bool,
|
||||
#[no_trace]
|
||||
sampler: WebGPUSampler,
|
||||
}
|
||||
|
||||
impl GPUSampler {
|
||||
fn new_inherited(
|
||||
channel: WebGPU,
|
||||
device: WebGPUDevice,
|
||||
compare_enable: bool,
|
||||
sampler: WebGPUSampler,
|
||||
label: USVString,
|
||||
) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
channel,
|
||||
label: DomRefCell::new(label),
|
||||
device,
|
||||
sampler,
|
||||
compare_enable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
channel: WebGPU,
|
||||
device: WebGPUDevice,
|
||||
compare_enable: bool,
|
||||
sampler: WebGPUSampler,
|
||||
label: USVString,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPUSampler::new_inherited(
|
||||
channel,
|
||||
device,
|
||||
compare_enable,
|
||||
sampler,
|
||||
label,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUSampler {
|
||||
pub fn id(&self) -> WebGPUSampler {
|
||||
self.sampler
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createsampler>
|
||||
pub fn create(device: &GPUDevice, descriptor: &GPUSamplerDescriptor) -> DomRoot<GPUSampler> {
|
||||
let sampler_id = device.global().wgpu_id_hub().create_sampler_id();
|
||||
let compare_enable = descriptor.compare.is_some();
|
||||
let desc = SamplerDescriptor {
|
||||
label: (&descriptor.parent).into(),
|
||||
address_modes: [
|
||||
descriptor.addressModeU.into(),
|
||||
descriptor.addressModeV.into(),
|
||||
descriptor.addressModeW.into(),
|
||||
],
|
||||
mag_filter: descriptor.magFilter.into(),
|
||||
min_filter: descriptor.minFilter.into(),
|
||||
mipmap_filter: descriptor.mipmapFilter.into(),
|
||||
lod_min_clamp: *descriptor.lodMinClamp,
|
||||
lod_max_clamp: *descriptor.lodMaxClamp,
|
||||
compare: descriptor.compare.map(Into::into),
|
||||
anisotropy_clamp: 1,
|
||||
border_color: None,
|
||||
};
|
||||
|
||||
device
|
||||
.channel()
|
||||
.0
|
||||
.send(WebGPURequest::CreateSampler {
|
||||
device_id: device.id().0,
|
||||
sampler_id,
|
||||
descriptor: desc,
|
||||
})
|
||||
.expect("Failed to create WebGPU sampler");
|
||||
|
||||
let sampler = WebGPUSampler(sampler_id);
|
||||
|
||||
GPUSampler::new(
|
||||
&device.global(),
|
||||
device.channel().clone(),
|
||||
device.id(),
|
||||
compare_enable,
|
||||
sampler,
|
||||
descriptor.parent.label.clone(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUSamplerMethods<crate::DomTypeHolder> for GPUSampler {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPUSampler {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DropSampler(self.sampler.0))
|
||||
{
|
||||
warn!("Failed to send DropSampler ({:?}) ({})", self.sampler.0, e);
|
||||
}
|
||||
}
|
||||
}
|
154
components/script/dom/webgpu/gpushadermodule.rs
Normal file
154
components/script/dom/webgpu/gpushadermodule.rs
Normal file
|
@ -0,0 +1,154 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use webgpu::{WebGPU, WebGPURequest, WebGPUResponse, WebGPUShaderModule};
|
||||
|
||||
use super::gpu::AsyncWGPUListener;
|
||||
use super::gpucompilationinfo::GPUCompilationInfo;
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUShaderModuleDescriptor, GPUShaderModuleMethods,
|
||||
};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::bindings::trace::RootedTraceableBox;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::dom::types::GPUDevice;
|
||||
use crate::dom::webgpu::gpu::response_async;
|
||||
use crate::realms::InRealm;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUShaderModule {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "defined in webgpu"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
label: DomRefCell<USVString>,
|
||||
#[no_trace]
|
||||
shader_module: WebGPUShaderModule,
|
||||
#[ignore_malloc_size_of = "promise"]
|
||||
compilation_info_promise: Rc<Promise>,
|
||||
}
|
||||
|
||||
impl GPUShaderModule {
|
||||
fn new_inherited(
|
||||
channel: WebGPU,
|
||||
shader_module: WebGPUShaderModule,
|
||||
label: USVString,
|
||||
promise: Rc<Promise>,
|
||||
) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
channel,
|
||||
label: DomRefCell::new(label),
|
||||
shader_module,
|
||||
compilation_info_promise: promise,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
channel: WebGPU,
|
||||
shader_module: WebGPUShaderModule,
|
||||
label: USVString,
|
||||
promise: Rc<Promise>,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPUShaderModule::new_inherited(
|
||||
channel,
|
||||
shader_module,
|
||||
label,
|
||||
promise,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUShaderModule {
|
||||
pub fn id(&self) -> WebGPUShaderModule {
|
||||
self.shader_module
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createshadermodule>
|
||||
pub fn create(
|
||||
device: &GPUDevice,
|
||||
descriptor: RootedTraceableBox<GPUShaderModuleDescriptor>,
|
||||
comp: InRealm,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<GPUShaderModule> {
|
||||
let program_id = device.global().wgpu_id_hub().create_shader_module_id();
|
||||
let promise = Promise::new_in_current_realm(comp, can_gc);
|
||||
let shader_module = GPUShaderModule::new(
|
||||
&device.global(),
|
||||
device.channel().clone(),
|
||||
WebGPUShaderModule(program_id),
|
||||
descriptor.parent.label.clone(),
|
||||
promise.clone(),
|
||||
);
|
||||
let sender = response_async(&promise, &*shader_module);
|
||||
device
|
||||
.channel()
|
||||
.0
|
||||
.send(WebGPURequest::CreateShaderModule {
|
||||
device_id: device.id().0,
|
||||
program_id,
|
||||
program: descriptor.code.0.clone(),
|
||||
label: None,
|
||||
sender,
|
||||
})
|
||||
.expect("Failed to create WebGPU ShaderModule");
|
||||
shader_module
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUShaderModuleMethods<crate::DomTypeHolder> for GPUShaderModule {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpushadermodule-getcompilationinfo>
|
||||
fn GetCompilationInfo(&self) -> Rc<Promise> {
|
||||
self.compilation_info_promise.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncWGPUListener for GPUShaderModule {
|
||||
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>, can_gc: CanGc) {
|
||||
match response {
|
||||
WebGPUResponse::CompilationInfo(info) => {
|
||||
let info = GPUCompilationInfo::from(&self.global(), info, can_gc);
|
||||
promise.resolve_native(&info);
|
||||
},
|
||||
_ => unreachable!("Wrong response received on AsyncWGPUListener for GPUShaderModule"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPUShaderModule {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DropShaderModule(self.shader_module.0))
|
||||
{
|
||||
warn!(
|
||||
"Failed to send DropShaderModule ({:?}) ({})",
|
||||
self.shader_module.0, e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
12
components/script/dom/webgpu/gpushaderstage.rs
Normal file
12
components/script/dom/webgpu/gpushaderstage.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::reflector::Reflector;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUShaderStage {
|
||||
reflector_: Reflector,
|
||||
}
|
177
components/script/dom/webgpu/gpusupportedfeatures.rs
Normal file
177
components/script/dom/webgpu/gpusupportedfeatures.rs
Normal file
|
@ -0,0 +1,177 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// check-tidy: no specs after this line
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use indexmap::IndexSet;
|
||||
use js::rust::HandleObject;
|
||||
use webgpu::wgt::Features;
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUFeatureName, GPUSupportedFeaturesMethods,
|
||||
};
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::like::Setlike;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUSupportedFeatures {
|
||||
reflector: Reflector,
|
||||
// internal storage for features
|
||||
#[custom_trace]
|
||||
internal: DomRefCell<IndexSet<GPUFeatureName>>,
|
||||
#[ignore_malloc_size_of = "defined in wgpu-types"]
|
||||
#[no_trace]
|
||||
features: Features,
|
||||
}
|
||||
|
||||
impl GPUSupportedFeatures {
|
||||
fn new(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
features: Features,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<GPUSupportedFeatures> {
|
||||
let mut set = IndexSet::new();
|
||||
if features.contains(Features::DEPTH_CLIP_CONTROL) {
|
||||
set.insert(GPUFeatureName::Depth_clip_control);
|
||||
}
|
||||
if features.contains(Features::DEPTH32FLOAT_STENCIL8) {
|
||||
set.insert(GPUFeatureName::Depth32float_stencil8);
|
||||
}
|
||||
if features.contains(Features::TEXTURE_COMPRESSION_BC) {
|
||||
set.insert(GPUFeatureName::Texture_compression_bc);
|
||||
}
|
||||
// TODO: texture-compression-bc-sliced-3d when wgpu supports it
|
||||
if features.contains(Features::TEXTURE_COMPRESSION_ETC2) {
|
||||
set.insert(GPUFeatureName::Texture_compression_etc2);
|
||||
}
|
||||
if features.contains(Features::TEXTURE_COMPRESSION_ASTC) {
|
||||
set.insert(GPUFeatureName::Texture_compression_astc);
|
||||
}
|
||||
if features.contains(Features::TIMESTAMP_QUERY) {
|
||||
set.insert(GPUFeatureName::Timestamp_query);
|
||||
}
|
||||
if features.contains(Features::INDIRECT_FIRST_INSTANCE) {
|
||||
set.insert(GPUFeatureName::Indirect_first_instance);
|
||||
}
|
||||
// While this feature exists in wgpu, it's not supported by naga yet
|
||||
// https://github.com/gfx-rs/wgpu/issues/4384
|
||||
/*
|
||||
if features.contains(Features::SHADER_F16) {
|
||||
set.insert(GPUFeatureName::Shader_f16);
|
||||
}
|
||||
*/
|
||||
if features.contains(Features::RG11B10UFLOAT_RENDERABLE) {
|
||||
set.insert(GPUFeatureName::Rg11b10ufloat_renderable);
|
||||
}
|
||||
if features.contains(Features::BGRA8UNORM_STORAGE) {
|
||||
set.insert(GPUFeatureName::Bgra8unorm_storage);
|
||||
}
|
||||
if features.contains(Features::FLOAT32_FILTERABLE) {
|
||||
set.insert(GPUFeatureName::Float32_filterable);
|
||||
}
|
||||
// TODO: clip-distances when wgpu supports it
|
||||
if features.contains(Features::DUAL_SOURCE_BLENDING) {
|
||||
set.insert(GPUFeatureName::Dual_source_blending);
|
||||
}
|
||||
|
||||
reflect_dom_object_with_proto(
|
||||
Box::new(GPUSupportedFeatures {
|
||||
reflector: Reflector::new(),
|
||||
internal: DomRefCell::new(set),
|
||||
features,
|
||||
}),
|
||||
global,
|
||||
proto,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Constructor(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
features: Features,
|
||||
can_gc: CanGc,
|
||||
) -> Fallible<DomRoot<GPUSupportedFeatures>> {
|
||||
Ok(GPUSupportedFeatures::new(global, proto, features, can_gc))
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUSupportedFeatures {
|
||||
pub fn wgpu_features(&self) -> Features {
|
||||
self.features
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUSupportedFeaturesMethods<crate::DomTypeHolder> for GPUSupportedFeatures {
|
||||
fn Size(&self) -> u32 {
|
||||
self.internal.size()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gpu_to_wgt_feature(feature: GPUFeatureName) -> Option<Features> {
|
||||
match feature {
|
||||
GPUFeatureName::Depth_clip_control => Some(Features::DEPTH_CLIP_CONTROL),
|
||||
GPUFeatureName::Depth32float_stencil8 => Some(Features::DEPTH32FLOAT_STENCIL8),
|
||||
GPUFeatureName::Texture_compression_bc => Some(Features::TEXTURE_COMPRESSION_BC),
|
||||
GPUFeatureName::Texture_compression_etc2 => Some(Features::TEXTURE_COMPRESSION_ETC2),
|
||||
GPUFeatureName::Texture_compression_astc => Some(Features::TEXTURE_COMPRESSION_ASTC),
|
||||
GPUFeatureName::Timestamp_query => Some(Features::TIMESTAMP_QUERY),
|
||||
GPUFeatureName::Indirect_first_instance => Some(Features::INDIRECT_FIRST_INSTANCE),
|
||||
// While this feature exists in wgpu, it's not supported by naga yet
|
||||
// https://github.com/gfx-rs/wgpu/issues/4384
|
||||
GPUFeatureName::Shader_f16 => None,
|
||||
GPUFeatureName::Rg11b10ufloat_renderable => Some(Features::RG11B10UFLOAT_RENDERABLE),
|
||||
GPUFeatureName::Bgra8unorm_storage => Some(Features::BGRA8UNORM_STORAGE),
|
||||
GPUFeatureName::Float32_filterable => Some(Features::FLOAT32_FILTERABLE),
|
||||
GPUFeatureName::Dual_source_blending => Some(Features::DUAL_SOURCE_BLENDING),
|
||||
GPUFeatureName::Texture_compression_bc_sliced_3d => None,
|
||||
GPUFeatureName::Clip_distances => None,
|
||||
}
|
||||
}
|
||||
|
||||
// this error is wrong because if we inline Self::Key and Self::Value all errors are gone
|
||||
#[allow(crown::unrooted_must_root)]
|
||||
impl Setlike for GPUSupportedFeatures {
|
||||
type Key = DOMString;
|
||||
|
||||
#[inline(always)]
|
||||
fn get_index(&self, index: u32) -> Option<Self::Key> {
|
||||
self.internal
|
||||
.get_index(index)
|
||||
.map(|k| DOMString::from_string(k.as_str().to_owned()))
|
||||
}
|
||||
#[inline(always)]
|
||||
fn size(&self) -> u32 {
|
||||
self.internal.size()
|
||||
}
|
||||
#[inline(always)]
|
||||
fn add(&self, _key: Self::Key) {
|
||||
unreachable!("readonly");
|
||||
}
|
||||
#[inline(always)]
|
||||
fn has(&self, key: Self::Key) -> bool {
|
||||
if let Ok(key) = key.parse() {
|
||||
self.internal.has(key)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn clear(&self) {
|
||||
unreachable!("readonly");
|
||||
}
|
||||
#[inline(always)]
|
||||
fn delete(&self, _key: Self::Key) -> bool {
|
||||
unreachable!("readonly");
|
||||
}
|
||||
}
|
316
components/script/dom/webgpu/gpusupportedlimits.rs
Normal file
316
components/script/dom/webgpu/gpusupportedlimits.rs
Normal file
|
@ -0,0 +1,316 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use num_traits::bounds::UpperBounded;
|
||||
use webgpu::wgt::Limits;
|
||||
use GPUSupportedLimits_Binding::GPUSupportedLimitsMethods;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUSupportedLimits_Binding;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUSupportedLimits {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "defined in wgpu-types"]
|
||||
#[no_trace]
|
||||
limits: Limits,
|
||||
}
|
||||
|
||||
impl GPUSupportedLimits {
|
||||
fn new_inherited(limits: Limits) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
limits,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope, limits: Limits) -> DomRoot<Self> {
|
||||
reflect_dom_object(Box::new(Self::new_inherited(limits)), global)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUSupportedLimitsMethods<crate::DomTypeHolder> for GPUSupportedLimits {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxtexturedimension1d>
|
||||
fn MaxTextureDimension1D(&self) -> u32 {
|
||||
self.limits.max_texture_dimension_1d
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxtexturedimension2d>
|
||||
fn MaxTextureDimension2D(&self) -> u32 {
|
||||
self.limits.max_texture_dimension_2d
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxtexturedimension3d>
|
||||
fn MaxTextureDimension3D(&self) -> u32 {
|
||||
self.limits.max_texture_dimension_3d
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxtexturearraylayers>
|
||||
fn MaxTextureArrayLayers(&self) -> u32 {
|
||||
self.limits.max_texture_array_layers
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxbindgroups>
|
||||
fn MaxBindGroups(&self) -> u32 {
|
||||
self.limits.max_bind_groups
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxbindingsperbindgroup>
|
||||
fn MaxBindingsPerBindGroup(&self) -> u32 {
|
||||
self.limits.max_bindings_per_bind_group
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxdynamicuniformbuffersperpipelinelayout>
|
||||
fn MaxDynamicUniformBuffersPerPipelineLayout(&self) -> u32 {
|
||||
self.limits.max_dynamic_uniform_buffers_per_pipeline_layout
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxdynamicstoragebuffersperpipelinelayout>
|
||||
fn MaxDynamicStorageBuffersPerPipelineLayout(&self) -> u32 {
|
||||
self.limits.max_dynamic_storage_buffers_per_pipeline_layout
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxsampledtexturespershaderstage>
|
||||
fn MaxSampledTexturesPerShaderStage(&self) -> u32 {
|
||||
self.limits.max_sampled_textures_per_shader_stage
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxsamplerspershaderstage>
|
||||
fn MaxSamplersPerShaderStage(&self) -> u32 {
|
||||
self.limits.max_samplers_per_shader_stage
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxstoragebufferspershaderstage>
|
||||
fn MaxStorageBuffersPerShaderStage(&self) -> u32 {
|
||||
self.limits.max_storage_buffers_per_shader_stage
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxstoragetexturespershaderstage>
|
||||
fn MaxStorageTexturesPerShaderStage(&self) -> u32 {
|
||||
self.limits.max_storage_textures_per_shader_stage
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxuniformbufferspershaderstage>
|
||||
fn MaxUniformBuffersPerShaderStage(&self) -> u32 {
|
||||
self.limits.max_uniform_buffers_per_shader_stage
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxuniformbufferbindingsize>
|
||||
fn MaxUniformBufferBindingSize(&self) -> u64 {
|
||||
self.limits.max_uniform_buffer_binding_size as u64
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxstoragebufferbindingsize>
|
||||
fn MaxStorageBufferBindingSize(&self) -> u64 {
|
||||
self.limits.max_storage_buffer_binding_size as u64
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-minuniformbufferoffsetalignment>
|
||||
fn MinUniformBufferOffsetAlignment(&self) -> u32 {
|
||||
self.limits.min_uniform_buffer_offset_alignment
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-minstoragebufferoffsetalignment>
|
||||
fn MinStorageBufferOffsetAlignment(&self) -> u32 {
|
||||
self.limits.min_storage_buffer_offset_alignment
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxvertexbuffers>
|
||||
fn MaxVertexBuffers(&self) -> u32 {
|
||||
self.limits.max_vertex_buffers
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxbuffersize>
|
||||
fn MaxBufferSize(&self) -> u64 {
|
||||
self.limits.max_buffer_size
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxvertexattributes>
|
||||
fn MaxVertexAttributes(&self) -> u32 {
|
||||
self.limits.max_vertex_attributes
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxvertexbufferarraystride>
|
||||
fn MaxVertexBufferArrayStride(&self) -> u32 {
|
||||
self.limits.max_vertex_buffer_array_stride
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxinterstageshadercomponents>
|
||||
fn MaxInterStageShaderComponents(&self) -> u32 {
|
||||
self.limits.max_inter_stage_shader_components
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcomputeworkgroupstoragesize>
|
||||
fn MaxComputeWorkgroupStorageSize(&self) -> u32 {
|
||||
self.limits.max_compute_workgroup_storage_size
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcomputeinvocationsperworkgroup>
|
||||
fn MaxComputeInvocationsPerWorkgroup(&self) -> u32 {
|
||||
self.limits.max_compute_invocations_per_workgroup
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcomputeworkgroupsizex>
|
||||
fn MaxComputeWorkgroupSizeX(&self) -> u32 {
|
||||
self.limits.max_compute_workgroup_size_x
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcomputeworkgroupsizey>
|
||||
fn MaxComputeWorkgroupSizeY(&self) -> u32 {
|
||||
self.limits.max_compute_workgroup_size_y
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcomputeworkgroupsizez>
|
||||
fn MaxComputeWorkgroupSizeZ(&self) -> u32 {
|
||||
self.limits.max_compute_workgroup_size_z
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcomputeworkgroupsperdimension>
|
||||
fn MaxComputeWorkgroupsPerDimension(&self) -> u32 {
|
||||
self.limits.max_compute_workgroups_per_dimension
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxbindgroupsplusvertexbuffers>
|
||||
fn MaxBindGroupsPlusVertexBuffers(&self) -> u32 {
|
||||
// Not on wgpu yet, so we craft it manually
|
||||
self.limits.max_bind_groups + self.limits.max_vertex_buffers
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxinterstageshadervariables>
|
||||
fn MaxInterStageShaderVariables(&self) -> u32 {
|
||||
// Not in wgpu yet, so we use default value from spec
|
||||
16
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcolorattachments>
|
||||
fn MaxColorAttachments(&self) -> u32 {
|
||||
self.limits.max_color_attachments
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcolorattachmentbytespersample>
|
||||
fn MaxColorAttachmentBytesPerSample(&self) -> u32 {
|
||||
self.limits.max_color_attachment_bytes_per_sample
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns false if unknown limit or other value error
|
||||
pub fn set_limit(limits: &mut Limits, limit: &str, value: u64) -> bool {
|
||||
/// per spec defaults are lower bounds for values
|
||||
///
|
||||
/// <https://www.w3.org/TR/webgpu/#limit-class-maximum>
|
||||
fn set_maximum<T>(limit: &mut T, value: u64) -> bool
|
||||
where
|
||||
T: Ord + Copy + TryFrom<u64> + UpperBounded,
|
||||
{
|
||||
if let Ok(value) = T::try_from(value) {
|
||||
*limit = value.max(*limit);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// per spec defaults are higher bounds for values
|
||||
///
|
||||
/// <https://www.w3.org/TR/webgpu/#limit-class-alignment>
|
||||
fn set_alignment<T>(limit: &mut T, value: u64) -> bool
|
||||
where
|
||||
T: Ord + Copy + TryFrom<u64> + UpperBounded,
|
||||
{
|
||||
if !value.is_power_of_two() {
|
||||
return false;
|
||||
}
|
||||
if let Ok(value) = T::try_from(value) {
|
||||
*limit = value.min(*limit);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
match limit {
|
||||
"maxTextureDimension1D" => set_maximum(&mut limits.max_texture_dimension_1d, value),
|
||||
"maxTextureDimension2D" => set_maximum(&mut limits.max_texture_dimension_2d, value),
|
||||
"maxTextureDimension3D" => set_maximum(&mut limits.max_texture_dimension_3d, value),
|
||||
"maxTextureArrayLayers" => set_maximum(&mut limits.max_texture_array_layers, value),
|
||||
"maxBindGroups" => set_maximum(&mut limits.max_bind_groups, value),
|
||||
"maxBindGroupsPlusVertexBuffers" => {
|
||||
// not in wgpu but we're allowed to give back better limits than requested.
|
||||
// we use dummy value to still produce value verification
|
||||
let mut v: u32 = 0;
|
||||
set_maximum(&mut v, value)
|
||||
},
|
||||
"maxBindingsPerBindGroup" => set_maximum(&mut limits.max_bindings_per_bind_group, value),
|
||||
"maxDynamicUniformBuffersPerPipelineLayout" => set_maximum(
|
||||
&mut limits.max_dynamic_uniform_buffers_per_pipeline_layout,
|
||||
value,
|
||||
),
|
||||
"maxDynamicStorageBuffersPerPipelineLayout" => set_maximum(
|
||||
&mut limits.max_dynamic_storage_buffers_per_pipeline_layout,
|
||||
value,
|
||||
),
|
||||
"maxSampledTexturesPerShaderStage" => {
|
||||
set_maximum(&mut limits.max_sampled_textures_per_shader_stage, value)
|
||||
},
|
||||
"maxSamplersPerShaderStage" => {
|
||||
set_maximum(&mut limits.max_samplers_per_shader_stage, value)
|
||||
},
|
||||
"maxStorageBuffersPerShaderStage" => {
|
||||
set_maximum(&mut limits.max_storage_buffers_per_shader_stage, value)
|
||||
},
|
||||
"maxStorageTexturesPerShaderStage" => {
|
||||
set_maximum(&mut limits.max_storage_textures_per_shader_stage, value)
|
||||
},
|
||||
"maxUniformBuffersPerShaderStage" => {
|
||||
set_maximum(&mut limits.max_uniform_buffers_per_shader_stage, value)
|
||||
},
|
||||
"maxUniformBufferBindingSize" => {
|
||||
set_maximum(&mut limits.max_uniform_buffer_binding_size, value)
|
||||
},
|
||||
"maxStorageBufferBindingSize" => {
|
||||
set_maximum(&mut limits.max_storage_buffer_binding_size, value)
|
||||
},
|
||||
"minUniformBufferOffsetAlignment" => {
|
||||
set_alignment(&mut limits.min_uniform_buffer_offset_alignment, value)
|
||||
},
|
||||
"minStorageBufferOffsetAlignment" => {
|
||||
set_alignment(&mut limits.min_storage_buffer_offset_alignment, value)
|
||||
},
|
||||
"maxVertexBuffers" => set_maximum(&mut limits.max_vertex_buffers, value),
|
||||
"maxBufferSize" => set_maximum(&mut limits.max_buffer_size, value),
|
||||
"maxVertexAttributes" => set_maximum(&mut limits.max_vertex_attributes, value),
|
||||
"maxVertexBufferArrayStride" => {
|
||||
set_maximum(&mut limits.max_vertex_buffer_array_stride, value)
|
||||
},
|
||||
"maxInterStageShaderComponents" => {
|
||||
set_maximum(&mut limits.max_inter_stage_shader_components, value)
|
||||
},
|
||||
"maxInterStageShaderVariables" => {
|
||||
// not in wgpu but we're allowed to give back better limits than requested.
|
||||
// we use dummy value to still produce value verification
|
||||
let mut v: u32 = 0;
|
||||
set_maximum(&mut v, value)
|
||||
},
|
||||
"maxColorAttachments" => set_maximum(&mut limits.max_color_attachments, value),
|
||||
"maxColorAttachmentBytesPerSample" => {
|
||||
set_maximum(&mut limits.max_color_attachment_bytes_per_sample, value)
|
||||
},
|
||||
"maxComputeWorkgroupStorageSize" => {
|
||||
set_maximum(&mut limits.max_compute_workgroup_storage_size, value)
|
||||
},
|
||||
"maxComputeInvocationsPerWorkgroup" => {
|
||||
set_maximum(&mut limits.max_compute_invocations_per_workgroup, value)
|
||||
},
|
||||
"maxComputeWorkgroupSizeX" => set_maximum(&mut limits.max_compute_workgroup_size_x, value),
|
||||
"maxComputeWorkgroupSizeY" => set_maximum(&mut limits.max_compute_workgroup_size_y, value),
|
||||
"maxComputeWorkgroupSizeZ" => set_maximum(&mut limits.max_compute_workgroup_size_z, value),
|
||||
"maxComputeWorkgroupsPerDimension" => {
|
||||
set_maximum(&mut limits.max_compute_workgroups_per_dimension, value)
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
285
components/script/dom/webgpu/gputexture.rs
Normal file
285
components/script/dom/webgpu/gputexture.rs
Normal file
|
@ -0,0 +1,285 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::string::String;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use webgpu::wgc::resource;
|
||||
use webgpu::{wgt, WebGPU, WebGPURequest, WebGPUTexture, WebGPUTextureView};
|
||||
|
||||
use super::gpuconvert::convert_texture_descriptor;
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUTextureAspect, GPUTextureDescriptor, GPUTextureDimension, GPUTextureFormat,
|
||||
GPUTextureMethods, GPUTextureViewDescriptor,
|
||||
};
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpudevice::GPUDevice;
|
||||
use crate::dom::gputextureview::GPUTextureView;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUTexture {
|
||||
reflector_: Reflector,
|
||||
#[no_trace]
|
||||
texture: WebGPUTexture,
|
||||
label: DomRefCell<USVString>,
|
||||
device: Dom<GPUDevice>,
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
#[ignore_malloc_size_of = "defined in wgpu"]
|
||||
#[no_trace]
|
||||
texture_size: wgt::Extent3d,
|
||||
mip_level_count: u32,
|
||||
sample_count: u32,
|
||||
dimension: GPUTextureDimension,
|
||||
format: GPUTextureFormat,
|
||||
texture_usage: u32,
|
||||
}
|
||||
|
||||
impl GPUTexture {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn new_inherited(
|
||||
texture: WebGPUTexture,
|
||||
device: &GPUDevice,
|
||||
channel: WebGPU,
|
||||
texture_size: wgt::Extent3d,
|
||||
mip_level_count: u32,
|
||||
sample_count: u32,
|
||||
dimension: GPUTextureDimension,
|
||||
format: GPUTextureFormat,
|
||||
texture_usage: u32,
|
||||
label: USVString,
|
||||
) -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
texture,
|
||||
label: DomRefCell::new(label),
|
||||
device: Dom::from_ref(device),
|
||||
channel,
|
||||
texture_size,
|
||||
mip_level_count,
|
||||
sample_count,
|
||||
dimension,
|
||||
format,
|
||||
texture_usage,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
texture: WebGPUTexture,
|
||||
device: &GPUDevice,
|
||||
channel: WebGPU,
|
||||
texture_size: wgt::Extent3d,
|
||||
mip_level_count: u32,
|
||||
sample_count: u32,
|
||||
dimension: GPUTextureDimension,
|
||||
format: GPUTextureFormat,
|
||||
texture_usage: u32,
|
||||
label: USVString,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPUTexture::new_inherited(
|
||||
texture,
|
||||
device,
|
||||
channel,
|
||||
texture_size,
|
||||
mip_level_count,
|
||||
sample_count,
|
||||
dimension,
|
||||
format,
|
||||
texture_usage,
|
||||
label,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPUTexture {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DropTexture(self.texture.0))
|
||||
{
|
||||
warn!(
|
||||
"Failed to send WebGPURequest::DropTexture({:?}) ({})",
|
||||
self.texture.0, e
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUTexture {
|
||||
pub fn id(&self) -> WebGPUTexture {
|
||||
self.texture
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createtexture>
|
||||
pub fn create(
|
||||
device: &GPUDevice,
|
||||
descriptor: &GPUTextureDescriptor,
|
||||
) -> Fallible<DomRoot<GPUTexture>> {
|
||||
let (desc, size) = convert_texture_descriptor(descriptor, device)?;
|
||||
|
||||
let texture_id = device.global().wgpu_id_hub().create_texture_id();
|
||||
|
||||
device
|
||||
.channel()
|
||||
.0
|
||||
.send(WebGPURequest::CreateTexture {
|
||||
device_id: device.id().0,
|
||||
texture_id,
|
||||
descriptor: desc,
|
||||
})
|
||||
.expect("Failed to create WebGPU Texture");
|
||||
|
||||
let texture = WebGPUTexture(texture_id);
|
||||
|
||||
Ok(GPUTexture::new(
|
||||
&device.global(),
|
||||
texture,
|
||||
device,
|
||||
device.channel().clone(),
|
||||
size,
|
||||
descriptor.mipLevelCount,
|
||||
descriptor.sampleCount,
|
||||
descriptor.dimension,
|
||||
descriptor.format,
|
||||
descriptor.usage,
|
||||
descriptor.parent.label.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUTextureMethods<crate::DomTypeHolder> for GPUTexture {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gputexture-createview>
|
||||
fn CreateView(
|
||||
&self,
|
||||
descriptor: &GPUTextureViewDescriptor,
|
||||
) -> Fallible<DomRoot<GPUTextureView>> {
|
||||
let desc = if !matches!(descriptor.mipLevelCount, Some(0)) &&
|
||||
!matches!(descriptor.arrayLayerCount, Some(0))
|
||||
{
|
||||
Some(resource::TextureViewDescriptor {
|
||||
label: (&descriptor.parent).into(),
|
||||
format: descriptor
|
||||
.format
|
||||
.map(|f| self.device.validate_texture_format_required_features(&f))
|
||||
.transpose()?,
|
||||
dimension: descriptor.dimension.map(|dimension| dimension.into()),
|
||||
range: wgt::ImageSubresourceRange {
|
||||
aspect: match descriptor.aspect {
|
||||
GPUTextureAspect::All => wgt::TextureAspect::All,
|
||||
GPUTextureAspect::Stencil_only => wgt::TextureAspect::StencilOnly,
|
||||
GPUTextureAspect::Depth_only => wgt::TextureAspect::DepthOnly,
|
||||
},
|
||||
base_mip_level: descriptor.baseMipLevel,
|
||||
mip_level_count: descriptor.mipLevelCount,
|
||||
base_array_layer: descriptor.baseArrayLayer,
|
||||
array_layer_count: descriptor.arrayLayerCount,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
self.device
|
||||
.dispatch_error(webgpu::Error::Validation(String::from(
|
||||
"arrayLayerCount and mipLevelCount cannot be 0",
|
||||
)));
|
||||
None
|
||||
};
|
||||
|
||||
let texture_view_id = self.global().wgpu_id_hub().create_texture_view_id();
|
||||
|
||||
self.channel
|
||||
.0
|
||||
.send(WebGPURequest::CreateTextureView {
|
||||
texture_id: self.texture.0,
|
||||
texture_view_id,
|
||||
device_id: self.device.id().0,
|
||||
descriptor: desc,
|
||||
})
|
||||
.expect("Failed to create WebGPU texture view");
|
||||
|
||||
let texture_view = WebGPUTextureView(texture_view_id);
|
||||
|
||||
Ok(GPUTextureView::new(
|
||||
&self.global(),
|
||||
self.channel.clone(),
|
||||
texture_view,
|
||||
self,
|
||||
descriptor.parent.label.clone(),
|
||||
))
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gputexture-destroy>
|
||||
fn Destroy(&self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DestroyTexture(self.texture.0))
|
||||
{
|
||||
warn!(
|
||||
"Failed to send WebGPURequest::DestroyTexture({:?}) ({})",
|
||||
self.texture.0, e
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gputexture-width>
|
||||
fn Width(&self) -> u32 {
|
||||
self.texture_size.width
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gputexture-height>
|
||||
fn Height(&self) -> u32 {
|
||||
self.texture_size.height
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gputexture-depthorarraylayers>
|
||||
fn DepthOrArrayLayers(&self) -> u32 {
|
||||
self.texture_size.depth_or_array_layers
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gputexture-miplevelcount>
|
||||
fn MipLevelCount(&self) -> u32 {
|
||||
self.mip_level_count
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gputexture-samplecount>
|
||||
fn SampleCount(&self) -> u32 {
|
||||
self.sample_count
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gputexture-dimension>
|
||||
fn Dimension(&self) -> GPUTextureDimension {
|
||||
self.dimension
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gputexture-format>
|
||||
fn Format(&self) -> GPUTextureFormat {
|
||||
self.format
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gputexture-usage>
|
||||
fn Usage(&self) -> u32 {
|
||||
self.texture_usage
|
||||
}
|
||||
}
|
12
components/script/dom/webgpu/gputextureusage.rs
Normal file
12
components/script/dom/webgpu/gputextureusage.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::reflector::Reflector;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUTextureUsage {
|
||||
reflector_: Reflector,
|
||||
}
|
94
components/script/dom/webgpu/gputextureview.rs
Normal file
94
components/script/dom/webgpu/gputextureview.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use webgpu::{WebGPU, WebGPURequest, WebGPUTextureView};
|
||||
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUTextureViewMethods;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::USVString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gputexture::GPUTexture;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUTextureView {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "defined in webgpu"]
|
||||
#[no_trace]
|
||||
channel: WebGPU,
|
||||
label: DomRefCell<USVString>,
|
||||
#[no_trace]
|
||||
texture_view: WebGPUTextureView,
|
||||
texture: Dom<GPUTexture>,
|
||||
}
|
||||
|
||||
impl GPUTextureView {
|
||||
fn new_inherited(
|
||||
channel: WebGPU,
|
||||
texture_view: WebGPUTextureView,
|
||||
texture: &GPUTexture,
|
||||
label: USVString,
|
||||
) -> GPUTextureView {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
channel,
|
||||
texture: Dom::from_ref(texture),
|
||||
label: DomRefCell::new(label),
|
||||
texture_view,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
channel: WebGPU,
|
||||
texture_view: WebGPUTextureView,
|
||||
texture: &GPUTexture,
|
||||
label: USVString,
|
||||
) -> DomRoot<GPUTextureView> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPUTextureView::new_inherited(
|
||||
channel,
|
||||
texture_view,
|
||||
texture,
|
||||
label,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUTextureView {
|
||||
pub fn id(&self) -> WebGPUTextureView {
|
||||
self.texture_view
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUTextureViewMethods<crate::DomTypeHolder> for GPUTextureView {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.borrow().clone()
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
|
||||
fn SetLabel(&self, value: USVString) {
|
||||
*self.label.borrow_mut() = value;
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GPUTextureView {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self
|
||||
.channel
|
||||
.0
|
||||
.send(WebGPURequest::DropTextureView(self.texture_view.0))
|
||||
{
|
||||
warn!(
|
||||
"Failed to send DropTextureView ({:?}) ({})",
|
||||
self.texture_view.0, e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
92
components/script/dom/webgpu/gpuuncapturederrorevent.rs
Normal file
92
components/script/dom/webgpu/gpuuncapturederrorevent.rs
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
use servo_atoms::Atom;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||
GPUUncapturedErrorEventInit, GPUUncapturedErrorEventMethods,
|
||||
};
|
||||
use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::gpuerror::GPUError;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUUncapturedErrorEvent {
|
||||
event: Event,
|
||||
#[ignore_malloc_size_of = "Because it is non-owning"]
|
||||
gpu_error: Dom<GPUError>,
|
||||
}
|
||||
|
||||
impl GPUUncapturedErrorEvent {
|
||||
fn new_inherited(init: &GPUUncapturedErrorEventInit) -> Self {
|
||||
Self {
|
||||
gpu_error: Dom::from_ref(&init.error),
|
||||
event: Event::new_inherited(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
type_: DOMString,
|
||||
init: &GPUUncapturedErrorEventInit,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
Self::new_with_proto(global, None, type_, init, can_gc)
|
||||
}
|
||||
|
||||
fn new_with_proto(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
type_: DOMString,
|
||||
init: &GPUUncapturedErrorEventInit,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
let ev = reflect_dom_object_with_proto(
|
||||
Box::new(GPUUncapturedErrorEvent::new_inherited(init)),
|
||||
global,
|
||||
proto,
|
||||
can_gc,
|
||||
);
|
||||
ev.event.init_event(
|
||||
Atom::from(type_),
|
||||
init.parent.bubbles,
|
||||
init.parent.cancelable,
|
||||
);
|
||||
ev
|
||||
}
|
||||
|
||||
pub fn event(&self) -> &Event {
|
||||
&self.event
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUUncapturedErrorEventMethods<crate::DomTypeHolder> for GPUUncapturedErrorEvent {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuuncapturederrorevent-gpuuncapturederrorevent>
|
||||
fn Constructor(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
type_: DOMString,
|
||||
init: &GPUUncapturedErrorEventInit,
|
||||
) -> DomRoot<Self> {
|
||||
GPUUncapturedErrorEvent::new_with_proto(global, proto, type_, init, can_gc)
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuuncapturederrorevent-error>
|
||||
fn Error(&self) -> DomRoot<GPUError> {
|
||||
DomRoot::from_ref(&self.gpu_error)
|
||||
}
|
||||
|
||||
/// <https://dom.spec.whatwg.org/#dom-event-istrusted>
|
||||
fn IsTrusted(&self) -> bool {
|
||||
self.event.IsTrusted()
|
||||
}
|
||||
}
|
53
components/script/dom/webgpu/gpuvalidationerror.rs
Normal file
53
components/script/dom/webgpu/gpuvalidationerror.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUValidationError_Binding::GPUValidationErrorMethods;
|
||||
use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::types::GPUError;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUValidationError {
|
||||
gpu_error: GPUError,
|
||||
}
|
||||
|
||||
impl GPUValidationError {
|
||||
fn new_inherited(message: DOMString) -> Self {
|
||||
Self {
|
||||
gpu_error: GPUError::new_inherited(message),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_proto(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
message: DOMString,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object_with_proto(
|
||||
Box::new(Self::new_inherited(message)),
|
||||
global,
|
||||
proto,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GPUValidationErrorMethods<crate::DomTypeHolder> for GPUValidationError {
|
||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpuvalidationerror-gpuvalidationerror>
|
||||
fn Constructor(
|
||||
global: &GlobalScope,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
message: DOMString,
|
||||
) -> DomRoot<Self> {
|
||||
Self::new_with_proto(global, proto, message, can_gc)
|
||||
}
|
||||
}
|
44
components/script/dom/webgpu/mod.rs
Normal file
44
components/script/dom/webgpu/mod.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
pub mod gpu;
|
||||
pub mod gpuadapter;
|
||||
pub mod gpuadapterinfo;
|
||||
pub mod gpubindgroup;
|
||||
pub mod gpubindgrouplayout;
|
||||
pub mod gpubuffer;
|
||||
pub mod gpubufferusage;
|
||||
pub mod gpucanvascontext;
|
||||
pub mod gpucolorwrite;
|
||||
pub mod gpucommandbuffer;
|
||||
pub mod gpucommandencoder;
|
||||
pub mod gpucompilationinfo;
|
||||
pub mod gpucompilationmessage;
|
||||
pub mod gpucomputepassencoder;
|
||||
pub mod gpucomputepipeline;
|
||||
pub mod gpuconvert;
|
||||
pub mod gpudevice;
|
||||
pub mod gpudevicelostinfo;
|
||||
pub mod gpuerror;
|
||||
pub mod gpuinternalerror;
|
||||
pub mod gpumapmode;
|
||||
pub mod gpuoutofmemoryerror;
|
||||
pub mod gpupipelineerror;
|
||||
pub mod gpupipelinelayout;
|
||||
pub mod gpuqueryset;
|
||||
pub mod gpuqueue;
|
||||
pub mod gpurenderbundle;
|
||||
pub mod gpurenderbundleencoder;
|
||||
pub mod gpurenderpassencoder;
|
||||
pub mod gpurenderpipeline;
|
||||
pub mod gpusampler;
|
||||
pub mod gpushadermodule;
|
||||
pub mod gpushaderstage;
|
||||
pub mod gpusupportedfeatures;
|
||||
pub mod gpusupportedlimits;
|
||||
pub mod gputexture;
|
||||
pub mod gputextureusage;
|
||||
pub mod gputextureview;
|
||||
pub mod gpuuncapturederrorevent;
|
||||
pub mod gpuvalidationerror;
|
Loading…
Add table
Add a link
Reference in a new issue