-
Notifications
You must be signed in to change notification settings - Fork 1.1k
[naga spv-out] Handle matCx2 in uniform buffers #8240
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
Open
jamienicol
wants to merge
8
commits into
gfx-rs:trunk
Choose a base branch
from
jamienicol:matCx2-uniform-spv
base: trunk
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+4,544
−1,402
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
8ef1922
[test] Add additional matrix struct_layout tests
jamienicol 06e89f3
[naga spv-out] Handle 2-row matrices in uniform buffers
jamienicol 5bdee64
add comment noting that some unfiform input subtests are marked as fa…
jamienicol 85656cc
add struct layout test for matCx2 followed by another struct member
jamienicol 10e18c5
fix doc typo
jamienicol e1ae0db
update stale references to hlsl_mat_cxN.wgsl
jamienicol 900bde9
set spv.debug = true for matcx2 snapshot test
jamienicol 9925f12
handle different bounds check policies
jamienicol File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,7 +1,91 @@ | ||||||||||||||||||||||||||||||||||||||||
/*! | ||||||||||||||||||||||||||||||||||||||||
Backend for [SPIR-V][spv] (Standard Portable Intermediate Representation). | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
# Layout of values in `uniform` buffers | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
WGSL's ["Internal Layout of Values"][ilov] rules specify how each WGSL type | ||||||||||||||||||||||||||||||||||||||||
should be stored in `uniform` and `storage` buffers, and Naga IR adheres to | ||||||||||||||||||||||||||||||||||||||||
these rules. The SPIR-V we generate must access values in that form, even when | ||||||||||||||||||||||||||||||||||||||||
it is not what Vulkan would use normally. Fortunately the rules for `storage` | ||||||||||||||||||||||||||||||||||||||||
buffers match Vulkan's, but some adjustments must be made when emitting SPIR-V | ||||||||||||||||||||||||||||||||||||||||
for `uniform` buffers. | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
## Padding in two-row matrices | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
In Vulkan's ["extended layout"][extended-layout] (also known as std140) used | ||||||||||||||||||||||||||||||||||||||||
for `uniform` buffers, matrices are defined in terms of arrays of their vector | ||||||||||||||||||||||||||||||||||||||||
type, and arrays are defined to have an alignment equal to the alignment of | ||||||||||||||||||||||||||||||||||||||||
their element type rounded up to a multiple of 16. This means that each column | ||||||||||||||||||||||||||||||||||||||||
of the vector has a minimum alignment of 16. WGSL, and consequently Naga IR, on | ||||||||||||||||||||||||||||||||||||||||
the other hand defines each column to have an alignment equal to the alignment | ||||||||||||||||||||||||||||||||||||||||
of the vector type, without being rounded up to 16. | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+15
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
To compensate for this, for any `struct` used as a `uniform` buffer which | ||||||||||||||||||||||||||||||||||||||||
contains a two-row matrix, we declare an additional "std140 compatible" type | ||||||||||||||||||||||||||||||||||||||||
in which each column of the matrix has been decomposed into the containing | ||||||||||||||||||||||||||||||||||||||||
struct. For example, the following WGSL struct type: | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
```ignore | ||||||||||||||||||||||||||||||||||||||||
struct Baz { | ||||||||||||||||||||||||||||||||||||||||
m: mat3x2<f32>, | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
is rendered as the SPIR-V struct type: | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
```ignore | ||||||||||||||||||||||||||||||||||||||||
OpTypeStruct %v2float %v2float %v2float | ||||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
This has the effect that struct indices in Naga IR for such types do not | ||||||||||||||||||||||||||||||||||||||||
correspond to the struct indices used in SPIR-V. A mapping of struct indices | ||||||||||||||||||||||||||||||||||||||||
for these types is maintained in [`Std140CompatTypeInfo`]. | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
Additionally, any two-row matrices that are declared directly as uniform | ||||||||||||||||||||||||||||||||||||||||
buffers without being wrapped in a struct are declared as a struct containing a | ||||||||||||||||||||||||||||||||||||||||
vector member for each column. Any array of a two-row matrix in a uniform | ||||||||||||||||||||||||||||||||||||||||
buffer is declared as an array of a struct containing a vector member for each | ||||||||||||||||||||||||||||||||||||||||
column. Any struct or array within a uniform buffer which contains a member or | ||||||||||||||||||||||||||||||||||||||||
whose base type requires a std140 compatible type declaration, itself requires a | ||||||||||||||||||||||||||||||||||||||||
std140 compatible type declaration. | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
Whenever a value of such a type is [`loaded`] we insert code to convert the | ||||||||||||||||||||||||||||||||||||||||
loaded value from the std140 compatible type to the regular type. This occurs | ||||||||||||||||||||||||||||||||||||||||
in `BlockContext::write_checked_load`, making use of the wrapper function | ||||||||||||||||||||||||||||||||||||||||
defined by `Writer::write_wrapped_convert_from_std140_compat_type`. For matrices | ||||||||||||||||||||||||||||||||||||||||
that have been decomposed as separate columns in the containing struct, we load | ||||||||||||||||||||||||||||||||||||||||
each column separately then composite the matrix type in | ||||||||||||||||||||||||||||||||||||||||
`BlockContext::maybe_write_load_uniform_matcx2_struct_member`. | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
Whenever a column of a matrix that has been decomposed into its containing | ||||||||||||||||||||||||||||||||||||||||
struct is [`accessed`] with a constant index we adjust the emitted access chain | ||||||||||||||||||||||||||||||||||||||||
to access from the containing struct instead, in `BlockContext::write_access_chain`. | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
Whenever a column of a uniform buffer two-row matrix is [`dynamically accessed`] | ||||||||||||||||||||||||||||||||||||||||
we must first load the matrix type, converting it from its std140 compatible | ||||||||||||||||||||||||||||||||||||||||
type as described above, then access the column using the wrapper function | ||||||||||||||||||||||||||||||||||||||||
defined by `Writer::write_wrapped_matcx2_get_column`. This is handled by | ||||||||||||||||||||||||||||||||||||||||
`BlockContext::maybe_write_uniform_matcx2_dynamic_access`. | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
Note that this approach differs somewhat from the equivalent code in the HLSL | ||||||||||||||||||||||||||||||||||||||||
backend. For HLSL all structs containing two-row matrices (or arrays of such) | ||||||||||||||||||||||||||||||||||||||||
have their declarations modified, not just those used as uniform buffers. | ||||||||||||||||||||||||||||||||||||||||
Two-row matrices and arrays of such only use modified type declarations when | ||||||||||||||||||||||||||||||||||||||||
used as uniform buffers, or additionally when used as struct member in any | ||||||||||||||||||||||||||||||||||||||||
context. This avoids the need to convert struct values when loading from uniform | ||||||||||||||||||||||||||||||||||||||||
buffers, but when loading arrays and matrices from uniform buffers or from any | ||||||||||||||||||||||||||||||||||||||||
struct the conversion is still required. In contrast, the approach used here | ||||||||||||||||||||||||||||||||||||||||
always requires converting *any* affected type when loading from a uniform | ||||||||||||||||||||||||||||||||||||||||
buffer, but consistently *only* when loading from a uniform buffer. As a result | ||||||||||||||||||||||||||||||||||||||||
this also means we only have to handle loads and not stores, as uniform buffers | ||||||||||||||||||||||||||||||||||||||||
are read-only. | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
[spv]: https://www.khronos.org/registry/SPIR-V/ | ||||||||||||||||||||||||||||||||||||||||
[ilov]: https://gpuweb.github.io/gpuweb/wgsl/#internal-value-layout | ||||||||||||||||||||||||||||||||||||||||
[extended-layout]: https://docs.vulkan.org/spec/latest/chapters/interfaces.html#interfaces-resources-layout | ||||||||||||||||||||||||||||||||||||||||
[`loaded`]: crate::Expression::Load | ||||||||||||||||||||||||||||||||||||||||
[`accessed`]: crate::Expression::AccessIndex | ||||||||||||||||||||||||||||||||||||||||
[`dynamically accessed`]: crate::Expression::Access | ||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
mod block; | ||||||||||||||||||||||||||||||||||||||||
|
@@ -462,6 +546,12 @@ enum WrappedFunction { | |||||||||||||||||||||||||||||||||||||||
left_type_id: Word, | ||||||||||||||||||||||||||||||||||||||||
right_type_id: Word, | ||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||
ConvertFromStd140CompatType { | ||||||||||||||||||||||||||||||||||||||||
r#type: Handle<crate::Type>, | ||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||
MatCx2GetColumn { | ||||||||||||||||||||||||||||||||||||||||
r#type: Handle<crate::Type>, | ||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
/// A map from evaluated [`Expression`](crate::Expression)s to their SPIR-V ids. | ||||||||||||||||||||||||||||||||||||||||
|
@@ -722,6 +812,20 @@ impl BlockContext<'_> { | |||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
/// Information about a type for which we have declared a std140 layout | ||||||||||||||||||||||||||||||||||||||||
/// compatible variant, because the type is used in a uniform but does not | ||||||||||||||||||||||||||||||||||||||||
/// adhere to std140 requirements. The uniform will be declared using the | ||||||||||||||||||||||||||||||||||||||||
/// type `type_id`, and the result of any `Load` will be immediately converted | ||||||||||||||||||||||||||||||||||||||||
/// to the base type. This is used for matrices with 2 rows, as well as any | ||||||||||||||||||||||||||||||||||||||||
/// arrays or structs containing such matrices. | ||||||||||||||||||||||||||||||||||||||||
pub struct Std140CompatTypeInfo { | ||||||||||||||||||||||||||||||||||||||||
/// ID of the std140 compatible type declaration. | ||||||||||||||||||||||||||||||||||||||||
type_id: Word, | ||||||||||||||||||||||||||||||||||||||||
/// For structs, a mapping of Naga IR struct member indices to the indices | ||||||||||||||||||||||||||||||||||||||||
/// used in the generated SPIR-V. For non-struct types this will be empty. | ||||||||||||||||||||||||||||||||||||||||
member_indices: Vec<u32>, | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
pub struct Writer { | ||||||||||||||||||||||||||||||||||||||||
physical_layout: PhysicalLayout, | ||||||||||||||||||||||||||||||||||||||||
logical_layout: LogicalLayout, | ||||||||||||||||||||||||||||||||||||||||
|
@@ -761,6 +865,7 @@ pub struct Writer { | |||||||||||||||||||||||||||||||||||||||
constant_ids: HandleVec<crate::Expression, Word>, | ||||||||||||||||||||||||||||||||||||||||
cached_constants: crate::FastHashMap<CachedConstant, Word>, | ||||||||||||||||||||||||||||||||||||||||
global_variables: HandleVec<crate::GlobalVariable, GlobalVariable>, | ||||||||||||||||||||||||||||||||||||||||
std140_compat_uniform_types: crate::FastHashMap<Handle<crate::Type>, Std140CompatTypeInfo>, | ||||||||||||||||||||||||||||||||||||||||
fake_missing_bindings: bool, | ||||||||||||||||||||||||||||||||||||||||
binding_map: BindingMap, | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
|
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.