Skip to content

Commit afee8a5

Browse files
committed
feat(core): Add ComputePass::transition_resources
1 parent 3a8b7ea commit afee8a5

12 files changed

Lines changed: 290 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Bottom level categories:
5050
- Added "limit bucketing" functionality which can adjust adapter limits and features to match one of several pre-defined buckets. This is controlled by the new `apply_limit_buckets` member in `RequestAdapterOptions`, which is `false` by default. By @andyleiserson in [#9119](https://github.com/gfx-rs/wgpu/pull/9119).
5151
- Make `wgpu_types::texture::format::TextureChannel` accessible as `wgpu::TextureChannel`. By @TornaxO7 in [#9394](https://github.com/gfx-rs/wgpu/pull/9349).
5252
- Add support for `per_vertex` in Metal and DX12, as well as some validation for `per_vertex`, and a new enable extension, `wgpu_per_vertex`. By @inner-daemons in [#9219](https://github.com/gfx-rs/wgpu/pull/9219).
53+
- Add `ComputePass` version of `CommandEncoder::transition_resources` that allows intra-pass transitions. By @wingertge in [#9371](https://github.com/gfx-rs/wgpu/pull/9371).
5354

5455
#### Metal
5556

player/src/lib.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,26 @@ impl Player {
10731073
query_index,
10741074
},
10751075
C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery,
1076+
C::TransitionResources {
1077+
buffer_transitions,
1078+
texture_transitions,
1079+
} => C::TransitionResources {
1080+
buffer_transitions: buffer_transitions
1081+
.into_iter()
1082+
.map(|buffer_transition| wgt::BufferTransition {
1083+
buffer: self.resolve_buffer_id(buffer_transition.buffer),
1084+
state: buffer_transition.state,
1085+
})
1086+
.collect(),
1087+
texture_transitions: texture_transitions
1088+
.into_iter()
1089+
.map(|texture_transition| wgt::TextureTransition {
1090+
texture: self.resolve_texture_view_id(texture_transition.texture),
1091+
selector: texture_transition.selector,
1092+
state: texture_transition.state,
1093+
})
1094+
.collect(),
1095+
},
10761096
}
10771097
}
10781098

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use wgpu_test::{gpu_test, GpuTestConfiguration, GpuTestInitializer, TestParameters};
2+
3+
pub fn all_tests(vec: &mut Vec<GpuTestInitializer>) {
4+
vec.push(COMPUTE_PASS_TRANSITION_RESOURCES);
5+
}
6+
7+
#[gpu_test]
8+
static COMPUTE_PASS_TRANSITION_RESOURCES: GpuTestConfiguration = GpuTestConfiguration::new()
9+
.parameters(TestParameters::default().enable_noop())
10+
.run_sync(|ctx| {
11+
let buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
12+
label: None,
13+
size: 128,
14+
usage: wgpu::BufferUsages::STORAGE,
15+
mapped_at_creation: false,
16+
});
17+
18+
let mut encoder = ctx
19+
.device
20+
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
21+
let mut pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
22+
label: None,
23+
timestamp_writes: None,
24+
});
25+
26+
pass.transition_resources(
27+
[wgpu::BufferTransition {
28+
buffer: &buffer,
29+
state: wgpu::BufferUses::STORAGE_READ_WRITE,
30+
}]
31+
.into_iter(),
32+
core::iter::empty(),
33+
);
34+
35+
drop(pass);
36+
37+
ctx.queue.submit([encoder.finish()]);
38+
});

