mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 20:28:32 +09:00
[Fix, Test] (GLState): give an atomic counter array its packed stride of four
This commit is contained in:
@@ -373,6 +373,13 @@ namespace MobileGL::MG_State::GLState {
|
||||
const auto& uniform = UniformAt(TProgramUniformIndex(index));
|
||||
if (GlBlockIndexFromTProgram(uniform.index) < 0) return -1;
|
||||
if (!uniform.type.isArray) return 0;
|
||||
// An atomic counter reaches the std140 branch below only because the transpiler
|
||||
// lowered it onto a synthesized block; the buffer it actually addresses is an
|
||||
// ATOMIC COUNTER buffer, whose elements are tightly packed uints (GL 4.6 core 7.6:
|
||||
// "each counter is a single 4-byte value"). Its array stride is therefore 4, not the
|
||||
// vec4 round-up std140 would apply
|
||||
// (KHR-GL43.shader_atomic_counters.basic-program-query wants 4 for ac_counter67[0]).
|
||||
if (IsActiveUniformAtomicCounter(index)) return 4;
|
||||
if (uniform.type.isMatrix) {
|
||||
const bool rowMajor = GetActiveUniformIsRowMajor(index) != 0;
|
||||
const int vectors = rowMajor ? uniform.type.matrixRows : uniform.type.matrixCols;
|
||||
|
||||
@@ -3401,3 +3401,81 @@ void main() { fragColor = vec4(1.0); }
|
||||
}
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
// GL 4.6 core 7.6: an atomic counter is a default-block uniform that addresses an ATOMIC COUNTER
|
||||
// buffer, where every counter is a tightly packed 4-byte value. MobileGL lowers each atomic_uint
|
||||
// onto a synthesized block, which used to drag the whole array-stride query onto the std140 rule
|
||||
// that rounds an element stride up to a vec4 - so an atomic counter array reported 16
|
||||
// (KHR-GL43.shader_atomic_counters.basic-program-query: "GL_UNIFORM_ARRAY_STRIDE is 16 should be
|
||||
// 4"). The offsets, matrix stride and row-major flag are pinned alongside it because the same
|
||||
// synthesized block feeds all four queries.
|
||||
TEST_F(ProgramTest, AtomicCounterArrayReportsThePackedFourByteStride) {
|
||||
const char* vsSource = R"(#version 430 core
|
||||
void main() { gl_Position = vec4(1.0); }
|
||||
)";
|
||||
const char* fsSource = R"(#version 430 core
|
||||
layout(location = 0) out vec4 o_color;
|
||||
layout(binding = 0, offset = 0) uniform atomic_uint ac_counter0;
|
||||
layout(binding = 0, offset = 4) uniform atomic_uint ac_counter1;
|
||||
layout(binding = 0) uniform atomic_uint ac_counter2;
|
||||
layout(binding = 0) uniform atomic_uint ac_counter67[2];
|
||||
layout(binding = 0) uniform atomic_uint ac_counter3;
|
||||
void main() {
|
||||
uint c = 0u;
|
||||
c += atomicCounterIncrement(ac_counter0);
|
||||
c += atomicCounterIncrement(ac_counter1);
|
||||
c += atomicCounterIncrement(ac_counter2);
|
||||
c += atomicCounterIncrement(ac_counter3);
|
||||
c += atomicCounterIncrement(ac_counter67[0]);
|
||||
c += atomicCounterIncrement(ac_counter67[1]);
|
||||
o_color = vec4(float(c));
|
||||
}
|
||||
)";
|
||||
const GLuint vs = CompileShaderChecked(GL_VERTEX_SHADER, vsSource);
|
||||
const GLuint fs = CompileShaderChecked(GL_FRAGMENT_SHADER, fsSource);
|
||||
const GLuint program = LinkVsFs(vs, fs, GL_TRUE);
|
||||
|
||||
GLint activeUniforms = 0;
|
||||
GetProgramiv(program, GL_ACTIVE_UNIFORMS, &activeUniforms);
|
||||
ASSERT_EQ(activeUniforms, 5);
|
||||
|
||||
// Declared offset -> expected {array size, array stride}. layout(offset=) pins the first two;
|
||||
// the rest are packed after them in declaration order, the array taking two 4-byte slots.
|
||||
struct Expectation {
|
||||
const char* name;
|
||||
GLint size;
|
||||
GLint offset;
|
||||
GLint arrayStride;
|
||||
};
|
||||
const Expectation expectations[] = {
|
||||
{"ac_counter0", 1, 0, 0}, {"ac_counter1", 1, 4, 0}, {"ac_counter2", 1, 8, 0},
|
||||
{"ac_counter67[0]", 2, 12, 4}, {"ac_counter3", 1, 20, 0},
|
||||
};
|
||||
|
||||
for (const auto& expected : expectations) {
|
||||
const char* queryName = expected.name;
|
||||
GLuint index = GL_INVALID_INDEX;
|
||||
GetUniformIndices(program, 1, &queryName, &index);
|
||||
ASSERT_NE(index, GL_INVALID_INDEX) << expected.name << " is not an active uniform";
|
||||
|
||||
GLint value = -2;
|
||||
GetActiveUniformsiv(program, 1, &index, GL_UNIFORM_TYPE, &value);
|
||||
EXPECT_EQ(value, static_cast<GLint>(GL_UNSIGNED_INT_ATOMIC_COUNTER)) << expected.name;
|
||||
GetActiveUniformsiv(program, 1, &index, GL_UNIFORM_SIZE, &value);
|
||||
EXPECT_EQ(value, expected.size) << expected.name;
|
||||
// An atomic counter is a default-block uniform however it was lowered.
|
||||
GetActiveUniformsiv(program, 1, &index, GL_UNIFORM_BLOCK_INDEX, &value);
|
||||
EXPECT_EQ(value, -1) << expected.name;
|
||||
GetActiveUniformsiv(program, 1, &index, GL_UNIFORM_OFFSET, &value);
|
||||
EXPECT_EQ(value, expected.offset) << expected.name;
|
||||
GetActiveUniformsiv(program, 1, &index, GL_UNIFORM_ARRAY_STRIDE, &value);
|
||||
EXPECT_EQ(value, expected.arrayStride) << expected.name;
|
||||
GetActiveUniformsiv(program, 1, &index, GL_UNIFORM_MATRIX_STRIDE, &value);
|
||||
EXPECT_EQ(value, 0) << expected.name;
|
||||
GetActiveUniformsiv(program, 1, &index, GL_UNIFORM_IS_ROW_MAJOR, &value);
|
||||
EXPECT_EQ(value, 0) << expected.name;
|
||||
GetActiveUniformsiv(program, 1, &index, GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX, &value);
|
||||
EXPECT_EQ(value, 0) << expected.name;
|
||||
}
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user