diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index d902db04..146bb8c3 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -453,12 +453,12 @@ namespace MobileGL::MG_Impl::GLImpl { MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params); break; case GL_COMPUTE_WORK_GROUP_SIZE: { // GL >= 4.3 - if (!programObject->GetLinkStatus()) { + if (!programObject->GetLinkStatus() || programObject->GetShaderIndexByStage(ShaderStage::Compute) < 0) { MG_State::pGLContext->RecordError( ErrorCode::InvalidOperation, MakeUnique("MG_Impl/GLImpl", __func__, std::to_string(program) + - " is not a program object that has been linked.")); + " is not a linked program object with a compute shader.")); return; } params[0] = static_cast(programObject->GetComputeLocalSize(0)); diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index 75b3b092..c1a059c5 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -62,6 +62,40 @@ namespace { return glType; } } + + static bool ComputeShaderDeclaresLocalSize(const MobileGL::String& source) { + bool inLineComment = false; + bool inBlockComment = false; + for (MobileGL::SizeT i = 0; i < source.length(); ++i) { + if (inLineComment) { + inLineComment = source[i] != '\n'; + continue; + } + if (inBlockComment) { + if (source[i] == '*' && i + 1 < source.length() && source[i + 1] == '/') { + inBlockComment = false; + ++i; + } + continue; + } + if (source[i] == '/' && i + 1 < source.length()) { + if (source[i + 1] == '/') { + inLineComment = true; + ++i; + continue; + } + if (source[i + 1] == '*') { + inBlockComment = true; + ++i; + continue; + } + } + if (source.compare(i, 11, "local_size_") == 0) { + return true; + } + } + return false; + } } namespace MobileGL::MG_State::GLState { @@ -170,9 +204,6 @@ namespace MobileGL::MG_State::GLState { } m_detachedShaders.clear(); - Vector shaderTypes(m_shaders.size()); - Vector> shaders(m_shaders.size()); - if (addDefaultFSIfMissingForRenderingPipelineProgram) { AddDefaultFragmentShaderIfMissing(); } @@ -187,6 +218,9 @@ namespace MobileGL::MG_State::GLState { return a->GetShaderStage() < b->GetShaderStage(); }); + Vector shaderTypes(m_shaders.size()); + Vector> shaders(m_shaders.size()); + for (SizeT i = 0; i < m_shaders.size(); i++) { shaderTypes[i] = MG_Util::ConvertShaderStageToGLEnum(m_shaders[i]->GetShaderStage()); MGLOG_D("ProgramObject %u: Preparing shader[%zu] stage %s at %p", m_externalIndex, i, @@ -201,6 +235,12 @@ namespace MobileGL::MG_State::GLState { m_externalIndex, i, m_infoLog.c_str()); return; } + if (m_shaders[i]->GetShaderStage() == ShaderStage::Compute && + !ComputeShaderDeclaresLocalSize(m_shaders[i]->GetShaderSource())) { + m_infoLog = "Compute shader is missing a local_size layout declaration."; + MGLOG_E("ProgramObject %u: Link failed - %s", m_externalIndex, m_infoLog.c_str()); + return; + } shaders[i] = m_shaders[i]->GetCompiledShader(); MGLOG_D("ProgramObject %u: shader[%zu] compiled shader ptr %p, src len %zu", m_externalIndex, i, shaders[i].get(), m_shaders[i]->GetShaderSource().length());