wgpu_core/command/
transition_resources.rs1use 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 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 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 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 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#[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}