Skip to content

Commit e5a4a5f

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 d5bd3ea commit e5a4a5f

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
@@ -52,13 +52,14 @@ impl<'w> BlockContext<'w> {
5252
/// - An optional [`Access`] or [`AccessIndex`], for case 3, applied to...
5353
/// - A [`naga::GlobalVariable`].
5454
///
55-
/// The SPIR-V generated takes into account wrapped globals; see
56-
/// [`global_needs_wrapper`].
55+
/// The generated SPIR-V takes into account wrapped globals; see
56+
/// [`back::spv::GlobalVariable`] for details.
5757
///
5858
/// [`naga::GlobalVariable`]: crate::Expression::GlobalVariable
5959
/// [`AccessIndex`]: crate::Expression::AccessIndex
6060
/// [`Access`]: crate::Expression::Access
6161
/// [`base`]: crate::Expression::Access::base
62+
/// [`back::spv::GlobalVariable`]: super::GlobalVariable
6263
pub(super) fn write_runtime_array_length(
6364
&mut self,
6465
array: Handle<crate::Expression>,

naga/src/back/spv/mod.rs

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

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

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

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

0 commit comments

Comments
 (0)