Skip to main content

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    /// Creates the bind groups for indirect validation shaders to read from `buffer`.
84    ///
85    /// `buffer_size` is the user-requested size of the buffer.
86    ///
87    /// `Ok(None)` will only be returned if `buffer_size` is `0`.
88    pub(crate) fn new(
89        indirect_validation: &IndirectValidation,
90        device: &crate::device::Device,
91        buffer_size: u64,
92        buffer: &dyn hal::DynBuffer,
93    ) -> Result<Option<Self>, DeviceError> {
94        let dispatch = indirect_validation.dispatch.create_src_bind_group(
95            device.raw(),
96            &device.limits,
97            buffer_size,
98            buffer,
99            device.instance_flags,
100        )?;
101        let draw = indirect_validation.draw.create_src_bind_group(
102            device.raw(),
103            &device.adapter.limits(),
104            buffer_size,
105            buffer,
106            device.instance_flags,
107        )?;
108
109        match (dispatch, draw) {
110            (None, None) => Ok(None),
111            (None, Some(_)) => unreachable!(),
112            (Some(_), None) => unreachable!(),
113            (Some(dispatch), Some(draw)) => Ok(Some(Self { dispatch, draw })),
114        }
115    }
116
117    pub(crate) fn dispose(self, device: &dyn hal::DynDevice) {
118        let Self { dispatch, draw } = self;
119
120        unsafe {
121            device.destroy_bind_group(dispatch);
122            device.destroy_bind_group(draw);
123        }
124    }
125}