Expand description
A minimal SPIR-V binary emitter: enough to write one compute shader by hand, and nothing more.
§Why hand-emit SPIR-V
The beachhead had to answer a question the roadmap asks explicitly: can ferrox’s shaders be built without a C++ toolchain at build time? There are three ways to get SPIR-V into a Rust binary and only one of them says yes without qualification:
glslangValidator/glslcinbuild.rs. This is what llama.cpp’s Vulkan backend does (it builds avulkan-shaders-genC++ program at configure time). It makes a C++ toolchain a build prerequisite for every ferrox user who enables the feature, on every platform, forever.ferrox-cudadeliberately refused the equivalent (cudarc in dynamic-loading mode, no nvcc) and this crate refuses it for the same reason.- Commit a pre-built
.spvblob. No build dependency, but the repo then carries an opaque binary that no reviewer can read and that silently drifts from whatever source it was generated from. This codebase’s whole test culture is against that. - Emit the words from Rust. The shader is ordinary reviewable Rust, there is no build step at all, and the emitter is small enough to hold in your head. That is this file.
The cost is stated honestly in the verdict: option 3 does not scale to a hundred kernels. It scales to one, which is exactly the size of a GO/NO-GO.
§What this is not
Not an SSA builder, not a validator, not a type deduplicator. It
writes words in the order it is told to, into the five sections
SPIR-V’s logical layout requires. Getting the layout or the types
wrong produces an invalid module, and the crate’s answer to that is
to run spirv-val over the emitted words in a test whenever the
tool is on PATH (see q8_0_matvec’s tests).
Structs§
- Builder
- Accumulates SPIR-V words per section and hands out result ids.
Enums§
- Section
- Where an instruction goes in SPIR-V’s required logical layout.
Constants§
- ADDRESSING_
LOGICAL - BUILTIN_
GLOBAL_ INVOCATION_ ID - CAP_
SHADER - DEC_
ARRAY_ STRIDE - DEC_
BINDING - DEC_
BLOCK - DEC_
BUFFER_ BLOCK - DEC_
BUILTIN - DEC_
DESCRIPTOR_ SET - DEC_
OFFSET - EXEC_
MODEL_ GL_ COMPUTE - EXEC_
MODE_ LOCAL_ SIZE - GENERATOR
- Generator magic. 0 is “unregistered”; tools accept it.
- MAGIC
- SPIR-V magic number (first word of every module).
- MEMORY_
MODEL_ GLSL450 - NONE
- OP_
ACCESS_ CHAIN - OP_
BITCAST - OP_
BITWISE_ AND - OP_
BITWISE_ OR - OP_
BITWISE_ XOR - OP_
BRANCH - OP_
BRANCH_ CONDITIONAL - OP_
CAPABILITY - OP_
COMPOSITE_ EXTRACT - OP_
CONSTANT - OP_
CONVERT_ S_ TO_ F - OP_
CONVERT_ U_ TO_ F - OP_
DECORATE - OP_
ENTRY_ POINT - OP_
EXECUTION_ MODE - OP_
FUNCTION - OP_
FUNCTION_ END - OP_
F_ ADD - OP_
F_ MUL - OP_
F_ NEGATE - OP_
I_ ADD - OP_
I_ EQUAL - OP_
I_ MUL - OP_
I_ NOT_ EQUAL - OP_
I_ SUB - OP_
LABEL - OP_LOAD
- OP_
LOOP_ MERGE - OP_
MEMBER_ DECORATE - OP_
MEMBER_ NAME - OP_
MEMORY_ MODEL - OP_NAME
- OP_
RETURN - OP_
SELECT - OP_
SELECTION_ MERGE - OP_
SHIFT_ LEFT_ LOGICAL - OP_
SHIFT_ RIGHT_ LOGICAL - OP_
STORE - OP_
TYPE_ BOOL - OP_
TYPE_ FLOAT - OP_
TYPE_ FUNCTION - OP_
TYPE_ INT - OP_
TYPE_ POINTER - OP_
TYPE_ RUNTIME_ ARRAY - OP_
TYPE_ STRUCT - OP_
TYPE_ VECTOR - OP_
TYPE_ VOID - OP_
U_ LESS_ THAN - OP_
VARIABLE - SC_
FUNCTION - SC_
INPUT - SC_
PUSH_ CONSTANT - SC_
UNIFORM - VERSION_
1_ 0 - Target SPIR-V version, encoded
0 | major<<16 | minor<<8 | 0.
Functions§
- encode_
string - SPIR-V literal string: UTF-8, NUL-terminated, zero-padded to a whole number of little-endian words.
- to_
bytes - The emitted words as the little-endian byte stream a
.spvfile holds, for handing to an external validator.