mirror of
https://github.com/servo/servo.git
synced 2025-07-29 10:10:34 +01:00
Auto merge of #27536 - kunalmohan:update-wgpu, r=kvark
Major fixes in error reporting in GPUCommandEncoder and ErrorScope Model <!-- Please describe your changes on the following line: --> 1. Update wgpu to use the error model on wgpu-core side. Register error Ids separately. 2. ~~Record errors only in `GPUCommandEncoder.finish()`. Errors are no longer recorded in ErrorScopes in transfer commands or while recording passes. Any errors that occur are stored on the server-side in `error_command_encoders: HashMap<id::CommandEncoderId, String>` and reported on `CommandEncoderFinish`. Note: This should be reverted when the spec gets updated.~~ 3. Correct a major flaw in ErrorScope Model. If multiple operations are issued inside scope and an early operation fails, the promise resolves and script execution continues. The scope, however, was not popped until the results of all its operations were received. This meant that if the user issues another operation, it was assumed to be issued in an error scope that has already been popped by the user, which led to the failure of a number of tests. This is solved by storing a `popped` boolean to check whether `popErrorScope()` has been called on a scope or not. Operation is now issued in the lastest scope for which `popped == false`. One of the tests used to crash, but it no longer does (All subtests under it fail now). That explains the large number of failing test expectations that have been added. Most of them fail due to the tests being outdated. I'll switch to the updated branch in the next PR. r?@kvark --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors <!-- Either: --> - [X] There are tests for these changes <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
commit
53467b80b9
8 changed files with 1200 additions and 508 deletions
|
@ -125,14 +125,32 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
|
|||
&self,
|
||||
descriptor: &GPUComputePassDescriptor,
|
||||
) -> DomRoot<GPUComputePassEncoder> {
|
||||
let scope_id = self.device.use_current_scope();
|
||||
self.set_state(
|
||||
GPUCommandEncoderState::EncodingComputePass,
|
||||
GPUCommandEncoderState::Open,
|
||||
);
|
||||
let (compute_pass, res) = if !self.valid.get() {
|
||||
(
|
||||
None,
|
||||
WebGPUOpResult::ValidationError(String::from(
|
||||
"CommandEncoder is not in Open State",
|
||||
)),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
Some(wgpu_com::ComputePass::new(self.encoder.0)),
|
||||
WebGPUOpResult::Success,
|
||||
)
|
||||
};
|
||||
|
||||
self.device.handle_server_msg(scope_id, res);
|
||||
|
||||
GPUComputePassEncoder::new(
|
||||
&self.global(),
|
||||
self.channel.clone(),
|
||||
&self,
|
||||
compute_pass,
|
||||
descriptor.parent.label.as_ref().cloned(),
|
||||
)
|
||||
}
|
||||
|
@ -142,102 +160,118 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
|
|||
&self,
|
||||
descriptor: &GPURenderPassDescriptor,
|
||||
) -> DomRoot<GPURenderPassEncoder> {
|
||||
let scope_id = self.device.use_current_scope();
|
||||
self.set_state(
|
||||
GPUCommandEncoderState::EncodingRenderPass,
|
||||
GPUCommandEncoderState::Open,
|
||||
);
|
||||
|
||||
let depth_stencil = descriptor.depthStencilAttachment.as_ref().map(|depth| {
|
||||
let (depth_load_op, clear_depth) = match depth.depthLoadValue {
|
||||
GPULoadOpOrFloat::GPULoadOp(_) => (wgpu_com::LoadOp::Load, 0.0f32),
|
||||
GPULoadOpOrFloat::Float(f) => (wgpu_com::LoadOp::Clear, *f),
|
||||
};
|
||||
let (stencil_load_op, clear_stencil) = match depth.stencilLoadValue {
|
||||
GPUStencilLoadValue::GPULoadOp(_) => (wgpu_com::LoadOp::Load, 0u32),
|
||||
GPUStencilLoadValue::RangeEnforcedUnsignedLong(l) => (wgpu_com::LoadOp::Clear, l),
|
||||
};
|
||||
let depth_channel = wgpu_com::PassChannel {
|
||||
load_op: depth_load_op,
|
||||
store_op: match depth.depthStoreOp {
|
||||
GPUStoreOp::Store => wgpu_com::StoreOp::Store,
|
||||
GPUStoreOp::Clear => wgpu_com::StoreOp::Clear,
|
||||
},
|
||||
clear_value: clear_depth,
|
||||
read_only: depth.depthReadOnly,
|
||||
};
|
||||
let stencil_channel = wgpu_com::PassChannel {
|
||||
load_op: stencil_load_op,
|
||||
store_op: match depth.stencilStoreOp {
|
||||
GPUStoreOp::Store => wgpu_com::StoreOp::Store,
|
||||
GPUStoreOp::Clear => wgpu_com::StoreOp::Clear,
|
||||
},
|
||||
clear_value: clear_stencil,
|
||||
read_only: depth.stencilReadOnly,
|
||||
};
|
||||
wgpu_com::DepthStencilAttachmentDescriptor {
|
||||
attachment: depth.attachment.id().0,
|
||||
depth: depth_channel,
|
||||
stencil: stencil_channel,
|
||||
}
|
||||
});
|
||||
let (render_pass, res) = if !self.valid.get() {
|
||||
(
|
||||
None,
|
||||
WebGPUOpResult::ValidationError(String::from(
|
||||
"CommandEncoder is not in Open State",
|
||||
)),
|
||||
)
|
||||
} else {
|
||||
let depth_stencil = descriptor.depthStencilAttachment.as_ref().map(|depth| {
|
||||
let (depth_load_op, clear_depth) = match depth.depthLoadValue {
|
||||
GPULoadOpOrFloat::GPULoadOp(_) => (wgpu_com::LoadOp::Load, 0.0f32),
|
||||
GPULoadOpOrFloat::Float(f) => (wgpu_com::LoadOp::Clear, *f),
|
||||
};
|
||||
let (stencil_load_op, clear_stencil) = match depth.stencilLoadValue {
|
||||
GPUStencilLoadValue::GPULoadOp(_) => (wgpu_com::LoadOp::Load, 0u32),
|
||||
GPUStencilLoadValue::RangeEnforcedUnsignedLong(l) => {
|
||||
(wgpu_com::LoadOp::Clear, l)
|
||||
},
|
||||
};
|
||||
let depth_channel = wgpu_com::PassChannel {
|
||||
load_op: depth_load_op,
|
||||
store_op: match depth.depthStoreOp {
|
||||
GPUStoreOp::Store => wgpu_com::StoreOp::Store,
|
||||
GPUStoreOp::Clear => wgpu_com::StoreOp::Clear,
|
||||
},
|
||||
clear_value: clear_depth,
|
||||
read_only: depth.depthReadOnly,
|
||||
};
|
||||
let stencil_channel = wgpu_com::PassChannel {
|
||||
load_op: stencil_load_op,
|
||||
store_op: match depth.stencilStoreOp {
|
||||
GPUStoreOp::Store => wgpu_com::StoreOp::Store,
|
||||
GPUStoreOp::Clear => wgpu_com::StoreOp::Clear,
|
||||
},
|
||||
clear_value: clear_stencil,
|
||||
read_only: depth.stencilReadOnly,
|
||||
};
|
||||
wgpu_com::DepthStencilAttachmentDescriptor {
|
||||
attachment: depth.attachment.id().0,
|
||||
depth: depth_channel,
|
||||
stencil: stencil_channel,
|
||||
}
|
||||
});
|
||||
|
||||
let desc = wgpu_com::RenderPassDescriptor {
|
||||
color_attachments: Cow::Owned(
|
||||
descriptor
|
||||
.colorAttachments
|
||||
.iter()
|
||||
.map(|color| {
|
||||
let (load_op, clear_value) = match color.loadValue {
|
||||
GPUColorLoad::GPULoadOp(_) => {
|
||||
(wgpu_com::LoadOp::Load, wgt::Color::TRANSPARENT)
|
||||
},
|
||||
GPUColorLoad::DoubleSequence(ref s) => {
|
||||
let mut w = s.clone();
|
||||
if w.len() < 3 {
|
||||
w.resize(3, Finite::wrap(0.0f64));
|
||||
}
|
||||
w.resize(4, Finite::wrap(1.0f64));
|
||||
(
|
||||
let desc = wgpu_com::RenderPassDescriptor {
|
||||
color_attachments: Cow::Owned(
|
||||
descriptor
|
||||
.colorAttachments
|
||||
.iter()
|
||||
.map(|color| {
|
||||
let (load_op, clear_value) = match color.loadValue {
|
||||
GPUColorLoad::GPULoadOp(_) => {
|
||||
(wgpu_com::LoadOp::Load, wgt::Color::TRANSPARENT)
|
||||
},
|
||||
GPUColorLoad::DoubleSequence(ref s) => {
|
||||
let mut w = s.clone();
|
||||
if w.len() < 3 {
|
||||
w.resize(3, Finite::wrap(0.0f64));
|
||||
}
|
||||
w.resize(4, Finite::wrap(1.0f64));
|
||||
(
|
||||
wgpu_com::LoadOp::Clear,
|
||||
wgt::Color {
|
||||
r: *w[0],
|
||||
g: *w[1],
|
||||
b: *w[2],
|
||||
a: *w[3],
|
||||
},
|
||||
)
|
||||
},
|
||||
GPUColorLoad::GPUColorDict(ref d) => (
|
||||
wgpu_com::LoadOp::Clear,
|
||||
wgt::Color {
|
||||
r: *w[0],
|
||||
g: *w[1],
|
||||
b: *w[2],
|
||||
a: *w[3],
|
||||
r: *d.r,
|
||||
g: *d.g,
|
||||
b: *d.b,
|
||||
a: *d.a,
|
||||
},
|
||||
)
|
||||
},
|
||||
GPUColorLoad::GPUColorDict(ref d) => (
|
||||
wgpu_com::LoadOp::Clear,
|
||||
wgt::Color {
|
||||
r: *d.r,
|
||||
g: *d.g,
|
||||
b: *d.b,
|
||||
a: *d.a,
|
||||
),
|
||||
};
|
||||
let channel = wgpu_com::PassChannel {
|
||||
load_op,
|
||||
store_op: match color.storeOp {
|
||||
GPUStoreOp::Store => wgpu_com::StoreOp::Store,
|
||||
GPUStoreOp::Clear => wgpu_com::StoreOp::Clear,
|
||||
},
|
||||
),
|
||||
};
|
||||
let channel = wgpu_com::PassChannel {
|
||||
load_op,
|
||||
store_op: match color.storeOp {
|
||||
GPUStoreOp::Store => wgpu_com::StoreOp::Store,
|
||||
GPUStoreOp::Clear => wgpu_com::StoreOp::Clear,
|
||||
},
|
||||
clear_value,
|
||||
read_only: false,
|
||||
};
|
||||
wgpu_com::ColorAttachmentDescriptor {
|
||||
attachment: color.attachment.id().0,
|
||||
resolve_target: color.resolveTarget.as_ref().map(|t| t.id().0),
|
||||
channel,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
depth_stencil_attachment: depth_stencil.as_ref(),
|
||||
clear_value,
|
||||
read_only: false,
|
||||
};
|
||||
wgpu_com::ColorAttachmentDescriptor {
|
||||
attachment: color.attachment.id().0,
|
||||
resolve_target: color.resolveTarget.as_ref().map(|t| t.id().0),
|
||||
channel,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
depth_stencil_attachment: depth_stencil.as_ref(),
|
||||
};
|
||||
(
|
||||
Some(wgpu_com::RenderPass::new(self.encoder.0, desc)),
|
||||
WebGPUOpResult::Success,
|
||||
)
|
||||
};
|
||||
|
||||
let render_pass = wgpu_com::RenderPass::new(self.encoder.0, desc);
|
||||
self.device.handle_server_msg(scope_id, res);
|
||||
|
||||
GPURenderPassEncoder::new(
|
||||
&self.global(),
|
||||
|
@ -257,10 +291,9 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
|
|||
destination_offset: GPUSize64,
|
||||
size: GPUSize64,
|
||||
) {
|
||||
let valid = *self.state.borrow() == GPUCommandEncoderState::Open;
|
||||
let scope_id = self.device.use_current_scope();
|
||||
|
||||
if !valid {
|
||||
if !(*self.state.borrow() == GPUCommandEncoderState::Open) {
|
||||
self.device.handle_server_msg(
|
||||
scope_id,
|
||||
WebGPUOpResult::ValidationError(String::from(
|
||||
|
@ -299,10 +332,9 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
|
|||
destination: &GPUTextureCopyView,
|
||||
copy_size: GPUExtent3D,
|
||||
) {
|
||||
let valid = *self.state.borrow() == GPUCommandEncoderState::Open;
|
||||
let scope_id = self.device.use_current_scope();
|
||||
|
||||
if !valid {
|
||||
if !(*self.state.borrow() == GPUCommandEncoderState::Open) {
|
||||
self.device.handle_server_msg(
|
||||
scope_id,
|
||||
WebGPUOpResult::ValidationError(String::from(
|
||||
|
@ -341,10 +373,9 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
|
|||
destination: &GPUBufferCopyView,
|
||||
copy_size: GPUExtent3D,
|
||||
) {
|
||||
let valid = *self.state.borrow() == GPUCommandEncoderState::Open;
|
||||
let scope_id = self.device.use_current_scope();
|
||||
|
||||
if !valid {
|
||||
if !(*self.state.borrow() == GPUCommandEncoderState::Open) {
|
||||
self.device.handle_server_msg(
|
||||
scope_id,
|
||||
WebGPUOpResult::ValidationError(String::from(
|
||||
|
@ -383,10 +414,9 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
|
|||
destination: &GPUTextureCopyView,
|
||||
copy_size: GPUExtent3D,
|
||||
) {
|
||||
let valid = *self.state.borrow() == GPUCommandEncoderState::Open;
|
||||
let scope_id = self.device.use_current_scope();
|
||||
|
||||
if !valid {
|
||||
if !(*self.state.borrow() == GPUCommandEncoderState::Open) {
|
||||
self.device.handle_server_msg(
|
||||
scope_id,
|
||||
WebGPUOpResult::ValidationError(String::from(
|
||||
|
@ -423,6 +453,7 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
|
|||
WebGPURequest::CommandEncoderFinish {
|
||||
command_encoder_id: self.encoder.0,
|
||||
device_id: self.device.id().0,
|
||||
is_error: !self.valid.get(),
|
||||
// TODO(zakorgy): We should use `_descriptor` here after it's not empty
|
||||
// and the underlying wgpu-core struct is serializable
|
||||
},
|
||||
|
|
|
@ -33,13 +33,14 @@ impl GPUComputePassEncoder {
|
|||
fn new_inherited(
|
||||
channel: WebGPU,
|
||||
parent: &GPUCommandEncoder,
|
||||
compute_pass: Option<ComputePass>,
|
||||
label: Option<USVString>,
|
||||
) -> Self {
|
||||
Self {
|
||||
channel,
|
||||
reflector_: Reflector::new(),
|
||||
label: DomRefCell::new(label),
|
||||
compute_pass: DomRefCell::new(Some(ComputePass::new(parent.id().0))),
|
||||
compute_pass: DomRefCell::new(compute_pass),
|
||||
command_encoder: Dom::from_ref(parent),
|
||||
}
|
||||
}
|
||||
|
@ -48,10 +49,16 @@ impl GPUComputePassEncoder {
|
|||
global: &GlobalScope,
|
||||
channel: WebGPU,
|
||||
parent: &GPUCommandEncoder,
|
||||
compute_pass: Option<ComputePass>,
|
||||
label: Option<USVString>,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(GPUComputePassEncoder::new_inherited(channel, parent, label)),
|
||||
Box::new(GPUComputePassEncoder::new_inherited(
|
||||
channel,
|
||||
parent,
|
||||
compute_pass,
|
||||
label,
|
||||
)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
|
@ -88,24 +95,23 @@ impl GPUComputePassEncoderMethods for GPUComputePassEncoder {
|
|||
|
||||
/// https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-endpass
|
||||
fn EndPass(&self) {
|
||||
if let Some(compute_pass) = self.compute_pass.borrow_mut().take() {
|
||||
self.channel
|
||||
.0
|
||||
.send((
|
||||
self.command_encoder.device().use_current_scope(),
|
||||
WebGPURequest::RunComputePass {
|
||||
command_encoder_id: self.command_encoder.id().0,
|
||||
device_id: self.command_encoder.device().id().0,
|
||||
compute_pass,
|
||||
},
|
||||
))
|
||||
.expect("Failed to send RunComputePass");
|
||||
let compute_pass = self.compute_pass.borrow_mut().take();
|
||||
self.channel
|
||||
.0
|
||||
.send((
|
||||
self.command_encoder.device().use_current_scope(),
|
||||
WebGPURequest::RunComputePass {
|
||||
command_encoder_id: self.command_encoder.id().0,
|
||||
device_id: self.command_encoder.device().id().0,
|
||||
compute_pass,
|
||||
},
|
||||
))
|
||||
.expect("Failed to send RunComputePass");
|
||||
|
||||
self.command_encoder.set_state(
|
||||
GPUCommandEncoderState::Open,
|
||||
GPUCommandEncoderState::EncodingComputePass,
|
||||
);
|
||||
}
|
||||
self.command_encoder.set_state(
|
||||
GPUCommandEncoderState::Open,
|
||||
GPUCommandEncoderState::EncodingComputePass,
|
||||
);
|
||||
}
|
||||
|
||||
/// https://gpuweb.github.io/gpuweb/#dom-gpuprogrammablepassencoder-setbindgroup
|
||||
|
|
|
@ -64,7 +64,7 @@ use crate::script_runtime::JSContext as SafeJSContext;
|
|||
use dom_struct::dom_struct;
|
||||
use js::jsapi::{Heap, JSObject};
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::HashMap;
|
||||
use std::ptr::NonNull;
|
||||
use std::rc::Rc;
|
||||
|
@ -82,10 +82,17 @@ struct ErrorScopeInfo {
|
|||
promise: Option<Rc<Promise>>,
|
||||
}
|
||||
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
struct ErrorScopeMetadata {
|
||||
id: ErrorScopeId,
|
||||
filter: GPUErrorFilter,
|
||||
popped: Cell<bool>,
|
||||
}
|
||||
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
struct ScopeContext {
|
||||
error_scopes: HashMap<ErrorScopeId, ErrorScopeInfo>,
|
||||
scope_stack: Vec<(ErrorScopeId, GPUErrorFilter)>,
|
||||
scope_stack: Vec<ErrorScopeMetadata>,
|
||||
next_scope_id: ErrorScopeId,
|
||||
}
|
||||
|
||||
|
@ -189,8 +196,8 @@ impl GPUDevice {
|
|||
.scope_stack
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|&&(id, fil)| id <= s_id && fil == filter)
|
||||
.map(|(id, _)| *id);
|
||||
.find(|meta| meta.id <= s_id && meta.filter == filter)
|
||||
.map(|meta| meta.id);
|
||||
if let Some(s) = scop {
|
||||
self.handle_error(s, err);
|
||||
} else {
|
||||
|
@ -237,14 +244,19 @@ impl GPUDevice {
|
|||
};
|
||||
if remove {
|
||||
let _ = context.error_scopes.remove(&scope);
|
||||
context.scope_stack.retain(|(id, _)| *id != scope);
|
||||
context.scope_stack.retain(|meta| meta.id != scope);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn use_current_scope(&self) -> Option<ErrorScopeId> {
|
||||
let mut context = self.scope_context.borrow_mut();
|
||||
let scope_id = context.scope_stack.last().copied();
|
||||
scope_id.and_then(|(s_id, _)| {
|
||||
let scope_id = context
|
||||
.scope_stack
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|meta| !meta.popped.get())
|
||||
.map(|meta| meta.id);
|
||||
scope_id.and_then(|s_id| {
|
||||
context.error_scopes.get_mut(&s_id).map(|mut scope| {
|
||||
scope.op_count += 1;
|
||||
s_id
|
||||
|
@ -293,15 +305,12 @@ impl GPUDeviceMethods for GPUDevice {
|
|||
|
||||
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbuffer
|
||||
fn CreateBuffer(&self, descriptor: &GPUBufferDescriptor) -> DomRoot<GPUBuffer> {
|
||||
let wgpu_descriptor = wgt::BufferDescriptor {
|
||||
let desc = wgt::BufferUsage::from_bits(descriptor.usage).map(|usg| wgt::BufferDescriptor {
|
||||
label: descriptor.parent.label.as_ref().map(|s| s.to_string()),
|
||||
size: descriptor.size,
|
||||
usage: match wgt::BufferUsage::from_bits(descriptor.usage) {
|
||||
Some(u) => u,
|
||||
None => wgt::BufferUsage::empty(),
|
||||
},
|
||||
usage: usg,
|
||||
mapped_at_creation: descriptor.mappedAtCreation,
|
||||
};
|
||||
});
|
||||
let id = self
|
||||
.global()
|
||||
.wgpu_id_hub()
|
||||
|
@ -309,6 +318,13 @@ impl GPUDeviceMethods for GPUDevice {
|
|||
.create_buffer_id(self.device.0.backend());
|
||||
|
||||
let scope_id = self.use_current_scope();
|
||||
if desc.is_none() {
|
||||
self.handle_server_msg(
|
||||
scope_id,
|
||||
WebGPUOpResult::ValidationError(String::from("Invalid GPUBufferUsage")),
|
||||
);
|
||||
}
|
||||
|
||||
self.channel
|
||||
.0
|
||||
.send((
|
||||
|
@ -316,7 +332,7 @@ impl GPUDeviceMethods for GPUDevice {
|
|||
WebGPURequest::CreateBuffer {
|
||||
device_id: self.device.0,
|
||||
buffer_id: id,
|
||||
descriptor: wgpu_descriptor,
|
||||
descriptor: desc,
|
||||
},
|
||||
))
|
||||
.expect("Failed to create WebGPU buffer");
|
||||
|
@ -357,13 +373,17 @@ impl GPUDeviceMethods for GPUDevice {
|
|||
&self,
|
||||
descriptor: &GPUBindGroupLayoutDescriptor,
|
||||
) -> DomRoot<GPUBindGroupLayout> {
|
||||
let mut valid = true;
|
||||
let entries = descriptor
|
||||
.entries
|
||||
.iter()
|
||||
.map(|bind| {
|
||||
let visibility = match wgt::ShaderStage::from_bits(bind.visibility) {
|
||||
Some(visibility) => visibility,
|
||||
None => wgt::ShaderStage::from_bits(0).unwrap(),
|
||||
None => {
|
||||
valid = false;
|
||||
wgt::ShaderStage::empty()
|
||||
},
|
||||
};
|
||||
let ty = match bind.type_ {
|
||||
GPUBindingType::Uniform_buffer => wgt::BindingType::UniformBuffer {
|
||||
|
@ -435,13 +455,21 @@ impl GPUDeviceMethods for GPUDevice {
|
|||
|
||||
let scope_id = self.use_current_scope();
|
||||
|
||||
let desc = wgt::BindGroupLayoutDescriptor {
|
||||
label: descriptor
|
||||
.parent
|
||||
.label
|
||||
.as_ref()
|
||||
.map(|s| Cow::Owned(s.to_string())),
|
||||
entries: Cow::Owned(entries),
|
||||
let desc = if valid {
|
||||
Some(wgt::BindGroupLayoutDescriptor {
|
||||
label: descriptor
|
||||
.parent
|
||||
.label
|
||||
.as_ref()
|
||||
.map(|s| Cow::Owned(s.to_string())),
|
||||
entries: Cow::Owned(entries),
|
||||
})
|
||||
} else {
|
||||
self.handle_server_msg(
|
||||
scope_id,
|
||||
WebGPUOpResult::ValidationError(String::from("Invalid GPUShaderStage")),
|
||||
);
|
||||
None
|
||||
};
|
||||
|
||||
let bind_group_layout_id = self
|
||||
|
@ -695,22 +723,20 @@ impl GPUDeviceMethods for GPUDevice {
|
|||
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createtexture
|
||||
fn CreateTexture(&self, descriptor: &GPUTextureDescriptor) -> DomRoot<GPUTexture> {
|
||||
let size = convert_texture_size_to_dict(&descriptor.size);
|
||||
let desc = wgt::TextureDescriptor {
|
||||
label: descriptor.parent.label.as_ref().map(|s| s.to_string()),
|
||||
size: convert_texture_size_to_wgt(&size),
|
||||
mip_level_count: descriptor.mipLevelCount,
|
||||
sample_count: descriptor.sampleCount,
|
||||
dimension: match descriptor.dimension {
|
||||
GPUTextureDimension::_1d => wgt::TextureDimension::D1,
|
||||
GPUTextureDimension::_2d => wgt::TextureDimension::D2,
|
||||
GPUTextureDimension::_3d => wgt::TextureDimension::D3,
|
||||
},
|
||||
format: convert_texture_format(descriptor.format),
|
||||
usage: match wgt::TextureUsage::from_bits(descriptor.usage) {
|
||||
Some(t) => t,
|
||||
None => wgt::TextureUsage::empty(),
|
||||
},
|
||||
};
|
||||
let desc =
|
||||
wgt::TextureUsage::from_bits(descriptor.usage).map(|usg| wgt::TextureDescriptor {
|
||||
label: descriptor.parent.label.as_ref().map(|s| s.to_string()),
|
||||
size: convert_texture_size_to_wgt(&size),
|
||||
mip_level_count: descriptor.mipLevelCount,
|
||||
sample_count: descriptor.sampleCount,
|
||||
dimension: match descriptor.dimension {
|
||||
GPUTextureDimension::_1d => wgt::TextureDimension::D1,
|
||||
GPUTextureDimension::_2d => wgt::TextureDimension::D2,
|
||||
GPUTextureDimension::_3d => wgt::TextureDimension::D3,
|
||||
},
|
||||
format: convert_texture_format(descriptor.format),
|
||||
usage: usg,
|
||||
});
|
||||
|
||||
let texture_id = self
|
||||
.global()
|
||||
|
@ -719,7 +745,12 @@ impl GPUDeviceMethods for GPUDevice {
|
|||
.create_texture_id(self.device.0.backend());
|
||||
|
||||
let scope_id = self.use_current_scope();
|
||||
|
||||
if desc.is_none() {
|
||||
self.handle_server_msg(
|
||||
scope_id,
|
||||
WebGPUOpResult::ValidationError(String::from("Invalid GPUTextureUsage")),
|
||||
);
|
||||
}
|
||||
self.channel
|
||||
.0
|
||||
.send((
|
||||
|
@ -803,110 +834,124 @@ impl GPUDeviceMethods for GPUDevice {
|
|||
) -> DomRoot<GPURenderPipeline> {
|
||||
let ref rs_desc = descriptor.rasterizationState;
|
||||
let ref vs_desc = descriptor.vertexState;
|
||||
|
||||
let desc = wgpu_pipe::RenderPipelineDescriptor {
|
||||
layout: descriptor.parent.layout.id().0,
|
||||
vertex_stage: wgpu_pipe::ProgrammableStageDescriptor {
|
||||
module: descriptor.vertexStage.module.id().0,
|
||||
entry_point: Cow::Owned(descriptor.vertexStage.entryPoint.to_string()),
|
||||
},
|
||||
fragment_stage: descriptor.fragmentStage.as_ref().map(|stage| {
|
||||
wgpu_pipe::ProgrammableStageDescriptor {
|
||||
module: stage.module.id().0,
|
||||
entry_point: Cow::Owned(stage.entryPoint.to_string()),
|
||||
}
|
||||
}),
|
||||
rasterization_state: Some(wgt::RasterizationStateDescriptor {
|
||||
front_face: match rs_desc.frontFace {
|
||||
GPUFrontFace::Ccw => wgt::FrontFace::Ccw,
|
||||
GPUFrontFace::Cw => wgt::FrontFace::Cw,
|
||||
},
|
||||
cull_mode: match rs_desc.cullMode {
|
||||
GPUCullMode::None => wgt::CullMode::None,
|
||||
GPUCullMode::Front => wgt::CullMode::Front,
|
||||
GPUCullMode::Back => wgt::CullMode::Back,
|
||||
},
|
||||
clamp_depth: rs_desc.clampDepth,
|
||||
depth_bias: rs_desc.depthBias,
|
||||
depth_bias_slope_scale: *rs_desc.depthBiasSlopeScale,
|
||||
depth_bias_clamp: *rs_desc.depthBiasClamp,
|
||||
}),
|
||||
primitive_topology: match descriptor.primitiveTopology {
|
||||
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,
|
||||
},
|
||||
color_states: Cow::Owned(
|
||||
descriptor
|
||||
.colorStates
|
||||
.iter()
|
||||
.map(|state| wgt::ColorStateDescriptor {
|
||||
format: convert_texture_format(state.format),
|
||||
alpha_blend: convert_blend_descriptor(&state.alphaBlend),
|
||||
color_blend: convert_blend_descriptor(&state.colorBlend),
|
||||
write_mask: match wgt::ColorWrite::from_bits(state.writeMask) {
|
||||
Some(mask) => mask,
|
||||
None => wgt::ColorWrite::empty(),
|
||||
let scope_id = self.use_current_scope();
|
||||
let mut valid = true;
|
||||
let color_states = Cow::Owned(
|
||||
descriptor
|
||||
.colorStates
|
||||
.iter()
|
||||
.map(|state| wgt::ColorStateDescriptor {
|
||||
format: convert_texture_format(state.format),
|
||||
alpha_blend: convert_blend_descriptor(&state.alphaBlend),
|
||||
color_blend: convert_blend_descriptor(&state.colorBlend),
|
||||
write_mask: match wgt::ColorWrite::from_bits(state.writeMask) {
|
||||
Some(mask) => mask,
|
||||
None => {
|
||||
valid = false;
|
||||
wgt::ColorWrite::empty()
|
||||
},
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
depth_stencil_state: descriptor.depthStencilState.as_ref().map(|dss_desc| {
|
||||
wgt::DepthStencilStateDescriptor {
|
||||
format: convert_texture_format(dss_desc.format),
|
||||
depth_write_enabled: dss_desc.depthWriteEnabled,
|
||||
depth_compare: convert_compare_function(dss_desc.depthCompare),
|
||||
stencil_front: wgt::StencilStateFaceDescriptor {
|
||||
compare: convert_compare_function(dss_desc.stencilFront.compare),
|
||||
fail_op: convert_stencil_op(dss_desc.stencilFront.failOp),
|
||||
depth_fail_op: convert_stencil_op(dss_desc.stencilFront.depthFailOp),
|
||||
pass_op: convert_stencil_op(dss_desc.stencilFront.passOp),
|
||||
},
|
||||
stencil_back: wgt::StencilStateFaceDescriptor {
|
||||
compare: convert_compare_function(dss_desc.stencilBack.compare),
|
||||
fail_op: convert_stencil_op(dss_desc.stencilBack.failOp),
|
||||
depth_fail_op: convert_stencil_op(dss_desc.stencilBack.depthFailOp),
|
||||
pass_op: convert_stencil_op(dss_desc.stencilBack.passOp),
|
||||
},
|
||||
stencil_read_mask: dss_desc.stencilReadMask,
|
||||
stencil_write_mask: dss_desc.stencilWriteMask,
|
||||
}
|
||||
}),
|
||||
vertex_state: wgt::VertexStateDescriptor {
|
||||
index_format: match vs_desc.indexFormat {
|
||||
GPUIndexFormat::Uint16 => wgt::IndexFormat::Uint16,
|
||||
GPUIndexFormat::Uint32 => wgt::IndexFormat::Uint32,
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
let desc = if valid {
|
||||
Some(wgpu_pipe::RenderPipelineDescriptor {
|
||||
layout: descriptor.parent.layout.id().0,
|
||||
vertex_stage: wgpu_pipe::ProgrammableStageDescriptor {
|
||||
module: descriptor.vertexStage.module.id().0,
|
||||
entry_point: Cow::Owned(descriptor.vertexStage.entryPoint.to_string()),
|
||||
},
|
||||
vertex_buffers: Cow::Owned(
|
||||
vs_desc
|
||||
.vertexBuffers
|
||||
.iter()
|
||||
.map(|buffer| wgt::VertexBufferDescriptor {
|
||||
stride: buffer.arrayStride,
|
||||
step_mode: match buffer.stepMode {
|
||||
GPUInputStepMode::Vertex => wgt::InputStepMode::Vertex,
|
||||
GPUInputStepMode::Instance => wgt::InputStepMode::Instance,
|
||||
},
|
||||
attributes: Cow::Owned(
|
||||
buffer
|
||||
.attributes
|
||||
.iter()
|
||||
.map(|att| wgt::VertexAttributeDescriptor {
|
||||
format: convert_vertex_format(att.format),
|
||||
offset: att.offset,
|
||||
shader_location: att.shaderLocation,
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
},
|
||||
sample_count: descriptor.sampleCount,
|
||||
sample_mask: descriptor.sampleMask,
|
||||
alpha_to_coverage_enabled: descriptor.alphaToCoverageEnabled,
|
||||
fragment_stage: descriptor.fragmentStage.as_ref().map(|stage| {
|
||||
wgpu_pipe::ProgrammableStageDescriptor {
|
||||
module: stage.module.id().0,
|
||||
entry_point: Cow::Owned(stage.entryPoint.to_string()),
|
||||
}
|
||||
}),
|
||||
rasterization_state: Some(wgt::RasterizationStateDescriptor {
|
||||
front_face: match rs_desc.frontFace {
|
||||
GPUFrontFace::Ccw => wgt::FrontFace::Ccw,
|
||||
GPUFrontFace::Cw => wgt::FrontFace::Cw,
|
||||
},
|
||||
cull_mode: match rs_desc.cullMode {
|
||||
GPUCullMode::None => wgt::CullMode::None,
|
||||
GPUCullMode::Front => wgt::CullMode::Front,
|
||||
GPUCullMode::Back => wgt::CullMode::Back,
|
||||
},
|
||||
clamp_depth: rs_desc.clampDepth,
|
||||
depth_bias: rs_desc.depthBias,
|
||||
depth_bias_slope_scale: *rs_desc.depthBiasSlopeScale,
|
||||
depth_bias_clamp: *rs_desc.depthBiasClamp,
|
||||
}),
|
||||
primitive_topology: match descriptor.primitiveTopology {
|
||||
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,
|
||||
},
|
||||
color_states,
|
||||
depth_stencil_state: descriptor.depthStencilState.as_ref().map(|dss_desc| {
|
||||
wgt::DepthStencilStateDescriptor {
|
||||
format: convert_texture_format(dss_desc.format),
|
||||
depth_write_enabled: dss_desc.depthWriteEnabled,
|
||||
depth_compare: convert_compare_function(dss_desc.depthCompare),
|
||||
stencil_front: wgt::StencilStateFaceDescriptor {
|
||||
compare: convert_compare_function(dss_desc.stencilFront.compare),
|
||||
fail_op: convert_stencil_op(dss_desc.stencilFront.failOp),
|
||||
depth_fail_op: convert_stencil_op(dss_desc.stencilFront.depthFailOp),
|
||||
pass_op: convert_stencil_op(dss_desc.stencilFront.passOp),
|
||||
},
|
||||
stencil_back: wgt::StencilStateFaceDescriptor {
|
||||
compare: convert_compare_function(dss_desc.stencilBack.compare),
|
||||
fail_op: convert_stencil_op(dss_desc.stencilBack.failOp),
|
||||
depth_fail_op: convert_stencil_op(dss_desc.stencilBack.depthFailOp),
|
||||
pass_op: convert_stencil_op(dss_desc.stencilBack.passOp),
|
||||
},
|
||||
stencil_read_mask: dss_desc.stencilReadMask,
|
||||
stencil_write_mask: dss_desc.stencilWriteMask,
|
||||
}
|
||||
}),
|
||||
vertex_state: wgt::VertexStateDescriptor {
|
||||
index_format: match vs_desc.indexFormat {
|
||||
GPUIndexFormat::Uint16 => wgt::IndexFormat::Uint16,
|
||||
GPUIndexFormat::Uint32 => wgt::IndexFormat::Uint32,
|
||||
},
|
||||
vertex_buffers: Cow::Owned(
|
||||
vs_desc
|
||||
.vertexBuffers
|
||||
.iter()
|
||||
.map(|buffer| wgt::VertexBufferDescriptor {
|
||||
stride: buffer.arrayStride,
|
||||
step_mode: match buffer.stepMode {
|
||||
GPUInputStepMode::Vertex => wgt::InputStepMode::Vertex,
|
||||
GPUInputStepMode::Instance => wgt::InputStepMode::Instance,
|
||||
},
|
||||
attributes: Cow::Owned(
|
||||
buffer
|
||||
.attributes
|
||||
.iter()
|
||||
.map(|att| wgt::VertexAttributeDescriptor {
|
||||
format: convert_vertex_format(att.format),
|
||||
offset: att.offset,
|
||||
shader_location: att.shaderLocation,
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
},
|
||||
sample_count: descriptor.sampleCount,
|
||||
sample_mask: descriptor.sampleMask,
|
||||
alpha_to_coverage_enabled: descriptor.alphaToCoverageEnabled,
|
||||
})
|
||||
} else {
|
||||
self.handle_server_msg(
|
||||
scope_id,
|
||||
WebGPUOpResult::ValidationError(String::from("Invalid GPUColorWriteFlags")),
|
||||
);
|
||||
None
|
||||
};
|
||||
|
||||
let render_pipeline_id = self
|
||||
|
@ -915,8 +960,6 @@ impl GPUDeviceMethods for GPUDevice {
|
|||
.lock()
|
||||
.create_render_pipeline_id(self.device.0.backend());
|
||||
|
||||
let scope_id = self.use_current_scope();
|
||||
|
||||
self.channel
|
||||
.0
|
||||
.send((
|
||||
|
@ -986,7 +1029,11 @@ impl GPUDeviceMethods for GPUDevice {
|
|||
promise: None,
|
||||
};
|
||||
let res = context.error_scopes.insert(scope_id, err_scope);
|
||||
context.scope_stack.push((scope_id, filter));
|
||||
context.scope_stack.push(ErrorScopeMetadata {
|
||||
id: scope_id,
|
||||
filter,
|
||||
popped: Cell::new(false),
|
||||
});
|
||||
assert!(res.is_none());
|
||||
}
|
||||
|
||||
|
@ -994,12 +1041,14 @@ impl GPUDeviceMethods for GPUDevice {
|
|||
fn PopErrorScope(&self, comp: InRealm) -> Rc<Promise> {
|
||||
let mut context = self.scope_context.borrow_mut();
|
||||
let promise = Promise::new_in_current_realm(&self.global(), comp);
|
||||
let scope_id = if let Some((e, _)) = context.scope_stack.last() {
|
||||
*e
|
||||
} else {
|
||||
promise.reject_error(Error::Operation);
|
||||
return promise;
|
||||
};
|
||||
let scope_id =
|
||||
if let Some(meta) = context.scope_stack.iter().rev().find(|m| !m.popped.get()) {
|
||||
meta.popped.set(true);
|
||||
meta.id
|
||||
} else {
|
||||
promise.reject_error(Error::Operation);
|
||||
return promise;
|
||||
};
|
||||
let remove = if let Some(mut err_scope) = context.error_scopes.get_mut(&scope_id) {
|
||||
if let Some(ref e) = err_scope.error {
|
||||
match e {
|
||||
|
@ -1017,7 +1066,7 @@ impl GPUDeviceMethods for GPUDevice {
|
|||
};
|
||||
if remove {
|
||||
let _ = context.error_scopes.remove(&scope_id);
|
||||
let _ = context.scope_stack.pop();
|
||||
context.scope_stack.retain(|meta| meta.id != scope_id);
|
||||
}
|
||||
promise
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ pub struct GPURenderPassEncoder {
|
|||
impl GPURenderPassEncoder {
|
||||
fn new_inherited(
|
||||
channel: WebGPU,
|
||||
render_pass: RenderPass,
|
||||
render_pass: Option<RenderPass>,
|
||||
parent: &GPUCommandEncoder,
|
||||
label: Option<USVString>,
|
||||
) -> Self {
|
||||
|
@ -43,7 +43,7 @@ impl GPURenderPassEncoder {
|
|||
channel,
|
||||
reflector_: Reflector::new(),
|
||||
label: DomRefCell::new(label),
|
||||
render_pass: DomRefCell::new(Some(render_pass)),
|
||||
render_pass: DomRefCell::new(render_pass),
|
||||
command_encoder: Dom::from_ref(parent),
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ impl GPURenderPassEncoder {
|
|||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
channel: WebGPU,
|
||||
render_pass: RenderPass,
|
||||
render_pass: Option<RenderPass>,
|
||||
parent: &GPUCommandEncoder,
|
||||
label: Option<USVString>,
|
||||
) -> DomRoot<Self> {
|
||||
|
@ -126,27 +126,27 @@ impl GPURenderPassEncoderMethods for GPURenderPassEncoder {
|
|||
|
||||
/// https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setblendcolor
|
||||
fn SetBlendColor(&self, color: GPUColor) {
|
||||
let colors = match color {
|
||||
GPUColor::GPUColorDict(d) => wgt::Color {
|
||||
r: *d.r,
|
||||
g: *d.g,
|
||||
b: *d.b,
|
||||
a: *d.a,
|
||||
},
|
||||
GPUColor::DoubleSequence(mut s) => {
|
||||
if s.len() < 3 {
|
||||
s.resize(3, Finite::wrap(0.0f64));
|
||||
}
|
||||
s.resize(4, Finite::wrap(1.0f64));
|
||||
wgt::Color {
|
||||
r: *s[0],
|
||||
g: *s[1],
|
||||
b: *s[2],
|
||||
a: *s[3],
|
||||
}
|
||||
},
|
||||
};
|
||||
if let Some(render_pass) = self.render_pass.borrow_mut().as_mut() {
|
||||
let colors = match color {
|
||||
GPUColor::GPUColorDict(d) => wgt::Color {
|
||||
r: *d.r,
|
||||
g: *d.g,
|
||||
b: *d.b,
|
||||
a: *d.a,
|
||||
},
|
||||
GPUColor::DoubleSequence(mut s) => {
|
||||
if s.len() < 3 {
|
||||
s.resize(3, Finite::wrap(0.0f64));
|
||||
}
|
||||
s.resize(4, Finite::wrap(1.0f64));
|
||||
wgt::Color {
|
||||
r: *s[0],
|
||||
g: *s[1],
|
||||
b: *s[2],
|
||||
a: *s[3],
|
||||
}
|
||||
},
|
||||
};
|
||||
wgpu_render::wgpu_render_pass_set_blend_color(render_pass, &colors);
|
||||
}
|
||||
}
|
||||
|
@ -160,24 +160,23 @@ impl GPURenderPassEncoderMethods for GPURenderPassEncoder {
|
|||
|
||||
/// https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-endpass
|
||||
fn EndPass(&self) {
|
||||
if let Some(render_pass) = self.render_pass.borrow_mut().take() {
|
||||
self.channel
|
||||
.0
|
||||
.send((
|
||||
self.command_encoder.device().use_current_scope(),
|
||||
WebGPURequest::RunRenderPass {
|
||||
command_encoder_id: self.command_encoder.id().0,
|
||||
device_id: self.command_encoder.device().id().0,
|
||||
render_pass,
|
||||
},
|
||||
))
|
||||
.expect("Failed to send RunRenderPass");
|
||||
let render_pass = self.render_pass.borrow_mut().take();
|
||||
self.channel
|
||||
.0
|
||||
.send((
|
||||
self.command_encoder.device().use_current_scope(),
|
||||
WebGPURequest::RunRenderPass {
|
||||
command_encoder_id: self.command_encoder.id().0,
|
||||
device_id: self.command_encoder.device().id().0,
|
||||
render_pass,
|
||||
},
|
||||
))
|
||||
.expect("Failed to send RunRenderPass");
|
||||
|
||||
self.command_encoder.set_state(
|
||||
GPUCommandEncoderState::Open,
|
||||
GPUCommandEncoderState::EncodingRenderPass,
|
||||
);
|
||||
}
|
||||
self.command_encoder.set_state(
|
||||
GPUCommandEncoderState::Open,
|
||||
GPUCommandEncoderState::EncodingRenderPass,
|
||||
);
|
||||
}
|
||||
|
||||
/// https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-setpipeline
|
||||
|
|
|
@ -16,8 +16,11 @@ use crate::dom::globalscope::GlobalScope;
|
|||
use crate::dom::gpudevice::{convert_texture_format, convert_texture_view_dimension, GPUDevice};
|
||||
use crate::dom::gputextureview::GPUTextureView;
|
||||
use dom_struct::dom_struct;
|
||||
use std::num::NonZeroU32;
|
||||
use std::string::String;
|
||||
use webgpu::{wgt, WebGPU, WebGPURequest, WebGPUTexture, WebGPUTextureView};
|
||||
use webgpu::{
|
||||
identity::WebGPUOpResult, wgt, WebGPU, WebGPURequest, WebGPUTexture, WebGPUTextureView,
|
||||
};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUTexture {
|
||||
|
@ -137,24 +140,48 @@ impl GPUTextureMethods for GPUTexture {
|
|||
};
|
||||
|
||||
let format = descriptor.format.unwrap_or(self.format);
|
||||
let scope_id = self.device.use_current_scope();
|
||||
let mut valid = true;
|
||||
let level_count = descriptor.mipLevelCount.and_then(|count| {
|
||||
if count == 0 {
|
||||
valid = false;
|
||||
}
|
||||
NonZeroU32::new(count)
|
||||
});
|
||||
let array_layer_count = descriptor.arrayLayerCount.and_then(|count| {
|
||||
if count == 0 {
|
||||
valid = false;
|
||||
}
|
||||
NonZeroU32::new(count)
|
||||
});
|
||||
|
||||
let desc = wgt::TextureViewDescriptor {
|
||||
label: descriptor
|
||||
.parent
|
||||
.label
|
||||
.as_ref()
|
||||
.map(|s| String::from(s.as_ref())),
|
||||
format: convert_texture_format(format),
|
||||
dimension: convert_texture_view_dimension(dimension),
|
||||
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,
|
||||
level_count: descriptor.mipLevelCount.as_ref().copied(),
|
||||
base_array_layer: descriptor.baseArrayLayer,
|
||||
array_layer_count: descriptor.arrayLayerCount.as_ref().copied(),
|
||||
let desc = if valid {
|
||||
Some(wgt::TextureViewDescriptor {
|
||||
label: descriptor
|
||||
.parent
|
||||
.label
|
||||
.as_ref()
|
||||
.map(|s| String::from(s.as_ref())),
|
||||
format: convert_texture_format(format),
|
||||
dimension: convert_texture_view_dimension(dimension),
|
||||
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,
|
||||
level_count,
|
||||
base_array_layer: descriptor.baseArrayLayer,
|
||||
array_layer_count,
|
||||
})
|
||||
} else {
|
||||
self.device.handle_server_msg(
|
||||
scope_id,
|
||||
WebGPUOpResult::ValidationError(String::from(
|
||||
"arrayLayerCount and mipLevelCount cannot be 0",
|
||||
)),
|
||||
);
|
||||
None
|
||||
};
|
||||
|
||||
let texture_view_id = self
|
||||
|
@ -163,8 +190,6 @@ impl GPUTextureMethods for GPUTexture {
|
|||
.lock()
|
||||
.create_texture_view_id(self.device.id().0.backend());
|
||||
|
||||
let scope_id = self.device.use_current_scope();
|
||||
|
||||
self.channel
|
||||
.0
|
||||
.send((
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue