wgpu_core/indirect_validation/
mod.rs

1use crate::{
2    device::DeviceError,
3    pipeline::{CreateComputePipelineError, CreateShaderModuleError},
4};
5use alloc::boxed::Box;
6use scopeguard::{guard, ScopeGuard};
7use thiserror::Error;
8
9mod dispatch;
10mod draw;
11mod utils;
12
13pub(crate) use dispatch::Dispatch;
14pub(crate) use draw::{Draw, DrawBatcher, DrawResources};
15
16#[derive(Clone, Debug, Error)]
17#[non_exhaustive]
18enum CreateIndirectValidationPipelineError {
19    #[error(transparent)]
20    DeviceError(#[from] DeviceError),
21    #[error(transparent)]
22    ShaderModule(#[from] CreateShaderModuleError),
23    #[error(transparent)]
24    ComputePipeline(#[from] CreateComputePipelineError),
25}
26
27pub(crate) struct IndirectValidation {
28    pub(crate) dispatch: Dispatch,
29    pub(crate) draw: Draw,
30}
31
32impl IndirectValidation {
33    pub(crate) fn new(
34        device: &dyn hal::DynDevice,
35        required_limits: &wgt::Limits,
36        required_features: &wgt::Features,
37        instance_flags: wgt::InstanceFlags,
38        backend: wgt::Backend,
39    ) -> Result<Self, DeviceError> {
40        let dispatch = match Dispatch::new(device, instance_flags, required_limits) {
41            Ok(dispatch) => dispatch,
42            Err(e) => {
43                log::error!("indirect-validation error: {e:?}");
44                return Err(DeviceError::Lost);
45            }
46        };
47        let dispatch = guard(dispatch, |dispatch| dispatch.dispose(device));
48
49        let draw = match Draw::new(
50            device,
51            required_features,
52            instance_flags,
53            backend,
54            required_limits,
55        ) {
56            Ok(draw) => draw,
57            Err(e) => {
58                log::error!("indirect-draw-validation error: {e:?}");
59                return Err(DeviceError::Lost);
60            }
61        };
62        Ok(Self {
63            dispatch: ScopeGuard::into_inner(dispatch),
64            draw,
65        })
66    }
67
68    pub(crate) fn dispose(self, device: &dyn hal::DynDevice) {
69        let Self { dispatch, draw } = self;
70
71        dispatch.dispose(device);
72        draw.dispose(device);
73    }
74}
75
76#[derive(Debug)]
77pub(crate) struct BindGroups {
78    pub(crate) dispatch: Box<dyn hal::DynBindGroup>,
79    draw: Box<dyn hal::DynBindGroup>,
80}
81
82impl BindGroups {
83    /// `Ok(None)` will only be returned if `buffer_size` is `0`.
84    pub(crate) fn new(
85        indirect_validation: &IndirectValidation,
86        device: &crate::device::Device,
87        buffer_size: u64,
88        buffer: &dyn hal::DynBuffer,
89    ) -> Result<Option<Self>, DeviceError> {
90        let dispatch = indirect_validation.dispatch.create_src_bind_group(
91            device.raw(),
92            &device.limits,
93            buffer_size,
94            buffer,
95            device.instance_flags,
96        )?;
97        let draw = indirect_validation.draw.create_src_bind_group(
98            device.raw(),
99            &device.adapter.limits(),
100            buffer_size,
101            buffer,
102            device.instance_flags,
103        )?;
104
105        match (dispatch, draw) {
106            (None, None) => Ok(None),
107            (None, Some(_)) => unreachable!(),
108            (Some(_), None) => unreachable!(),
109            (Some(dispatch), Some(draw)) => Ok(Some(Self { dispatch, draw })),
110        }
111    }
112
113    pub(crate) fn dispose(self, device: &dyn hal::DynDevice) {
114        let Self { dispatch, draw } = self;
115
116        unsafe {
117            device.destroy_bind_group(dispatch);
118            device.destroy_bind_group(draw);
119        }
120    }
121}