unoplatform/uno · error · Exception

GetActiveUniform did not report uWave

Error message

GetActiveUniform did not report uWave[{BarCount}] (saw {activeUniforms} active uniforms)

What it means

QuerySyncGlCanvasElement enumerates the active uniforms of _barsProgram via gl.GetProgram(ACTIVE_UNIFORMS) + gl.GetActiveUniform, expecting to find uWave reported as an array of size 8 (BarCount) with type Float. If no uniform matching `uWave`, size 8, type Float is found, this throws — meaning the program introspection did not surface the uWave array as expected.

Solutions

  1. Print every (name, size, type) triple in the loop to see exactly how the driver reports uWave — most drivers report 'uWave[0]' with size 8 and type FLOAT, but a quirk needs to be seen to be handled.
  2. Confirm the uWave array is genuinely used with a dynamically-indexed read in the shader (it is: `uWave[gl_InstanceID]`) — if a driver prunes it anyway, force it active by adding a dummy use or move the index to a non-instance-driven source.
  3. Loosen the match: check `name.StartsWith("uWave")` and `size == BarCount || size == 1` (some drivers report size 1 for arrays) before throwing.
  4. Request the uniform's location with GetUniformLocation(program, "uWave[0]") and GetUniformLocation(program, "uWave") to confirm both forms resolve; -1 for both means the compiler pruned it.
  5. If the driver reports UniformType.FloatVec4 instead of Float for the array element, that indicates the array was coalesced — inspect the shader source for an unintended redeclaration.

Example fix

// before
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)");

// after — collect all uniforms for diagnosis and tolerate driver quirks
var report = new List<string>();
for (uint i = 0; i < activeUniforms; i++)
{
    var name = gl.GetActiveUniform(_barsProgram, i, out int size, out UniformType type);
    report.Add($"{name} size={size} type={type}");
    foundWave |= name.StartsWith("uWave", StringComparison.Ordinal)
        && (size == BarCount || size == 1)
        && type == UniformType.Float;
}
if (!foundWave)
    throw new Exception($"uWave not reported. Active uniforms:\n{string.Join('\n', report)}");
Defensive patterns

Strategy: validation

Validate before calling

// Enumerate active uniforms with full diagnostics and tolerate driver-specific reporting quirks
var report = new List<string>();
var found = false;
for (uint i = 0; i < activeUniforms; i++)
{
    var (name, size, type) = (gl.GetActiveUniform(_barsProgram, i, out int s, out UniformType t), s, t);
    report.Add($"{name} size={size} type={type}");
    found |= name.StartsWith("uWave") && (size == BarCount || size == 1) && type == UniformType.Float;
}
if (!found) App.MainWindow?.LogError($"uWave not found. Uniforms:\n{string.Join('\n', report)}");

Try / catch

try { /* introspection loop + assertion */ }
catch (Exception ex) when (ex.Message.Contains("GetActiveUniform"))
{
    // Driver may have pruned or coalesced uWave; rendering may still work
    App.MainWindow?.LogError(ex.Message);
}

Prevention

When it happens

Trigger: The loop at lines 143-148 iterates all active uniforms; foundWave stays false if no entry has name starting 'uWave', size == BarCount (8), and UniformType.Float. The throw at line 151 reports how many active uniforms were seen.

Common situations: uWave was optimized out by the GLSL compiler because the driver determined the array was not effectively used (it is used via uWave[gl_InstanceID], which some drivers fail to track as a dynamic index and prune); the driver reports the array name as 'uWave[0]' (correct) but with size 1 instead of 8 due to a driver bug; the type is reported as FloatVec3 or similar because of an introspection quirk; the uniform was inactive and thus not enumerated at all (ACTIVE_UNIFORMS only lists active uniforms).

Related errors


AI-assisted analysis of unoplatform/uno@0418340488 (2026-08-13). Data as JSON: /api/errors/fdcb91c0d9fc7676. Report an issue: GitHub.

Appendix: source

Thrown at src/SamplesApp/SamplesApp.Samples/Windows_UI_Composition/QuerySyncGlCanvasElement.cs:151

			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)
			{
				throw new Exception("ValidateProgram failed: " + gl.GetProgramInfoLog(_barsProgram));
			}

			_query = gl.GenQuery();

			// Init must finish error-clean; surface anything the calls above raised.
			var err = gl.GetError();
			if (err != GLEnum.NoError)
			{
				throw new Exception($"GL error at end of Init: 0x{(int)err:x}");
			}
		}

View on GitHub (pinned to 0418340488)