wgpu_core/command/
transition_resources.rs

1use thiserror::Error;
2use wgt::error::{ErrorType, WebGpuError};
3
4use crate::{
5    command::{CommandBuffer, 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_buf = hub
26            .command_buffers
27            .get(command_encoder_id.into_command_buffer_id());
28        let mut cmd_buf_data = cmd_buf.data.lock();
29        cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
30            // Get and lock device
31            let device = &cmd_buf.device;
32            device.check_is_valid()?;
33            let snatch_guard = &device.snatchable_lock.read();
34
35            let mut usage_scope = device.new_usage_scope();
36            let indices = &device.tracker_indices;
37            usage_scope.buffers.set_size(indices.buffers.size());
38            usage_scope.textures.set_size(indices.textures.size());
39
40            // Process buffer transitions
41            for buffer_transition in buffer_transitions {
42                let buffer = hub.buffers.get(buffer_transition.buffer).get()?;
43                buffer.same_device_as(cmd_buf.as_ref())?;
44
45                usage_scope
46                    .buffers
47                    .merge_single(&buffer, buffer_transition.state)?;
48            }
49
50            // Process texture transitions
51            for texture_transition in texture_transitions {
52                let texture = hub.textures.get(texture_transition.texture).get()?;
53                texture.same_device_as(cmd_buf.as_ref())?;
54
55                unsafe {
56                    usage_scope.textures.merge_single(
57                        &texture,
58                        texture_transition.selector,
59                        texture_transition.state,
60                    )
61                }?;
62            }
63
64            // Record any needed barriers based on tracker data
65            let cmd_buf_raw = cmd_buf_data.encoder.open()?;
66            CommandBuffer::insert_barriers_from_scope(
67                cmd_buf_raw,
68                &mut cmd_buf_data.trackers,
69                &usage_scope,
70                snatch_guard,
71            );
72            Ok(())
73        })
74    }
75}
76
77/// Error encountered while attempting to perform [`Global::command_encoder_transition_resources`].
78#[derive(Clone, Debug, Error)]
79#[non_exhaustive]
80pub enum TransitionResourcesError {
81    #[error(transparent)]
82    Device(#[from] DeviceError),
83    #[error(transparent)]
84    EncoderState(#[from] EncoderStateError),
85    #[error(transparent)]
86    InvalidResource(#[from] InvalidResourceError),
87    #[error(transparent)]
88    ResourceUsage(#[from] ResourceUsageCompatibilityError),
89}
90
91impl WebGpuError for TransitionResourcesError {
92    fn webgpu_error_type(&self) -> ErrorType {
93        let e: &dyn WebGpuError = match self {
94            Self::Device(e) => e,
95            Self::EncoderState(e) => e,
96            Self::InvalidResource(e) => e,
97            Self::ResourceUsage(e) => e,
98        };
99        e.webgpu_error_type()
100    }
101}