diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index a5d3a6c4..251520b1 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -1200,6 +1200,19 @@ namespace MobileGL::MG_Impl::GLImpl { std::to_string(program) + " is not the name of a program object.")); return -1; } + if (name == nullptr) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", __func__, "name cannot be null.")); + return -1; + } + if (!programObject->GetLinkStatus()) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", __func__, + std::to_string(program) + " has not been linked successfully.")); + return -1; + } return programObject->GetFragmentDataLocation(name); } diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index a67c82c5..56e120ef 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -214,6 +214,7 @@ namespace MobileGL::MG_State::GLState { if (result) { m_linkStatus = true; m_program = result.value(); + m_linkedFragDataLocation = m_explicitFragDataLocation; MGLOG_D("ProgramObject %u: LinkProgram succeeded, TProgram ptr %p", m_externalIndex, m_program.get()); } else { m_infoLog = result.error().log; @@ -592,12 +593,12 @@ namespace MobileGL::MG_State::GLState { Int ProgramObject::GetFragmentDataLocation(const char* name) { if (!m_program || !name) return -1; - const auto explicitLocation = m_explicitFragDataLocation.find(name); + const auto explicitLocation = m_linkedFragDataLocation.find(name); const Int outputCount = m_program->getNumPipeOutputs(); for (Int index = 0; index < outputCount; ++index) { const auto& output = m_program->getPipeOutput(index); if (output.name != name) continue; - if (explicitLocation != m_explicitFragDataLocation.end()) return static_cast(explicitLocation->second); + if (explicitLocation != m_linkedFragDataLocation.end()) return static_cast(explicitLocation->second); return static_cast(output.layoutLocation()); } return -1; diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h index e041baa6..432f6e4f 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h @@ -257,6 +257,7 @@ namespace MobileGL::MG_State::GLState { // FragData (Frag out) UnorderedMap m_explicitFragDataLocation; + UnorderedMap m_linkedFragDataLocation; // Uniforms UnorderedMap m_uniformLocations; diff --git a/MobileGL/MG_Test/Program/ProgramUtilTest.cpp b/MobileGL/MG_Test/Program/ProgramUtilTest.cpp index 2aa1b3f7..19649104 100644 --- a/MobileGL/MG_Test/Program/ProgramUtilTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramUtilTest.cpp @@ -142,6 +142,30 @@ void main() { EXPECT_EQ(source.find("#define"), String::npos); } +TEST_F(ProgramUtilTest, PreprocessLegacyFragmentShaderModernizesFragData) { + using namespace MG_Util::ShaderTranspiler; + + String source = R"(#version 130 +void main() { + gl_FragData[0] = vec4(1.0); + gl_FragData[1].a = 0.5; +})"; + + PreprocessShaderSource(ShaderStage::Fragment, source); + + EXPECT_EQ(source.find("#version 460 core\n"), 0); + EXPECT_NE(source.find("layout(location = 0) out vec4 mg_FragData[8];\n"), String::npos); + EXPECT_NE(source.find("mg_FragData[0] = vec4(1.0);"), String::npos); + EXPECT_NE(source.find("mg_FragData[1].a = 0.5;"), String::npos); + EXPECT_EQ(source.find("gl_FragData"), String::npos); + + ShaderAttrib attrib{.shaderType = GL_FRAGMENT_SHADER, .sourceStr = source}; + auto res = ShaderCompiler::CompileShader(attrib); + if (!res) { + FAIL() << "errc: " << res.error().errc << "\nlog: " << res.error().log << "\nsource:\n" << source; + } +} + TEST_F(ProgramUtilTest, PreprocessFragmentShaderInjectsDepthRangeShim) { using namespace MG_Util::ShaderTranspiler; diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp b/MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp index e75728a7..2cf8dcb2 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderSourceProcessor.cpp @@ -286,10 +286,15 @@ namespace { if (stage == MobileGL::ShaderStage::Fragment) { ReplaceIdentifier(source, "varying", "in"); const bool usesFragColor = source.find("gl_FragColor") != MobileGL::String::npos; + const bool usesFragData = source.find("gl_FragData") != MobileGL::String::npos; if (usesFragColor) { ReplaceIdentifier(source, "gl_FragColor", "mg_FragColor"); source.insert(FindAfterVersionDirective(source), "out vec4 mg_FragColor;\n"); } + if (usesFragData) { + ReplaceIdentifier(source, "gl_FragData", "mg_FragData"); + source.insert(FindAfterVersionDirective(source), "layout(location = 0) out vec4 mg_FragData[8];\n"); + } } }