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 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 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 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 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 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#[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}