This is a fairly fundamental change on how IDs are handled.
It serves many purposes:
- Improve performance. We only need to iterate over IDs which are
relevant at any one time.
- Makes sure we iterate through IDs in SPIR-V module declaration order
rather than ID space. IDs don't have to be monotonically increasing,
which was an assumption SPIRV-Cross used to have. It has apparently
never been a problem until now.
- Support LUTs of structs. We do this by interleaving declaration of
constants and struct types in SPIR-V module order.
To support this, the ParsedIR interface needed to change slightly.
Before setting any ID with variant_set<T> we let ParsedIR know
that an ID with a specific type has been added. The surface for change
should be minimal.
ParsedIR will maintain a per-type list of IDs which the cross-compiler
will need to consider for later.
Instead of looping over ir.ids[] (which can be extremely large), we loop
over types now, using:
ir.for_each_typed_id<SPIRVariable>([&](uint32_t id, SPIRVariable &var) {
handle_variable(var);
});
Now we make sure that we're never looking at irrelevant types.
A block name cannot alias with any name in its own scope,
and it cannot alias with any other "global" name.
To solve this, we need to complicate the name cache updates a little bit
where we have a "primary" namespace and "secondary" namespace.
Avoids certain cases of variance between translation units by forcing
every dependent expression of a store to be temporary.
Should avoid the major failure cases where invariance matters.
Previously, when generating non-Vulkan GLSL, each use of a spec constant
would be subsituted for its default value and the declaration of the constant
itself would be omitted completely.
This change slightly alters this behavior. The uses of the constant are kept,
as well as the declaration, although the latter is stripped of the layout
qualifier. The declaration is also prepended with the following code:
#ifndef <constant name>_value
#define <constant name> <default constant value>
#endif
and the constant itself now looks like
const <constant type> <constant name> = <constant name>_value;
The rationale for this change is that it gives the user a way to provide
custom values for specialization constants even when the target does not
support them.
- Add new Windows support
- Use CMake/CTest instead of Make + shell scripts
- Use --parallel in CTest
- Fix CTest on Windows
- Cleanups in test_shaders.py
- Force specific commit for SPIRV-Headers
- Fix Inf/NaN odd-ball case by moving to ASM
Need some pretty hideous ladder variable system, but high level
languages do not support breaking out of a loop. break in switch blocks
and break in loops alias each other.
When the name of an alias global variable collides with a global
declaration, MSL would emit inconsistent names, sometimes with the
naming fix, sometimes without, because names were being tracked in two
separate meta blocks. Fix this by always redirecting parameter naming to
the original base variable as necessary.
MSL would force thread const& which would not work if the input argument
came from a different storage class.
Emit proper non-reference arguments for such values.
Deal with various query functions which require dummy sampler.
In SPIR-V, separate images are used, but GLSL (even Vulkan GLSL)
requires combined sampler images ...
Update SPIRV-Tools/glslang commits.
Use vulkan1.1 environment for testing.
Found new "errors" in SPIRV-Tools, so disable validation on those shaders
for now.
Certain patterns with OpVectorShuffle (and probably others) will cascade
to so large, that they can cause OOM. After we have observed
force_recompile, don't spend unnecessary memory emitting code which will
never be used.
Normally, temporary declaration must dominate any use of it,
so we generally did not need to analyze the CFG for these variables,
but there is an edge case where you have an inliner doing:
do {
create_temporary;
break;
} while(0);
use_temporary;
The inside of the loop dominates the outer scope, but we cannot emit
code like this in GLSL, so make sure we hoist these temporaries outside
the "loop".
HLSL UAVs are a bit annoying because they can share block types,
so reflection becomes rather awkward. Sometimes we will need to make
some nasty fallbacks, so add a reflection interface which lets you query
post-shader compile which names was actually declared in the shader.
We don't have a mechanism to move temporaries to their appropriate
scope, and Phi behavior is weird enough that it will be a heroic effort
to not do this rather ugly codegen :(
Previously, we would generate parentheses proactively when generating
binary ops, however, this leads to uglier code and hits warnings in
compilers when used as a conditional.
- Only consider I/O variables if part of OpEntryPoint.
- Keep a safe fallback if #entry-points is 1 to avoid potentially
breaking previously working shaders.
There was a potential problem if variables were invalidated and SPIR-V
read expressions which depended on other expression which in turn depended on the
invalidated variable.
Also fixes issue where variables were considered immutable if they were
forwardable. This allowed some incorrect optimizations to slip through.
OpName is only for debug information, so we must be very careful that
we do not reuse the same name for different variables.
This was previously done for local variables, but this commit extends
this to global variables as well.
In some cases we need to bitcast when dealing with int vs. uint.
SPIR-V allows inputs to be of different integer signedness, so we need
to deal with this somehow.
Add testing system to test SPIR-V assembly.
For now, test all possible combination for all major cases.
- IAdd (which doesn't care about input type as long as they're equal)
- SDiv/UDiv operations which case about input type.
- Arith/Logical right shifts.
- IEqual to test outputs to bvec, which shouldn't get output cast. Also
tests casting in function-like calls.