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