eval::internal

The parts of libeval that the compile lanes share: values, slot layout, GLSL assembly and SPIR-V compilation.

Group eval

Detailed description

The types and functions in this namespace are the implementation of eval::Graph and eval::Program. They are not a stable interface: use eval::Graph and eval::Program instead.

The namespace holds the runtime value type and its matrix operations, the layout of input and output slots in the flat float buffer, the assembler that wraps the expressions in one GLSL unit, the type oracle that asks glslang for the type of an expression, and compileUnitToSpirv(), which compiles a unit to validated SPIR-V.

Function documentation

codegenNativeSlotIsPackable

bool internal::codegenNativeSlotIsPackable(eval::Type t)

`SUP-49` step 4 — does the native emitter have a slot case for t?

The native lane and the SPIR-V lane share `slotFloatWidth`, so widening a type there widens the offsets BOTH lanes hand out — and the native emitter only reads what it has a case for. A type this table widens and `Codegen::emit`'s prologue does not reconstruct would read too few floats and shift every later slot down the buffer: silently, and into plausible numbers rather than an error.

So the emitter's case list is stated once, here, and `Graph::compile` refuses `Backend::Native` for a slot it does not cover. Returns true when the emitter has a case for t, and false otherwise. `isUnsupported` cannot stand in for this — it walks the expression AST and never sees the SLOT types, which is the same blind spot §SUR-69 and §SUR-71 each cost a defect to find. `testEvalUnit::nativeSlotEmissionMatchesTheAbiWidth` asks the generated C++ rather than this predicate, because a predicate cannot see a defect in the code it describes.

compileUnitToSpirv

bool internal::compileUnitToSpirv(eval::internal::GlslLane lane, const QVector<eval::internal::CodegenSlot> &inputs, const QVector<eval::internal::CodegenSlot> &outputs, const QStringList &expressions, const QString &prelude, QByteArray *spirv, QString *diagnostic, int *blamedOutput = nullptr, int *blamedElement = nullptr)

Assemble one unit and compile it to validated SPIR-V.

`SUP-5` — the compile half of the lane, shared by the interpreter lane and the GPU lane. It is split out because the **GPU** lane needs exactly this and nothing after it. `SpirvUnit::build` goes on to load a `spir::Module` and pre-flight it against the interpreter's opcode coverage. A QRhi dispatch needs neither, and a module load whose result nobody reads is a cost with no reader.

It is split rather than duplicated for the reason `SUP-13` gives about the assembler (§SUR-25c): two call sites into glslang become two front ends when either one gets an option the other does not have.

lane picks the envelope AND the glslang stage, which must agree. A `Fragment` envelope parsed as `EShLangCompute` fails on `gl_FragCoord`, not on anything a caller can act on.

inputs, outputs, expressions and prelude go to assembleUnit() without change: expressions is GLSL source, positional against outputs, and prelude is emitted verbatim ahead of the entry point.

Returns true on success, and sets spirv, when it is not null, to the validated SPIR-V words. Returns false, with diagnostic naming the stage that refused: assembly, glslang, link, SPIR-V generation, or the validator. The function clears each non-null output first.

`SUP-29` — blamedOutput, when not null, is set to the index of the output whose expression glslang blamed, or -1 when the error belongs to the envelope or cannot be attributed. This is how a spreadsheet diagnostic reaches a cell: the assembler knows which line each expression landed on, glslang reports a line, and the two meet here. blamedElement, when not null, is set to the index WITHIN that output (`SUP-89`), which for a wide slot is the cell, or -1. A caller that passes null for both gets the behavior from before `SUP-29`.

In this section