[Fix, Test] (GLImpl, ProgramState): answer the classic uniform queries for atomic counters at GL level

This commit is contained in:
2026-08-21 00:07:07 -04:00
parent 325ba07776
commit 7a7340ebe2
3 changed files with 131 additions and 0 deletions
@@ -225,6 +225,9 @@ namespace MobileGL::MG_State::GLState {
}
GLenum GetActiveUniformType(Uint index) const {
// The lowered counter is a plain uint inside a synthesized block; what the GL
// client declared - and what glGetActiveUniform must report - is an atomic_uint.
if (IsActiveUniformAtomicCounter(index)) return GL_UNSIGNED_INT_ATOMIC_COUNTER;
auto& uniform = Artifacts().program->getUniform(TProgramUniformIndex(index));
return uniform.glDefineType;
}
@@ -244,10 +247,49 @@ namespace MobileGL::MG_State::GLState {
Int GetActiveUniformBlockIndex(Uint index) const {
auto& uniform = Artifacts().program->getUniform(TProgramUniformIndex(index));
// An atomic counter is a DEFAULT-BLOCK uniform to GL, whatever block the
// transpiler lowered it onto (GL 4.6 core 7.6, table 7.6): -1.
if (IsActiveUniformAtomicCounter(index)) return -1;
// Members of the synthesized global UBO are default-block uniforms to GL: -1.
return GlBlockIndexFromTProgram(uniform.index);
}
// The transpiler lowers every atomic_uint onto a synthesized gl_AtomicCounterBlock_N
// block, but GL keeps seeing an atomic counter as a default-block uniform of type
// GL_UNSIGNED_INT_ATOMIC_COUNTER that points at an atomic-counter BUFFER. These two
// answer for that GL-level declaration; without them the query surface reports the
// lowering instead (GL_UNSIGNED_INT, block index 0) and
// KHR-GL43.shader_atomic_counters.basic-program-query fails on both.
//
// The returned value is an index into the GL_ACTIVE_ATOMIC_COUNTER_BUFFERS list, i.e.
// the RANK of the owning counter block among the counter blocks in glslang's block
// order - exactly how ProgramInterface numbers the GL_ATOMIC_COUNTER_BUFFER
// resources glGetActiveAtomicCounterBufferiv answers from. -1 when this uniform is
// not an atomic counter.
Int GetActiveUniformAtomicCounterBufferIndex(Uint index) const {
const Int tIndex = TProgramUniformIndex(index);
if (tIndex < 0) return -1;
const Int owner = Artifacts().program->getUniform(tIndex).index;
if (owner < 0) return -1;
const Int blockCount = Artifacts().program->getNumUniformBlocks();
if (owner >= blockCount) return -1;
const SizeT prefixLength = StringView(MG_Util::ShaderTranspiler::ATOMIC_COUNTER_BLOCK_PREFIX).size();
Int counterBufferIndex = 0;
for (Int i = 0; i < blockCount; ++i) {
const auto& blockName = Artifacts().program->getUniformBlock(i).name;
if (blockName.compare(0, prefixLength, MG_Util::ShaderTranspiler::ATOMIC_COUNTER_BLOCK_PREFIX) != 0) {
continue;
}
if (i == owner) return counterBufferIndex;
++counterBufferIndex;
}
return -1;
}
Bool IsActiveUniformAtomicCounter(Uint index) const {
return GetActiveUniformAtomicCounterBufferIndex(index) >= 0;
}
// GL_UNIFORM_OFFSET: byte offset within the owning named block; -1 for a default-block
// uniform. The relaxed parse gives global-UBO members real byte offsets, but GL must keep
// seeing them as default-block uniforms, so gate on the GL-visible block index.