Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[naga spv-out] Consolidate explanation of global wrapping. #6336

Merged
merged 1 commit into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 2 additions & 15 deletions naga/src/back/spv/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,22 +85,9 @@ impl crate::AddressSpace {

/// Return true if the global requires a type decorated with `Block`.
///
/// In the Vulkan spec 1.3.296, the section [Descriptor Set Interface][dsi] says:
/// See [`back::spv::GlobalVariable`] for details.
///
/// > Variables identified with the `Uniform` storage class are used to
/// > access transparent buffer backed resources. Such variables must
/// > be:
/// >
/// > - typed as `OpTypeStruct`, or an array of this type,
/// >
/// > - identified with a `Block` or `BufferBlock` decoration, and
/// >
/// > - laid out explicitly using the `Offset`, `ArrayStride`, and
/// > `MatrixStride` decorations as specified in §15.6.4, "Offset
/// > and Stride Assignment."
///
/// [dsi]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#interfaces-resources-descset
// See `back::spv::GlobalVariable::access_id` for details.
/// [`back::spv::GlobalVariable`]: super::GlobalVariable
pub fn global_needs_wrapper(ir_module: &crate::Module, var: &crate::GlobalVariable) -> bool {
match var.space {
crate::AddressSpace::Uniform
Expand Down
5 changes: 3 additions & 2 deletions naga/src/back/spv/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,14 @@ impl<'w> BlockContext<'w> {
/// - An optional [`Access`] or [`AccessIndex`], for case 3, applied to...
/// - A [`GlobalVariable`].
///
/// The SPIR-V generated takes into account wrapped globals; see
/// [`global_needs_wrapper`].
/// The generated SPIR-V takes into account wrapped globals; see
/// [`back::spv::GlobalVariable`] for details.
///
/// [`GlobalVariable`]: crate::Expression::GlobalVariable
/// [`AccessIndex`]: crate::Expression::AccessIndex
/// [`Access`]: crate::Expression::Access
/// [`base`]: crate::Expression::Access::base
/// [`back::spv::GlobalVariable`]: super::GlobalVariable
pub(super) fn write_runtime_array_length(
&mut self,
array: Handle<crate::Expression>,
Expand Down
77 changes: 57 additions & 20 deletions naga/src/back/spv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,38 +467,75 @@ enum CachedConstant {
ZeroValue(Word),
}

/// The SPIR-V representation of a [`crate::GlobalVariable`].
///
/// In the Vulkan spec 1.3.296, the section [Descriptor Set Interface][dsi] says:
///
/// > Variables identified with the `Uniform` storage class are used to access
/// > transparent buffer backed resources. Such variables *must* be:
/// >
/// > - typed as `OpTypeStruct`, or an array of this type,
/// >
/// > - identified with a `Block` or `BufferBlock` decoration, and
/// >
/// > - laid out explicitly using the `Offset`, `ArrayStride`, and `MatrixStride`
/// > decorations as specified in "Offset and Stride Assignment".
///
/// This is followed by identical language for the `StorageBuffer`,
/// except that a `BufferBlock` decoration is not allowed.
///
/// When we encounter a global variable in the [`Storage`] or [`Uniform`]
/// address spaces whose type is not already [`Struct`], this backend implicitly
/// wraps the global variable in a struct: we generate a SPIR-V global variable
/// holding an `OpTypeStruct` with a single member, whose type is what the Naga
/// global's type would suggest, decorated as required above.
///
/// The [`helpers::global_needs_wrapper`] function determines whether a given
/// [`crate::GlobalVariable`] needs to be wrapped.
///
/// [dsi]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#interfaces-resources-descset
/// [`Storage`]: crate::AddressSpace::Storage
/// [`Uniform`]: crate::AddressSpace::Uniform
/// [`Struct`]: crate::TypeInner::Struct
#[derive(Clone)]
struct GlobalVariable {
/// ID of the OpVariable that declares the global.
/// The SPIR-V id of the `OpVariable` that declares the global.
///
/// If this global has been implicitly wrapped in an `OpTypeStruct`, this id
/// refers to the wrapper, not the original Naga value it contains. If you
/// need the Naga value, use [`access_id`] instead of this field.
///
/// If you need the variable's value, use [`access_id`] instead of this
/// field. If we wrapped the Naga IR `GlobalVariable`'s type in a struct to
/// comply with Vulkan's requirements, then this points to the `OpVariable`
/// with the synthesized struct type, whereas `access_id` points to the
/// field of said struct that holds the variable's actual value.
/// If this global is not implicitly wrapped, this is the same as
/// [`access_id`].
///
/// This is used to compute the `access_id` pointer in function prologues,
/// and used for `ArrayLength` expressions, which do need the struct.
/// and used for `ArrayLength` expressions, which need to pass the wrapper
/// struct.
///
/// [`access_id`]: GlobalVariable::access_id
var_id: Word,

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

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

Expand Down