mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +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:
@@ -205,6 +205,7 @@ namespace MobileGL {
|
||||
resolver =
|
||||
MakeUnique<TMglGlslIoResolver>(*program, (EShLanguage)stage, attrib.explicitVertexInLocations,
|
||||
attrib.explicitFragmentOutLocations,
|
||||
attrib.explicitFragmentOutIndices,
|
||||
attrib.explicitOpaqueUniformBindings);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@ namespace MobileGL {
|
||||
Vector<SharedPtr<glslang::TShader>> shaders;
|
||||
UnorderedMap<String, Uint> explicitVertexInLocations;
|
||||
UnorderedMap<String, Uint> explicitFragmentOutLocations;
|
||||
// Dual-source blend color index per fragment output (glBindFragDataLocationIndexed) ->
|
||||
// emitted as layout(index = N).
|
||||
UnorderedMap<String, Uint> explicitFragmentOutIndices;
|
||||
UnorderedMap<String, Uint>* explicitOpaqueUniformBindings = nullptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -76,6 +76,15 @@ namespace MobileGL {
|
||||
auto& writableType = ent.symbol->getWritableType();
|
||||
writableType.getQualifier().layoutLocation = it->second;
|
||||
}
|
||||
// Dual-source blend color index (glBindFragDataLocationIndexed) -> layout(index = N).
|
||||
// Only the non-zero (dual-source) index is emitted: index 0 is the GL default, and
|
||||
// emitting an explicit "index = 0" qualifier would demand GL_EXT_blend_func_extended on
|
||||
// GLES even for ordinary single-source fragment outputs.
|
||||
auto idxIt = m_explicitFragOutIndices.find(name.c_str());
|
||||
if (idxIt != m_explicitFragOutIndices.end() && idxIt->second != 0) {
|
||||
auto& writableType = ent.symbol->getWritableType();
|
||||
writableType.getQualifier().layoutIndex = idxIt->second;
|
||||
}
|
||||
}
|
||||
if (ShouldAssignPlainUniformLocation(type)) {
|
||||
const int size = glslang::TIntermediate::computeTypeUniformLocationSize(type);
|
||||
|
||||
@@ -26,13 +26,15 @@ namespace MobileGL {
|
||||
public:
|
||||
using ExplicitVarSlotMap = UnorderedMap<String, Uint>;
|
||||
TMglGlslIoResolver(const glslang::TIntermediate& intermediate, const ExplicitVarSlotMap& vertexIns,
|
||||
const ExplicitVarSlotMap& fragOuts, ExplicitVarSlotMap* opaqueUniformBindings)
|
||||
const ExplicitVarSlotMap& fragOuts, const ExplicitVarSlotMap& fragOutIndices,
|
||||
ExplicitVarSlotMap* opaqueUniformBindings)
|
||||
: TDefaultGlslIoResolver(intermediate), m_explicitVertexIns(vertexIns), m_explicitFragOuts(fragOuts),
|
||||
m_explicitOpaqueUniformBindings(opaqueUniformBindings) {}
|
||||
m_explicitFragOutIndices(fragOutIndices), m_explicitOpaqueUniformBindings(opaqueUniformBindings) {}
|
||||
TMglGlslIoResolver(const glslang::TProgram& program, const EShLanguage stage,
|
||||
const ExplicitVarSlotMap& vertexIns, const ExplicitVarSlotMap& fragOuts,
|
||||
ExplicitVarSlotMap* opaqueUniformBindings)
|
||||
: TMglGlslIoResolver(*program.getIntermediate(stage), vertexIns, fragOuts, opaqueUniformBindings) {}
|
||||
const ExplicitVarSlotMap& fragOutIndices, ExplicitVarSlotMap* opaqueUniformBindings)
|
||||
: TMglGlslIoResolver(*program.getIntermediate(stage), vertexIns, fragOuts, fragOutIndices,
|
||||
opaqueUniformBindings) {}
|
||||
void reserverStorageSlot(glslang::TVarEntryInfo& ent, TInfoSink& infoSink) override;
|
||||
void reserverResourceSlot(glslang::TVarEntryInfo& ent, TInfoSink& infoSink) override;
|
||||
int resolveUniformLocation(EShLanguage stage, glslang::TVarEntryInfo& ent) override;
|
||||
@@ -43,6 +45,7 @@ namespace MobileGL {
|
||||
|
||||
const ExplicitVarSlotMap& m_explicitVertexIns;
|
||||
const ExplicitVarSlotMap& m_explicitFragOuts;
|
||||
const ExplicitVarSlotMap& m_explicitFragOutIndices;
|
||||
ExplicitVarSlotMap* m_explicitOpaqueUniformBindings = nullptr;
|
||||
std::map<glslang::TString, int> m_plainUniformLocationSizeByName;
|
||||
std::map<glslang::TString, int> m_plainUniformLocationByName;
|
||||
|
||||
Reference in New Issue
Block a user