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

Add runtime array type #596

Merged
merged 2 commits into from
May 31, 2021
Merged

Add runtime array type #596

merged 2 commits into from
May 31, 2021

Conversation

khyperia
Copy link
Contributor

This allows runtime descriptor arrays, which aren't wrapped in a block struct, and have no length.

@khyperia khyperia requested a review from eddyb as a code owner April 16, 2021 10:44
arr = in(reg) self,
index = in(reg) index,
}
loop {}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an open issue for supporting it: #570

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, my bad. I should've seen that beforehand.

arr = in(reg) self,
index = in(reg) index,
}
loop {}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

Copy link
Contributor

@Hentropy Hentropy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Descriptor indexing also works for buffers, both sized and unsized as in #389. For that to work, there needs to be a separate type for DescriptorArray and RuntimeDescriptorArray because arrays and slices in storage buffer or uniform storage are inferred to be buffers that need to be wrapped in SpirvType::InterfaceBlock. It also makes it a little bit clearer what the type is for, someone was lil confused in chat on the weekend about it. I didn't know this was in progress, and it's something I need so I had started working on it myself about the same time you did. Kind of a shame to do duplicate work, but it's essentially the extension of this that allows for (possibly variably sized) buffers as well as opaque resources. See #597

Comment on lines +4 to +8
pub struct RuntimeArray<T> {
// spooky! this field does not exist, so if it's referenced in rust code, things will explode
_do_not_touch: u32,
_phantom: PhantomData<T>,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling this RuntimeArray is a bit confusing, someone was already in chat asking whether this was used for runtime data arrays. RuntimeDescriptorArray is a bit verbose, but it's also unambiguous, and for descriptor arrays of buffers this type needs to insert a block decorated struct around the buffer and have special indexing behaviour to handle that.

The u32 field is a bit strange, descriptor arrays, like descriptors, don't really have size/alignment per se. Since the compiler is handling this specially anyways, is it necessary?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the compiler is handling this specially anyways, is it necessary?

You have to avoid making it a ZST, because those can be assumed to be data-less tokens, i.e. they have only "existence" but no memory/register representation. For example, (SomeZST, f32) is represented as just an f32, and so there is no way to recover any data the backend may want to keep in the ZST type.

The other option (instead of a dummy field) is a !Sized type, via extern { type Foo; }, which we should maybe move to at some point.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'd love to move to extern { type Foo; }, but IIRC it requires a #[feature] and I'd like to keep those limited if at all possible (and AFAIK there's no other way to create an unsized yet no wide pointer type)

Comment on lines +17 to +23
asm! {
"%result = OpAccessChain _ {arr} {index}",
"OpReturnValue %result",
"%unused = OpLabel",
arr = in(reg) self,
index = in(reg) index,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only works for the opaque resource types, extending this to support buffers requires a compiler implemented function.

// The spirv type of it will be generated by querying the type of the first generic.
if let Some(elem_ty) = substs.types().next() {
let element = trans_type_impl(cx, span, cx.layout_of(elem_ty), false);
Ok(SpirvType::RuntimeArray { element }.def(span, cx))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.def() produces an array stride decoration, which isn't necessary for opaque resource types (shader-playground GLSL example) and is explicitly forbidden for buffers.

if is_pair {
self.tcx.sess.span_err(
hir_param.ty_span,
"uniform_constant buffers must use &RuntimeArray<T>, not &[T]",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uniform_constant buffers

I thought UniformConstant was only for non-buffers?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An array of Image2d must use a direct OpTypeRuntimeArray not wrapped in a struct, i.e. &RuntimeArray<Image2d> instead of &[Image2d] (which is a large part of the point of this PR, supporting runtime arrays of images)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, but the word buffer might be incorrect here, idk what "an array of images" is called, it might not be a "buffer" so the error message might be able to be improved, but I think the code is correct.

Copy link
Contributor

@eddyb eddyb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine, but feel free to do some of the suggested changes.

Comment on lines 300 to 301
// is_pair implies is_unsized (but is_unsized doesn't imply is_pair, for RuntimeArray<T>)
assert!(!is_pair || is_unsized);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this become really confusing if someone uses some type that just happens to be represented as a pair? I think you could replace if is_pair { below with if is_unsized_with_len { given:

let is_unsized_with_len = is_unsized && matches!(entry_arg_abi.mode, PassMode::Pair(..));

@khyperia khyperia merged commit 5d22f60 into main May 31, 2021
@khyperia khyperia deleted the runtimearray branch May 31, 2021 09:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants