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:
@@ -49,6 +49,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
static SharedPtr<MG_State::GLState::SamplerObject> g_rawDepthFetchSamplerState;
|
static SharedPtr<MG_State::GLState::SamplerObject> g_rawDepthFetchSamplerState;
|
||||||
static SharedPtr<SamplerImpl::BackendSamplerObject> g_rawDepthFetchSamplerBackend;
|
static SharedPtr<SamplerImpl::BackendSamplerObject> g_rawDepthFetchSamplerBackend;
|
||||||
|
|
||||||
|
static Bool IsDualSourceBlendFactor(BlendFactor v) {
|
||||||
|
switch (v) {
|
||||||
|
case BlendFactor::Src1Color:
|
||||||
|
case BlendFactor::OneMinusSrc1Color:
|
||||||
|
case BlendFactor::Src1Alpha:
|
||||||
|
case BlendFactor::OneMinusSrc1Alpha:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum class DrawSyncBit : Uint32 {
|
enum class DrawSyncBit : Uint32 {
|
||||||
None = 0,
|
None = 0,
|
||||||
IndexBuffer = 1 << 0,
|
IndexBuffer = 1 << 0,
|
||||||
@@ -583,6 +595,27 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
const auto& targetStates = parameters.BlendStates;
|
const auto& targetStates = parameters.BlendStates;
|
||||||
auto& syncedStates = g_syncedRenderStateParameters.BlendStates;
|
auto& syncedStates = g_syncedRenderStateParameters.BlendStates;
|
||||||
|
|
||||||
|
// Dual-source blending (GL_SRC1_* factors from glBlendFunc paired with
|
||||||
|
// glBindFragDataLocationIndexed) needs GL_EXT_blend_func_extended; GLES core has none.
|
||||||
|
// Detected at load and surfaced in the POST. There is no fallback, so if a draw actually
|
||||||
|
// enables blending with a SRC1 factor on a driver that lacks it, hard-fail here at use
|
||||||
|
// time rather than let the driver reject glBlendFuncSeparate and silently mis-blend.
|
||||||
|
if (!g_GLESCapabilities.SupportsDualSourceBlend) {
|
||||||
|
for (Uint i = 0; i < FBO::MAX_DRAW_BUFFERS; ++i) {
|
||||||
|
const auto& s = targetStates[i];
|
||||||
|
if (s.Enabled &&
|
||||||
|
(IsDualSourceBlendFactor(s.SrcFactorRGB) || IsDualSourceBlendFactor(s.DstFactorRGB) ||
|
||||||
|
IsDualSourceBlendFactor(s.SrcFactorAlpha) || IsDualSourceBlendFactor(s.DstFactorAlpha))) {
|
||||||
|
THROW_EXCEPTION(
|
||||||
|
"Dual-source blending (GL_SRC1_* blend factor) was used on draw buffer " +
|
||||||
|
std::to_string(i) +
|
||||||
|
", but the GLES driver does not expose GL_EXT_blend_func_extended (see the "
|
||||||
|
"dual-source blend row in the driver POST). No fallback exists; the draw "
|
||||||
|
"cannot proceed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Bool allEnabled = true;
|
Bool allEnabled = true;
|
||||||
Bool allDisabled = true;
|
Bool allDisabled = true;
|
||||||
Bool anyCapDirty = false;
|
Bool anyCapDirty = false;
|
||||||
|
|||||||
@@ -135,6 +135,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return attachment;
|
return attachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Bool IsDualSourceBlendFactor(BlendFactor v) {
|
||||||
|
switch (v) {
|
||||||
|
case BlendFactor::Src1Color:
|
||||||
|
case BlendFactor::OneMinusSrc1Color:
|
||||||
|
case BlendFactor::Src1Alpha:
|
||||||
|
case BlendFactor::OneMinusSrc1Alpha:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static Bool ShouldUseTransientVertexIndexBuffer(const MG_State::GLState::BufferObject& bufferObject) {
|
static Bool ShouldUseTransientVertexIndexBuffer(const MG_State::GLState::BufferObject& bufferObject) {
|
||||||
switch (bufferObject.GetUsage()) {
|
switch (bufferObject.GetUsage()) {
|
||||||
case BufferUsage::StreamDraw:
|
case BufferUsage::StreamDraw:
|
||||||
@@ -3245,6 +3257,20 @@ void main() {
|
|||||||
program.GetExternalIndex());
|
program.GetExternalIndex());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
// Dual-source blending (GL_SRC1_* factors from glBlendFunc paired with
|
||||||
|
// glBindFragDataLocationIndexed) requires the dualSrcBlend device feature. It is detected at
|
||||||
|
// device creation and surfaced in the POST; if a shader actually issues a draw with a SRC1
|
||||||
|
// factor on a device that lacks it, there is no fallback, so hard-fail here at use time
|
||||||
|
// rather than silently mistranslating the blend equation.
|
||||||
|
if (effectiveBlendEnabled && !m_dualSrcBlendFeatureEnabled &&
|
||||||
|
(IsDualSourceBlendFactor(srcRGB) || IsDualSourceBlendFactor(dstRGB) ||
|
||||||
|
IsDualSourceBlendFactor(srcAlpha) || IsDualSourceBlendFactor(dstAlpha))) {
|
||||||
|
THROW_EXCEPTION(
|
||||||
|
"Dual-source blending (GL_SRC1_* blend factor) was used on color attachment " +
|
||||||
|
std::to_string(i) +
|
||||||
|
", but the Vulkan device does not support the dualSrcBlend feature (see the "
|
||||||
|
"dualSrcBlend row in the driver POST). No fallback exists; the draw cannot proceed.");
|
||||||
|
}
|
||||||
payload.colorBlendAttachments[i] = MakeColorBlendAttachmentState(
|
payload.colorBlendAttachments[i] = MakeColorBlendAttachmentState(
|
||||||
effectiveBlendEnabled,
|
effectiveBlendEnabled,
|
||||||
MG_Util::ConvertBlendFactorToVkEnum(srcRGB),
|
MG_Util::ConvertBlendFactorToVkEnum(srcRGB),
|
||||||
|
|||||||
@@ -282,6 +282,7 @@ namespace MobileGL::MG_State::GLState {
|
|||||||
MG_Util::ShaderTranspiler::ProgramAttrib attrib{.shaders = Move(shaders),
|
MG_Util::ShaderTranspiler::ProgramAttrib attrib{.shaders = Move(shaders),
|
||||||
.explicitVertexInLocations = m_explicitAttribLocations,
|
.explicitVertexInLocations = m_explicitAttribLocations,
|
||||||
.explicitFragmentOutLocations = m_explicitFragDataLocation,
|
.explicitFragmentOutLocations = m_explicitFragDataLocation,
|
||||||
|
.explicitFragmentOutIndices = m_explicitFragDataIndex,
|
||||||
.explicitOpaqueUniformBindings =
|
.explicitOpaqueUniformBindings =
|
||||||
&m_explicitOpaqueUniformBindings};
|
&m_explicitOpaqueUniformBindings};
|
||||||
|
|
||||||
@@ -579,6 +580,7 @@ namespace MobileGL::MG_State::GLState {
|
|||||||
ProgramAttrib attrib{.shaders = Move(shaders),
|
ProgramAttrib attrib{.shaders = Move(shaders),
|
||||||
.explicitVertexInLocations = m_explicitAttribLocations,
|
.explicitVertexInLocations = m_explicitAttribLocations,
|
||||||
.explicitFragmentOutLocations = m_explicitFragDataLocation,
|
.explicitFragmentOutLocations = m_explicitFragDataLocation,
|
||||||
|
.explicitFragmentOutIndices = m_explicitFragDataIndex,
|
||||||
.explicitOpaqueUniformBindings = &m_explicitOpaqueUniformBindings};
|
.explicitOpaqueUniformBindings = &m_explicitOpaqueUniformBindings};
|
||||||
MGLOG_D("ProgramObject %u: GenerateBinary - linking program for binary", m_externalIndex);
|
MGLOG_D("ProgramObject %u: GenerateBinary - linking program for binary", m_externalIndex);
|
||||||
auto programResult = ShaderCompiler::LinkProgram(attrib);
|
auto programResult = ShaderCompiler::LinkProgram(attrib);
|
||||||
|
|||||||
@@ -27,6 +27,12 @@ namespace MobileGL {
|
|||||||
OneMinusConstantColor,
|
OneMinusConstantColor,
|
||||||
ConstantAlpha,
|
ConstantAlpha,
|
||||||
OneMinusConstantAlpha,
|
OneMinusConstantAlpha,
|
||||||
|
// Dual-source blend factors (GL_SRC1_*, glBindFragDataLocationIndexed); require the
|
||||||
|
// dualSrcBlend device feature.
|
||||||
|
Src1Color,
|
||||||
|
OneMinusSrc1Color,
|
||||||
|
Src1Alpha,
|
||||||
|
OneMinusSrc1Alpha,
|
||||||
BlendFactorCount,
|
BlendFactorCount,
|
||||||
Unknown = -1
|
Unknown = -1
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1399,6 +1399,25 @@ TEST_F(ProgramTest, CompileAndLinkWithExplicitFragmentOut) {
|
|||||||
EXPECT_EQ(GetFragDataIndex(program, "fragColor"), 1);
|
EXPECT_EQ(GetFragDataIndex(program, "fragColor"), 1);
|
||||||
EXPECT_EQ(GetFragDataIndex(program, "notAnActiveOutput"), -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.
|
// glBindFragDataLocation is equivalent to index 0 and resets it.
|
||||||
BindFragDataLocation(program, 0, "fragColor");
|
BindFragDataLocation(program, 0, "fragColor");
|
||||||
LinkProgram(program);
|
LinkProgram(program);
|
||||||
|
|||||||
@@ -742,6 +742,9 @@ namespace MobileGL::MG_Util::BackendLoader {
|
|||||||
if (std::strcmp(extension, "GL_EXT_disjoint_timer_query") == 0) {
|
if (std::strcmp(extension, "GL_EXT_disjoint_timer_query") == 0) {
|
||||||
caps.SupportsDisjointTimerQuery = true;
|
caps.SupportsDisjointTimerQuery = true;
|
||||||
}
|
}
|
||||||
|
if (std::strcmp(extension, "GL_EXT_blend_func_extended") == 0) {
|
||||||
|
caps.SupportsDualSourceBlend = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -754,6 +757,8 @@ namespace MobileGL::MG_Util::BackendLoader {
|
|||||||
glesFuncs.glColorMaskiOES != nullptr;
|
glesFuncs.glColorMaskiOES != nullptr;
|
||||||
MGLOG_I(" glPolygonMode (NV/ANGLE): %s", caps.SupportsPolygonMode ? "yes" : "no");
|
MGLOG_I(" glPolygonMode (NV/ANGLE): %s", caps.SupportsPolygonMode ? "yes" : "no");
|
||||||
MGLOG_I(" indexed glColorMaski: %s", caps.SupportsIndexedColorMask ? "yes" : "no");
|
MGLOG_I(" indexed glColorMaski: %s", caps.SupportsIndexedColorMask ? "yes" : "no");
|
||||||
|
MGLOG_I(" dual-source blend (EXT_blend_func_extended): %s",
|
||||||
|
caps.SupportsDualSourceBlend ? "yes" : "no");
|
||||||
|
|
||||||
MGLOG_I("OpenGL ES capabilities:");
|
MGLOG_I("OpenGL ES capabilities:");
|
||||||
glesFuncs.glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &caps.UniformBufferOffsetAlignment);
|
glesFuncs.glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &caps.UniformBufferOffsetAlignment);
|
||||||
|
|||||||
@@ -1040,6 +1040,10 @@ namespace MobileGL {
|
|||||||
// An indexed glColorMaski entry point loaded (GLES 3.2 core, or GL_OES/EXT_draw_buffers_indexed).
|
// An indexed glColorMaski entry point loaded (GLES 3.2 core, or GL_OES/EXT_draw_buffers_indexed).
|
||||||
// Without it, only the non-indexed glColorMask (draw buffer 0 broadcast) is available.
|
// Without it, only the non-indexed glColorMask (draw buffer 0 broadcast) is available.
|
||||||
Bool SupportsIndexedColorMask = false;
|
Bool SupportsIndexedColorMask = false;
|
||||||
|
// GL_EXT_blend_func_extended is present: the driver accepts GL_SRC1_* dual-source blend
|
||||||
|
// factors and layout(index = 1) fragment outputs. GLES core has no dual-source blending,
|
||||||
|
// so without this a draw using a SRC1 factor cannot proceed.
|
||||||
|
Bool SupportsDualSourceBlend = false;
|
||||||
// GL_RENDERER contains "ANGLE".
|
// GL_RENDERER contains "ANGLE".
|
||||||
Bool IsAngleRenderer = false;
|
Bool IsAngleRenderer = false;
|
||||||
// GL_RENDERER contains both "ANGLE" and "llvmpipe".
|
// GL_RENDERER contains both "ANGLE" and "llvmpipe".
|
||||||
|
|||||||
@@ -40,6 +40,14 @@ namespace MobileGL {
|
|||||||
return BlendFactor::ConstantAlpha;
|
return BlendFactor::ConstantAlpha;
|
||||||
case GL_ONE_MINUS_CONSTANT_ALPHA:
|
case GL_ONE_MINUS_CONSTANT_ALPHA:
|
||||||
return BlendFactor::OneMinusConstantAlpha;
|
return BlendFactor::OneMinusConstantAlpha;
|
||||||
|
case GL_SRC1_COLOR:
|
||||||
|
return BlendFactor::Src1Color;
|
||||||
|
case GL_ONE_MINUS_SRC1_COLOR:
|
||||||
|
return BlendFactor::OneMinusSrc1Color;
|
||||||
|
case GL_SRC1_ALPHA:
|
||||||
|
return BlendFactor::Src1Alpha;
|
||||||
|
case GL_ONE_MINUS_SRC1_ALPHA:
|
||||||
|
return BlendFactor::OneMinusSrc1Alpha;
|
||||||
default:
|
default:
|
||||||
return BlendFactor::Unknown;
|
return BlendFactor::Unknown;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,14 @@ namespace MobileGL {
|
|||||||
return GL_CONSTANT_ALPHA;
|
return GL_CONSTANT_ALPHA;
|
||||||
case BlendFactor::OneMinusConstantAlpha:
|
case BlendFactor::OneMinusConstantAlpha:
|
||||||
return GL_ONE_MINUS_CONSTANT_ALPHA;
|
return GL_ONE_MINUS_CONSTANT_ALPHA;
|
||||||
|
case BlendFactor::Src1Color:
|
||||||
|
return GL_SRC1_COLOR;
|
||||||
|
case BlendFactor::OneMinusSrc1Color:
|
||||||
|
return GL_ONE_MINUS_SRC1_COLOR;
|
||||||
|
case BlendFactor::Src1Alpha:
|
||||||
|
return GL_SRC1_ALPHA;
|
||||||
|
case BlendFactor::OneMinusSrc1Alpha:
|
||||||
|
return GL_ONE_MINUS_SRC1_ALPHA;
|
||||||
default:
|
default:
|
||||||
return GL_UNKNOWN_MGL;
|
return GL_UNKNOWN_MGL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,14 @@ namespace MobileGL {
|
|||||||
return "ConstantAlpha";
|
return "ConstantAlpha";
|
||||||
case BlendFactor::OneMinusConstantAlpha:
|
case BlendFactor::OneMinusConstantAlpha:
|
||||||
return "OneMinusConstantAlpha";
|
return "OneMinusConstantAlpha";
|
||||||
|
case BlendFactor::Src1Color:
|
||||||
|
return "Src1Color";
|
||||||
|
case BlendFactor::OneMinusSrc1Color:
|
||||||
|
return "OneMinusSrc1Color";
|
||||||
|
case BlendFactor::Src1Alpha:
|
||||||
|
return "Src1Alpha";
|
||||||
|
case BlendFactor::OneMinusSrc1Alpha:
|
||||||
|
return "OneMinusSrc1Alpha";
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -175,6 +175,14 @@ namespace MobileGL {
|
|||||||
return VK_BLEND_FACTOR_CONSTANT_ALPHA;
|
return VK_BLEND_FACTOR_CONSTANT_ALPHA;
|
||||||
case BlendFactor::OneMinusConstantAlpha:
|
case BlendFactor::OneMinusConstantAlpha:
|
||||||
return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
|
return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA;
|
||||||
|
case BlendFactor::Src1Color:
|
||||||
|
return VK_BLEND_FACTOR_SRC1_COLOR;
|
||||||
|
case BlendFactor::OneMinusSrc1Color:
|
||||||
|
return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
|
||||||
|
case BlendFactor::Src1Alpha:
|
||||||
|
return VK_BLEND_FACTOR_SRC1_ALPHA;
|
||||||
|
case BlendFactor::OneMinusSrc1Alpha:
|
||||||
|
return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
|
||||||
default:
|
default:
|
||||||
return VK_BLEND_FACTOR_ONE;
|
return VK_BLEND_FACTOR_ONE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -248,6 +248,13 @@ namespace MobileGL::MG_Util::SelfTest {
|
|||||||
builder.Warn("Indexed color mask",
|
builder.Warn("Indexed color mask",
|
||||||
"no indexed glColorMaski; per-draw-buffer color masks fall back to draw buffer 0");
|
"no indexed glColorMaski; per-draw-buffer color masks fall back to draw buffer 0");
|
||||||
}
|
}
|
||||||
|
if (caps.SupportsDualSourceBlend) {
|
||||||
|
builder.Pass("Dual-source blend",
|
||||||
|
"GL_SRC1_* dual-source blend factors available via GL_EXT_blend_func_extended");
|
||||||
|
} else {
|
||||||
|
builder.Warn("Dual-source blend",
|
||||||
|
"no GL_EXT_blend_func_extended; GL_SRC1_* dual-source blend factors hard-fail at draw");
|
||||||
|
}
|
||||||
|
|
||||||
if (es31) {
|
if (es31) {
|
||||||
GLint maxVertexSsboBlocks = 0;
|
GLint maxVertexSsboBlocks = 0;
|
||||||
|
|||||||
@@ -205,6 +205,7 @@ namespace MobileGL {
|
|||||||
resolver =
|
resolver =
|
||||||
MakeUnique<TMglGlslIoResolver>(*program, (EShLanguage)stage, attrib.explicitVertexInLocations,
|
MakeUnique<TMglGlslIoResolver>(*program, (EShLanguage)stage, attrib.explicitVertexInLocations,
|
||||||
attrib.explicitFragmentOutLocations,
|
attrib.explicitFragmentOutLocations,
|
||||||
|
attrib.explicitFragmentOutIndices,
|
||||||
attrib.explicitOpaqueUniformBindings);
|
attrib.explicitOpaqueUniformBindings);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ namespace MobileGL {
|
|||||||
Vector<SharedPtr<glslang::TShader>> shaders;
|
Vector<SharedPtr<glslang::TShader>> shaders;
|
||||||
UnorderedMap<String, Uint> explicitVertexInLocations;
|
UnorderedMap<String, Uint> explicitVertexInLocations;
|
||||||
UnorderedMap<String, Uint> explicitFragmentOutLocations;
|
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;
|
UnorderedMap<String, Uint>* explicitOpaqueUniformBindings = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,15 @@ namespace MobileGL {
|
|||||||
auto& writableType = ent.symbol->getWritableType();
|
auto& writableType = ent.symbol->getWritableType();
|
||||||
writableType.getQualifier().layoutLocation = it->second;
|
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)) {
|
if (ShouldAssignPlainUniformLocation(type)) {
|
||||||
const int size = glslang::TIntermediate::computeTypeUniformLocationSize(type);
|
const int size = glslang::TIntermediate::computeTypeUniformLocationSize(type);
|
||||||
|
|||||||
@@ -26,13 +26,15 @@ namespace MobileGL {
|
|||||||
public:
|
public:
|
||||||
using ExplicitVarSlotMap = UnorderedMap<String, Uint>;
|
using ExplicitVarSlotMap = UnorderedMap<String, Uint>;
|
||||||
TMglGlslIoResolver(const glslang::TIntermediate& intermediate, const ExplicitVarSlotMap& vertexIns,
|
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),
|
: 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,
|
TMglGlslIoResolver(const glslang::TProgram& program, const EShLanguage stage,
|
||||||
const ExplicitVarSlotMap& vertexIns, const ExplicitVarSlotMap& fragOuts,
|
const ExplicitVarSlotMap& vertexIns, const ExplicitVarSlotMap& fragOuts,
|
||||||
ExplicitVarSlotMap* opaqueUniformBindings)
|
const ExplicitVarSlotMap& fragOutIndices, ExplicitVarSlotMap* opaqueUniformBindings)
|
||||||
: TMglGlslIoResolver(*program.getIntermediate(stage), vertexIns, fragOuts, opaqueUniformBindings) {}
|
: TMglGlslIoResolver(*program.getIntermediate(stage), vertexIns, fragOuts, fragOutIndices,
|
||||||
|
opaqueUniformBindings) {}
|
||||||
void reserverStorageSlot(glslang::TVarEntryInfo& ent, TInfoSink& infoSink) override;
|
void reserverStorageSlot(glslang::TVarEntryInfo& ent, TInfoSink& infoSink) override;
|
||||||
void reserverResourceSlot(glslang::TVarEntryInfo& ent, TInfoSink& infoSink) override;
|
void reserverResourceSlot(glslang::TVarEntryInfo& ent, TInfoSink& infoSink) override;
|
||||||
int resolveUniformLocation(EShLanguage stage, glslang::TVarEntryInfo& ent) override;
|
int resolveUniformLocation(EShLanguage stage, glslang::TVarEntryInfo& ent) override;
|
||||||
@@ -43,6 +45,7 @@ namespace MobileGL {
|
|||||||
|
|
||||||
const ExplicitVarSlotMap& m_explicitVertexIns;
|
const ExplicitVarSlotMap& m_explicitVertexIns;
|
||||||
const ExplicitVarSlotMap& m_explicitFragOuts;
|
const ExplicitVarSlotMap& m_explicitFragOuts;
|
||||||
|
const ExplicitVarSlotMap& m_explicitFragOutIndices;
|
||||||
ExplicitVarSlotMap* m_explicitOpaqueUniformBindings = nullptr;
|
ExplicitVarSlotMap* m_explicitOpaqueUniformBindings = nullptr;
|
||||||
std::map<glslang::TString, int> m_plainUniformLocationSizeByName;
|
std::map<glslang::TString, int> m_plainUniformLocationSizeByName;
|
||||||
std::map<glslang::TString, int> m_plainUniformLocationByName;
|
std::map<glslang::TString, int> m_plainUniformLocationByName;
|
||||||
|
|||||||
Reference in New Issue
Block a user