tests/tests/wgpu-gpu/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ mod clear_texture;
2323
mod clip_distances;
2424
mod cloneable_types;
2525
mod compute_pass_ownership;
26+
mod compute_pass_transition_resources;
2627
mod create_surface_error;
2728
mod device;
2829
mod dispatch_workgroups_indirect;
@@ -155,6 +156,7 @@ fn all_tests() -> Vec<wgpu_test::GpuTestInitializer> {
155156
transfer::all_tests(&mut tests);
156157
transient::all_tests(&mut tests);
157158
transition_resources::all_tests(&mut tests);
159+
compute_pass_transition_resources::all_tests(&mut tests);
158160
vertex_formats::all_tests(&mut tests);
159161
vertex_indices::all_tests(&mut tests);
160162
vertex_state::all_tests(&mut tests);

wgpu-core/src/command/compute.rs

Lines changed: 123 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::{
2121
ArcCommand, ArcPassTimestampWrites, BasePass, BindGroupStateChange, CommandEncoder,
2222
CommandEncoderError, DebugGroupError, EncoderStateError, InnerCommandEncoder, MapPassErr,
2323
PassErrorScope, PassStateError, PassTimestampWrites, QueryUseError, StateChange,
24-
TimestampWritesError,
24+
TimestampWritesError, TransitionResourcesError,
2525
},
2626
device::{Device, DeviceError, MissingDownlevelFlags, MissingFeatures},
2727
global::Global,
@@ -30,9 +30,9 @@ use crate::{
3030
pipeline::ComputePipeline,
3131
resource::{
3232
self, Buffer, DestroyedResourceError, InvalidResourceError, Labeled,
33-
MissingBufferUsageError, ParentDevice, RawResourceAccess, Trackable,
33+
MissingBufferUsageError, ParentDevice, RawResourceAccess, TextureView, Trackable,
3434
},
35-
track::{ResourceUsageCompatibilityError, Tracker},
35+
track::{ResourceUsageCompatibilityError, TextureViewBindGroupState, Tracker},
3636
Label,
3737
};
3838

@@ -179,6 +179,8 @@ pub enum ComputePassErrorInner {
179179
#[error(transparent)]
180180
QueryUse(#[from] QueryUseError),
181181
#[error(transparent)]
182+
TransitionResources(#[from] TransitionResourcesError),
183+
#[error(transparent)]
182184
MissingFeatures(#[from] MissingFeatures),
183185
#[error(transparent)]
184186
MissingDownlevelFlags(#[from] MissingDownlevelFlags),
@@ -235,6 +237,7 @@ impl WebGpuError for ComputePassError {
235237
ComputePassErrorInner::Bind(e) => e.webgpu_error_type(),
236238
ComputePassErrorInner::ImmediateData(e) => e.webgpu_error_type(),
237239
ComputePassErrorInner::QueryUse(e) => e.webgpu_error_type(),
240+
ComputePassErrorInner::TransitionResources(e) => e.webgpu_error_type(),
238241
ComputePassErrorInner::MissingFeatures(e) => e.webgpu_error_type(),
239242
ComputePassErrorInner::MissingDownlevelFlags(e) => e.webgpu_error_type(),
240243
ComputePassErrorInner::InvalidResource(e) => e.webgpu_error_type(),
@@ -368,6 +371,70 @@ impl<'scope, 'snatch_guard, 'cmd_enc> State<'scope, 'snatch_guard, 'cmd_enc> {
368371
}
369372
}
370373

374+
/// Compute pass version of [`CommandEncoder::transition_resources`](crate::CommandEncoder::transition_resources).
375+
/// See also `State::flush_bindings` for details on the implementation.
376+
fn transition_resources(
377+
state: &mut State,
378+
buffer_transitions: Vec<wgt::BufferTransition<Arc<Buffer>>>,
379+
texture_transitions: Vec<wgt::TextureTransition<Arc<TextureView>>>,
380+
) -> Result<(), TransitionResourcesError> {
381+
let indices = &state.pass.base.device.tracker_indices;
382+
state.pass.scope.buffers.set_size(indices.buffers.size());
383+
state.pass.scope.textures.set_size(indices.textures.size());
384+
385+
let mut buffer_ids = Vec::with_capacity(buffer_transitions.len());
386+
let mut textures = TextureViewBindGroupState::new();
387+
388+
// Process buffer transitions
389+
for buffer_transition in buffer_transitions {
390+
buffer_transition
391+
.buffer
392+
.same_device(state.pass.base.device)?;
393+
394+
state
395+
.pass
396+
.scope
397+
.buffers
398+
.merge_single(&buffer_transition.buffer, buffer_transition.state)?;
399+
buffer_ids.push(buffer_transition.buffer.tracker_index());
400+
}
401+
402+
state
403+
.intermediate_trackers
404+
.buffers
405+
.set_and_remove_from_usage_scope_sparse(&mut state.pass.scope.buffers, buffer_ids);
406+
407+
// Process texture transitions
408+
for texture_transition in texture_transitions {
409+
texture_transition
410+
.texture
411+
.same_device(state.pass.base.device)?;
412+
413+
unsafe {
414+
state.pass.scope.textures.merge_single(
415+
&texture_transition.texture.parent,
416+
texture_transition.selector,
417+
texture_transition.state,
418+
)
419+
}?;
420+
421+
textures.insert_single(texture_transition.texture, texture_transition.state);
422+
}
423+
424+
state
425+
.intermediate_trackers
426+
.textures
427+
.set_and_remove_from_usage_scope_sparse(&mut state.pass.scope.textures, &textures);
428+
429+
// Record any needed barriers based on tracker data
430+
CommandEncoder::drain_barriers(
431+
state.pass.base.raw_encoder,
432+
&mut state.intermediate_trackers,
433+
state.pass.base.snatch_guard,
434+
);
435+
Ok(())
436+
}
437+
371438
// Running the compute pass.
372439

373440
impl Global {
@@ -729,6 +796,14 @@ pub(super) fn encode_compute_pass(
729796
end_pipeline_statistics_query(state.pass.base.raw_encoder, &mut state.active_query)
730797
.map_pass_err(scope)?;
731798
}
799+
ArcComputeCommand::TransitionResources {
800+
buffer_transitions,
801+
texture_transitions,
802+
} => {
803+
let scope = PassErrorScope::TransitionResources;
804+
transition_resources(&mut state, buffer_transitions, texture_transitions)
805+
.map_pass_err(scope)?;
806+
}
732807
}
733808
}
734809

@@ -1316,4 +1391,49 @@ impl Global {
13161391

13171392
Ok(())
13181393
}
1394+
1395+
pub fn compute_pass_transition_resources(
1396+
&self,
1397+
pass: &mut ComputePass,
1398+
buffer_transitions: impl Iterator<Item = wgt::BufferTransition<id::BufferId>>,
1399+
texture_transitions: impl Iterator<Item = wgt::TextureTransition<id::TextureViewId>>,
1400+
) -> Result<(), PassStateError> {
1401+
let scope = PassErrorScope::TransitionResources;
1402+
let base = pass_base!(pass, scope);
1403+
1404+
let hub = &self.hub;
1405+
let buffer_transitions = pass_try!(
1406+
base,
1407+
scope,
1408+
buffer_transitions
1409+
.map(|buffer_transition| -> Result<_, InvalidResourceError> {
1410+
Ok(wgt::BufferTransition {
1411+
buffer: hub.buffers.get(buffer_transition.buffer).get()?,
1412+
state: buffer_transition.state,
1413+
})
1414+
})
1415+
.collect::<Result<Vec<_>, _>>()
1416+
);
1417+
1418+
let texture_transitions = pass_try!(
1419+
base,
1420+
scope,
1421+
texture_transitions
1422+
.map(|texture_transition| -> Result<_, InvalidResourceError> {
1423+
Ok(wgt::TextureTransition {
1424+
texture: hub.texture_views.get(texture_transition.texture).get()?,
1425+
selector: texture_transition.selector,
1426+
state: texture_transition.state,
1427+
})
1428+
})
1429+
.collect::<Result<Vec<_>, _>>()
1430+
);
1431+
1432+
base.commands.push(ArcComputeCommand::TransitionResources {
1433+
buffer_transitions,
1434+
texture_transitions,
1435+
});
1436+
1437+
Ok(())
1438+
}
13191439
}

wgpu-core/src/command/compute_command.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use alloc::vec::Vec;
2+
13
#[cfg(feature = "serde")]
24
use crate::command::serde_object_reference_struct;
35
use crate::command::{ArcReferences, ReferenceType};
@@ -64,6 +66,11 @@ pub enum ComputeCommand<R: ReferenceType> {
6466
},
6567

6668
EndPipelineStatisticsQuery,
69+
70+
TransitionResources {
71+
buffer_transitions: Vec<wgt::BufferTransition<R::Buffer>>,
72+
texture_transitions: Vec<wgt::TextureTransition<R::TextureView>>,
73+
},
6774
}
6875

6976
/// cbindgen:ignore

wgpu-core/src/command/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,6 +2047,8 @@ pub enum PassErrorScope {
20472047
BeginPipelineStatisticsQuery,
20482048
#[error("In a end_pipeline_statistics_query command")]
20492049
EndPipelineStatisticsQuery,
2050+
#[error("In a transition_resources command")]
2051+
TransitionResources,
20502052
#[error("In a execute_bundle command")]
20512053
ExecuteBundle,
20522054
#[error("In a dispatch command, indirect:{indirect}")]

wgpu-core/src/device/trace/record.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,26 @@ impl IntoTrace for ArcComputeCommand {
492492
query_index,
493493
},
494494
C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery,
495+
C::TransitionResources {
496+
buffer_transitions,
497+
texture_transitions,
498+
} => C::TransitionResources {
499+
buffer_transitions: buffer_transitions
500+
.into_iter()
501+
.map(|buffer_transition| wgt::BufferTransition {
502+
buffer: buffer_transition.buffer.into_trace(),
503+
state: buffer_transition.state,
504+
})
505+
.collect(),
506+
texture_transitions: texture_transitions
507+
.into_iter()
508+
.map(|texture_transition| wgt::TextureTransition {
509+
texture: texture_transition.texture.into_trace(),
510+
selector: texture_transition.selector,
511+
state: texture_transition.state,
512+
})
513+
.collect(),
514+
},
495515
}
496516
}
497517
}

wgpu/src/api/compute_pass.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,31 @@ impl ComputePass<'_> {
102102
.dispatch_workgroups_indirect(&indirect_buffer.inner, indirect_offset);
103103
}
104104

