-
Notifications
You must be signed in to change notification settings - Fork 244
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
Blocks (StorageBuffer and PushConstant) #289
Conversation
I was able to run this code, performing the operation y *= alpha. So with this PR, we'd be pretty close to being able to implement a lot of things. Note that we probably do want to be able to use runtime arrays instead of arrays, and need a way to access the array with a dynamic index. With a literal Rust invokes InBoundsAccessChain, but with a variable it creates a slice and then indexes that. Creating a slice requires Addresses since it uses intrinsics::offset. This will probably have to be fixed via asm!, to invoke access chain.
|
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.
This looks good, and is almost what our plans are for this area. In the future, though, could you collaborate with us to figure out what the best work is to do before submitting PRs? I hate to see any wasted work going down paths that we don't intend to go down.
/// Handles `#[spirv(block)]`. Note this is only called in the scalar translation code, because this is only | ||
/// used for spooky builtin stuff, and we pinky promise to never have more than one pointer field in one of these. | ||
// TODO: Enforce this is only used in spirv-std. |
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.
This comment isn't correct, right? It's the opposite of what's actually happening, it's only called in the ADT translation code. I believe this should be called at the entrypoint of trans_type_impl
, in the same for loop that trans_image
is called, and error when applied to a struct that results in a scalar or otherwise non-struct representation.
@@ -48,6 +48,54 @@ macro_rules! storage_class { | |||
} | |||
}; | |||
|
|||
// Interior Block |
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.
While the #[spirv(block)]
attribute matches our plans in this area for a hack quick fix, we were planning on having the user apply the attribute themselves to types used in block contexts. As you pointed out, there are many problems with this type-wrapping approach, surfacing most obviously with the storage class mismatch issues you're hitting.
(Do keep in mind that this is intended to be a quick hack fix before we're able to fully implement the bindings RFC, as that will replace this whole system with something much more elegant)
Fixes #247. For compute shaders, more work like #282 is needed, but I believe that otherwise StorageBuffer as it is should be fine.
First, this PR adds an internal block decorated struct to StorageBuffer and PushConstant. This is necessary per spec, and certain platforms require it.
This creates a problem. When accessing the inner field, ie self.block.value, the resulting pointer has Function storage class. Idk if this is just a limitation or deficiency of the current method of applying storage classes (through the type system), but essentially the inner T type is typically user defined, and so can't be associated with a storage class (as it might not even be user defined but built in like an array, or reused in different places, say in glam). That means that it will have Function storage class. So despite the copy, you still end up with an access chain (ie in load / store) with mismatching storage classes, which may work on some systems but is incorrect and will fail validation. Essentially any reference that is obtained from a variable must have the same storage class, and any operations like access chain, load, store, etc, must inherit this as well.
It turns out that in this specific case, say PushConstant -> PushConstantBlock -> T (self.block.value), Rust emits a pointercast from *{PushConstant} PushConstantBlock to *{Function} T. I added logic to pointercast to apply the PushConstant storage to *T, but conservatively this only happens when the function is marked with the really_unsafe_ignore_bitcasts attribute. Note that this applies to all storage classes, including StorageBuffer.
Alternatively to the pointercast change, is to implement the access via asm! #254.