Skip to content

Commit 80f0700

Browse files
committed
[naga spv-in] Add support for Memory Barriers
1 parent 96c1fb1 commit 80f0700

27 files changed

+370
-68
lines changed

naga/src/back/dot/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ impl StatementGraph {
112112
}
113113
"Continue"
114114
}
115-
S::Barrier(_flags) => "Barrier",
115+
S::ControlBarrier(_flags) | S::MemoryBarrier(_flags) => "Barrier",
116116
S::Block(ref b) => {
117117
let (other, last) = self.add(b, targets);
118118
self.flow.push((id, other, ""));

naga/src/back/glsl/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2457,7 +2457,7 @@ impl<'a, W: Write> Writer<'a, W> {
24572457
// keyword which ceases all further processing in a fragment shader, it's called OpKill
24582458
// in spir-v that's why it's called `Statement::Kill`
24592459
Statement::Kill => writeln!(self.out, "{level}discard;")?,
2460-
Statement::Barrier(flags) => {
2460+
Statement::ControlBarrier(flags) | Statement::MemoryBarrier(flags) => {
24612461
self.write_barrier(flags, level)?;
24622462
}
24632463
// Stores in glsl are just variable assignments written as `pointer = value;`

naga/src/back/hlsl/writer.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,7 +1618,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
16181618
}
16191619

16201620
writeln!(self.out, "{level}}}")?;
1621-
self.write_barrier(crate::Barrier::WORK_GROUP, level)
1621+
self.write_control_barrier(crate::Barrier::WORK_GROUP, level)
16221622
}
16231623

16241624
/// Helper method used to write switches
@@ -2259,8 +2259,11 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
22592259
writeln!(self.out, "{level}continue;")?
22602260
}
22612261
}
2262-
Statement::Barrier(barrier) => {
2263-
self.write_barrier(barrier, level)?;
2262+
Statement::ControlBarrier(barrier) => {
2263+
self.write_control_barrier(barrier, level)?;
2264+
}
2265+
Statement::MemoryBarrier(barrier) => {
2266+
self.write_memory_barrier(barrier, level)?;
22642267
}
22652268
Statement::ImageStore {
22662269
image,
@@ -2433,12 +2436,12 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
24332436
writeln!(self.out, ");")?;
24342437
}
24352438
Statement::WorkGroupUniformLoad { pointer, result } => {
2436-
self.write_barrier(crate::Barrier::WORK_GROUP, level)?;
2439+
self.write_control_barrier(crate::Barrier::WORK_GROUP, level)?;
24372440
write!(self.out, "{level}")?;
24382441
let name = Baked(result).to_string();
24392442
self.write_named_expr(module, pointer, name, result, func_ctx)?;
24402443

2441-
self.write_barrier(crate::Barrier::WORK_GROUP, level)?;
2444+
self.write_control_barrier(crate::Barrier::WORK_GROUP, level)?;
24422445
}
24432446
Statement::Switch {
24442447
selector,
@@ -4231,7 +4234,11 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
42314234
Ok(())
42324235
}
42334236

4234-
fn write_barrier(&mut self, barrier: crate::Barrier, level: back::Level) -> BackendResult {
4237+
fn write_control_barrier(
4238+
&mut self,
4239+
barrier: crate::Barrier,
4240+
level: back::Level,
4241+
) -> BackendResult {
42354242
if barrier.contains(crate::Barrier::STORAGE) {
42364243
writeln!(self.out, "{level}DeviceMemoryBarrierWithGroupSync();")?;
42374244
}
@@ -4246,6 +4253,26 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
42464253
}
42474254
Ok(())
42484255
}
4256+
4257+
fn write_memory_barrier(
4258+
&mut self,
4259+
barrier: crate::Barrier,
4260+
level: back::Level,
4261+
) -> BackendResult {
4262+
if barrier.contains(crate::Barrier::STORAGE) {
4263+
writeln!(self.out, "{level}DeviceMemoryBarrier();")?;
4264+
}
4265+
if barrier.contains(crate::Barrier::WORK_GROUP) {
4266+
writeln!(self.out, "{level}GroupMemoryBarrier();")?;
4267+
}
4268+
if barrier.contains(crate::Barrier::SUB_GROUP) {
4269+
// Does not exist in DirectX
4270+
}
4271+
if barrier.contains(crate::Barrier::TEXTURE) {
4272+
writeln!(self.out, "{level}DeviceMemoryBarrier();")?;
4273+
}
4274+
Ok(())
4275+
}
42494276
}
42504277

