Skip to content

Commit d3e09dd

Browse files
committed
[naga spv-out] Consolidate explanation of global wrapping.
Consolidate the explanation of why and how we wrap Naga global variables in structs to satisfy Vulkan's requirements, and include it in the documentation for `back::spv::GlobalVariable`. Clarify `GlobalVariable`'s members documentation.
1 parent 6e528aa commit d3e09dd

File tree

3 files changed

+62
-37
lines changed

3 files changed

+62
-37
lines changed

naga/src/back/spv/helpers.rs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -85,22 +85,9 @@ impl crate::AddressSpace {
8585

8686
/// Return true if the global requires a type decorated with `Block`.
8787
///
88-
/// In the Vulkan spec 1.3.296, the section [Descriptor Set Interface][dsi] says:
88+
/// See [`back::spv::GlobalVariable`] for details.
8989
///
90-
/// > Variables identified with the `Uniform` storage class are used to
91-
/// > access transparent buffer backed resources. Such variables must
92-
/// > be:
93-
/// >
94-
/// > - typed as `OpTypeStruct`, or an array of this type,
95-
/// >
96-
/// > - identified with a `Block` or `BufferBlock` decoration, and
97-
/// >
98-
/// > - laid out explicitly using the `Offset`, `ArrayStride`, and
99-
/// > `MatrixStride` decorations as specified in §15.6.4, "Offset
100-
/// > and Stride Assignment."
101-
///
102-
/// [dsi]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#interfaces-resources-descset
103-
// See `back::spv::GlobalVariable::access_id` for details.
90+
/// [`back::spv::GlobalVariable`]: super::GlobalVariable
10491
pub fn global_needs_wrapper(ir_module: &crate::Module, var: &crate::GlobalVariable) -> bool {
10592
match var.space {
10693
crate::AddressSpace::Uniform

naga/src/back/spv/index.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,14 @@ impl<'w> BlockContext<'w> {
6767
/// - An optional [`Access`] or [`AccessIndex`], for case 3, applied to...
6868
/// - A [`GlobalVariable`].
6969
///
70-
/// The SPIR-V generated takes into account wrapped globals; see
71-
/// [`global_needs_wrapper`].
70+
/// The generated SPIR-V takes into account wrapped globals; see
71+
/// [`back::spv::GlobalVariable`] for details.
7272
///
7373
/// [`GlobalVariable`]: crate::Expression::GlobalVariable
7474
/// [`AccessIndex`]: crate::Expression::AccessIndex
7575
/// [`Access`]: crate::Expression::Access
7676
/// [`base`]: crate::Expression::Access::base
77+
/// [`back::spv::GlobalVariable`]: super::GlobalVariable
7778
pub(super) fn write_runtime_array_length(
7879
&mut self,
7980
array: Handle<crate::Expression>,

naga/src/back/spv/mod.rs

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -467,38 +467,75 @@ enum CachedConstant {
467467
ZeroValue(Word),
468468
}
469469

470+
/// The SPIR-V representation of a [`crate::GlobalVariable`].
471+
///
472+
/// In the Vulkan spec 1.3.296, the section [Descriptor Set Interface][dsi] says:
473+
///
474+
/// > Variables identified with the `Uniform` storage class are used to access
475+
/// > transparent buffer backed resources. Such variables *must* be:
476+
/// >
477+
/// > - typed as `OpTypeStruct`, or an array of this type,
478+
/// >
479+
/// > - identified with a `Block` or `BufferBlock` decoration, and
480+
/// >
481+
/// > - laid out explicitly using the `Offset`, `ArrayStride`, and `MatrixStride`
482+
/// > decorations as specified in "Offset and Stride Assignment".
483+
///
484+
/// This is followed by identical language for the `StorageBuffer`,
485+
/// except that a `BufferBlock` decoration is not allowed.
486+
///
487+
/// When we encounter a global variable in the [`Storage`] or [`Uniform`]
488+
/// address spaces whose type is not already [`Struct`], this backend implicitly
489+
/// wraps the global variable in a struct: we generate a SPIR-V global variable
490+
/// holding an `OpTypeStruct` with a single member, whose type is what the Naga
491+
/// global's type would suggest, decorated as required above.
492+
///
493+
/// The [`helpers::global_needs_wrapper`] function determines whether a given
494+
/// [`crate::GlobalVariable`] needs to be wrapped.
495+
///
496+
/// [dsi]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#interfaces-resources-descset
497+
/// [`Storage`]: crate::AddressSpace::Storage
498+
/// [`Uniform`]: crate::AddressSpace::Uniform
499+
/// [`Struct`]: crate::TypeInner::Struct
470500
#[derive(Clone)]
471501
struct GlobalVariable {
472-
/// ID of the OpVariable that declares the global.
502+
/// The SPIR-V id of the `OpVariable` that declares the global.
503+
///
504+
/// If this global has been implicitly wrapped in an `OpTypeStruct`, this id
505+
/// refers to the wrapper, not the original Naga value it contains. If you
506+
/// need the Naga value, use [`access_id`] instead of this field.
473507
///
474-
/// If you need the variable's value, use [`access_id`] instead of this
475-
/// field. If we wrapped the Naga IR `GlobalVariable`'s type in a struct to
476-
/// comply with Vulkan's requirements, then this points to the `OpVariable`
477-
/// with the synthesized struct type, whereas `access_id` points to the
478-
/// field of said struct that holds the variable's actual value.
508+
/// If this global is not implicitly wrapped, this is the same as
509+
/// [`access_id`].
479510
///
480511
/// This is used to compute the `access_id` pointer in function prologues,
481-
/// and used for `ArrayLength` expressions, which do need the struct.
512+
/// and used for `ArrayLength` expressions, which need to pass the wrapper
513+
/// struct.
482514
///
483515
/// [`access_id`]: GlobalVariable::access_id
484516
var_id: Word,
485517

486-
/// For `AddressSpace::Handle` variables, this ID is recorded in the function
487-
/// prelude block (and reset before every function) as `OpLoad` of the variable.
488-
/// It is then used for all the global ops, such as `OpImageSample`.
518+
/// The loaded value of a `AddressSpace::Handle` global variable.
519+
///
520+
/// If the current function uses this global variable, this is the id of an
521+
/// `OpLoad` instruction in the function's prologue that loads its value.
522+
/// (This value is assigned as we write the prologue code of each function.)
523+
/// It is then used for all operations on the global, such as `OpImageSample`.
489524
handle_id: Word,
490525

491-
/// Actual ID used to access this variable.
492-
/// For wrapped buffer variables, this ID is `OpAccessChain` into the
493-
/// wrapper. Otherwise, the same as `var_id`.
526+
/// The SPIR-V id of a pointer to this variable's Naga IR value.
527+
///
528+
/// If the current function uses this global variable, and it has been
529+
/// implicitly wrapped in an `OpTypeStruct`, this is the id of an
530+
/// `OpAccessChain` instruction in the function's prologue that refers to
531+
/// the wrapped value inside the struct. (This value is assigned as we write
532+
/// the prologue code of each function.) If you need the wrapper struct
533+
/// itself, use [`var_id`] instead of this field.
534+
///
535+
/// If this global is not implicitly wrapped, this is the same as
536+
/// [`var_id`].
494537
///
495-
/// Vulkan requires that globals in the `StorageBuffer` and `Uniform` storage
496-
/// classes must be structs with the `Block` decoration, but WGSL and Naga IR
497-
/// make no such requirement. So for such variables, we generate a wrapper struct
498-
/// type with a single element of the type given by Naga, generate an
499-
/// `OpAccessChain` for that member in the function prelude, and use that pointer
500-
/// to refer to the global in the function body. This is the id of that access,
501-
/// updated for each function in `write_function`.
538+
/// [`var_id`]: GlobalVariable::var_id
502539
access_id: Word,
503540
}
504541

0 commit comments

Comments
 (0)