diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index f87dae04..ecc37248 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -837,6 +837,39 @@ namespace MobileGL { MGLOG_D("%s: \"%s\" at uniformBlockIndex %02d, length = %d", __func__, uniformBlockName, uniformBlockIndex, *length); } + void BindFragDataLocation_State(GLuint program, GLuint colorNumber, const char* name) { + auto programObject = TryToGetProgramObject(program); + if (programObject == nullptr) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, "`program` is not the name of a program object.")); + return; + } + if (strncmp(name, "gl_", 3) == 0) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, + "`name` starts with the reserved prefix `gl_`.")); + return; + } + // TODO: Emit error "if `colorNumber` is greater than or equal to `GL_MAX_DRAW_BUFFERS`" + + MGLOG_D("%s: loc %02d = \"%s\"", __func__, index, name); + programObject->SetExplicitFragmentOutLocation(colorNumber, name); + } + + GLint GetFragDataLocation_State(GLuint program, const char* name) { + auto programObject = TryToGetProgramObject(program); + if (programObject == nullptr) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeShared("MG_Impl/GLImpl", __func__, "`program` is not the name of a program object.")); + return -1; + } + return programObject->GetFragmentDataLocation(name); + } + + void ValidateProgram_State(GLuint program) { // THROW_UNIMPL_EXCEPTION; } @@ -1039,6 +1072,14 @@ namespace MobileGL { GetActiveUniformBlockName_State(program, uniformBlockIndex, bufSize, length, uniformBlockName); } + void BindFragDataLocation(GLuint program, GLuint colorNumber, const char* name) { + BindFragDataLocation_State(program, colorNumber, name); + } + + GLint GetFragDataLocation(GLuint program, const char* name) { + return GetFragDataLocation_State(program, name); + } + void ValidateProgram(GLuint program) { ValidateProgram_State(program); } diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.h b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.h index afbf524e..8fdf32db 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.h +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.h @@ -53,6 +53,8 @@ namespace MobileGL { void UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); void GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params); void GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName); + void BindFragDataLocation(GLuint program, GLuint colorNumber, const char* name); + GLint GetFragDataLocation(GLuint program, const char* name); void ValidateProgram(GLuint program); } // namespace MG_Impl::GLImpl } // namespace MobileGL diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index 099eae53..60d30763 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -86,7 +86,8 @@ namespace MobileGL { MG_Util::ShaderTranspiler::ProgramAttrib attrib{ .shaders = Move(shaders), - .explicitVertexInLocations = m_explicitAttribLocations + .explicitVertexInLocations = m_explicitAttribLocations, + .explicitFragmentOutLocations = m_explicitFragDataLocation }; MGLOG_D("ProgramObject %u: Calling ShaderCompiler::LinkProgram", m_externalIndex); @@ -376,7 +377,8 @@ namespace MobileGL { ProgramAttrib attrib{ .shaders = Move(shaders), - .explicitVertexInLocations = m_explicitAttribLocations + .explicitVertexInLocations = m_explicitAttribLocations, + .explicitFragmentOutLocations = m_explicitFragDataLocation }; MGLOG_D("ProgramObject %u: GenerateBinary - linking program for binary", m_externalIndex); auto programResult = ShaderCompiler::LinkProgram(attrib); @@ -472,6 +474,22 @@ namespace MobileGL { MGLOG_D("ProgramObject %u: SetExplicitVertexInLocation - stored explicit location for '%s' -> %u", m_externalIndex, name, index); } + + void ProgramObject::SetExplicitFragmentOutLocation(Uint index, const char* name) { + MGLOG_D("ProgramObject %u: SetExplicitFragmentOutLocation called name='%s' index=%u", m_externalIndex, name, + index); + m_explicitFragDataLocation[name] = index; + MGLOG_D("ProgramObject %u: SetExplicitFragmentOutLocation - stored explicit location for '%s' -> %u", + m_externalIndex, name, index); + } + + Int ProgramObject::GetFragmentDataLocation(const char* name) { + // TODO: should retrieve "post-mortem" location from glslang instead + auto it = m_explicitFragDataLocation.find(name); + if (it == m_explicitFragDataLocation.end()) + return -1; + return it->second; + } } // namespace GLState } // namespace MG_State } // namespace MobileGL diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h index 0d8474e1..7506f2a6 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h @@ -18,6 +18,8 @@ namespace MobileGL { void MarkAsDeleted(); void SetExplicitVertexInLocation(Uint index, const char* name); + void SetExplicitFragmentOutLocation(Uint index, const char* name); + Int GetFragmentDataLocation(const char* name); Vector>& GetAttachedShaders(); const String& GetInfoLog() const { return m_infoLog; } @@ -119,13 +121,16 @@ namespace MobileGL { Vector> m_generatedSpirv; - // Attributes + // Attributes (Vertex in) UnorderedMap m_explicitAttribLocations; Vector m_attribs; Vector m_attribTypes; // For SpvcSession::SetVertexAttribLocation() // UnorderedMap m_attribLocation; + // FragData (Frag out) + UnorderedMap m_explicitFragDataLocation; + // Uniforms UnorderedMap m_uniformLocations; // Ordered by location, diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index 4fb40c35..119c51b6 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -872,7 +872,7 @@ void main() { fragColor = color * ColorModulator; })"; -TEST_F(ProgramTest, CompileAndLinkOptfineSample1) { +TEST_F(ProgramTest, CompileAndLinkWithExplicitVertexIn) { char infoLog[1024] = ""; GLuint fs = CreateShader(GL_FRAGMENT_SHADER); @@ -913,10 +913,72 @@ TEST_F(ProgramTest, CompileAndLinkOptfineSample1) { auto programObject = MG_State::pGLContext->GetCurrentProgram(); auto& spirvs = programObject->GetGeneratedSpirv(); - char* found_correct_uv0 = nullptr; + auto& vertexSpirv = spirvs[1]; // 0 - fragment, 1 - vertex + char* pSrcVertIn = nullptr; const char* needle = "layout(location = 2) in vec2 UV0;"; - for (auto spirv: spirvs) { - MG_Util::ShaderTranspiler::SpvcSession spvcSession(spirv); + // for (auto spirv: spirvs) { + MG_Util::ShaderTranspiler::SpvcSession spvcSession(vertexSpirv); + spvc_compiler_options options; + spvcSession.CreateOptions(&options); + + spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, 460); + spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, SPVC_FALSE); + // spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS, SPVC_FALSE); + + spvcSession.SetOptions(options); + + const char* result = nullptr; + spvcSession.Compile(&result); + printf("%s\n\n", result); + const char* ret = strstr(result, needle); + if (ret) + pSrcVertIn = (char*)ret; + // } + ASSERT_TRUE(pSrcVertIn != nullptr) << "Not found expected string in generated shader.\n(Searching for \"" << needle << "\")"; +} + +TEST_F(ProgramTest, CompileAndLinkWithExplicitFragmentOut) { + char infoLog[1024] = ""; + + GLuint fs = CreateShader(GL_FRAGMENT_SHADER); + ShaderSource(fs, 1, &optifine_fs1, NULL); + CompileShader(fs); + GLint fsStatus = GL_FALSE; + GetShaderiv(fs, GL_COMPILE_STATUS, &fsStatus); + GetShaderInfoLog(fs, 1024, nullptr, infoLog); + ASSERT_EQ(fsStatus, GL_TRUE) << infoLog; + + GLuint vs = CreateShader(GL_VERTEX_SHADER); + ShaderSource(vs, 1, &optifine_vs1, NULL); + CompileShader(vs); + GLint vsStatus = GL_FALSE; + GetShaderiv(vs, GL_COMPILE_STATUS, &vsStatus); + GetShaderInfoLog(vs, 1024, nullptr, infoLog); + ASSERT_EQ(vsStatus, GL_TRUE) << infoLog; + + GLuint program = CreateProgram(); + AttachShader(program, fs); + AttachShader(program, vs); + + BindFragDataLocation(program, 7, "fragColor"); + + LinkProgram(program); + GLint linkStatus = GL_FALSE; + GetProgramiv(program, GL_LINK_STATUS, &linkStatus); + ASSERT_EQ(linkStatus, GL_TRUE); + printf("Program linked.\n"); + + UseProgram(program); + GLint fragColorLoc = GetFragDataLocation(program, "fragColor"); + ASSERT_EQ(fragColorLoc, 7); + + auto programObject = MG_State::pGLContext->GetCurrentProgram(); + auto& spirvs = programObject->GetGeneratedSpirv(); + auto& fragSpirv = spirvs[0]; // 0 - fragment, 1 - vertex + char* pSrcfragOut = nullptr; + const char* needle = "layout(location = 7) out vec4 fragColor;"; + // for (auto spirv: spirvs) { + MG_Util::ShaderTranspiler::SpvcSession spvcSession(fragSpirv); spvc_compiler_options options; spvcSession.CreateOptions(&options); @@ -931,8 +993,7 @@ TEST_F(ProgramTest, CompileAndLinkOptfineSample1) { printf("%s\n\n", result); const char* ret = strstr(result, needle); if (ret) - found_correct_uv0 = (char*)ret; - } - ASSERT_TRUE(found_correct_uv0 != nullptr) << "Not found correct attribute in generated shader.\n(Searching for \"" << needle << "\")"; + pSrcfragOut = (char*)ret; + // } + ASSERT_TRUE(pSrcfragOut != nullptr) << "Not found expected string in generated shader.\n(Searching for \"" << needle << "\")"; } -