42514278
pub(super) struct MatrixType {

naga/src/back/msl/writer.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3541,7 +3541,8 @@ impl<W: Write> Writer<W> {
35413541
crate::Statement::Kill => {
35423542
writeln!(self.out, "{level}{NAMESPACE}::discard_fragment();")?;
35433543
}
3544-
crate::Statement::Barrier(flags) => {
3544+
crate::Statement::ControlBarrier(flags)
3545+
| crate::Statement::MemoryBarrier(flags) => {
35453546
self.write_barrier(flags, level)?;
35463547
}
35473548
crate::Statement::Store { pointer, value } => {

naga/src/back/pipeline_constants.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,11 @@ fn adjust_stmt(new_pos: &HandleVec<Expression, Handle<Expression>>, stmt: &mut S
798798
crate::RayQueryFunction::Terminate => {}
799799
}
800800
}
801-
Statement::Break | Statement::Continue | Statement::Kill | Statement::Barrier(_) => {}
801+
Statement::Break
802+
| Statement::Continue
803+
| Statement::Kill
804+
| Statement::ControlBarrier(_)
805+
| Statement::MemoryBarrier(_) => {}
802806
}
803807
}
804808

naga/src/back/spv/block.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3031,8 +3031,11 @@ impl BlockContext<'_> {
30313031
self.function.consume(block, Instruction::kill());
30323032
return Ok(BlockExitDisposition::Discarded);
30333033
}
3034-
Statement::Barrier(flags) => {
3035-
self.writer.write_barrier(flags, &mut block);
3034+
Statement::ControlBarrier(flags) => {
3035+
self.writer.write_control_barrier(flags, &mut block);
3036+
}
3037+
Statement::MemoryBarrier(flags) => {
3038+
self.writer.write_memory_barrier(flags, &mut block);
30363039
}
30373040
Statement::Store { pointer, value } => {
30383041
let value_id = self.cached[value];
@@ -3367,7 +3370,7 @@ impl BlockContext<'_> {
33673370
}
33683371
Statement::WorkGroupUniformLoad { pointer, result } => {
33693372
self.writer
3370-
.write_barrier(crate::Barrier::WORK_GROUP, &mut block);
3373+
.write_control_barrier(crate::Barrier::WORK_GROUP, &mut block);
33713374
let result_type_id = self.get_expression_type_id(&self.fun_info[result].ty);
33723375
// Embed the body of
33733376
match self.write_access_chain(
@@ -3407,7 +3410,7 @@ impl BlockContext<'_> {
34073410
}
34083411
}
34093412
self.writer
3410-
.write_barrier(crate::Barrier::WORK_GROUP, &mut block);
3413+
.write_control_barrier(crate::Barrier::WORK_GROUP, &mut block);
34113414
}
34123415
Statement::RayQuery { query, ref fun } => {
34133416
self.write_ray_query_function(query, fun, &mut block);

naga/src/back/spv/instructions.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,12 @@ impl super::Instruction {
11381138
instruction.add_operand(semantics_id);
11391139
instruction
11401140
}
1141+
pub(super) fn memory_barrier(mem_scope_id: Word, semantics_id: Word) -> Self {
1142+
let mut instruction = Self::new(Op::MemoryBarrier);
1143+
instruction.add_operand(mem_scope_id);
1144+
instruction.add_operand(semantics_id);
1145+
instruction
1146+
}
11411147

11421148
// Group Instructions
11431149

naga/src/back/spv/writer.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,7 +1641,7 @@ impl Writer {
16411641
Ok(id)
16421642
}
16431643

1644-
pub(super) fn write_barrier(&mut self, flags: crate::Barrier, block: &mut Block) {
1644+
pub(super) fn write_control_barrier(&mut self, flags: crate::Barrier, block: &mut Block) {
16451645
let memory_scope = if flags.contains(crate::Barrier::STORAGE) {
16461646
spirv::Scope::Device
16471647
} else {
@@ -1674,6 +1674,37 @@ impl Writer {
16741674
));
16751675
}
16761676

1677+
pub(super) fn write_memory_barrier(&mut self, flags: crate::Barrier, block: &mut Block) {
1678+
let mut semantics = spirv::MemorySemantics::ACQUIRE_RELEASE;
1679+
semantics.set(
1680+
spirv::MemorySemantics::UNIFORM_MEMORY,
1681+
flags.contains(crate::Barrier::STORAGE),
1682+
);
1683+
semantics.set(
1684+
spirv::MemorySemantics::WORKGROUP_MEMORY,
1685+
flags.contains(crate::Barrier::WORK_GROUP),
1686+
);
1687+
semantics.set(
1688+
spirv::MemorySemantics::SUBGROUP_MEMORY,
1689+
flags.contains(crate::Barrier::SUB_GROUP),
1690+
);
1691+
semantics.set(
1692+
spirv::MemorySemantics::IMAGE_MEMORY,
1693+
flags.contains(crate::Barrier::TEXTURE),
1694+
);
1695+
let mem_scope_id = if flags.contains(crate::Barrier::STORAGE) {
1696+
self.get_index_constant(spirv::Scope::Device as u32)
1697+
} else if flags.contains(crate::Barrier::SUB_GROUP) {
1698+
self.get_index_constant(spirv::Scope::Subgroup as u32)
1699+
} else {
1700+
self.get_index_constant(spirv::Scope::Workgroup as u32)
1701+
};
1702+
let semantics_id = self.get_index_constant(semantics.bits());
1703+
block
1704+
.body
1705+
.push(Instruction::memory_barrier(mem_scope_id, semantics_id));
1706+
}
1707+
16771708
fn generate_workgroup_vars_init_block(
16781709
&mut self,
16791710
entry_id: Word,
@@ -1774,7 +1805,7 @@ impl Writer {
17741805

17751806
let mut post_if_block = Block::new(merge_id);
17761807

1777-
self.write_barrier(crate::Barrier::WORK_GROUP, &mut post_if_block);
1808+
self.write_control_barrier(crate::Barrier::WORK_GROUP, &mut post_if_block);
17781809

17791810
let next_id = self.id_gen.next();
17801811
function.consume(post_if_block, Instruction::branch(next_id));

naga/src/back/wgsl/writer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ impl<W: Write> Writer<W> {
830830
Statement::Continue => {
831831
writeln!(self.out, "{level}continue;")?;
832832
}
833-
Statement::Barrier(barrier) => {
833+
Statement::ControlBarrier(barrier) | Statement::MemoryBarrier(barrier) => {
834834
if barrier.contains(crate::Barrier::STORAGE) {
835835
writeln!(self.out, "{level}storageBarrier();")?;
836836
}

naga/src/compact/statements.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ impl FunctionTracer<'_> {
153153
St::Break
154154
| St::Continue
155155
| St::Kill
156-
| St::Barrier(_)
156+
| St::ControlBarrier(_)
157+
| St::MemoryBarrier(_)
157158
| St::Return { value: None } => {}
158159
}
159160
}
@@ -360,7 +361,8 @@ impl FunctionMap {
360361
St::Break
361362
| St::Continue
362363
| St::Kill
363-
| St::Barrier(_)
364+
| St::ControlBarrier(_)
365+
| St::MemoryBarrier(_)
364366
| St::Return { value: None } => {}
365367
}
366368
}

naga/src/front/glsl/builtins.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2035,8 +2035,10 @@ impl MacroCall {
20352035
)?,
20362036
MacroCall::Barrier => {
20372037
ctx.emit_restart();
2038-
ctx.body
2039-
.push(crate::Statement::Barrier(crate::Barrier::all()), meta);
2038+
ctx.body.push(
2039+
crate::Statement::ControlBarrier(crate::Barrier::all()),
2040+
meta,
2041+
);
20402042
return Ok(None);
20412043
}
20422044
MacroCall::SmoothStep { splatted } => {

naga/src/front/spv/mod.rs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3868,11 +3868,50 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
38683868
crate::Barrier::TEXTURE,
38693869
semantics & spirv::MemorySemantics::IMAGE_MEMORY.bits() != 0,
38703870
);
3871-
block.push(crate::Statement::Barrier(flags), span);
3871+
block.push(crate::Statement::ControlBarrier(flags), span);
38723872
} else {
38733873
log::warn!("Unsupported barrier execution scope: {}", exec_scope);
38743874
}
38753875
}
3876+
Op::MemoryBarrier => {
3877+
inst.expect(3)?;
3878+
let mem_scope_id = self.next()?;
3879+
let semantics_id = self.next()?;
3880+
let mem_scope_const = self.lookup_constant.lookup(mem_scope_id)?;
3881+
let semantics_const = self.lookup_constant.lookup(semantics_id)?;
3882+
3883+
let mem_scope = resolve_constant(ctx.gctx(), &mem_scope_const.inner)
3884+
.ok_or(Error::InvalidBarrierScope(mem_scope_id))?;
3885+
let semantics = resolve_constant(ctx.gctx(), &semantics_const.inner)
3886+
.ok_or(Error::InvalidBarrierMemorySemantics(semantics_id))?;
3887+
3888+
let mut flags = if mem_scope == spirv::Scope::Device as u32 {
3889+
crate::Barrier::STORAGE
3890+
} else if mem_scope == spirv::Scope::Workgroup as u32 {
3891+
crate::Barrier::WORK_GROUP
3892+
} else if mem_scope == spirv::Scope::Subgroup as u32 {
3893+
crate::Barrier::SUB_GROUP
3894+
} else {
3895+
crate::Barrier::empty()
3896+
};
3897+
flags.set(
3898+
crate::Barrier::STORAGE,
3899+
semantics & spirv::MemorySemantics::UNIFORM_MEMORY.bits() != 0,
3900+
);
3901+
flags.set(
3902+
crate::Barrier::WORK_GROUP,
3903+
semantics & (spirv::MemorySemantics::WORKGROUP_MEMORY).bits() != 0,
3904+
);
3905+
flags.set(
3906+
crate::Barrier::SUB_GROUP,
3907+
semantics & spirv::MemorySemantics::SUBGROUP_MEMORY.bits() != 0,
3908+
);
3909+
flags.set(
3910+
crate::Barrier::TEXTURE,
3911+
semantics & spirv::MemorySemantics::IMAGE_MEMORY.bits() != 0,
3912+
);
3913+
block.push(crate::Statement::MemoryBarrier(flags), span);
3914+
}
38763915
Op::CopyObject => {
38773916
inst.expect(4)?;
38783917
let result_type_id = self.next()?;
@@ -4508,7 +4547,8 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
45084547
| S::Continue
45094548
| S::Return { .. }
45104549
| S::Kill
4511-
| S::Barrier(_)
4550+
| S::ControlBarrier(_)
4551+
| S::MemoryBarrier(_)
45124552
| S::Store { .. }
45134553
| S::ImageStore { .. }
45144554
| S::Atomic { .. }

naga/src/front/wgsl/lower/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2618,31 +2618,31 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
26182618

26192619
let rctx = ctx.runtime_expression_ctx(span)?;
26202620
rctx.block
2621-
.push(ir::Statement::Barrier(ir::Barrier::STORAGE), span);
2621+
.push(ir::Statement::ControlBarrier(ir::Barrier::STORAGE), span);
26222622
return Ok(None);
26232623
}
26242624
"workgroupBarrier" => {
26252625
ctx.prepare_args(arguments, 0, span).finish()?;
26262626

26272627
let rctx = ctx.runtime_expression_ctx(span)?;
26282628
rctx.block
2629-
.push(ir::Statement::Barrier(ir::Barrier::WORK_GROUP), span);
2629+
.push(ir::Statement::ControlBarrier(ir::Barrier::WORK_GROUP), span);
26302630
return Ok(None);
26312631
}
26322632
"subgroupBarrier" => {
26332633
ctx.prepare_args(arguments, 0, span).finish()?;
26342634

26352635
let rctx = ctx.runtime_expression_ctx(span)?;
26362636
rctx.block
2637-
.push(ir::Statement::Barrier(ir::Barrier::SUB_GROUP), span);
2637+
.push(ir::Statement::ControlBarrier(ir::Barrier::SUB_GROUP), span);
26382638
return Ok(None);
26392639
}
26402640
"textureBarrier" => {
26412641
ctx.prepare_args(arguments, 0, span).finish()?;
26422642

26432643
let rctx = ctx.runtime_expression_ctx(span)?;
26442644
rctx.block
2645-
.push(ir::Statement::Barrier(ir::Barrier::TEXTURE), span);
2645+
.push(ir::Statement::ControlBarrier(ir::Barrier::TEXTURE), span);
26462646
return Ok(None);
26472647
}
26482648
"workgroupUniformLoad" => {

naga/src/ir/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1878,7 +1878,12 @@ pub enum Statement {
18781878
/// Synchronize invocations within the work group.
18791879
/// The `Barrier` flags control which memory accesses should be synchronized.
18801880
/// If empty, this becomes purely an execution barrier.
1881-
Barrier(Barrier),
1881+
ControlBarrier(Barrier),
1882+
1883+
/// Synchronize invocations within the work group.
1884+
/// The `Barrier` flags control which memory accesses should be synchronized.
1885+
MemoryBarrier(Barrier),
1886+
18821887
/// Stores a value at an address.
18831888
///
18841889
/// For [`TypeInner::Atomic`] type behind the pointer, the value

naga/src/proc/terminator.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ pub fn ensure_block_returns(block: &mut crate::Block) {
4242
| S::SubgroupBallot { .. }
4343
| S::SubgroupCollectiveOperation { .. }
4444
| S::SubgroupGather { .. }
45-
| S::Barrier(_)),
45+
| S::ControlBarrier(_)
46+
| S::MemoryBarrier(_)),
4647
)
4748
| None => block.push(S::Return { value: None }, Default::default()),
4849
}

naga/src/valid/analyzer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,7 @@ impl FunctionInfo {
902902
ExitFlags::empty()
903903
},
904904
},
905-
S::Barrier(_) => FunctionUniformity {
905+
S::ControlBarrier(_) | S::MemoryBarrier(_) => FunctionUniformity {
906906
result: Uniformity {
907907
non_uniform_result: None,
908908
requirements: UniformityRequirements::WORK_GROUP_BARRIER,

0 commit comments

Comments
 (0)