105+
/// Transition resources to an underlying hal resource state. Compute pass version of
106+
/// [`CommandEncoder::transition_resources`].
107+
///
108+
/// This is an advanced, native-only API (no-op on web). Useful for native interoperability.
109+
///
110+
/// A user wanting to interoperate with the underlying native graphics APIs (Vulkan, DirectX12, Metal, etc) can use this API to generate barriers between wgpu commands and
111+
/// the native API commands, for synchronization and resource state transition purposes.
112+
pub fn transition_resources<'a>(
113+
&mut self,
114+
buffer_transitions: impl Iterator<Item = wgt::BufferTransition<&'a Buffer>>,
115+
texture_transitions: impl Iterator<Item = wgt::TextureTransition<&'a TextureView>>,
116+
) {
117+
self.inner.transition_resources(
118+
&mut buffer_transitions.map(|t| wgt::BufferTransition {
119+
buffer: &t.buffer.inner,
120+
state: t.state,
121+
}),
122+
&mut texture_transitions.map(|t| wgt::TextureTransition {
123+
texture: &t.texture.inner,
124+
selector: t.selector,
125+
state: t.state,
126+
}),
127+
);
128+
}
129+
105130
impl_deferred_command_buffer_actions!();
106131

107132
#[cfg(custom)]

wgpu/src/backend/webgpu.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3392,6 +3392,18 @@ impl dispatch::ComputePassInterface for WebComputePassEncoder {
33923392
self.inner
33933393
.dispatch_workgroups_indirect_with_f64(&indirect_buffer.inner, indirect_offset as f64);
33943394
}
3395+
3396+
fn transition_resources<'a>(
3397+
&mut self,
3398+
_buffer_transitions: &mut dyn Iterator<
3399+
Item = wgt::BufferTransition<&'a dispatch::DispatchBuffer>,
3400+
>,
3401+
_texture_transitions: &mut dyn Iterator<
3402+
Item = wgt::TextureTransition<&'a dispatch::DispatchTextureView>,
3403+
>,
3404+
) {
3405+
// noop
3406+
}
33953407
}
33963408
impl Drop for WebComputePassEncoder {
33973409
fn drop(&mut self) {

0 commit comments

Comments
 (0)