bindUniformBlock abstract method
Fills the uniform block blockName of shader from members and binds
it. False when the shader has no such block.
A block the compiler dropped is false; a block missing a member the caller named throws. The two look alike and are not: a compiler drops a whole block nothing reads, which is ordinary and which the caller is entitled to shrug at, but a block that exists without one of the members written into it means the two ends disagree about its shape. Zeros are a plausible value for most of what goes through here — a shadow strength of zero is a scene with no shadows and no error — so silence there is indistinguishable from working.
That distinction is load-bearing in the other direction too: binding a block a compiled shader does not have takes the process down with no Dart stack, which is why the block case is a return value rather than a throw.
This doc comment used to say the opposite, on the grounds that "the
unlit model legitimately has no light_direction". It has one: FragInfo
is declared once, in lib/surface.glsl, and every shader that reads any
of it includes the whole block. The web backend threw all along and drew
every golden, which is what settled it — the same bundle was a named
exception in a browser and a quietly wrong picture on a phone.
A backend with no reflection of its shaders cannot tell the two apart and is not asked to: the software rasteriser hands the block to a Dart shader that looks up what it needs by name, so a member nobody reads costs a map entry. What is forbidden is a backend that can see the disagreement and says nothing.
So the return value is true unconditionally on such a backend, and a
caller branching on it must know that. There is nothing for the software
rasteriser to answer false about — a Dart stage declares no blocks, so
"the compiler dropped this one" is not a state it has — and returning
false for a block it had merely never been handed would be inventing an
answer. The value is therefore a report from the backends that reflect and
a constant from the one that does not, which is the honest shape and not a
forgotten branch. The conformance check
a block missing a member the caller named is refused uses exactly this
to tell the two kinds of backend apart before holding either to the member
rule.
Every uniform in this engine is a float vector, a matrix or an array of either, which is why Float32List is the only value type. Integer and boolean uniforms are encoded as floats in the shaders on purpose.
Implementation
bool bindUniformBlock(
ShaderHandle shader,
String blockName,
Map<String, Float32List> members,
);