wgpu_core/command/
transition_resources.rs

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