unoplatform/uno · error · Exception

GetActiveUniform did not report uWave[{BarCount}] (saw {acti

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.

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)

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.