unoplatform/uno · error · Exception
GetUniform readback mismatch: got {firstComponent}, expected
Error message
GetUniform readback mismatch: got {firstComponent}, expected {_palette[0]} What it means
QuerySyncGlCanvasElement uploads a 4-element vec3 palette via gl.Uniform3(loc, 4, _palette) then immediately reads the first component back via gl.GetUniform and asserts it matches the uploaded value within 0.001. A mismatch means the uniform upload or readback is silently wrong — the GL driver stored or returned a different value, which would corrupt the bar coloring.
Source
Thrown at src/SamplesApp/SamplesApp.Samples/Windows_UI_Composition/QuerySyncGlCanvasElement.cs:137
gl.BindVertexArray(_barsVao);
gl.BindBuffer(BufferTargetARB.ArrayBuffer, _quadVbo);
gl.VertexAttribPointer(0, 2, GLEnum.Float, false, 2 * sizeof(float), (void*)0);
gl.EnableVertexAttribArray(0);
_probeVao = gl.GenVertexArray();
gl.BindVertexArray(_probeVao);
_probeVbo = _quadVbo;
gl.BindBuffer(BufferTargetARB.ArrayBuffer, _probeVbo);
gl.VertexAttribPointer(0, 2, GLEnum.Float, false, 2 * sizeof(float), (void*)0);
gl.EnableVertexAttribArray(0);
// The palette never changes; upload once and read it back as a sanity check.
gl.UseProgram(_barsProgram);
gl.Uniform3(_uPaletteLoc, 4, new ReadOnlySpan<float>(_palette));
gl.GetUniform(_barsProgram, _uPaletteLoc, out float firstComponent);
if (Math.Abs(firstComponent - _palette[0]) > 0.001f)
{
throw new Exception($"GetUniform readback mismatch: got {firstComponent}, expected {_palette[0]}");
}
// Program introspection: enumerate active uniforms and validate the program.
gl.GetProgram(_barsProgram, ProgramPropertyARB.ActiveUniforms, out int activeUniforms);
var foundWave = false;
for (uint i = 0; i < activeUniforms; i++)
{
var name = gl.GetActiveUniform(_barsProgram, i, out int size, out UniformType type);
// Array uniforms report as "uWave[0]" with size = element count.
foundWave |= name.StartsWith("uWave", StringComparison.Ordinal) && size == BarCount && type == UniformType.Float;
}
if (!foundWave)
{
throw new Exception($"GetActiveUniform did not report uWave[{BarCount}] (saw {activeUniforms} active uniforms)");
}
gl.ValidateProgram(_barsProgram);
gl.GetProgram(_barsProgram, ProgramPropertyARB.ValidateStatus, out int validateStatus);
if (validateStatus != (int)GLEnum.True)View on GitHub (pinned to 0418340488)
Solutions
- Call gl.GetError() between Uniform3 and GetUniform to detect whether the upload itself failed (e.g. 0x502 invalid_operation if the location is wrong).
- Confirm _uPaletteLoc is non-negative (-1 means the uniform was optimized out and Uniform3 is a no-op).
- Read back the full array with GetUniformfv-style calls (4 vec3 = 12 floats) and compare element-by-element, not just the first component — a stride mismatch shows up at elements 1-3.
- If the driver reports the location for `uPalette[0]` vs `uPalette` differently, request the location with GetUniformLocation(program, "uPalette[0]") explicitly.
- On WebGL2/GLES, verify array uniform upload stride — Uniform3 with count=4 expects a tightly-packed 12-float span, which _palette is (3*4 floats).
Example fix
// before
gl.Uniform3(_uPaletteLoc, 4, new ReadOnlySpan<float>(_palette));
gl.GetUniform(_barsProgram, _uPaletteLoc, out float firstComponent);
if (Math.Abs(firstComponent - _palette[0]) > 0.001f)
throw new Exception($"GetUniform readback mismatch: got {firstComponent}, expected {_palette[0]}");
// after — verify location + read back the full array
if (_uPaletteLoc < 0)
throw new Exception("uPalette uniform was optimized out by the compiler");
gl.Uniform3(_uPaletteLoc, 4, new ReadOnlySpan<float>(_palette));
var back = new float[12];
gl.GetUniform(_barsProgram, _uPaletteLoc, back);
for (int i = 0; i < 12; i++)
if (Math.Abs(back[i] - _palette[i]) > 0.001f)
throw new Exception($"GetUniform readback mismatch at [{i}]: got {back[i]}, expected {_palette[i]}"); Defensive patterns
Strategy: validation
Validate before calling
// Validate the uniform location is active before uploading, then read the full array back
if (_uPaletteLoc < 0) return; // uniform optimized out; upload is a no-op
gl.Uniform3(_uPaletteLoc, 4, new ReadOnlySpan<float>(_palette));
var back = new float[12];
gl.GetUniform(_barsProgram, _uPaletteLoc, back);
for (int i = 0; i < 12; i++)
if (Math.Abs(back[i] - _palette[i]) > 0.001f) return; // driver quirk; do not throw Try / catch
try { /* readback assertion */ }
catch (Exception ex) when (ex.Message.Contains("GetUniform readback"))
{
// Non-fatal: the uniform upload likely worked; the readback semantics differ on this driver
App.MainWindow?.LogError(ex.Message);
} Prevention
- Confirm GetUniformLocation returns >= 0 before Uniform3.
- Read back the full array, not just the first component, to catch stride issues.
- Tolerate driver quirks in GetUniform readback — the upload is what matters for rendering.
- Drain GetError between upload and readback to detect upload failure.
When it happens
Trigger: After gl.UseProgram(_barsProgram) + gl.Uniform3(_uPaletteLoc, 4, palette) at line 133, then gl.GetUniform(_barsProgram, _uPaletteLoc, out float firstComponent) at line 134. The assertion Math.Abs(firstComponent - _palette[0]) > 0.001f at line 135 fires.
Common situations: GetUniform reading an array uniform returns only the first array element — but if _uPaletteLoc resolved to the array root vs the [0] element differently across drivers, the read value differs; the uniform was optimized out by the GLSL compiler (uPalette is used in the vertex shader so it should stay active, but a driver that prunes aggressively could); a silent GL error from the Uniform3 call left the value unchanged; the vec3 array stride in the upload does not match what the driver expects.
Related errors
- GetActiveUniform did not report uWave[{BarCount}] (saw {acti
- Program link failed: {infoLog}
- {name} uniform not found on shader.
- Program link failed: {infoLog}
- {type} compile failed: {infoLog}
AI-assisted analysis of unoplatform/uno@0418340488 (2026-08-13).
Data as JSON: /api/errors/10fa1a13cfd50d7c.
Report an issue: GitHub.