[Fix, Test] (GLState): keep the atomic-counter and storage blocks out of the GL uniform-block list

This commit is contained in:
2026-08-21 11:54:45 -04:00
parent fdbe0b3117
commit f5a0779385
6 changed files with 368 additions and 43 deletions
+35 -19
View File
@@ -680,7 +680,9 @@ namespace MobileGL::MG_Impl::GLImpl {
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params);
break;
case GL_ACTIVE_UNIFORM_BLOCKS: // GL >= 3.1
*params = programObject->GetActiveUniformBlocksCount();
// Uniform blocks only. GetActiveUniformBlocksCount() is the internal block space,
// which also carries the storage blocks and the synthesized atomic counter blocks.
*params = programObject->GetGlUniformBlockCount();
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params);
break;
case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: // ditto.
@@ -1716,7 +1718,10 @@ namespace MobileGL::MG_Impl::GLImpl {
return GL_INVALID_INDEX;
}
const auto& index = programObject->GetUniformBlockIndex(uniformBlockName);
// GetGlUniformBlockIndex, not GetUniformBlockIndex: the latter answers in the internal
// block space, which also resolves storage blocks and the synthesized atomic counter
// blocks. Neither is a uniform block (GL 4.6 core 7.6), so both are GL_INVALID_INDEX here.
const auto index = programObject->GetGlUniformBlockIndex(uniformBlockName);
MGLOG_D("GBI prog=%u name='%s' -> %d", program, uniformBlockName ? uniformBlockName : "(null)", (Int)index);
return index;
}
@@ -1730,7 +1735,7 @@ namespace MobileGL::MG_Impl::GLImpl {
"Program object" + std::to_string(program) + " that has been linked."));
return;
}
if (!programObject->IsActiveUniformBlock(uniformBlockIndex)) {
if (!programObject->IsActiveGlUniformBlock(uniformBlockIndex)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>(
@@ -1741,8 +1746,11 @@ namespace MobileGL::MG_Impl::GLImpl {
std::to_string(program) + "."));
return;
}
// The GL_UNIFORM_BLOCK index space skips the storage and atomic counter blocks the
// block-keyed tables still carry; translate before touching them.
const Uint blockIndex = static_cast<Uint>(programObject->BlockIndexFromGlUniformBlock(uniformBlockIndex));
MGLOG_D("UBB prog=%u idx=%u binding=%u", program, uniformBlockIndex, uniformBlockBinding);
programObject->SetUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
programObject->SetUniformBlockBinding(blockIndex, uniformBlockBinding);
}
void GetActiveUniformBlockiv_State(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params) {
@@ -1754,7 +1762,7 @@ namespace MobileGL::MG_Impl::GLImpl {
"Program object" + std::to_string(program) + " that has been linked."));
return;
}
if (!programObject->IsActiveUniformBlock(uniformBlockIndex)) {
if (!programObject->IsActiveGlUniformBlock(uniformBlockIndex)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>(
@@ -1765,61 +1773,68 @@ namespace MobileGL::MG_Impl::GLImpl {
std::to_string(program) + "."));
return;
}
// The GL_UNIFORM_BLOCK index space skips the storage and atomic counter blocks the
// block-keyed tables still carry; every accessor below is indexed by the block space.
const Uint blockIndex = static_cast<Uint>(programObject->BlockIndexFromGlUniformBlock(uniformBlockIndex));
switch (pname) {
case GL_UNIFORM_BLOCK_DATA_SIZE: {
*params = (GLint)programObject->GetUBOSizeAt(uniformBlockIndex);
*params = (GLint)programObject->GetUBOSizeAt(blockIndex);
MGLOG_D("%s: GL_UNIFORM_BLOCK_DATA_SIZE = %d", __func__, *params);
break;
}
case GL_UNIFORM_BLOCK_NAME_LENGTH: {
*params = (GLint)programObject->GetUniformBlockName(uniformBlockIndex).length() + 1;
*params = (GLint)programObject->GetUniformBlockName(blockIndex).length() + 1;
MGLOG_D("%s: GL_UNIFORM_BLOCK_NAME_LENGTH = %d", __func__, *params);
break;
}
case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: {
*params = programObject->GetUniformBlockActiveUniformCount(uniformBlockIndex);
*params = programObject->GetUniformBlockActiveUniformCount(blockIndex);
MGLOG_D("%s: GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS = %d", __func__, *params);
break;
}
case GL_UNIFORM_BLOCK_BINDING: {
*params = static_cast<GLint>(programObject->GetUniformBlockBinding(uniformBlockIndex));
*params = static_cast<GLint>(programObject->GetUniformBlockBinding(blockIndex));
MGLOG_D("%s: GL_UNIFORM_BLOCK_BINDING = %d", __func__, *params);
break;
}
case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
*params = BoolToGLInt(programObject->IsUniformBlockReferencedByStage(uniformBlockIndex, EShLangVertex));
*params = BoolToGLInt(programObject->IsUniformBlockReferencedByStage(blockIndex, EShLangVertex));
MGLOG_D("%s: GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER = %d", __func__, *params);
break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER:
*params =
BoolToGLInt(programObject->IsUniformBlockReferencedByStage(uniformBlockIndex, EShLangTessControl));
BoolToGLInt(programObject->IsUniformBlockReferencedByStage(blockIndex, EShLangTessControl));
MGLOG_D("%s: GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER = %d", __func__, *params);
break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER:
*params =
BoolToGLInt(programObject->IsUniformBlockReferencedByStage(uniformBlockIndex, EShLangTessEvaluation));
BoolToGLInt(programObject->IsUniformBlockReferencedByStage(blockIndex, EShLangTessEvaluation));
MGLOG_D("%s: GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER = %d", __func__, *params);
break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER:
*params = BoolToGLInt(programObject->IsUniformBlockReferencedByStage(uniformBlockIndex, EShLangGeometry));
*params = BoolToGLInt(programObject->IsUniformBlockReferencedByStage(blockIndex, EShLangGeometry));
MGLOG_D("%s: GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER = %d", __func__, *params);
break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
*params = BoolToGLInt(programObject->IsUniformBlockReferencedByStage(uniformBlockIndex, EShLangFragment));
*params = BoolToGLInt(programObject->IsUniformBlockReferencedByStage(blockIndex, EShLangFragment));
MGLOG_D("%s: GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER = %d", __func__, *params);
break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER:
*params = BoolToGLInt(programObject->IsUniformBlockReferencedByStage(uniformBlockIndex, EShLangCompute));
*params = BoolToGLInt(programObject->IsUniformBlockReferencedByStage(blockIndex, EShLangCompute));
MGLOG_D("%s: GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER = %d", __func__, *params);
break;
case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: {
// Member entries of an arrayed block are recorded against the first instance;
// every instance of the array reports that shared member set (matches
// GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, which scans with the same owner index).
const Int ownerIndex = static_cast<Int>(programObject->GetUniformBlockMemberOwnerIndex(uniformBlockIndex));
//
// Both sides of the comparison are BLOCK indices: GetUniformBlockMemberOwnerIndex
// answers in that space, so the scan uses GetActiveUniformOwnerBlockIndex rather
// than the GL_UNIFORM_BLOCK-space GetActiveUniformBlockIndex.
const Int ownerIndex = static_cast<Int>(programObject->GetUniformBlockMemberOwnerIndex(blockIndex));
GLint uniformIndexCount = 0;
for (Uint uniformIndex = 0; uniformIndex < programObject->GetUniformCount(); ++uniformIndex) {
if (programObject->GetActiveUniformBlockIndex(uniformIndex) != ownerIndex) {
if (programObject->GetActiveUniformOwnerBlockIndex(uniformIndex) != ownerIndex) {
continue;
}
params[uniformIndexCount++] = static_cast<GLint>(uniformIndex);
@@ -1849,7 +1864,7 @@ namespace MobileGL::MG_Impl::GLImpl {
" is not a program object that has been linked."));
return;
}
if (!programObject->IsActiveUniformBlock(uniformBlockIndex)) {
if (!programObject->IsActiveGlUniformBlock(uniformBlockIndex)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>(
@@ -1859,7 +1874,8 @@ namespace MobileGL::MG_Impl::GLImpl {
"not the index of an active uniform block in program."));
return;
}
const auto& name = programObject->GetUniformBlockName(uniformBlockIndex);
const auto& name = programObject->GetUniformBlockName(
static_cast<Uint>(programObject->BlockIndexFromGlUniformBlock(uniformBlockIndex)));
CopyStr(bufSize, length, uniformBlockName, name.c_str(), (GLsizei)name.length());
MGLOG_D("%s: \"%s\" at uniformBlockIndex %02d, length = %d", __func__, uniformBlockName, uniformBlockIndex,
length ? *length : 0);
@@ -305,13 +305,17 @@ namespace MobileGL::MG_Impl::GLImpl::ProgramInterface {
// GL_UNIFORM_BLOCK keeps the index space glUniformBlockBinding and
// glGetActiveUniformBlockiv already use, so an index handed out here is usable
// with them (which is exactly what the CTS does).
const Int glBlockCount = program.GetActiveUniformBlocksCount();
const Int glBlockCount = program.GetGlUniformBlockCount();
for (Int glIndex = 0; glIndex < glBlockCount; ++glIndex) {
// The block-space index the block-keyed accessors want; the two spaces differ
// whenever the program also has a storage or atomic counter block, which
// glslang files under the same reflection list (no EShReflectionSeparateBuffers).
const Int blockIndex = program.BlockIndexFromGlUniformBlock(static_cast<Uint>(glIndex));
Resource resource;
resource.name = program.GetUniformBlockName(glIndex);
resource.bufferBinding = static_cast<GLint>(program.GetUniformBlockBinding(glIndex));
resource.bufferDataSize = static_cast<GLint>(program.GetUBOSizeAt(glIndex));
const Int tIndex = program.TProgramBlockIndex(static_cast<Uint>(glIndex));
resource.name = program.GetUniformBlockName(static_cast<Uint>(blockIndex));
resource.bufferBinding = static_cast<GLint>(program.GetUniformBlockBinding(static_cast<Uint>(blockIndex)));
resource.bufferDataSize = static_cast<GLint>(program.GetUBOSizeAt(static_cast<Uint>(blockIndex)));
const Int tIndex = program.TProgramBlockIndex(static_cast<Uint>(blockIndex));
if (tIndex >= 0 && tIndex < blockCount) {
resource.stages = UniformBlockStages(reflection.blockReflection[tIndex],
stagesFromMembers, tIndex);
@@ -388,12 +392,16 @@ namespace MobileGL::MG_Impl::GLImpl::ProgramInterface {
static_cast<GLuint>(i));
}
}
for (SizeT blockIndex = 0; blockIndex < model.uniformBlocks.size(); ++blockIndex) {
for (SizeT glBlockIndex = 0; glBlockIndex < model.uniformBlocks.size(); ++glBlockIndex) {
// Members of an arrayed block are reflected once, against instance [0].
const Int owner = static_cast<Int>(program.GetUniformBlockMemberOwnerIndex(static_cast<Uint>(blockIndex)));
// GetUniformBlockMemberOwnerIndex takes and answers BLOCK indices, while
// Resource::blockIndex is a GL_UNIFORM_BLOCK index, so translate both ways.
const Int blockIndex = program.BlockIndexFromGlUniformBlock(static_cast<Uint>(glBlockIndex));
const Int owner = program.GlUniformBlockIndexFromBlock(
static_cast<Int>(program.GetUniformBlockMemberOwnerIndex(static_cast<Uint>(blockIndex))));
for (SizeT i = 0; i < model.uniforms.size(); ++i) {
if (model.uniforms[i].blockIndex == owner) {
model.uniformBlocks[blockIndex].activeVariables.push_back(static_cast<GLuint>(i));
model.uniformBlocks[glBlockIndex].activeVariables.push_back(static_cast<GLuint>(i));
}
}
}