diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index 86dfa415..a8ba513c 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -100,7 +100,7 @@ namespace MobileGL { } GLuint CreateShader_State(GLenum type) { - auto shaderId = MG_State::pGLContext->CreateShader(MG_State::GLState::GetMGLShaderStageByGLShaderType(type)); + auto shaderId = MG_State::pGLContext->CreateShader(MG_State::GLState::ConvertMGLShaderStageByGLShaderType(type)); if (shaderId == 0) { MG_State::pGLContext->RecordError( ErrorCode::InvalidValue, @@ -199,7 +199,68 @@ namespace MobileGL { } void GetProgramiv_State(GLuint program, GLenum pname, GLint* params) { - THROW_UNIMPL_EXCEPTION; + auto programObject = TryToGetProgramObject(program); + if (!programObject) + return; + + switch (pname) { + case GL_DELETE_STATUS: + *params = programObject->GetDeleteStatus(); + break; + case GL_LINK_STATUS: + *params = programObject->GetLinkStatus(); + break; + case GL_VALIDATE_STATUS: + *params = programObject->GetValidateStatus(); + break; + case GL_INFO_LOG_LENGTH: { + const auto& log = programObject->GetInfoLog(); + *params = log.length(); + break; + } + case GL_ATTACHED_SHADERS: { + const auto& attachedShaders = programObject->GetAttachedShaders(); + *params = attachedShaders.size(); + break; + } + case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS: + *params = programObject->GetActiveAtomicCounterCount(); + break; + case GL_ACTIVE_ATTRIBUTES: + *params = programObject->GetActiveAttributesCount(); + break; + case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: + *params = programObject->GetActiveAttributesMaxLength(); + break; + case GL_ACTIVE_UNIFORMS: + *params = programObject->GetUniformCount(); + break; + case GL_ACTIVE_UNIFORM_MAX_LENGTH: + *params = programObject->GetUniformMaxLength(); + break; + case GL_ACTIVE_UNIFORM_BLOCKS: // GL >= 3.1 + *params = programObject->GetActiveUniformBlocksCount(); + break; + case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: // ditto. + *params = programObject->GetActiveUniformBlocksMaxLength(); + break; + case GL_COMPUTE_WORK_GROUP_SIZE: // GL >= 4.3 + + case GL_PROGRAM_BINARY_LENGTH: + + case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: + case GL_TRANSFORM_FEEDBACK_VARYINGS: + case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: + case GL_GEOMETRY_VERTICES_OUT: + case GL_GEOMETRY_INPUT_TYPE: + case GL_GEOMETRY_OUTPUT_TYPE: + default: + MG_State::pGLContext->RecordError( + ErrorCode::InvalidEnum, + MakeShared("MG_Impl/GLImpl", __func__, + "`pname` is not an accepted value.")); + return; + } } void GetProgramInfoLog_State(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog) { @@ -212,7 +273,33 @@ namespace MobileGL { } void GetShaderiv_State(GLuint shader, GLenum pname, GLint* params) { - THROW_UNIMPL_EXCEPTION; + auto shaderObject = TryToGetShaderObject(shader); + if (!shaderObject) + return; + + switch (pname) { + case GL_SHADER_TYPE: + *params = ConvertGLShaderTypeByMGLShaderStage(shaderObject->GetShaderStage()); + break; + case GL_DELETE_STATUS: + *params = shaderObject->GetDeleteStatus(); + break; + case GL_COMPILE_STATUS: + *params = shaderObject->GetCompileStatus(); + break; + case GL_INFO_LOG_LENGTH: + *params = shaderObject->GetInfoLog().length(); + break; + case GL_SHADER_SOURCE_LENGTH: + *params = shaderObject->GetShaderSource().length(); + break; + default: + MG_State::pGLContext->RecordError( + ErrorCode::InvalidEnum, + MakeShared("MG_Impl/GLImpl", __func__, + "`pname` is not an accepted value.")); + return; + } } void GetShaderInfoLog_State(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog) { diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index 99a06c5b..f4534ed4 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -26,12 +26,12 @@ namespace MobileGL { } void ProgramObject::Link() { - PreLink(); + // PreLink(); Vector shaderTypes(m_shaders.size()); Vector> shaders(m_shaders.size()); for (SizeT i = 0; i < m_shaders.size(); i++) { - shaderTypes[i] = GetGLShaderTypeByMGLShaderStage(m_shaders[i]->GetShaderStage()); + shaderTypes[i] = ConvertGLShaderTypeByMGLShaderStage(m_shaders[i]->GetShaderStage()); shaders[i] = m_shaders[i]->GetCompiledShader(); } @@ -43,17 +43,15 @@ namespace MobileGL { auto result = MG_Util::ShaderTranspiler::ShaderCompiler::LinkProgram(attrib); if (result) { m_linkStatus = true; - m_programBinary = Move(result.value()); + m_program = result.value(); } else { m_linkStatus = false; m_infoLog = result.error().log; - - const std::string e = std::format("Shader link failed: \nerrc: {}\nmsg: {}\n", result.error().errc, - result.error().log); - THROW_EXCEPTION(e); } - PostLink(); + // PostLink(); + + DoReflection(); } void ProgramObject::MarkAsDeleted() { @@ -64,99 +62,139 @@ namespace MobileGL { return m_shaders; } - void ProgramObject::PreLink() { - m_uniforms.clear(); - m_uniformOffsets.clear(); - - for (const auto& shader : m_shaders) { - for (const auto& [name, loc] : shader->GetUniformLocations()) { - // collect all the names to map - if (loc != 4095 || m_uniforms.find(name) == m_uniforms.end()) { - m_uniforms[name] = loc; - } - - // set a flag for those who have an explicit location - if (loc != 4095) { - if (loc >= m_uniformOffsets.size()) { - m_uniformOffsets.reserve(std::bit_ceil(loc + 1)); - m_uniformOffsets.resize(loc + 1, 0); - } - assert(m_uniformOffsets[loc] == 0); - m_uniformOffsets[loc] = 1; - } - } + void ProgramObject::DoReflection() { + if (!m_program->buildReflection()) { + m_linkStatus = false; + m_infoLog = "Build reflection failed."; + return; } - // Let's find a location for those who doesn't have one yet - Uint nextLocation = 0; - - // Find first empty location - for (SizeT i = 0; i < m_uniformOffsets.size(); i++) { - if (m_uniformOffsets[i] == 0) { - nextLocation = i; - break; - } + auto uniformCount = m_program->getNumUniformVariables(); + for (int i = 0; i < uniformCount; i++) { + auto& uniform = m_program->getUniform(i); + auto location = uniform.layoutLocation(); + m_maxUniformLocation = std::max(m_maxUniformLocation, location); + m_uniformNameMaxLength = std::max(m_uniformNameMaxLength, (Int)uniform.name.length()); + m_uniformLocations[uniform.name] = location; } - for (auto& [name, loc] : m_uniforms) { - if (loc == 4095) { - // check if we drained all the holes already - if (nextLocation >= m_uniformOffsets.size()) { - loc = nextLocation; - m_uniformOffsets.push_back(1); - nextLocation++; - continue; - } + m_uniformNames.resize(m_maxUniformLocation + 1); + m_uniformTypes.resize(m_maxUniformLocation + 1); + m_uniformOffsets.resize(m_maxUniformLocation + 1); - // assign an empty location - loc = nextLocation; - m_uniformOffsets[loc] = 1; - - // Find next empty location - for (nextLocation++; nextLocation < m_uniformOffsets.size(); nextLocation++) { - if (m_uniformOffsets[nextLocation] == 0) break; - } - } + for (int i = 0; i < uniformCount; i++) { + auto& uniform = m_program->getUniform(i); + auto location = uniform.layoutLocation(); + m_uniformNames[location] = uniform.name; + m_uniformTypes[location] = uniform.glDefineType; } - m_uniformNames.resize(m_uniformOffsets.size()); - for (auto& [name, loc] : m_uniforms) { - m_uniformNames[loc] = name; - m_uniformNameMaxLength = std::max(m_uniformNameMaxLength, (Int)name.length()); + int inCount = m_program->getNumPipeInputs(); + for (int i = 0; i < inCount; i++) { + auto& inVar = m_program->getPipeInput(i); + m_attribInNameMaxLength = std::max(m_attribInNameMaxLength, (Int)inVar.name.length()); + } + + int uboCount = m_program->getNumUniformBlocks(); + for (int i = 0; i < uboCount; i++) { + auto& ubo = m_program->getUniformBlock(i); + m_uniformBlockNameMaxLength = std::max(m_uniformBlockNameMaxLength, (Int)ubo.name.length()); } } - void ProgramObject::PostLink() { - if (m_programBinary.empty()) { - assert(false); - return; - } - MG_Util::ShaderTranspiler::SpvcSession session(m_programBinary[0]); - const char* src = nullptr; // we don't care the source atm - auto result = session.Compile(&src); - if (result != SPVC_SUCCESS) { - assert(false); - return; - } - m_metadata = session.GetMetadata(); - auto& uniformOffsets = m_metadata.plainUniformOffsetsInUBO; - for (const auto& [name, offset] : uniformOffsets) { - assert(m_uniforms.find(name) != m_uniforms.end()); - assert(m_uniforms[name] < m_uniformOffsets.size()); - m_uniformOffsets[m_uniforms[name]] = offset; - } - m_uboScratch.resize(m_metadata.uboSize, 0); - - auto& types = m_metadata.plainUniformMemberTypes; - - assert(types.size() == m_uniformOffsets.size()); - m_uniformTypes.resize(m_uniformOffsets.size()); - for (const auto& [name, type] : types) { - auto gltype = MG_Util::ConvertSpvcTypeToGLEnum(type); - auto location = m_uniforms[name]; - m_uniformTypes[location] = gltype; - } - } + // void ProgramObject::PreLink() { + // m_uniforms.clear(); + // m_uniformOffsets.clear(); + // + // for (const auto& shader : m_shaders) { + // for (const auto& [name, loc] : shader->GetUniformLocations()) { + // // collect all the names to map + // if (loc != 4095 || m_uniforms.find(name) == m_uniforms.end()) { + // m_uniforms[name] = loc; + // } + // + // // set a flag for those who have an explicit location + // if (loc != 4095) { + // if (loc >= m_uniformOffsets.size()) { + // m_uniformOffsets.reserve(std::bit_ceil(loc + 1)); + // m_uniformOffsets.resize(loc + 1, 0); + // } + // assert(m_uniformOffsets[loc] == 0); + // m_uniformOffsets[loc] = 1; + // } + // } + // } + // + // // Let's find a location for those who doesn't have one yet + // Uint nextLocation = 0; + // + // // Find first empty location + // for (SizeT i = 0; i < m_uniformOffsets.size(); i++) { + // if (m_uniformOffsets[i] == 0) { + // nextLocation = i; + // break; + // } + // } + // + // for (auto& [name, loc] : m_uniforms) { + // if (loc == 4095) { + // // check if we drained all the holes already + // if (nextLocation >= m_uniformOffsets.size()) { + // loc = nextLocation; + // m_uniformOffsets.push_back(1); + // nextLocation++; + // continue; + // } + // + // // assign an empty location + // loc = nextLocation; + // m_uniformOffsets[loc] = 1; + // + // // Find next empty location + // for (nextLocation++; nextLocation < m_uniformOffsets.size(); nextLocation++) { + // if (m_uniformOffsets[nextLocation] == 0) break; + // } + // } + // } + // + // m_uniformNames.resize(m_uniformOffsets.size()); + // for (auto& [name, loc] : m_uniforms) { + // m_uniformNames[loc] = name; + // m_uniformNameMaxLength = std::max(m_uniformNameMaxLength, (Int)name.length()); + // } + // } + // + // void ProgramObject::PostLink() { + // if (m_programBinary.empty()) { + // assert(false); + // return; + // } + // MG_Util::ShaderTranspiler::SpvcSession session(m_programBinary[0]); + // const char* src = nullptr; // we don't care the source atm + // auto result = session.Compile(&src); + // if (result != SPVC_SUCCESS) { + // assert(false); + // return; + // } + // m_metadata = session.GetMetadata(); + // auto& uniformOffsets = m_metadata.plainUniformOffsetsInUBO; + // for (const auto& [name, offset] : uniformOffsets) { + // assert(m_uniforms.find(name) != m_uniforms.end()); + // assert(m_uniforms[name] < m_uniformOffsets.size()); + // m_uniformOffsets[m_uniforms[name]] = offset; + // } + // m_uboScratch.resize(m_metadata.uboSize, 0); + // + // auto& types = m_metadata.plainUniformMemberTypes; + // + // assert(types.size() == m_uniformOffsets.size()); + // m_uniformTypes.resize(m_uniformOffsets.size()); + // for (const auto& [name, type] : types) { + // auto gltype = MG_Util::ConvertSpvcTypeToGLEnum(type); + // auto location = m_uniforms[name]; + // m_uniformTypes[location] = gltype; + // } + // } } // namespace GLState } // namespace MG_State } // namespace MobileGL \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h index 6309da71..76a65543 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h @@ -17,10 +17,10 @@ namespace MobileGL { Vector>& GetAttachedShaders(); const String& GetInfoLog() const { return m_infoLog; } Int GetUniformMaxLength() const { return m_uniformNameMaxLength; } - Uint GetUniformCount() { return m_uniformOffsets.size(); } + Uint GetUniformCount() { return m_uniformNames.size(); } Int GetUniformLocation(const String& name) { - const auto it = m_uniforms.find(name); - return (it == m_uniforms.end()) ? -1 : it->second; + const auto it = m_uniformLocations.find(name); + return (it == m_uniformLocations.end()) ? -1 : it->second; } GLenum GetUniformType(Uint index) const { return m_uniformTypes[index]; @@ -29,28 +29,40 @@ namespace MobileGL { const String& GetUniformName(Uint index) const { return m_uniformNames[index]; } + + Bool GetDeleteStatus() const { return m_deleteStatus; } + Bool GetLinkStatus() const { return m_linkStatus; } + Bool GetValidateStatus() const { return m_validateStatus; } + Int GetActiveAtomicCounterCount() const { return m_program->getNumAtomicCounters(); } + Int GetActiveAttributesCount() const { return m_program->getNumPipeInputs(); } + Int GetActiveUniformBlocksCount() const { return m_program->getNumUniformBlocks(); } + Int GetActiveAttributesMaxLength() const { return m_attribInNameMaxLength; } + Int GetActiveUniformBlocksMaxLength() const { return m_uniformBlockNameMaxLength; } private: - void PreLink(); - void PostLink(); + void DoReflection(); + // void PreLink(); + // void PostLink(); const Uint m_id = 0; Vector> m_shaders; - // basically this contains SPIR-V in binary format - Vector> m_programBinary; + + SharedPtr m_program; // Uniforms - MG_Util::ShaderTranspiler::SpvcMetadata m_metadata; + // MG_Util::ShaderTranspiler::SpvcMetadata m_metadata; - UnorderedMap m_uniforms; - // 0 or 1 for if the location is explicitly specified at PreLink stage, - // offsets into global ubo for PostLink - Vector m_uniformOffsets; + UnorderedMap m_uniformLocations; Vector m_uniformNames; Vector m_uniformTypes; + // Need to be reflected after linking of SPIR-V binary + Vector m_uniformOffsets; Vector m_uboScratch; + Uint m_maxUniformLocation = 0; Int m_uniformNameMaxLength = 0; + Int m_attribInNameMaxLength = 0; + Int m_uniformBlockNameMaxLength = 0; String m_infoLog; Bool m_deleteStatus = false; diff --git a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp index d90f40e9..145ef741 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.cpp @@ -15,15 +15,19 @@ namespace MobileGL { } void ShaderObject::Compile() { - if (!DoReflection()) { - return; - } + // if (!DoReflection()) { + // return; + // } using namespace MG_Util::ShaderTranspiler; + + // Compile for OpenGL here, so that we can do validation and link + // like a real OpenGL driver at linking stage + // Will compile for other backends later. ShaderAttrib attrib{ - .shaderType = GetGLShaderTypeByMGLShaderStage(m_stage), + .shaderType = ConvertGLShaderTypeByMGLShaderStage(m_stage), .sourceStr = m_source, - .flags = 0 + .flags = ShaderCompileBits::CompileForOpenGL }; auto result = ShaderCompiler::CompileShader(attrib); @@ -33,9 +37,6 @@ namespace MobileGL { } else { m_compileStatus = false; m_infoLog = result.error().log; - - const std::string e = std::format("Shader compilation failed: \nerrc: {}\nmsg: {}\n", - result.error().errc, result.error().log); } } @@ -43,35 +44,36 @@ namespace MobileGL { m_deleteStatus = true; } - bool ShaderObject::DoReflection() { - using namespace MG_Util::ShaderTranspiler; - ShaderAttrib attrib{ - .shaderType = GetGLShaderTypeByMGLShaderStage(m_stage), - .sourceStr = m_source, - .flags = ShaderCompileBits::CompileForOpenGL - }; + // bool ShaderObject::DoReflection() { + // using namespace MG_Util::ShaderTranspiler; + // ShaderAttrib attrib{ + // .shaderType = GetGLShaderTypeByMGLShaderStage(m_stage), + // .sourceStr = m_source, + // .flags = ShaderCompileBits::CompileForOpenGL + // }; + // + // auto result = ShaderCompiler::CompileShader(attrib); + // if (!result) { + // m_compileStatus = false; + // m_infoLog = result.error().log; + // + // const std::string e = std::format("Shader compilation failed: \nerrc: {}\nmsg: {}\n", + // result.error().errc, result.error().log); + // return false; + // } + // + // auto pShader = result.value(); + // auto root = pShader->getIntermediate()->getTreeRoot(); + // UniformTraverser traverser; + // root->traverse(&traverser); + // auto& symbols = traverser.GetCollectedSymbols(); + // for (const auto& symbol : symbols) { + // m_uniforms[symbol->getName().c_str()] = symbol->getQualifier().layoutLocation; + // } + // + // return true; + // } - auto result = ShaderCompiler::CompileShader(attrib); - if (!result) { - m_compileStatus = false; - m_infoLog = result.error().log; - - const std::string e = std::format("Shader compilation failed: \nerrc: {}\nmsg: {}\n", - result.error().errc, result.error().log); - return false; - } - - auto pShader = result.value(); - auto root = pShader->getIntermediate()->getTreeRoot(); - UniformTraverser traverser; - root->traverse(&traverser); - auto& symbols = traverser.GetCollectedSymbols(); - for (const auto& symbol : symbols) { - m_uniforms[symbol->getName().c_str()] = symbol->getQualifier().layoutLocation; - } - - return true; - } } // namespace GLState } // namespace MG_State } // namespace MobileGL \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h index bdbf74e4..21818928 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ShaderObject.h @@ -14,7 +14,7 @@ namespace MobileGL { Unknown = -1 }; - inline static GLenum GetGLShaderTypeByMGLShaderStage(ShaderStage stage) { + inline static GLenum ConvertGLShaderTypeByMGLShaderStage(ShaderStage stage) { switch (stage) { case ShaderStage::Vertex: return GL_VERTEX_SHADER; @@ -34,7 +34,7 @@ namespace MobileGL { } } - inline static ShaderStage GetMGLShaderStageByGLShaderType(GLenum type) { + inline static ShaderStage ConvertMGLShaderStageByGLShaderType(GLenum type) { switch (type) { case GL_VERTEX_SHADER: return ShaderStage::Vertex; @@ -68,8 +68,10 @@ namespace MobileGL { SharedPtr GetCompiledShader() const { return m_shader; } const String& GetInfoLog() const { return m_infoLog; } const UnorderedMap& GetUniformLocations() const { return m_uniforms; } + Bool GetCompileStatus() const { return m_compileStatus; } + Bool GetDeleteStatus() const { return m_deleteStatus; } private: - bool DoReflection(); + // bool DoReflection(); const Uint m_id = 0; const ShaderStage m_stage; String m_source; diff --git a/MobileGL/MG_Test/CMakeLists.txt b/MobileGL/MG_Test/CMakeLists.txt index 1b669467..b4efe926 100644 --- a/MobileGL/MG_Test/CMakeLists.txt +++ b/MobileGL/MG_Test/CMakeLists.txt @@ -3,8 +3,6 @@ project(MobileGLTest) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_BUILD_TYPE Debug) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0") include(FetchContent) FetchContent_Declare( diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index 3504e45a..6e0cd42a 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -52,11 +52,12 @@ uniform vec2 InSize; layout(location = 1) uniform vec3 Gray; uniform vec3 RedMatrix; -uniform vec3 GreenMatrix; +uniform vec3 GreenMatrix0; uniform vec3 BlueMatrix; uniform vec3 Offset; uniform vec3 ColorScale; layout(location = 6) uniform float Saturation; +uniform int AQuickFoxJumpsOverALazyDog; out vec4 fragColor; @@ -65,7 +66,7 @@ void main() { // Color Matrix float RedValue = dot(InTexel.rgb, RedMatrix); - float GreenValue = dot(InTexel.rgb, GreenMatrix); + float GreenValue = dot(InTexel.rgb, GreenMatrix0); float BlueValue = dot(InTexel.rgb, BlueMatrix); vec3 OutColor = vec3(RedValue, GreenValue, BlueValue); @@ -116,4 +117,10 @@ TEST_F(ProgramTest, CompileAndLink) { EXPECT_EQ(GetUniformLocation(program, "ProjMat"), 0); EXPECT_EQ(GetUniformLocation(program, "Gray"), 1); EXPECT_EQ(GetUniformLocation(program, "Saturation"), 6); + GLint uniformCount = 0; + GetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniformCount); + EXPECT_EQ(uniformCount, 11); + GLint uniformNameMaxLength = 0; + GetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformNameMaxLength); + EXPECT_EQ(uniformNameMaxLength, 12); } diff --git a/MobileGL/MG_Test/Program/ProgramUtilTest.cpp b/MobileGL/MG_Test/Program/ProgramUtilTest.cpp index 58f650fb..da2d5506 100644 --- a/MobileGL/MG_Test/Program/ProgramUtilTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramUtilTest.cpp @@ -143,8 +143,15 @@ TEST_F(ProgramUtilTest, CompileFragmentShaderWithDiscard) { FAIL() << "errc: " << program_res.error().errc << "\nlog: " << program_res.error().log; } + auto program = program_res.value(); - auto spirvs = program_res.value(); + ProgramBinaryAttrib binaryAttrib { + .shaderTypes = { GL_FRAGMENT_SHADER }, + .program = *program, + }; + auto bin_res = ShaderCompiler::GetSpirvBinaryFromProgram(binaryAttrib); + + auto spirvs = bin_res.value(); Vector sessions(spirvs.size()); for (SizeT i = 0; i < spirvs.size(); ++i) { @@ -282,7 +289,13 @@ TEST_F(ProgramUtilTest, DecompProgram) { FAIL() << "errc: " << program_res.error().errc << "\nlog: " << program_res.error().log; } - auto spirvs = program_res.value(); + ProgramBinaryAttrib binaryAttrib { + .shaderTypes = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER }, + .program = *program_res.value(), + }; + auto bin_res = ShaderCompiler::GetSpirvBinaryFromProgram(binaryAttrib); + + auto spirvs = bin_res.value(); Vector sessions(spirvs.size()); for (SizeT i = 0; i < spirvs.size(); ++i) { diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp index f98faf69..f9971ea3 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp @@ -159,22 +159,22 @@ namespace MobileGL { return res; } - Result>> ShaderCompiler::LinkProgram(const ProgramAttrib& attrib) { - glslang::TProgram program; + Result> ShaderCompiler::LinkProgram(const ProgramAttrib& attrib) { + SharedPtr program = MakeShared(); for (auto& s : attrib.shaders) { - program.addShader(s.get()); + program->addShader(s.get()); } - if (!program.link(EShMsgDefault)) { + if (!program->link(EShMsgDefault)) { ResultInfo r; - r.log = "Error: [glslang] Cannot link the program:\n" + std::string(program.getInfoLog()); + r.log = "Error: [glslang] Cannot link the program:\n" + std::string(program->getInfoLog()); r.errc = -3; return std::unexpected(r); } UniquePtr resolver; for (unsigned stage = 0; stage < EShLangCount; stage++) { - auto* pResolver = program.getGlslIoResolver((EShLanguage)stage); + auto* pResolver = program->getGlslIoResolver((EShLanguage)stage); if (pResolver) { resolver = UniquePtr(pResolver); break; @@ -182,20 +182,24 @@ namespace MobileGL { } auto ioMapper = UniquePtr(glslang::GetGlslIoMapper()); - if (!program.mapIO(resolver.get(), ioMapper.get())) { + if (!program->mapIO(resolver.get(), ioMapper.get())) { ResultInfo r; - r.log = "Error: [glslang] Cannot mapIO:\n" + std::string(program.getInfoLog()); + r.log = "Error: [glslang] Cannot mapIO:\n" + std::string(program->getInfoLog()); r.errc = -4; return std::unexpected(r); } + return program; + } + + Result>> ShaderCompiler::GetSpirvBinaryFromProgram(const ProgramBinaryAttrib &attrib) { glslang::SpvOptions spvOptions; spvOptions.disableOptimizer = false; Vector> allSpirv; for (auto type : attrib.shaderTypes) { Vector spirv; - GlslangToSpv(*program.getIntermediate(ConvertGLEnumToEShLanguage(type)), spirv, &spvOptions); + GlslangToSpv(*attrib.program.getIntermediate(ConvertGLEnumToEShLanguage(type)), spirv, &spvOptions); allSpirv.push_back(spirv); } diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h index 0fadb5de..6c6ef566 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h @@ -8,7 +8,8 @@ namespace MobileGL { class ShaderCompiler { public: static Result> CompileShader(const ShaderAttrib& attrib); - static Result>> LinkProgram(const ProgramAttrib& attrib); + static Result> LinkProgram(const ProgramAttrib& attrib); + static Result>> GetSpirvBinaryFromProgram(const ProgramBinaryAttrib& attrib); static Result DecompileShader(SpvcSession& session); }; } // namespace ShaderTranspiler diff --git a/MobileGL/MG_Util/ShaderTranspiler/Types.h b/MobileGL/MG_Util/ShaderTranspiler/Types.h index dc0fc2c8..c4c90ef1 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/Types.h +++ b/MobileGL/MG_Util/ShaderTranspiler/Types.h @@ -24,6 +24,11 @@ namespace MobileGL { Vector> shaders; }; + struct ProgramBinaryAttrib { + Vector shaderTypes; + const glslang::TProgram& program; + }; + struct ResultInfo { Int errc = 0; String log;