Skip to main content

wgpu_core/command/
transition_resources.rs

1use alloc::{sync::Arc, vec::Vec};
2
3use thiserror::Error;
4use wgt::error::{ErrorType, WebGpuError};
5
6use crate::{
7    command::{encoder::EncodingState, ArcCommand, CommandEncoder, EncoderStateError},
8    device::DeviceError,
9    global::Global,
10    id::{BufferId, CommandEncoderId, TextureId},
11    resource::{Buffer, InvalidResourceError, ParentDevice, Texture},
12    track::ResourceUsageCompatibilityError,
13};
14
15impl Global {
16    pub fn command_encoder_transition_resources(
17        &self,
18        command_encoder_id: CommandEncoderId,
19        buffer_transitions: impl Iterator<Item = wgt::BufferTransition<BufferId>>,
20        texture_transitions: impl Iterator<Item = wgt::TextureTransition<TextureId>>,
21    ) -> Result<(), EncoderStateError> {
22        profiling::scope!("CommandEncoder::transition_resources");
23
24        let hub = &self.hub;
25
26        // Lock command encoder for recording
27        let cmd_enc = hub.command_encoders.get(command_encoder_id);
28        let mut cmd_buf_data = cmd_enc.data.lock();
29        let snatch_guard = cmd_enc.device.snatchable_lock.read();
30        cmd_buf_data.push_with(|| -> Result<_, TransitionResourcesError> {
31            Ok(ArcCommand::TransitionResources {
32                buffer_transitions: buffer_transitions
33                    .map(|t| {
34                        Ok(wgt::BufferTransition {
35                            buffer: self.resolve_buffer_id(t.buffer)?,
36                            state: t.state,
37                        })
38                    })
39                    .collect::<Result<_, TransitionResourcesError>>()?,
40                texture_transitions: texture_transitions
41                    .map(|t| {
42                        let texture = self.resolve_texture_id(t.texture);
43                        texture.check_valid(&snatch_guard)?;
44                        Ok(wgt::TextureTransition {
45                            texture,
46                            selector: t.selector,
47                            state: t.state,
48                        })
49                    })
50                    .collect::<Result<_, TransitionResourcesError>>()?,
51            })
52        })
53    }
54}
55
56#[inline(never)]
57pub(crate) fn transition_resources(
58    state: &mut EncodingState,
59    buffer_transitions: Vec<wgt::BufferTransition<Arc<Buffer>>>,
60    texture_transitions: Vec<wgt::TextureTransition<Arc<Texture>>>,
61) -> Result<(), TransitionResourcesError> {
62    let mut usage_scope = state.device.new_usage_scope();
63    let indices = &state.device.tracker_indices;
64    usage_scope.buffers.set_size(indices.buffers.size());
65    usage_scope.textures.set_size(indices.textures.size());
66
67    // Process buffer transitions
68    for buffer_transition in buffer_transitions {
69        buffer_transition.buffer.same_device(state.device)?;
70
71        usage_scope
72            .buffers
73            .merge_single(&buffer_transition.buffer, buffer_transition.state)?;
74    }
75
76    // Process texture transitions
77    for texture_transition in texture_transitions {
78        texture_transition.texture.same_device(state.device)?;
79
80        unsafe {
81            usage_scope.textures.merge_single(
82                &texture_transition.texture,
83                texture_transition.selector,
84                texture_transition.state,
85            )
86        }?;
87    }
88
89    // Record any needed barriers based on tracker data
90    CommandEncoder::insert_barriers_from_scope(
91        state.raw_encoder,
92        state.tracker,
93        &usage_scope,
94        state.snatch_guard,
95    );
96    Ok(())
97}
98
99/// Error encountered while attempting to perform [`Global::command_encoder_transition_resources`].
100#[derive(Clone, Debug, Error)]
101#[non_exhaustive]
102pub enum TransitionResourcesError {
103    #[error(transparent)]
104    Device(#[from] DeviceError),
105    #[error(transparent)]
106    EncoderState(#[from] EncoderStateError),
107    #[error(transparent)]
108    InvalidResource(#[from] InvalidResourceError),
109    #[error(transparent)]
110    ResourceUsage(#[from] ResourceUsageCompatibilityError),
111}
112
113impl WebGpuError for TransitionResourcesError {
114    fn webgpu_error_type(&self) -> ErrorType {
115        match self {
116            Self::Device(e) => e.webgpu_error_type(),
117            Self::EncoderState(e) => e.webgpu_error_type(),
118            Self::InvalidResource(e) => e.webgpu_error_type(),
119            Self::ResourceUsage(e) => e.webgpu_error_type(),
120        }
121    }
122}