mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 06:44:14 +00:00
[error] render bundles
This commit is contained in:
parent
6307294e2b
commit
c6bc37dbde
@ -91,7 +91,9 @@ fn main() {
|
||||
None,
|
||||
id
|
||||
));
|
||||
assert_eq!(error, None);
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
id
|
||||
}
|
||||
_ => panic!("Expected Action::Init"),
|
||||
|
@ -117,8 +117,12 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
}
|
||||
}
|
||||
}
|
||||
self.command_encoder_finish::<B>(encoder, &wgt::CommandBufferDescriptor { label: None })
|
||||
.unwrap()
|
||||
let (cmd_buf, error) = self
|
||||
.command_encoder_finish::<B>(encoder, &wgt::CommandBufferDescriptor { label: None });
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
cmd_buf
|
||||
}
|
||||
|
||||
fn process<B: wgc::hub::GfxBackend>(
|
||||
@ -138,7 +142,9 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
A::CreateBuffer(id, desc) => {
|
||||
self.device_maintain_ids::<B>(device).unwrap();
|
||||
let (_, error) = self.device_create_buffer::<B>(device, &desc, id);
|
||||
assert_eq!(error, None);
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
}
|
||||
A::FreeBuffer(id) => {
|
||||
self.buffer_destroy::<B>(id).unwrap();
|
||||
@ -149,7 +155,9 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
A::CreateTexture(id, desc) => {
|
||||
self.device_maintain_ids::<B>(device).unwrap();
|
||||
let (_, error) = self.device_create_texture::<B>(device, &desc, id);
|
||||
assert_eq!(error, None);
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
}
|
||||
A::FreeTexture(id) => {
|
||||
self.texture_destroy::<B>(id).unwrap();
|
||||
@ -164,7 +172,9 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
} => {
|
||||
self.device_maintain_ids::<B>(device).unwrap();
|
||||
let (_, error) = self.texture_create_view::<B>(parent_id, &desc, id);
|
||||
assert_eq!(error, None);
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
}
|
||||
A::DestroyTextureView(id) => {
|
||||
self.texture_view_drop::<B>(id).unwrap();
|
||||
@ -172,7 +182,9 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
A::CreateSampler(id, desc) => {
|
||||
self.device_maintain_ids::<B>(device).unwrap();
|
||||
let (_, error) = self.device_create_sampler::<B>(device, &desc, id);
|
||||
assert_eq!(error, None);
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
}
|
||||
A::DestroySampler(id) => {
|
||||
self.sampler_drop::<B>(id);
|
||||
@ -187,7 +199,9 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
}
|
||||
A::CreateBindGroupLayout(id, desc) => {
|
||||
let (_, error) = self.device_create_bind_group_layout::<B>(device, &desc, id);
|
||||
assert_eq!(error, None);
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
}
|
||||
A::DestroyBindGroupLayout(id) => {
|
||||
self.bind_group_layout_drop::<B>(id);
|
||||
@ -195,7 +209,9 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
A::CreatePipelineLayout(id, desc) => {
|
||||
self.device_maintain_ids::<B>(device).unwrap();
|
||||
let (_, error) = self.device_create_pipeline_layout::<B>(device, &desc, id);
|
||||
assert_eq!(error, None);
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
}
|
||||
A::DestroyPipelineLayout(id) => {
|
||||
self.pipeline_layout_drop::<B>(id);
|
||||
@ -203,7 +219,9 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
A::CreateBindGroup(id, desc) => {
|
||||
self.device_maintain_ids::<B>(device).unwrap();
|
||||
let (_, error) = self.device_create_bind_group::<B>(device, &desc, id);
|
||||
assert_eq!(error, None);
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
}
|
||||
A::DestroyBindGroup(id) => {
|
||||
self.bind_group_drop::<B>(id);
|
||||
@ -224,7 +242,9 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
label,
|
||||
};
|
||||
let (_, error) = self.device_create_shader_module::<B>(device, &desc, id);
|
||||
assert_eq!(error, None);
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
}
|
||||
A::DestroyShaderModule(id) => {
|
||||
self.shader_module_drop::<B>(id);
|
||||
@ -233,7 +253,9 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
self.device_maintain_ids::<B>(device).unwrap();
|
||||
let (_, _, error) =
|
||||
self.device_create_compute_pipeline::<B>(device, &desc, id, None);
|
||||
assert_eq!(error, None);
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
}
|
||||
A::DestroyComputePipeline(id) => {
|
||||
self.compute_pipeline_drop::<B>(id);
|
||||
@ -242,7 +264,9 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
self.device_maintain_ids::<B>(device).unwrap();
|
||||
let (_, _, error) =
|
||||
self.device_create_render_pipeline::<B>(device, &desc, id, None);
|
||||
assert_eq!(error, None);
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
}
|
||||
A::DestroyRenderPipeline(id) => {
|
||||
self.render_pipeline_drop::<B>(id);
|
||||
@ -250,12 +274,14 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
A::CreateRenderBundle { id, desc, base } => {
|
||||
let bundle =
|
||||
wgc::command::RenderBundleEncoder::new(&desc, device, Some(base)).unwrap();
|
||||
self.render_bundle_encoder_finish::<B>(
|
||||
let (_, error) = self.render_bundle_encoder_finish::<B>(
|
||||
bundle,
|
||||
&wgt::RenderBundleDescriptor { label: desc.label },
|
||||
id,
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
}
|
||||
A::DestroyRenderBundle(id) => {
|
||||
self.render_bundle_drop::<B>(id);
|
||||
@ -288,13 +314,14 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
.unwrap();
|
||||
}
|
||||
A::Submit(_index, commands) => {
|
||||
let encoder = self
|
||||
.device_create_command_encoder::<B>(
|
||||
device,
|
||||
&wgt::CommandEncoderDescriptor { label: None },
|
||||
comb_manager.alloc(device.backend()),
|
||||
)
|
||||
.unwrap();
|
||||
let (encoder, error) = self.device_create_command_encoder::<B>(
|
||||
device,
|
||||
&wgt::CommandEncoderDescriptor { label: None },
|
||||
comb_manager.alloc(device.backend()),
|
||||
);
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
let cmdbuf = self.encode_commands::<B>(encoder, commands);
|
||||
self.queue_submit::<B>(device, &[cmdbuf]).unwrap();
|
||||
}
|
||||
|
@ -98,7 +98,9 @@ impl Test<'_> {
|
||||
None,
|
||||
device
|
||||
));
|
||||
assert_eq!(error, None);
|
||||
if let Some(e) = error {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
|
||||
let mut command_buffer_id_manager = wgc::hub::IdentityManager::default();
|
||||
println!("\t\t\tRunning...");
|
||||
|
@ -26,7 +26,7 @@ use std::{
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum CreateBindGroupLayoutError {
|
||||
#[error(transparent)]
|
||||
Device(#[from] DeviceError),
|
||||
@ -40,7 +40,7 @@ pub enum CreateBindGroupLayoutError {
|
||||
TooManyBindings(BindingTypeMaxCountError),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum CreateBindGroupError {
|
||||
#[error(transparent)]
|
||||
Device(#[from] DeviceError),
|
||||
@ -96,7 +96,7 @@ pub enum CreateBindGroupError {
|
||||
DepthStencilAspect,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum BindingZone {
|
||||
#[error("stage {0:?}")]
|
||||
Stage(wgt::ShaderStage),
|
||||
@ -104,7 +104,7 @@ pub enum BindingZone {
|
||||
Pipeline,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
#[error("too many bindings of type {kind:?} in {zone}, limit is {count}")]
|
||||
pub struct BindingTypeMaxCountError {
|
||||
pub kind: BindingTypeMaxCountErrorKind,
|
||||
@ -112,7 +112,7 @@ pub struct BindingTypeMaxCountError {
|
||||
pub count: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BindingTypeMaxCountErrorKind {
|
||||
DynamicUniformBuffers,
|
||||
DynamicStorageBuffers,
|
||||
@ -336,7 +336,7 @@ impl<B: hal::Backend> Resource for BindGroupLayout<B> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum CreatePipelineLayoutError {
|
||||
#[error(transparent)]
|
||||
Device(#[from] DeviceError),
|
||||
|
@ -44,9 +44,10 @@ use crate::{
|
||||
},
|
||||
conv,
|
||||
device::{
|
||||
AttachmentData, DeviceError, RenderPassContext, MAX_VERTEX_BUFFERS, SHADER_STAGE_COUNT,
|
||||
AttachmentData, Device, DeviceError, RenderPassContext, MAX_VERTEX_BUFFERS,
|
||||
SHADER_STAGE_COUNT,
|
||||
},
|
||||
hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Input, Resource, Storage, Token},
|
||||
hub::{GfxBackend, GlobalIdentityHandlerFactory, Hub, Resource, Storage, Token},
|
||||
id,
|
||||
resource::BufferUse,
|
||||
span,
|
||||
@ -55,7 +56,7 @@ use crate::{
|
||||
Label, LabelHelpers, LifeGuard, Stored, MAX_BIND_GROUPS,
|
||||
};
|
||||
use arrayvec::ArrayVec;
|
||||
use std::{borrow::Cow, iter, marker::PhantomData, ops::Range};
|
||||
use std::{borrow::Cow, iter, ops::Range};
|
||||
use thiserror::Error;
|
||||
|
||||
/// Describes a [`RenderBundleEncoder`].
|
||||
@ -111,9 +112,328 @@ impl RenderBundleEncoder {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn dummy(parent_id: id::DeviceId) -> Self {
|
||||
Self {
|
||||
base: BasePass::new(),
|
||||
parent_id,
|
||||
context: RenderPassContext {
|
||||
attachments: AttachmentData {
|
||||
colors: ArrayVec::new(),
|
||||
resolves: ArrayVec::new(),
|
||||
depth_stencil: None,
|
||||
},
|
||||
sample_count: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parent(&self) -> id::DeviceId {
|
||||
self.parent_id
|
||||
}
|
||||
|
||||
pub(crate) fn finish<B: hal::Backend, G: GlobalIdentityHandlerFactory>(
|
||||
self,
|
||||
desc: &RenderBundleDescriptor,
|
||||
device: &Device<B>,
|
||||
hub: &Hub<B, G>,
|
||||
token: &mut Token<Device<B>>,
|
||||
) -> Result<RenderBundle, RenderBundleError> {
|
||||
let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(token);
|
||||
let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token);
|
||||
let (pipeline_guard, mut token) = hub.render_pipelines.read(&mut token);
|
||||
let (buffer_guard, _) = hub.buffers.read(&mut token);
|
||||
|
||||
let mut state = State {
|
||||
trackers: TrackerSet::new(self.parent_id.backend()),
|
||||
index: IndexState::new(),
|
||||
vertex: (0..MAX_VERTEX_BUFFERS)
|
||||
.map(|_| VertexState::new())
|
||||
.collect(),
|
||||
bind: (0..MAX_BIND_GROUPS).map(|_| BindState::new()).collect(),
|
||||
push_constant_ranges: PushConstantState::new(),
|
||||
raw_dynamic_offsets: Vec::new(),
|
||||
flat_dynamic_offsets: Vec::new(),
|
||||
used_bind_groups: 0,
|
||||
pipeline: StateChange::new(),
|
||||
};
|
||||
let mut commands = Vec::new();
|
||||
let mut base = self.base.as_ref();
|
||||
let mut pipeline_layout_id = None::<id::Valid<id::PipelineLayoutId>>;
|
||||
|
||||
for &command in base.commands {
|
||||
match command {
|
||||
RenderCommand::SetBindGroup {
|
||||
index,
|
||||
num_dynamic_offsets,
|
||||
bind_group_id,
|
||||
} => {
|
||||
let scope = PassErrorScope::SetBindGroup(bind_group_id);
|
||||
|
||||
let max_bind_groups = device.limits.max_bind_groups;
|
||||
if (index as u32) >= max_bind_groups {
|
||||
return Err(RenderCommandError::BindGroupIndexOutOfRange {
|
||||
index,
|
||||
max: max_bind_groups,
|
||||
})
|
||||
.map_pass_err(scope);
|
||||
}
|
||||
|
||||
let offsets = &base.dynamic_offsets[..num_dynamic_offsets as usize];
|
||||
base.dynamic_offsets = &base.dynamic_offsets[num_dynamic_offsets as usize..];
|
||||
// Check for misaligned offsets.
|
||||
if let Some(offset) = offsets
|
||||
.iter()
|
||||
.map(|offset| *offset as wgt::BufferAddress)
|
||||
.find(|offset| offset % wgt::BIND_BUFFER_ALIGNMENT != 0)
|
||||
{
|
||||
return Err(RenderCommandError::UnalignedBufferOffset(offset))
|
||||
.map_pass_err(scope);
|
||||
}
|
||||
|
||||
let bind_group = state
|
||||
.trackers
|
||||
.bind_groups
|
||||
.use_extend(&*bind_group_guard, bind_group_id, (), ())
|
||||
.map_err(|_| RenderCommandError::InvalidBindGroup(bind_group_id))
|
||||
.map_pass_err(scope)?;
|
||||
if bind_group.dynamic_binding_info.len() != offsets.len() {
|
||||
return Err(RenderCommandError::InvalidDynamicOffsetCount {
|
||||
actual: offsets.len(),
|
||||
expected: bind_group.dynamic_binding_info.len(),
|
||||
})
|
||||
.map_pass_err(scope);
|
||||
}
|
||||
|
||||
state.set_bind_group(index, bind_group_id, bind_group.layout_id, offsets);
|
||||
state
|
||||
.trackers
|
||||
.merge_extend(&bind_group.used)
|
||||
.map_pass_err(scope)?;
|
||||
}
|
||||
RenderCommand::SetPipeline(pipeline_id) => {
|
||||
let scope = PassErrorScope::SetPipelineRender(pipeline_id);
|
||||
if state.pipeline.set_and_check_redundant(pipeline_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let pipeline = state
|
||||
.trackers
|
||||
.render_pipes
|
||||
.use_extend(&*pipeline_guard, pipeline_id, (), ())
|
||||
.unwrap();
|
||||
|
||||
self.context
|
||||
.check_compatible(&pipeline.pass_context)
|
||||
.map_err(RenderCommandError::IncompatiblePipeline)
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
//TODO: check read-only depth
|
||||
|
||||
let layout = &pipeline_layout_guard[pipeline.layout_id.value];
|
||||
pipeline_layout_id = Some(pipeline.layout_id.value);
|
||||
|
||||
state.set_pipeline(
|
||||
pipeline.index_format,
|
||||
&pipeline.vertex_strides,
|
||||
&layout.bind_group_layout_ids,
|
||||
&layout.push_constant_ranges,
|
||||
);
|
||||
commands.push(command);
|
||||
if let Some(iter) = state.flush_push_constants() {
|
||||
commands.extend(iter)
|
||||
}
|
||||
}
|
||||
RenderCommand::SetIndexBuffer {
|
||||
buffer_id,
|
||||
offset,
|
||||
size,
|
||||
} => {
|
||||
let scope = PassErrorScope::SetIndexBuffer(buffer_id);
|
||||
let buffer = state
|
||||
.trackers
|
||||
.buffers
|
||||
.use_extend(&*buffer_guard, buffer_id, (), BufferUse::INDEX)
|
||||
.unwrap();
|
||||
check_buffer_usage(buffer.usage, wgt::BufferUsage::INDEX)
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
let end = match size {
|
||||
Some(s) => offset + s.get(),
|
||||
None => buffer.size,
|
||||
};
|
||||
state.index.set_buffer(buffer_id, offset..end);
|
||||
}
|
||||
RenderCommand::SetVertexBuffer {
|
||||
slot,
|
||||
buffer_id,
|
||||
offset,
|
||||
size,
|
||||
} => {
|
||||
let scope = PassErrorScope::SetVertexBuffer(buffer_id);
|
||||
let buffer = state
|
||||
.trackers
|
||||
.buffers
|
||||
.use_extend(&*buffer_guard, buffer_id, (), BufferUse::VERTEX)
|
||||
.unwrap();
|
||||
check_buffer_usage(buffer.usage, wgt::BufferUsage::VERTEX)
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
let end = match size {
|
||||
Some(s) => offset + s.get(),
|
||||
None => buffer.size,
|
||||
};
|
||||
state.vertex[slot as usize].set_buffer(buffer_id, offset..end);
|
||||
}
|
||||
RenderCommand::SetPushConstant {
|
||||
stages,
|
||||
offset,
|
||||
size_bytes,
|
||||
values_offset: _,
|
||||
} => {
|
||||
let scope = PassErrorScope::SetPushConstant;
|
||||
let end_offset = offset + size_bytes;
|
||||
|
||||
let pipeline_layout_id = pipeline_layout_id
|
||||
.ok_or(DrawError::MissingPipeline)
|
||||
.map_pass_err(scope)?;
|
||||
let pipeline_layout = &pipeline_layout_guard[pipeline_layout_id];
|
||||
|
||||
pipeline_layout
|
||||
.validate_push_constant_ranges(stages, offset, end_offset)
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
commands.push(command);
|
||||
}
|
||||
RenderCommand::Draw {
|
||||
vertex_count,
|
||||
instance_count,
|
||||
first_vertex,
|
||||
first_instance,
|
||||
} => {
|
||||
let scope = PassErrorScope::Draw;
|
||||
let (vertex_limit, instance_limit) = state.vertex_limits();
|
||||
let last_vertex = first_vertex + vertex_count;
|
||||
if last_vertex > vertex_limit {
|
||||
return Err(DrawError::VertexBeyondLimit {
|
||||
last_vertex,
|
||||
vertex_limit,
|
||||
})
|
||||
.map_pass_err(scope);
|
||||
}
|
||||
let last_instance = first_instance + instance_count;
|
||||
if last_instance > instance_limit {
|
||||
return Err(DrawError::InstanceBeyondLimit {
|
||||
last_instance,
|
||||
instance_limit,
|
||||
})
|
||||
.map_pass_err(scope);
|
||||
}
|
||||
commands.extend(state.flush_vertices());
|
||||
commands.extend(state.flush_binds());
|
||||
commands.push(command);
|
||||
}
|
||||
RenderCommand::DrawIndexed {
|
||||
index_count,
|
||||
instance_count,
|
||||
first_index,
|
||||
base_vertex: _,
|
||||
first_instance,
|
||||
} => {
|
||||
let scope = PassErrorScope::DrawIndexed;
|
||||
//TODO: validate that base_vertex + max_index() is within the provided range
|
||||
let (_, instance_limit) = state.vertex_limits();
|
||||
let index_limit = state.index.limit();
|
||||
let last_index = first_index + index_count;
|
||||
if last_index > index_limit {
|
||||
return Err(DrawError::IndexBeyondLimit {
|
||||
last_index,
|
||||
index_limit,
|
||||
})
|
||||
.map_pass_err(scope);
|
||||
}
|
||||
let last_instance = first_instance + instance_count;
|
||||
if last_instance > instance_limit {
|
||||
return Err(DrawError::InstanceBeyondLimit {
|
||||
last_instance,
|
||||
instance_limit,
|
||||
})
|
||||
.map_pass_err(scope);
|
||||
}
|
||||
commands.extend(state.index.flush());
|
||||
commands.extend(state.flush_vertices());
|
||||
commands.extend(state.flush_binds());
|
||||
commands.push(command);
|
||||
}
|
||||
RenderCommand::MultiDrawIndirect {
|
||||
buffer_id,
|
||||
offset: _,
|
||||
count: None,
|
||||
indexed: false,
|
||||
} => {
|
||||
let scope = PassErrorScope::DrawIndirect;
|
||||
let buffer = state
|
||||
.trackers
|
||||
.buffers
|
||||
.use_extend(&*buffer_guard, buffer_id, (), BufferUse::INDIRECT)
|
||||
.unwrap();
|
||||
check_buffer_usage(buffer.usage, wgt::BufferUsage::INDIRECT)
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
commands.extend(state.flush_vertices());
|
||||
commands.extend(state.flush_binds());
|
||||
commands.push(command);
|
||||
}
|
||||
RenderCommand::MultiDrawIndirect {
|
||||
buffer_id,
|
||||
offset: _,
|
||||
count: None,
|
||||
indexed: true,
|
||||
} => {
|
||||
let scope = PassErrorScope::DrawIndexedIndirect;
|
||||
let buffer = state
|
||||
.trackers
|
||||
.buffers
|
||||
.use_extend(&*buffer_guard, buffer_id, (), BufferUse::INDIRECT)
|
||||
.map_err(|err| RenderCommandError::Buffer(buffer_id, err))
|
||||
.map_pass_err(scope)?;
|
||||
check_buffer_usage(buffer.usage, wgt::BufferUsage::INDIRECT)
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
commands.extend(state.index.flush());
|
||||
commands.extend(state.flush_vertices());
|
||||
commands.extend(state.flush_binds());
|
||||
commands.push(command);
|
||||
}
|
||||
RenderCommand::MultiDrawIndirect { .. }
|
||||
| RenderCommand::MultiDrawIndirectCount { .. } => unimplemented!(),
|
||||
RenderCommand::PushDebugGroup { color: _, len: _ } => unimplemented!(),
|
||||
RenderCommand::InsertDebugMarker { color: _, len: _ } => unimplemented!(),
|
||||
RenderCommand::PopDebugGroup => unimplemented!(),
|
||||
RenderCommand::ExecuteBundle(_)
|
||||
| RenderCommand::SetBlendColor(_)
|
||||
| RenderCommand::SetStencilReference(_)
|
||||
| RenderCommand::SetViewport { .. }
|
||||
| RenderCommand::SetScissor(_) => unreachable!("not supported by a render bundle"),
|
||||
}
|
||||
}
|
||||
|
||||
let _ = desc.label; //TODO: actually use
|
||||
Ok(RenderBundle {
|
||||
base: BasePass {
|
||||
commands,
|
||||
dynamic_offsets: state.flat_dynamic_offsets,
|
||||
string_data: Vec::new(),
|
||||
push_constant_data: Vec::new(),
|
||||
},
|
||||
device_id: Stored {
|
||||
value: id::Valid(self.parent_id),
|
||||
ref_count: device.life_guard.add_ref(),
|
||||
},
|
||||
used: state.trackers,
|
||||
context: self.context,
|
||||
life_guard: LifeGuard::new(desc.label.borrow_or_default()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Error type returned from `RenderBundleEncoder::new` if the sample count is invalid.
|
||||
@ -150,6 +470,11 @@ unsafe impl Send for RenderBundle {}
|
||||
unsafe impl Sync for RenderBundle {}
|
||||
|
||||
impl RenderBundle {
|
||||
#[cfg(feature = "trace")]
|
||||
pub(crate) fn to_base_pass(&self) -> BasePass<RenderCommand> {
|
||||
BasePass::from_ref(self.base.as_ref())
|
||||
}
|
||||
|
||||
/// Actually encode the contents into a native command buffer.
|
||||
///
|
||||
/// This is partially duplicating the logic of `command_encoder_run_render_pass`.
|
||||
@ -685,6 +1010,13 @@ pub struct RenderBundleError {
|
||||
inner: RenderBundleErrorInner,
|
||||
}
|
||||
|
||||
impl RenderBundleError {
|
||||
pub(crate) const INVALID_DEVICE: Self = RenderBundleError {
|
||||
scope: PassErrorScope::Bundle,
|
||||
inner: RenderBundleErrorInner::Device(DeviceError::Invalid),
|
||||
};
|
||||
}
|
||||
|
||||
impl<T, E> MapPassErr<T, RenderBundleError> for Result<T, E>
|
||||
where
|
||||
E: Into<RenderBundleErrorInner>,
|
||||
@ -697,356 +1029,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
pub fn render_bundle_encoder_finish<B: GfxBackend>(
|
||||
&self,
|
||||
bundle_encoder: RenderBundleEncoder,
|
||||
desc: &RenderBundleDescriptor,
|
||||
id_in: Input<G, id::RenderBundleId>,
|
||||
) -> Result<id::RenderBundleId, RenderBundleError> {
|
||||
span!(_guard, INFO, "RenderBundleEncoder::finish");
|
||||
let scope = PassErrorScope::Bundle;
|
||||
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
let (device_guard, mut token) = hub.devices.read(&mut token);
|
||||
|
||||
let device = device_guard
|
||||
.get(bundle_encoder.parent_id)
|
||||
.map_err(|_| DeviceError::Invalid)
|
||||
.map_pass_err(scope)?;
|
||||
let render_bundle = {
|
||||
let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token);
|
||||
let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token);
|
||||
let (pipeline_guard, mut token) = hub.render_pipelines.read(&mut token);
|
||||
let (buffer_guard, _) = hub.buffers.read(&mut token);
|
||||
|
||||
let mut state = State {
|
||||
trackers: TrackerSet::new(bundle_encoder.parent_id.backend()),
|
||||
index: IndexState::new(),
|
||||
vertex: (0..MAX_VERTEX_BUFFERS)
|
||||
.map(|_| VertexState::new())
|
||||
.collect(),
|
||||
bind: (0..MAX_BIND_GROUPS).map(|_| BindState::new()).collect(),
|
||||
push_constant_ranges: PushConstantState::new(),
|
||||
raw_dynamic_offsets: Vec::new(),
|
||||
flat_dynamic_offsets: Vec::new(),
|
||||
used_bind_groups: 0,
|
||||
pipeline: StateChange::new(),
|
||||
};
|
||||
let mut commands = Vec::new();
|
||||
let mut base = bundle_encoder.base.as_ref();
|
||||
let mut pipeline_layout_id = None::<id::Valid<id::PipelineLayoutId>>;
|
||||
|
||||
for &command in base.commands {
|
||||
match command {
|
||||
RenderCommand::SetBindGroup {
|
||||
index,
|
||||
num_dynamic_offsets,
|
||||
bind_group_id,
|
||||
} => {
|
||||
let scope = PassErrorScope::SetBindGroup(bind_group_id);
|
||||
|
||||
let max_bind_groups = device.limits.max_bind_groups;
|
||||
if (index as u32) >= max_bind_groups {
|
||||
return Err(RenderCommandError::BindGroupIndexOutOfRange {
|
||||
index,
|
||||
max: max_bind_groups,
|
||||
})
|
||||
.map_pass_err(scope);
|
||||
}
|
||||
|
||||
let offsets = &base.dynamic_offsets[..num_dynamic_offsets as usize];
|
||||
base.dynamic_offsets =
|
||||
&base.dynamic_offsets[num_dynamic_offsets as usize..];
|
||||
// Check for misaligned offsets.
|
||||
if let Some(offset) = offsets
|
||||
.iter()
|
||||
.map(|offset| *offset as wgt::BufferAddress)
|
||||
.find(|offset| offset % wgt::BIND_BUFFER_ALIGNMENT != 0)
|
||||
{
|
||||
return Err(RenderCommandError::UnalignedBufferOffset(offset))
|
||||
.map_pass_err(scope);
|
||||
}
|
||||
|
||||
let bind_group = state
|
||||
.trackers
|
||||
.bind_groups
|
||||
.use_extend(&*bind_group_guard, bind_group_id, (), ())
|
||||
.map_err(|_| RenderCommandError::InvalidBindGroup(bind_group_id))
|
||||
.map_pass_err(scope)?;
|
||||
if bind_group.dynamic_binding_info.len() != offsets.len() {
|
||||
return Err(RenderCommandError::InvalidDynamicOffsetCount {
|
||||
actual: offsets.len(),
|
||||
expected: bind_group.dynamic_binding_info.len(),
|
||||
})
|
||||
.map_pass_err(scope);
|
||||
}
|
||||
|
||||
state.set_bind_group(index, bind_group_id, bind_group.layout_id, offsets);
|
||||
state
|
||||
.trackers
|
||||
.merge_extend(&bind_group.used)
|
||||
.map_pass_err(scope)?;
|
||||
}
|
||||
RenderCommand::SetPipeline(pipeline_id) => {
|
||||
let scope = PassErrorScope::SetPipelineRender(pipeline_id);
|
||||
if state.pipeline.set_and_check_redundant(pipeline_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let pipeline = state
|
||||
.trackers
|
||||
.render_pipes
|
||||
.use_extend(&*pipeline_guard, pipeline_id, (), ())
|
||||
.unwrap();
|
||||
|
||||
bundle_encoder
|
||||
.context
|
||||
.check_compatible(&pipeline.pass_context)
|
||||
.map_err(RenderCommandError::IncompatiblePipeline)
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
//TODO: check read-only depth
|
||||
|
||||
let layout = &pipeline_layout_guard[pipeline.layout_id.value];
|
||||
pipeline_layout_id = Some(pipeline.layout_id.value);
|
||||
|
||||
state.set_pipeline(
|
||||
pipeline.index_format,
|
||||
&pipeline.vertex_strides,
|
||||
&layout.bind_group_layout_ids,
|
||||
&layout.push_constant_ranges,
|
||||
);
|
||||
commands.push(command);
|
||||
if let Some(iter) = state.flush_push_constants() {
|
||||
commands.extend(iter)
|
||||
}
|
||||
}
|
||||
RenderCommand::SetIndexBuffer {
|
||||
buffer_id,
|
||||
offset,
|
||||
size,
|
||||
} => {
|
||||
let scope = PassErrorScope::SetIndexBuffer(buffer_id);
|
||||
let buffer = state
|
||||
.trackers
|
||||
.buffers
|
||||
.use_extend(&*buffer_guard, buffer_id, (), BufferUse::INDEX)
|
||||
.unwrap();
|
||||
check_buffer_usage(buffer.usage, wgt::BufferUsage::INDEX)
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
let end = match size {
|
||||
Some(s) => offset + s.get(),
|
||||
None => buffer.size,
|
||||
};
|
||||
state.index.set_buffer(buffer_id, offset..end);
|
||||
}
|
||||
RenderCommand::SetVertexBuffer {
|
||||
slot,
|
||||
buffer_id,
|
||||
offset,
|
||||
size,
|
||||
} => {
|
||||
let scope = PassErrorScope::SetVertexBuffer(buffer_id);
|
||||
let buffer = state
|
||||
.trackers
|
||||
.buffers
|
||||
.use_extend(&*buffer_guard, buffer_id, (), BufferUse::VERTEX)
|
||||
.unwrap();
|
||||
check_buffer_usage(buffer.usage, wgt::BufferUsage::VERTEX)
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
let end = match size {
|
||||
Some(s) => offset + s.get(),
|
||||
None => buffer.size,
|
||||
};
|
||||
state.vertex[slot as usize].set_buffer(buffer_id, offset..end);
|
||||
}
|
||||
RenderCommand::SetPushConstant {
|
||||
stages,
|
||||
offset,
|
||||
size_bytes,
|
||||
values_offset: _,
|
||||
} => {
|
||||
let scope = PassErrorScope::SetPushConstant;
|
||||
let end_offset = offset + size_bytes;
|
||||
|
||||
let pipeline_layout_id = pipeline_layout_id
|
||||
.ok_or(DrawError::MissingPipeline)
|
||||
.map_pass_err(scope)?;
|
||||
let pipeline_layout = &pipeline_layout_guard[pipeline_layout_id];
|
||||
|
||||
pipeline_layout
|
||||
.validate_push_constant_ranges(stages, offset, end_offset)
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
commands.push(command);
|
||||
}
|
||||
RenderCommand::Draw {
|
||||
vertex_count,
|
||||
instance_count,
|
||||
first_vertex,
|
||||
first_instance,
|
||||
} => {
|
||||
let scope = PassErrorScope::Draw;
|
||||
let (vertex_limit, instance_limit) = state.vertex_limits();
|
||||
let last_vertex = first_vertex + vertex_count;
|
||||
if last_vertex > vertex_limit {
|
||||
return Err(DrawError::VertexBeyondLimit {
|
||||
last_vertex,
|
||||
vertex_limit,
|
||||
})
|
||||
.map_pass_err(scope);
|
||||
}
|
||||
let last_instance = first_instance + instance_count;
|
||||
if last_instance > instance_limit {
|
||||
return Err(DrawError::InstanceBeyondLimit {
|
||||
last_instance,
|
||||
instance_limit,
|
||||
})
|
||||
.map_pass_err(scope);
|
||||
}
|
||||
commands.extend(state.flush_vertices());
|
||||
commands.extend(state.flush_binds());
|
||||
commands.push(command);
|
||||
}
|
||||
RenderCommand::DrawIndexed {
|
||||
index_count,
|
||||
instance_count,
|
||||
first_index,
|
||||
base_vertex: _,
|
||||
first_instance,
|
||||
} => {
|
||||
let scope = PassErrorScope::DrawIndexed;
|
||||
//TODO: validate that base_vertex + max_index() is within the provided range
|
||||
let (_, instance_limit) = state.vertex_limits();
|
||||
let index_limit = state.index.limit();
|
||||
let last_index = first_index + index_count;
|
||||
if last_index > index_limit {
|
||||
return Err(DrawError::IndexBeyondLimit {
|
||||
last_index,
|
||||
index_limit,
|
||||
})
|
||||
.map_pass_err(scope);
|
||||
}
|
||||
let last_instance = first_instance + instance_count;
|
||||
if last_instance > instance_limit {
|
||||
return Err(DrawError::InstanceBeyondLimit {
|
||||
last_instance,
|
||||
instance_limit,
|
||||
})
|
||||
.map_pass_err(scope);
|
||||
}
|
||||
commands.extend(state.index.flush());
|
||||
commands.extend(state.flush_vertices());
|
||||
commands.extend(state.flush_binds());
|
||||
commands.push(command);
|
||||
}
|
||||
RenderCommand::MultiDrawIndirect {
|
||||
buffer_id,
|
||||
offset: _,
|
||||
count: None,
|
||||
indexed: false,
|
||||
} => {
|
||||
let scope = PassErrorScope::DrawIndirect;
|
||||
let buffer = state
|
||||
.trackers
|
||||
.buffers
|
||||
.use_extend(&*buffer_guard, buffer_id, (), BufferUse::INDIRECT)
|
||||
.unwrap();
|
||||
check_buffer_usage(buffer.usage, wgt::BufferUsage::INDIRECT)
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
commands.extend(state.flush_vertices());
|
||||
commands.extend(state.flush_binds());
|
||||
commands.push(command);
|
||||
}
|
||||
RenderCommand::MultiDrawIndirect {
|
||||
buffer_id,
|
||||
offset: _,
|
||||
count: None,
|
||||
indexed: true,
|
||||
} => {
|
||||
let scope = PassErrorScope::DrawIndexedIndirect;
|
||||
let buffer = state
|
||||
.trackers
|
||||
.buffers
|
||||
.use_extend(&*buffer_guard, buffer_id, (), BufferUse::INDIRECT)
|
||||
.map_err(|err| RenderCommandError::Buffer(buffer_id, err))
|
||||
.map_pass_err(scope)?;
|
||||
check_buffer_usage(buffer.usage, wgt::BufferUsage::INDIRECT)
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
commands.extend(state.index.flush());
|
||||
commands.extend(state.flush_vertices());
|
||||
commands.extend(state.flush_binds());
|
||||
commands.push(command);
|
||||
}
|
||||
RenderCommand::MultiDrawIndirect { .. }
|
||||
| RenderCommand::MultiDrawIndirectCount { .. } => unimplemented!(),
|
||||
RenderCommand::PushDebugGroup { color: _, len: _ } => unimplemented!(),
|
||||
RenderCommand::InsertDebugMarker { color: _, len: _ } => unimplemented!(),
|
||||
RenderCommand::PopDebugGroup => unimplemented!(),
|
||||
RenderCommand::ExecuteBundle(_)
|
||||
| RenderCommand::SetBlendColor(_)
|
||||
| RenderCommand::SetStencilReference(_)
|
||||
| RenderCommand::SetViewport { .. }
|
||||
| RenderCommand::SetScissor(_) => {
|
||||
unreachable!("not supported by a render bundle")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tracing::debug!("Render bundle {:?} = {:#?}", id_in, state.trackers);
|
||||
let _ = desc.label; //TODO: actually use
|
||||
//TODO: check if the device is still alive
|
||||
RenderBundle {
|
||||
base: BasePass {
|
||||
commands,
|
||||
dynamic_offsets: state.flat_dynamic_offsets,
|
||||
string_data: Vec::new(),
|
||||
push_constant_data: Vec::new(),
|
||||
},
|
||||
device_id: Stored {
|
||||
value: id::Valid(bundle_encoder.parent_id),
|
||||
ref_count: device.life_guard.add_ref(),
|
||||
},
|
||||
used: state.trackers,
|
||||
context: bundle_encoder.context,
|
||||
life_guard: LifeGuard::new(desc.label.borrow_or_default()),
|
||||
}
|
||||
};
|
||||
|
||||
let ref_count = render_bundle.life_guard.add_ref();
|
||||
let id = hub
|
||||
.render_bundles
|
||||
.register_identity(id_in, render_bundle, &mut token);
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref trace) = device.trace {
|
||||
use crate::device::trace;
|
||||
let (bundle_guard, _) = hub.render_bundles.read(&mut token);
|
||||
let bundle = &bundle_guard[id];
|
||||
let label = desc.label.as_ref().map(|l| l.as_ref());
|
||||
trace.lock().add(trace::Action::CreateRenderBundle {
|
||||
id: id.0,
|
||||
desc: trace::new_render_bundle_encoder_descriptor(label, &bundle.context),
|
||||
base: BasePass::from_ref(bundle.base.as_ref()),
|
||||
});
|
||||
}
|
||||
|
||||
device
|
||||
.trackers
|
||||
.lock()
|
||||
.bundles
|
||||
.init(id, ref_count, PhantomData)
|
||||
.unwrap();
|
||||
Ok(id.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod bundle_ffi {
|
||||
use super::{RenderBundleEncoder, RenderCommand};
|
||||
use crate::{id, span, RawString};
|
||||
|
@ -186,7 +186,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
&self,
|
||||
encoder_id: id::CommandEncoderId,
|
||||
_desc: &wgt::CommandBufferDescriptor<Label>,
|
||||
) -> Result<id::CommandBufferId, CommandEncoderError> {
|
||||
) -> (id::CommandBufferId, Option<CommandEncoderError>) {
|
||||
span!(_guard, INFO, "CommandEncoder::finish");
|
||||
|
||||
let hub = B::hub(self);
|
||||
@ -194,18 +194,25 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let (swap_chain_guard, mut token) = hub.swap_chains.read(&mut token);
|
||||
//TODO: actually close the last recorded command buffer
|
||||
let (mut cmd_buf_guard, _) = hub.command_buffers.write(&mut token);
|
||||
let cmd_buf = CommandBuffer::get_encoder(&mut *cmd_buf_guard, encoder_id)?;
|
||||
cmd_buf.is_recording = false;
|
||||
// stop tracking the swapchain image, if used
|
||||
if let Some((ref sc_id, _)) = cmd_buf.used_swap_chain {
|
||||
let view_id = swap_chain_guard[sc_id.value]
|
||||
.acquired_view_id
|
||||
.as_ref()
|
||||
.expect("Used swap chain frame has already presented");
|
||||
cmd_buf.trackers.views.remove(view_id.value);
|
||||
}
|
||||
tracing::trace!("Command buffer {:?} {:#?}", encoder_id, cmd_buf.trackers);
|
||||
Ok(encoder_id)
|
||||
|
||||
let error = match CommandBuffer::get_encoder(&mut *cmd_buf_guard, encoder_id) {
|
||||
Ok(cmd_buf) => {
|
||||
cmd_buf.is_recording = false;
|
||||
// stop tracking the swapchain image, if used
|
||||
if let Some((ref sc_id, _)) = cmd_buf.used_swap_chain {
|
||||
let view_id = swap_chain_guard[sc_id.value]
|
||||
.acquired_view_id
|
||||
.as_ref()
|
||||
.expect("Used swap chain frame has already presented");
|
||||
cmd_buf.trackers.views.remove(view_id.value);
|
||||
}
|
||||
tracing::trace!("Command buffer {:?} {:#?}", encoder_id, cmd_buf.trackers);
|
||||
None
|
||||
}
|
||||
Err(e) => Some(e),
|
||||
};
|
||||
|
||||
(encoder_id, error)
|
||||
}
|
||||
|
||||
pub fn command_encoder_push_debug_group<B: GfxBackend>(
|
||||
|
@ -2206,10 +2206,10 @@ impl<B: hal::Backend> crate::hub::Resource for Device<B> {
|
||||
}
|
||||
|
||||
#[error("device is invalid")]
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub struct InvalidDevice;
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum DeviceError {
|
||||
#[error("parent device is invalid")]
|
||||
Invalid,
|
||||
@ -3288,72 +3288,66 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
device_id: id::DeviceId,
|
||||
desc: &wgt::CommandEncoderDescriptor<Label>,
|
||||
id_in: Input<G, id::CommandEncoderId>,
|
||||
) -> Result<id::CommandEncoderId, command::CommandAllocatorError> {
|
||||
) -> (id::CommandEncoderId, Option<command::CommandAllocatorError>) {
|
||||
span!(_guard, INFO, "Device::create_command_encoder");
|
||||
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
|
||||
let (device_guard, mut token) = hub.devices.read(&mut token);
|
||||
let device = device_guard
|
||||
.get(device_id)
|
||||
.map_err(|_| DeviceError::Invalid)?;
|
||||
let error = loop {
|
||||
let device = match device_guard.get(device_id) {
|
||||
Ok(device) => device,
|
||||
Err(_) => break DeviceError::Invalid.into(),
|
||||
};
|
||||
|
||||
let dev_stored = Stored {
|
||||
value: id::Valid(device_id),
|
||||
ref_count: device.life_guard.add_ref(),
|
||||
let dev_stored = Stored {
|
||||
value: id::Valid(device_id),
|
||||
ref_count: device.life_guard.add_ref(),
|
||||
};
|
||||
|
||||
let mut command_buffer = match device.cmd_allocator.allocate(
|
||||
dev_stored,
|
||||
&device.raw,
|
||||
device.limits.clone(),
|
||||
device.private_features,
|
||||
&desc.label,
|
||||
#[cfg(feature = "trace")]
|
||||
device.trace.is_some(),
|
||||
) {
|
||||
Ok(cmd_buf) => cmd_buf,
|
||||
Err(e) => break e,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let raw_command_buffer = command_buffer.raw.last_mut().unwrap();
|
||||
if let Some(ref label) = desc.label {
|
||||
device
|
||||
.raw
|
||||
.set_command_buffer_name(raw_command_buffer, label);
|
||||
}
|
||||
raw_command_buffer.begin_primary(hal::command::CommandBufferFlags::ONE_TIME_SUBMIT);
|
||||
}
|
||||
|
||||
let id = hub
|
||||
.command_buffers
|
||||
.register_identity(id_in, command_buffer, &mut token);
|
||||
|
||||
return (id.0, None);
|
||||
};
|
||||
|
||||
let mut command_buffer = device.cmd_allocator.allocate(
|
||||
dev_stored,
|
||||
&device.raw,
|
||||
device.limits.clone(),
|
||||
device.private_features,
|
||||
&desc.label,
|
||||
#[cfg(feature = "trace")]
|
||||
device.trace.is_some(),
|
||||
)?;
|
||||
|
||||
unsafe {
|
||||
let raw_command_buffer = command_buffer.raw.last_mut().unwrap();
|
||||
if let Some(ref label) = desc.label {
|
||||
device
|
||||
.raw
|
||||
.set_command_buffer_name(raw_command_buffer, label);
|
||||
}
|
||||
raw_command_buffer.begin_primary(hal::command::CommandBufferFlags::ONE_TIME_SUBMIT);
|
||||
}
|
||||
|
||||
let id = hub
|
||||
.command_buffers
|
||||
.register_identity(id_in, command_buffer, &mut token);
|
||||
|
||||
Ok(id.0)
|
||||
}
|
||||
|
||||
pub fn command_encoder_error<B: GfxBackend>(
|
||||
&self,
|
||||
id_in: Input<G, id::CommandEncoderId>,
|
||||
) -> id::CommandEncoderId {
|
||||
B::hub(self)
|
||||
.command_buffers
|
||||
.register_error(id_in, "", &mut Token::root())
|
||||
let id = B::hub(self).command_buffers.register_error(
|
||||
id_in,
|
||||
desc.label.borrow_or_default(),
|
||||
&mut token,
|
||||
);
|
||||
(id, Some(error))
|
||||
}
|
||||
|
||||
pub fn command_buffer_label<B: GfxBackend>(&self, id: id::CommandBufferId) -> String {
|
||||
B::hub(self).command_buffers.label_for_resource(id)
|
||||
}
|
||||
|
||||
pub fn command_buffer_error<B: GfxBackend>(
|
||||
&self,
|
||||
id_in: Input<G, id::CommandBufferId>,
|
||||
label: Option<&str>,
|
||||
) -> id::CommandBufferId {
|
||||
B::hub(self)
|
||||
.command_buffers
|
||||
.register_error(id_in, label.unwrap_or(""), &mut Token::root())
|
||||
}
|
||||
|
||||
pub fn command_encoder_drop<B: GfxBackend>(&self, command_encoder_id: id::CommandEncoderId) {
|
||||
span!(_guard, INFO, "CommandEncoder::drop");
|
||||
|
||||
@ -3380,28 +3374,81 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
&self,
|
||||
device_id: id::DeviceId,
|
||||
desc: &command::RenderBundleEncoderDescriptor,
|
||||
) -> Result<id::RenderBundleEncoderId, command::CreateRenderBundleError> {
|
||||
) -> (
|
||||
id::RenderBundleEncoderId,
|
||||
Option<command::CreateRenderBundleError>,
|
||||
) {
|
||||
span!(_guard, INFO, "Device::create_render_bundle_encoder");
|
||||
let encoder = command::RenderBundleEncoder::new(desc, device_id, None);
|
||||
encoder.map(|encoder| Box::into_raw(Box::new(encoder)))
|
||||
let (encoder, error) = match command::RenderBundleEncoder::new(desc, device_id, None) {
|
||||
Ok(encoder) => (encoder, None),
|
||||
Err(e) => (command::RenderBundleEncoder::dummy(device_id), Some(e)),
|
||||
};
|
||||
(Box::into_raw(Box::new(encoder)), error)
|
||||
}
|
||||
|
||||
pub fn render_bundle_encoder_finish<B: GfxBackend>(
|
||||
&self,
|
||||
bundle_encoder: command::RenderBundleEncoder,
|
||||
desc: &command::RenderBundleDescriptor,
|
||||
id_in: Input<G, id::RenderBundleId>,
|
||||
) -> (id::RenderBundleId, Option<command::RenderBundleError>) {
|
||||
span!(_guard, INFO, "RenderBundleEncoder::finish");
|
||||
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
let (device_guard, mut token) = hub.devices.read(&mut token);
|
||||
|
||||
let error = loop {
|
||||
let device = match device_guard.get(bundle_encoder.parent()) {
|
||||
Ok(device) => device,
|
||||
Err(_) => break command::RenderBundleError::INVALID_DEVICE,
|
||||
};
|
||||
|
||||
let render_bundle = match bundle_encoder.finish(desc, device, &hub, &mut token) {
|
||||
Ok(bundle) => bundle,
|
||||
Err(e) => break e,
|
||||
};
|
||||
|
||||
tracing::debug!("Render bundle {:?} = {:#?}", id_in, render_bundle.used);
|
||||
|
||||
let ref_count = render_bundle.life_guard.add_ref();
|
||||
let id = hub
|
||||
.render_bundles
|
||||
.register_identity(id_in, render_bundle, &mut token);
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref trace) = device.trace {
|
||||
let (bundle_guard, _) = hub.render_bundles.read(&mut token);
|
||||
let bundle = &bundle_guard[id];
|
||||
let label = desc.label.as_ref().map(|l| l.as_ref());
|
||||
trace.lock().add(trace::Action::CreateRenderBundle {
|
||||
id: id.0,
|
||||
desc: trace::new_render_bundle_encoder_descriptor(label, &bundle.context),
|
||||
base: bundle.to_base_pass(),
|
||||
});
|
||||
}
|
||||
|
||||
device
|
||||
.trackers
|
||||
.lock()
|
||||
.bundles
|
||||
.init(id, ref_count, PhantomData)
|
||||
.unwrap();
|
||||
return (id.0, None);
|
||||
};
|
||||
|
||||
let id = B::hub(self).render_bundles.register_error(
|
||||
id_in,
|
||||
desc.label.borrow_or_default(),
|
||||
&mut token,
|
||||
);
|
||||
(id, Some(error))
|
||||
}
|
||||
|
||||
pub fn render_bundle_label<B: GfxBackend>(&self, id: id::RenderBundleId) -> String {
|
||||
B::hub(self).render_bundles.label_for_resource(id)
|
||||
}
|
||||
|
||||
pub fn render_bundle_error<B: GfxBackend>(
|
||||
&self,
|
||||
id_in: Input<G, id::RenderBundleId>,
|
||||
label: Option<&str>,
|
||||
) -> id::RenderBundleId {
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
let (_, mut token) = hub.devices.read(&mut token);
|
||||
hub.render_bundles
|
||||
.register_error(id_in, label.unwrap_or(""), &mut token)
|
||||
}
|
||||
|
||||
pub fn render_bundle_drop<B: GfxBackend>(&self, render_bundle_id: id::RenderBundleId) {
|
||||
span!(_guard, INFO, "RenderBundle::drop");
|
||||
let hub = B::hub(self);
|
||||
@ -3529,18 +3576,6 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
B::hub(self).render_pipelines.label_for_resource(id)
|
||||
}
|
||||
|
||||
pub fn render_pipeline_error<B: GfxBackend>(
|
||||
&self,
|
||||
id_in: Input<G, id::RenderPipelineId>,
|
||||
label: Option<&str>,
|
||||
) -> id::RenderPipelineId {
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
let (_, mut token) = hub.devices.read(&mut token);
|
||||
hub.render_pipelines
|
||||
.register_error(id_in, label.unwrap_or(""), &mut token)
|
||||
}
|
||||
|
||||
pub fn render_pipeline_drop<B: GfxBackend>(&self, render_pipeline_id: id::RenderPipelineId) {
|
||||
span!(_guard, INFO, "RenderPipeline::drop");
|
||||
let hub = B::hub(self);
|
||||
|
@ -417,7 +417,7 @@ impl AdapterInfo {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
/// Error when requesting a device from the adaptor
|
||||
pub enum RequestDeviceError {
|
||||
#[error("parent adapter is invalid")]
|
||||
|
@ -57,7 +57,7 @@ impl<B: hal::Backend> Resource for ShaderModule<B> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum CreateShaderModuleError {
|
||||
#[error(transparent)]
|
||||
Device(#[from] DeviceError),
|
||||
@ -80,7 +80,7 @@ pub struct ProgrammableStageDescriptor<'a> {
|
||||
/// Number of implicit bind groups derived at pipeline creation.
|
||||
pub type ImplicitBindGroupCount = u8;
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum ImplicitLayoutError {
|
||||
#[error("missing IDs for deriving {0} bind groups")]
|
||||
MissingIds(ImplicitBindGroupCount),
|
||||
@ -104,7 +104,7 @@ pub struct ComputePipelineDescriptor<'a> {
|
||||
pub compute_stage: ProgrammableStageDescriptor<'a>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum CreateComputePipelineError {
|
||||
#[error(transparent)]
|
||||
Device(#[from] DeviceError),
|
||||
@ -193,7 +193,7 @@ pub struct RenderPipelineDescriptor<'a> {
|
||||
pub alpha_to_coverage_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum CreateRenderPipelineError {
|
||||
#[error(transparent)]
|
||||
Device(#[from] DeviceError),
|
||||
|
@ -126,7 +126,7 @@ impl BufferMapOperation {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum BufferAccessError {
|
||||
#[error(transparent)]
|
||||
Device(#[from] DeviceError),
|
||||
@ -166,7 +166,7 @@ pub struct Buffer<B: hal::Backend> {
|
||||
pub(crate) map_state: BufferMapState<B>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum CreateBufferError {
|
||||
#[error(transparent)]
|
||||
Device(#[from] DeviceError),
|
||||
@ -207,14 +207,14 @@ pub struct Texture<B: hal::Backend> {
|
||||
pub(crate) life_guard: LifeGuard,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum TextureErrorDimension {
|
||||
X,
|
||||
Y,
|
||||
Z,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum TextureDimensionError {
|
||||
#[error("Dimension {0:?} is zero")]
|
||||
Zero(TextureErrorDimension),
|
||||
@ -224,7 +224,7 @@ pub enum TextureDimensionError {
|
||||
InvalidSampleCount(u32),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum CreateTextureError {
|
||||
#[error(transparent)]
|
||||
Device(#[from] DeviceError),
|
||||
@ -305,7 +305,7 @@ pub struct TextureView<B: hal::Backend> {
|
||||
pub(crate) life_guard: LifeGuard,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum CreateTextureViewError {
|
||||
#[error("parent texture is invalid or destroyed")]
|
||||
InvalidTexture,
|
||||
@ -411,7 +411,7 @@ pub struct Sampler<B: hal::Backend> {
|
||||
pub(crate) comparison: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum CreateSamplerError {
|
||||
#[error(transparent)]
|
||||
Device(#[from] DeviceError),
|
||||
|
@ -8,7 +8,7 @@ use std::collections::hash_map::Entry;
|
||||
use thiserror::Error;
|
||||
use wgt::{BindGroupLayoutEntry, BindingType};
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
#[error("buffer usage is {actual:?} which does not contain required usage {expected:?}")]
|
||||
pub struct MissingBufferUsageError {
|
||||
pub(crate) actual: wgt::BufferUsage,
|
||||
@ -28,7 +28,7 @@ pub fn check_buffer_usage(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
#[error("texture usage is {actual:?} which does not contain required usage {expected:?}")]
|
||||
pub struct MissingTextureUsageError {
|
||||
pub(crate) actual: wgt::TextureUsage,
|
||||
@ -48,7 +48,7 @@ pub fn check_texture_usage(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum BindingError {
|
||||
#[error("binding is missing from the pipeline layout")]
|
||||
Missing,
|
||||
@ -78,7 +78,7 @@ pub enum BindingError {
|
||||
BadStorageFormat(wgt::TextureFormat),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum InputError {
|
||||
#[error("input is not provided by the earlier stage in the pipeline")]
|
||||
Missing,
|
||||
@ -87,7 +87,7 @@ pub enum InputError {
|
||||
}
|
||||
|
||||
/// Errors produced when validating a programmable stage of a pipeline.
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum StageError {
|
||||
#[error("shader module is invalid")]
|
||||
InvalidModule,
|
||||
|
Loading…
Reference in New Issue
Block a user