mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
[Feat] (MobileGL): full dual-source blending across state, transpiler, and both backends
Wire GL_SRC1_* dual-source blend factors (glBlendFunc) end to end with the
glBindFragDataLocationIndexed color index, so a fragment shader can drive both
dual-source blend inputs.
State + converters:
- RenderState BlendFactor gains Src1Color/OneMinusSrc1Color/Src1Alpha/
OneMinusSrc1Alpha; GLToMG/MGToGL/MGToVk/MGToStr converters map them to
GL_SRC1_*, VK_BLEND_FACTOR_SRC1_*, and readable names.
Transpiler layout(index = N):
- ProgramAttrib carries explicitFragmentOutIndices; ProgramObject threads
m_explicitFragDataIndex into it at both link sites.
- TMglGlslIoResolver applies the color index as TQualifier.layoutIndex on the
fragment output, emitting layout(index = 1) via the glslang Index decoration
-> SPIRV-Cross path. Only the non-zero (dual-source) index is emitted: index 0
is the GL default and an explicit "index = 0" would demand
GL_EXT_blend_func_extended on GLES for ordinary single-source outputs.
Feature detection, POST, and hard-fail at use time (no silent fallback):
- Vulkan: dualSrcBlend is detected at device creation and cached; a draw whose
enabled blend state uses a SRC1 factor without the feature throws at pipeline
build with the reason and a pointer to the POST row.
- GLES: GL_EXT_blend_func_extended detected at load into
GLESCapabilities.SupportsDualSourceBlend; a draw enabling blend with a SRC1
factor without it throws in the blend-state sync with the same guidance.
- DriverPost adds a dual-source-blend row for both backends (Pass/Warn).
Tests:
- ProgramTest.CompileAndLinkWithExplicitFragmentOut now asserts the transpiled
fragment shader carries layout(location = 0, index = 1) after a re-link with
glBindFragDataLocationIndexed(index 1), and still omits any index qualifier
for the plain index-0 output.
This commit is contained in:
@@ -1399,6 +1399,25 @@ TEST_F(ProgramTest, CompileAndLinkWithExplicitFragmentOut) {
|
||||
EXPECT_EQ(GetFragDataIndex(program, "fragColor"), 1);
|
||||
EXPECT_EQ(GetFragDataIndex(program, "notAnActiveOutput"), -1);
|
||||
|
||||
// The color index must reach the transpiled shader as layout(location = 0, index = 1) so the
|
||||
// driver binds fragColor as the second dual-source input; the SPIR-V Index decoration set from
|
||||
// the glslang layoutIndex round-trips through SPIRV-Cross.
|
||||
auto& spirvsIndexed = programObject->GetGeneratedSpirv();
|
||||
auto& fragSpirvIndexed = spirvsIndexed[programObject->GetShaderIndexByStage(ShaderStage::Fragment)];
|
||||
MG_Util::ShaderTranspiler::SpvcSession spvcSessionIndexed(fragSpirvIndexed,
|
||||
MG_Util::ShaderTranspiler::SessionUsageBit::Transpile);
|
||||
spvc_compiler_options optionsIndexed;
|
||||
spvcSessionIndexed.CreateOptions(&optionsIndexed);
|
||||
spvc_compiler_options_set_uint(optionsIndexed, SPVC_COMPILER_OPTION_GLSL_VERSION, 460);
|
||||
spvc_compiler_options_set_bool(optionsIndexed, SPVC_COMPILER_OPTION_GLSL_ES, SPVC_FALSE);
|
||||
spvcSessionIndexed.SetOptions(optionsIndexed);
|
||||
const char* resultIndexed = nullptr;
|
||||
spvcSessionIndexed.Compile(&resultIndexed);
|
||||
printf("%s\n\n", resultIndexed);
|
||||
const char* indexNeedle = "index = 1";
|
||||
ASSERT_TRUE(strstr(resultIndexed, indexNeedle) != nullptr)
|
||||
<< "Expected dual-source color index in generated shader.\n(Searching for \"" << indexNeedle << "\")";
|
||||
|
||||
// glBindFragDataLocation is equivalent to index 0 and resets it.
|
||||
BindFragDataLocation(program, 0, "fragColor");
|
||||
LinkProgram(program);
|
||||
|
||||
Reference in New Issue
Block a user