mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Fix, Test] (ShaderTranspiler, DirectGLES): stop printing the default fragment-output colour index into ESSL
This commit is contained in:
@@ -5865,6 +5865,16 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
spvcSession.SetAtomicCounterBlockBindings(atomicCounterEsslBindingTop,
|
spvcSession.SetAtomicCounterBlockBindings(atomicCounterEsslBindingTop,
|
||||||
outAtomicCounterGlBindings);
|
outAtomicCounterGlBindings);
|
||||||
|
|
||||||
|
// `layout(index = 0)` is the GL default spelled out loud, and GLSL ES has no such
|
||||||
|
// qualifier in core - a stage that prints it is refused with "index layout
|
||||||
|
// qualifier requires EXT_blend_func_extended" and the whole program then draws
|
||||||
|
// nothing. Drop the decoration when it carries the default; a REAL dual-source
|
||||||
|
// index (1) is left alone, because that one genuinely needs the extension and the
|
||||||
|
// driver has to see it. Fragment stage only: no other stage can carry it.
|
||||||
|
if (glShaderType == GL_FRAGMENT_SHADER) {
|
||||||
|
spvcSession.DropDefaultFragmentOutputColorIndex();
|
||||||
|
}
|
||||||
|
|
||||||
const char* result = nullptr;
|
const char* result = nullptr;
|
||||||
spvcSession.Compile(&result);
|
spvcSession.Compile(&result);
|
||||||
|
|
||||||
|
|||||||
@@ -179,6 +179,13 @@ void main()
|
|||||||
in flat uint v_index;
|
in flat uint v_index;
|
||||||
out vec4 o_color;
|
out vec4 o_color;
|
||||||
void main() { o_color = vec4(0.0, 1.0, 0.0, 1.0); }
|
void main() { o_color = vec4(0.0, 1.0, 0.0, 1.0); }
|
||||||
|
)";
|
||||||
|
|
||||||
|
// The colour index spelled out at its default value. Says nothing that
|
||||||
|
// `layout(location = 0)` alone does not, and must therefore cost nothing.
|
||||||
|
constexpr const char* kExplicitColorIndexFS = R"(#version 420 core
|
||||||
|
layout(location = 0, index = 0) out vec4 o_color;
|
||||||
|
void main() { o_color = vec4(0.0, 1.0, 0.0, 1.0); }
|
||||||
)";
|
)";
|
||||||
|
|
||||||
class Glsl420DeclarationScenario : public ScenarioTest {
|
class Glsl420DeclarationScenario : public ScenarioTest {
|
||||||
@@ -473,4 +480,24 @@ void main() { o_color = vec4(0.0, 1.0, 0.0, 1.0); }
|
|||||||
EXPECT_EQ(centre.g, 255) << "the atomic-counter shader linked but painted nothing";
|
EXPECT_EQ(centre.g, 255) << "the atomic-counter shader linked but painted nothing";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `layout(location = 0, index = 0)` is the GL default written out loud, and an application
|
||||||
|
// is entitled to write it - KHR-GL43.shader_atomic_counters.basic-program-query does. It has
|
||||||
|
// to reach the driver as an ORDINARY single-source output: GLSL ES has no `index` qualifier
|
||||||
|
// in core, so a transpiler that prints the decoration back gets "index layout qualifier
|
||||||
|
// requires EXT_blend_func_extended", the stage never compiles, the program runs with a stage
|
||||||
|
// missing and the draw paints nothing at all. Black, not red - which is why the conformance
|
||||||
|
// case looked like the atomic counters had stopped counting.
|
||||||
|
TEST_F(Glsl420DeclarationScenario, AnExplicitDefaultColorIndexStillDraws) {
|
||||||
|
if (!Ready()) return;
|
||||||
|
|
||||||
|
const GLuint program = Build(kQuadVS, kExplicitColorIndexFS);
|
||||||
|
if (program == 0) return;
|
||||||
|
|
||||||
|
const Rgba8 centre = DrawAndRead(program);
|
||||||
|
EXPECT_EQ(FirstGLError(), 0u);
|
||||||
|
EXPECT_EQ(centre.g, 255) << "a fragment output declared layout(location = 0, index = 0) painted "
|
||||||
|
"nothing; its stage was almost certainly refused by the driver";
|
||||||
|
EXPECT_EQ(centre.r, 0u);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace MGITest
|
} // namespace MGITest
|
||||||
|
|||||||
@@ -442,6 +442,23 @@ namespace MobileGL {
|
|||||||
SPVC_CHK_RETURN
|
SPVC_CHK_RETURN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spvc_result SpvcSession::DropDefaultFragmentOutputColorIndex() {
|
||||||
|
if (!(usage & SessionUsageBit::Transpile)) return SPVC_ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
SPVC_CHK_INIT
|
||||||
|
const spvc_reflected_resource* list = nullptr;
|
||||||
|
size_t count = 0;
|
||||||
|
SPVC_CHK_RESULT(spvc_resources_get_resource_list_for_type(
|
||||||
|
resources, SPVC_RESOURCE_TYPE_STAGE_OUTPUT, &list, &count));
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
const spvc_reflected_resource& resource = list[i];
|
||||||
|
if (!spvc_compiler_has_decoration(compiler, resource.id, SpvDecorationIndex)) continue;
|
||||||
|
if (spvc_compiler_get_decoration(compiler, resource.id, SpvDecorationIndex) != 0u) continue;
|
||||||
|
spvc_compiler_unset_decoration(compiler, resource.id, SpvDecorationIndex);
|
||||||
|
}
|
||||||
|
SPVC_CHK_RETURN
|
||||||
|
}
|
||||||
|
|
||||||
spvc_result SpvcSession::Compile(const char** result) {
|
spvc_result SpvcSession::Compile(const char** result) {
|
||||||
if (!(usage & SessionUsageBit::Transpile)) return SPVC_ERROR_INVALID_ARGUMENT;
|
if (!(usage & SessionUsageBit::Transpile)) return SPVC_ERROR_INVALID_ARGUMENT;
|
||||||
SPVC_CHK_INIT
|
SPVC_CHK_INIT
|
||||||
|
|||||||
@@ -120,6 +120,25 @@ namespace MobileGL {
|
|||||||
// `outGlBindings` is appended to, so one vector can collect a whole program's
|
// `outGlBindings` is appended to, so one vector can collect a whole program's
|
||||||
// stages; it may repeat a binding declared by several of them.
|
// stages; it may repeat a binding declared by several of them.
|
||||||
spvc_result SetAtomicCounterBlockBindings(Int topBinding, Vector<Int>& outGlBindings);
|
spvc_result SetAtomicCounterBlockBindings(Int topBinding, Vector<Int>& outGlBindings);
|
||||||
|
// Drops the Index decoration from every fragment output that carries the DEFAULT
|
||||||
|
// colour index 0, so the emitted ESSL does not print `index = 0`.
|
||||||
|
//
|
||||||
|
// Index 0 is what every single-source fragment output already is, in GL and in
|
||||||
|
// ESSL alike, and SPIR-V carries the decoration only because the application
|
||||||
|
// spelled the qualifier out - `layout(location = 0, index = 0) out vec4 c;` is
|
||||||
|
// legal desktop GLSL and says nothing. Printing it back into ESSL is NOT
|
||||||
|
// harmless: GLSL ES has no `index` layout qualifier in core, so the driver
|
||||||
|
// answers "index layout qualifier requires EXT_blend_func_extended" and refuses
|
||||||
|
// the stage. The program then links nothing and every draw with it renders
|
||||||
|
// NOTHING - verified on Mesa 26.1.4 llvmpipe with no MobileGL in the process,
|
||||||
|
// and it is why KHR-GL43.shader_atomic_counters.basic-program-query read back a
|
||||||
|
// black render target.
|
||||||
|
//
|
||||||
|
// A NON-zero index is left exactly as it is: that one really does select the
|
||||||
|
// second dual-source input and cannot be expressed without the extension, so it
|
||||||
|
// must keep reaching the driver (the frontend's own glBindFragDataLocationIndexed
|
||||||
|
// path already emits only non-zero indices for the same reason).
|
||||||
|
spvc_result DropDefaultFragmentOutputColorIndex();
|
||||||
spvc_result Compile(const char** result);
|
spvc_result Compile(const char** result);
|
||||||
const SpvcMetadata& GetMetadata() const;
|
const SpvcMetadata& GetMetadata() const;
|
||||||
const char* GetLastErrorString() const;
|
const char* GetLastErrorString() const;
|
||||||
|
|||||||
Reference in New Issue
Block a user