Now all my glsl shaders build, though most likely none of them
correctly. However, I'm finally out of that tunnel... only to find
myself in a moonlit forest fill with the sounds of wolves (at least, I
hope they're wolves).
All was fine... until the texture handling. Ugh, what a mess: 16
variants of "texture", times all the sampler variants. And I haven't
done even half of them.
I won't say it belongs in glsl-builtins, though the glsl-specific stuff
probably does (glsl texture handling is a mess). Also adds sampler
attribute handling (which falls back to image when necessary).
If `@intrinsic()` is followed by `[expr_list]` then those expresses will
be used to create the intrinsic rather than the function's parameters,
allowing for reordering, adding extra parameters or even complex
expressions.
However, only the parsing is implemented.
Unfortunately, this require using different syntax for the two cases:
type.attr works in cases where types are expected, but not in
expressions (lots of shift/reduce and reduce/reduce conflicts). However,
treating type like an Objective-C class works nicely, though
`[type attrib(params)]` looks a little odd. However, this allows using
generic types to provide function calls (eg, converting texture
coordinates).
I had forgotten that subpassInput can't be used but the normal imageLoad
functions since they don't (and mustn't, by the spec) have subpassInput
as a possible type. While creating a specialized version works, I think
I need to come up with a better way of specifying intrinsics.
It seems the base atomic functions should use const for the data
parameters and just a reference for the mem parameter (not entirely sure
yet as I need to check with spirv-val, but there are still build
issues). Using __imageTexel correctly took a little thinking since it
returns a pointer but the atomic functions take a reference.
I guess I hadn't thought of it because GLSL doesn't have `auto`, but
since the builtin functions are implemented in Ruamoko, `auto` is
available and I use it for the atomic image functions.
Used the wrong generic type name for gvec4*, and missed @construct. Now
gridplane.frag tries to generate spir-v again (fails due to the
instruction names).
The goal is to make it easy to get size/coord/base types from image
types without creating a zillion type functions.
It was necessary to make it possible for any type to have an attribute
function (returns an expression so it can be more useful: types are
returned via type expressions). Algebra types were the first victim
(which was nice for testing).
And disable it for GLSL. I might need to make it target-dependent
instead as I don't know if I'll be able to implement it in SPIR-V, and
when I get to the C back-end, it will be superfluous.
GLSL's texture functions are a bit of a nightmare. The return types are
wrong, but I need to decide how I want to pull the sample type from a
texture or sampler.
Spir-v is pretty slack with the exact types of the operants to the
right-shift instructions so no need to care about the type for shift so
long as it has the correct number of components.
I had already implemented the code generation side (though using type
ids instead of encodings is a nice change), but I hadn't implemented the
actual evaluation or even called it. Now return types can be computed
from generic parameters (eg, ivecN from vecN).
It's still not great (mostly on the language side, I think), but
different glsl shader types get the correct model and fragment shaders
even get the correct mode.
Access qualifiers aren't supported yet, and some of the image handling
is a bit messy (currently tied to glsl when it should be general), but
the basics are there. However, now I've got to sort out the execution
model (need Fragment or GLCompute for ImplicitLod).
I really don't like the way they're included (I'm really looking forward
to #embed, but gotta wait for gcc 15), and I'm a tad grumpy that the
documentation for them
(https://registry.khronos.org/SPIR-V/specs/unified1/MachineReadableGrammar.html)
is wrong (missing fields), but I think I like the result.
The grammars (core and glsl.std.450) are parsed into structs that should
be fairly easy to interpret: the instructions, kinds, and enumerant
values are sorted by name for search with bsearch. Having the data
parsed in means source code can refer to the items by name rather than
magic numbers, which will be very nice for intrinsics and image types
(and probably a few other things).
The idea is to allow certain contexts to interpret something like `2D`
as an identifier instead of 2.0 (double), or (not sure I'll go there,
5e12 as a bivector instead of a double or float.
In the end, it does simplify things a lot, though it helped get function
pointers working at least a bit (they're not quite the same as C yet,
but I think that's mostly that functions can be struct fields).
They should now work in generic contexts, but the pressing need to work
on arrays was due to constant expressions for element counts breaking.
As a side effect, function pointers are now a thing (and seem to work
like they do in C)