bool GLSLESProgram::compile(const bool checkErrors) { if (mCompiled == 1) { return true; } // Only create a shader object if glsl es is supported if (isSupported()) { GL_CHECK_ERROR // Create shader object GLenum shaderType = 0x0000; if (mType == GPT_VERTEX_PROGRAM) { shaderType = GL_VERTEX_SHADER; } else if (mType == GPT_FRAGMENT_PROGRAM) { shaderType = GL_FRAGMENT_SHADER; } mGLHandle = glCreateShader(shaderType); GL_CHECK_ERROR } // Add preprocessor extras and main source if (!mSource.empty()) { const char *source = mSource.c_str(); glShaderSource(mGLHandle, 1, &source, NULL); // Check for load errors GL_CHECK_ERROR } if (checkErrors) logObjectInfo("GLSL ES compiling: " + mName, mGLHandle); glCompileShader(mGLHandle); GL_CHECK_ERROR // Check for compile errors glGetShaderiv(mGLHandle, GL_COMPILE_STATUS, &mCompiled); if(!mCompiled && checkErrors) { String message = logObjectInfo("GLSL ES compile log: " + mName, mGLHandle); checkAndFixInvalidDefaultPrecisionError(message); } // Log a message that the shader compiled successfully. if (mCompiled && checkErrors) logObjectInfo("GLSL ES compiled: " + mName, mGLHandle); return (mCompiled == 1); }
void GLSLProgram::getMicrocodeFromCache(uint32 id) { GpuProgramManager::Microcode cacheMicrocode = GpuProgramManager::getSingleton().getMicrocodeFromCache(id); cacheMicrocode->seek(0); // Turns out we need this param when loading. GLenum binaryFormat = 0; cacheMicrocode->read(&binaryFormat, sizeof(GLenum)); // Get size of binary. GLint binaryLength = static_cast<GLint>(cacheMicrocode->size() - sizeof(GLenum)); // Load binary. OGRE_CHECK_GL_ERROR(glProgramBinary(mGLProgramHandle, binaryFormat, cacheMicrocode->getCurrentPtr(), binaryLength)); GLint success = 0; OGRE_CHECK_GL_ERROR(glGetProgramiv(mGLProgramHandle, GL_LINK_STATUS, &success)); if(success) { mLinked = true; return; } logObjectInfo("could not load from cache "+getCombinedName(), mGLProgramHandle); // Something must have changed since the program binaries // were cached away. Fallback to source shader loading path, // and then retrieve and cache new program binaries once again. compileAndLink(); }
void GLSLProgramPipeline::compileIndividualProgram(GLSLGpuProgram *program) { GLint linkStatus = 0; // Compile and attach program if(program && !program->isLinked()) { try { program->getGLSLProgram()->compile(true); } catch (Exception& e) { LogManager::getSingleton().stream() << e.getDescription(); mTriedToLinkAndFailed = true; return; } GLuint programHandle = program->getGLSLProgram()->getGLProgramHandle(); OGRE_CHECK_GL_ERROR(glProgramParameteri(programHandle, GL_PROGRAM_SEPARABLE, GL_TRUE)); program->getGLSLProgram()->attachToProgramObject(programHandle); OGRE_CHECK_GL_ERROR(glLinkProgram(programHandle)); OGRE_CHECK_GL_ERROR(glGetProgramiv(programHandle, GL_LINK_STATUS, &linkStatus)); program->setLinked(linkStatus); mLinked = linkStatus; mTriedToLinkAndFailed = !linkStatus; logObjectInfo( getCombinedName() + String("GLSL program result : "), programHandle ); if(program->getType() == GPT_VERTEX_PROGRAM) setSkeletalAnimationIncluded(program->isSkeletalAnimationIncluded()); } }
//----------------------------------------------------------------------------- void checkForGLSLError(const String& ogreMethod, const String& errorTextPrefix, const GLhandleARB obj, const bool forceInfoLog, const bool forceException) { GLenum glErr; bool errorsFound = false; String msg = errorTextPrefix; // get all the GL errors glErr = glGetError(); while (glErr != GL_NO_ERROR) { const char* glerrStr = (const char*)gluErrorString(glErr); if (glerrStr) { msg += String(glerrStr); } glErr = glGetError(); errorsFound = true; } // if errors were found then put them in the Log and raise and exception if (errorsFound || forceInfoLog) { // if shader or program object then get the log message and send to the log manager msg += logObjectInfo( msg, obj ); if (forceException) { OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, msg, ogreMethod); } } }
//----------------------------------------------------------------------------- void GL3PlusRenderToVertexBuffer::bindVerticesOutput(Pass* pass) { VertexDeclaration* declaration = mVertexData->vertexDeclaration; size_t elemCount = declaration->getElementCount(); if (elemCount > 0) { GLuint linkProgramId = 0; // Have GLSL shaders, using varying attributes if(Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS)) { GLSLProgramPipeline* programPipeline = GLSLProgramPipelineManager::getSingleton().getActiveProgramPipeline(); linkProgramId = programPipeline->getGLProgramPipelineHandle(); } else { GLSLLinkProgram* linkProgram = GLSLLinkProgramManager::getSingleton().getActiveLinkProgram(); linkProgramId = linkProgram->getGLProgramHandle(); } // Note: 64 is the minimum number of interleaved attributes allowed by GL_EXT_transform_feedback // So we are using it. Otherwise we could query during rendersystem initialisation and use a dynamic sized array. // But that would require C99. // const GLchar *names[64]; const GLchar *names[1] = {"gl_Position"};//, "oUv0", "oUv1", "oUv2" }; // vector<const GLchar*>::type names; // for (unsigned short e = 0; e < elemCount; e++) // { // const VertexElement* element = declaration->getElement(e); // String varyingName = getSemanticVaryingName(element->getSemantic(), element->getIndex()); // names[e] = varyingName.c_str(); //// names.push_back(varyingName.c_str()); // } OGRE_CHECK_GL_ERROR(glTransformFeedbackVaryings(linkProgramId, elemCount, names, GL_INTERLEAVED_ATTRIBS)); OGRE_CHECK_GL_ERROR(glLinkProgram(linkProgramId)); GLint didLink = 0; OGRE_CHECK_GL_ERROR(glGetProgramiv( linkProgramId, GL_LINK_STATUS, &didLink )); logObjectInfo( String("RVB GLSL link result : "), linkProgramId ); if(glIsProgram(linkProgramId)) { glValidateProgram(linkProgramId); } logObjectInfo( String("RVB GLSL validation result : "), linkProgramId ); } }
//----------------------------------------------------------------------- void GLSLProgram::detachFromProgramObject( const GLuint programObject ) { OGRE_CHECK_GL_ERROR(glDetachShader(programObject, mGLShaderHandle)); logObjectInfo( "Error detaching " + mName + " shader object from GLSL Program Object", programObject ); // attach child objects GLSLProgramContainerIterator childprogramcurrent = mAttachedGLSLPrograms.begin(); GLSLProgramContainerIterator childprogramend = mAttachedGLSLPrograms.end(); while (childprogramcurrent != childprogramend) { GLSLProgram* childShader = *childprogramcurrent; childShader->detachFromProgramObject( programObject ); ++childprogramcurrent; } }
//--------------------------------------------------------------------------- bool GLSLProgram::compile(const bool checkErrors) { glCompileShaderARB(mGLHandle); // check for compile errors glGetObjectParameterivARB(mGLHandle, GL_OBJECT_COMPILE_STATUS_ARB, &mCompiled); // force exception if not compiled if (checkErrors) { checkForGLSLError( "GLSLProgram::loadFromSource", "Cannot compile GLSL high-level shader : " + mName + " ", mGLHandle, !mCompiled, !mCompiled ); if (mCompiled) { logObjectInfo( mName + " : GLSL compiled ", mGLHandle ); } } return (mCompiled == 1); }
//----------------------------------------------------------------------- void GLSLProgram::attachToProgramObject( const GLuint programObject ) { // attach child objects GLSLProgramContainerIterator childprogramcurrent = mAttachedGLSLPrograms.begin(); GLSLProgramContainerIterator childprogramend = mAttachedGLSLPrograms.end(); while (childprogramcurrent != childprogramend) { GLSLProgram* childShader = *childprogramcurrent; // bug in ATI GLSL linker : modules without main function must be recompiled each time // they are linked to a different program object // don't check for compile errors since there won't be any // *** minor inconvenience until ATI fixes there driver childShader->compile(true); childShader->attachToProgramObject( programObject ); ++childprogramcurrent; } OGRE_CHECK_GL_ERROR(glAttachShader(programObject, mGLShaderHandle)); logObjectInfo( "Error attaching " + mName + " shader object to GLSL Program Object", programObject ); }
//----------------------------------------------------------------------- void GLSLLinkProgram::activate(void) { if (!mLinked) { if (mVertexProgram) { // Some drivers (e.g. OS X on nvidia) incorrectly determine the attribute binding automatically // and end up aliasing existing built-ins. So avoid! // Bind all used attribs - not all possible ones otherwise we'll get // lots of warnings in the log, and also may end up aliasing names used // as varyings by accident // Because we can't ask GL whether an attribute is used in the shader // until it is linked (chicken and egg!) we have to parse the source size_t numAttribs = sizeof(msCustomAttributes)/sizeof(CustomAttribute); const String& vpSource = mVertexProgram->getGLSLProgram()->getSource(); for (size_t i = 0; i < numAttribs; ++i) { const CustomAttribute& a = msCustomAttributes[i]; // we're looking for either: // attribute vec<n> <semantic_name> // in vec<n> <semantic_name> // The latter is recommended in GLSL 1.3 onwards // be slightly flexible about formatting String::size_type pos = vpSource.find(a.name); if (pos != String::npos) { String::size_type startpos = vpSource.find("attribute", pos < 20 ? 0 : pos-20); if (startpos == String::npos) startpos = vpSource.find("in", pos-20); if (startpos != String::npos && startpos < pos) { // final check String expr = vpSource.substr(startpos, pos + a.name.length() - startpos); StringVector vec = StringUtil::split(expr); if ((vec[0] == "in" || vec[0] == "attribute") && vec[2] == a.name) glBindAttribLocationARB(mGLHandle, a.attrib, a.name.c_str()); } } } } if (mGeometryProgram) { RenderOperation::OperationType inputOperationType = mGeometryProgram->getGLSLProgram()->getInputOperationType(); glProgramParameteriEXT(mGLHandle,GL_GEOMETRY_INPUT_TYPE_EXT, getGLGeometryInputPrimitiveType(inputOperationType, mGeometryProgram->isAdjacencyInfoRequired())); RenderOperation::OperationType outputOperationType = mGeometryProgram->getGLSLProgram()->getOutputOperationType(); switch (outputOperationType) { case RenderOperation::OT_POINT_LIST: case RenderOperation::OT_LINE_STRIP: case RenderOperation::OT_TRIANGLE_STRIP: case RenderOperation::OT_LINE_LIST: case RenderOperation::OT_TRIANGLE_LIST: case RenderOperation::OT_TRIANGLE_FAN: break; } glProgramParameteriEXT(mGLHandle,GL_GEOMETRY_OUTPUT_TYPE_EXT, getGLGeometryOutputPrimitiveType(outputOperationType)); glProgramParameteriEXT(mGLHandle,GL_GEOMETRY_VERTICES_OUT_EXT, mGeometryProgram->getGLSLProgram()->getMaxOutputVertices()); } glLinkProgramARB( mGLHandle ); glGetObjectParameterivARB( mGLHandle, GL_OBJECT_LINK_STATUS_ARB, &mLinked ); // force logging and raise exception if not linked checkForGLSLError( "GLSLLinkProgram::Activate", "Error linking GLSL Program Object : ", mGLHandle, !mLinked, !mLinked ); if(mLinked) { logObjectInfo( String("GLSL link result : "), mGLHandle ); buildGLUniformReferences(); extractAttributes(); } } if (mLinked) { checkForGLSLError( "GLSLLinkProgram::Activate", "Error prior to using GLSL Program Object : ", mGLHandle, false, false); glUseProgramObjectARB( mGLHandle ); checkForGLSLError( "GLSLLinkProgram::Activate", "Error using GLSL Program Object : ", mGLHandle, false, false); } }
void GLSLProgramPipeline::compileAndLink() { OGRE_CHECK_GL_ERROR(glGenProgramPipelines(1, &mGLProgramPipelineHandle)); OGRE_CHECK_GL_ERROR(glBindProgramPipeline(mGLProgramPipelineHandle)); mVertexArrayObject = new GL3PlusVertexArrayObject(); mVertexArrayObject->bind(); compileIndividualProgram(mVertexProgram); compileIndividualProgram(mFragmentProgram); compileIndividualProgram(mGeometryProgram); compileIndividualProgram(mDomainProgram); compileIndividualProgram(mHullProgram); compileIndividualProgram(mComputeProgram); if(mLinked) { if ( GpuProgramManager::getSingleton().getSaveMicrocodesToCache() ) { // Add to the microcode to the cache String name; name = getCombinedName(); // Get buffer size GLint binaryLength = 0; OGRE_CHECK_GL_ERROR(glGetProgramiv(mGLProgramPipelineHandle, GL_PROGRAM_BINARY_LENGTH, &binaryLength)); // Create microcode GpuProgramManager::Microcode newMicrocode = GpuProgramManager::getSingleton().createMicrocode(binaryLength + sizeof(GLenum)); // Get binary OGRE_CHECK_GL_ERROR(glGetProgramBinary(mGLProgramPipelineHandle, binaryLength, NULL, (GLenum *)newMicrocode->getPtr(), newMicrocode->getPtr() + sizeof(GLenum))); // Add to the microcode to the cache GpuProgramManager::getSingleton().addMicrocodeToCache(name, newMicrocode); } if(mVertexProgram && mVertexProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_VERTEX_SHADER_BIT, mVertexProgram->getGLSLProgram()->getGLProgramHandle())); } if(mFragmentProgram && mFragmentProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_FRAGMENT_SHADER_BIT, mFragmentProgram->getGLSLProgram()->getGLProgramHandle())); } if(mGeometryProgram && mGeometryProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_GEOMETRY_SHADER_BIT, mGeometryProgram->getGLSLProgram()->getGLProgramHandle())); } if(mDomainProgram && mDomainProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_TESS_EVALUATION_SHADER_BIT, mDomainProgram->getGLSLProgram()->getGLProgramHandle())); } if(mHullProgram && mHullProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_TESS_CONTROL_SHADER_BIT, mHullProgram->getGLSLProgram()->getGLProgramHandle())); } if(mComputeProgram && mComputeProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_COMPUTE_SHADER_BIT, mComputeProgram->getGLSLProgram()->getGLProgramHandle())); } // Validate pipeline logObjectInfo( getCombinedName() + String("GLSL program pipeline result : "), mGLProgramPipelineHandle ); // if(getGLSupport()->checkExtension("GL_KHR_debug") || gl3wIsSupported(4, 3)) // glObjectLabel(GL_PROGRAM_PIPELINE, mGLProgramPipelineHandle, 0, // (mVertexProgram->getName() + "/" + mFragmentProgram->getName()).c_str()); } }
void GLSLSeparableProgram::compileAndLink() { // Ensure no monolithic programs are in use. OGRE_CHECK_GL_ERROR(glUseProgram(0)); OGRE_CHECK_GL_ERROR(glGenProgramPipelines(1, &mGLProgramPipelineHandle)); //OGRE_CHECK_GL_ERROR(glBindProgramPipeline(mGLProgramPipelineHandle)); mVertexArrayObject->bind(); loadIndividualProgram(mVertexShader); loadIndividualProgram(mDomainShader); loadIndividualProgram(mHullShader); loadIndividualProgram(mGeometryShader); loadIndividualProgram(mFragmentShader); loadIndividualProgram(mComputeShader); if (mLinked) { // if (GpuProgramManager::getSingleton().getSaveMicrocodesToCache() ) // { // // Add to the microcode to the cache // String name; // name = getCombinedName(); // // Get buffer size // GLint binaryLength = 0; // //OGRE_CHECK_GL_ERROR(glGetProgramiv(mGLProgramPipelineHandle, GL_PROGRAM_BINARY_LENGTH, &binaryLength)); // OGRE_CHECK_GL_ERROR(glGetProgramiv(, GL_PROGRAM_BINARY_LENGTH, &binaryLength)); // // Create microcode // GpuProgramManager::Microcode newMicrocode = // GpuProgramManager::getSingleton().createMicrocode((unsigned long)binaryLength + sizeof(GLenum)); // // Get binary // OGRE_CHECK_GL_ERROR(glGetProgramBinary(, binaryLength, NULL, (GLenum *)newMicrocode->getPtr(), newMicrocode->getPtr() + sizeof(GLenum))); // // Add to the microcode to the cache // GpuProgramManager::getSingleton().addMicrocodeToCache(name, newMicrocode); // } if (mVertexShader && mVertexShader->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_VERTEX_SHADER_BIT, mVertexShader->getGLProgramHandle())); } if (mDomainShader && mDomainShader->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_TESS_EVALUATION_SHADER_BIT, mDomainShader->getGLProgramHandle())); } if (mHullShader && mHullShader->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_TESS_CONTROL_SHADER_BIT, mHullShader->getGLProgramHandle())); } if (mGeometryShader && mGeometryShader->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_GEOMETRY_SHADER_BIT, mGeometryShader->getGLProgramHandle())); } if (mFragmentShader && mFragmentShader->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_FRAGMENT_SHADER_BIT, mFragmentShader->getGLProgramHandle())); } if (mComputeShader && mComputeShader->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStages(mGLProgramPipelineHandle, GL_COMPUTE_SHADER_BIT, mComputeShader->getGLProgramHandle())); } // Validate pipeline OGRE_CHECK_GL_ERROR(glValidateProgramPipeline(mGLProgramPipelineHandle)); logObjectInfo( getCombinedName() + String("GLSL program pipeline validation result: "), mGLProgramPipelineHandle ); // if (getGLSupport()->checkExtension("GL_KHR_debug") || gl3wIsSupported(4, 3)) // glObjectLabel(GL_PROGRAM_PIPELINE, mGLProgramPipelineHandle, 0, // (mVertexShader->getName() + "/" + mFragmentShader->getName()).c_str()); } }
void GLSLSeparableProgram::loadIndividualProgram(GLSLShader *program) { if (program && !program->isLinked()) { GLint linkStatus = 0; String programName = program->getName(); GLuint programHandle = program->getGLProgramHandle(); OGRE_CHECK_GL_ERROR(glProgramParameteri(programHandle, GL_PROGRAM_SEPARABLE, GL_TRUE)); //if (GpuProgramManager::getSingleton().getSaveMicrocodesToCache()) OGRE_CHECK_GL_ERROR(glProgramParameteri(programHandle, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE)); // Use precompiled program if possible. bool microcodeAvailableInCache = GpuProgramManager::getSingleton().isMicrocodeAvailableInCache(programName); if (microcodeAvailableInCache) { GpuProgramManager::Microcode cacheMicrocode = GpuProgramManager::getSingleton().getMicrocodeFromCache(programName); cacheMicrocode->seek(0); GLenum binaryFormat = 0; cacheMicrocode->read(&binaryFormat, sizeof(GLenum)); GLint binaryLength = cacheMicrocode->size() - sizeof(GLenum); OGRE_CHECK_GL_ERROR(glProgramBinary(programHandle, binaryFormat, cacheMicrocode->getPtr() + sizeof(GLenum), binaryLength)); OGRE_CHECK_GL_ERROR(glGetProgramiv(programHandle, GL_LINK_STATUS, &linkStatus)); if (!linkStatus) logObjectInfo("Could not use cached binary " + programName, programHandle); } // Compilation needed if precompiled program is // unavailable or failed to link. if (!linkStatus) { try { program->compile(true); } catch (Exception& e) { LogManager::getSingleton().stream() << e.getDescription(); mTriedToLinkAndFailed = true; return; } program->attachToProgramObject(programHandle); OGRE_CHECK_GL_ERROR(glLinkProgram(programHandle)); OGRE_CHECK_GL_ERROR(glGetProgramiv(programHandle, GL_LINK_STATUS, &linkStatus)); // Binary cache needs an update. microcodeAvailableInCache = false; } program->setLinked(linkStatus); mLinked = linkStatus; mTriedToLinkAndFailed = !linkStatus; logObjectInfo( getCombinedName() + String("GLSL program result : "), programHandle ); if (program->getType() == GPT_VERTEX_PROGRAM) setSkeletalAnimationIncluded(program->isSkeletalAnimationIncluded()); // Add the microcode to the cache. if (!microcodeAvailableInCache && mLinked && GpuProgramManager::getSingleton().getSaveMicrocodesToCache() ) { // Get buffer size. GLint binaryLength = 0; OGRE_CHECK_GL_ERROR(glGetProgramiv(programHandle, GL_PROGRAM_BINARY_LENGTH, &binaryLength)); // Create microcode. GpuProgramManager::Microcode newMicrocode = GpuProgramManager::getSingleton().createMicrocode((unsigned long)binaryLength + sizeof(GLenum)); // Get binary. OGRE_CHECK_GL_ERROR(glGetProgramBinary(programHandle, binaryLength, NULL, (GLenum *)newMicrocode->getPtr(), newMicrocode->getPtr() + sizeof(GLenum))); // std::vector<uchar> buffer(binaryLength); // GLenum format(0); // OGRE_CHECK_GL_ERROR(glGetProgramBinary(programHandle, binaryLength, NULL, &format, &buffer[0])); // GLenum binaryFormat = 0; // std::vector<uchar> binaryData(binaryLength); // newMicrocode->read(&binaryFormat, sizeof(GLenum)); // newMicrocode->read(&binaryData[0], binaryLength); GpuProgramManager::getSingleton().addMicrocodeToCache(programName, newMicrocode); } } }
bool GLSLESProgram::compile(const bool checkErrors) { if (mCompiled == 1) { return true; } // Only create a shader object if glsl es is supported if (isSupported()) { // Create shader object GLenum shaderType = 0x0000; if (mType == GPT_VERTEX_PROGRAM) { shaderType = GL_VERTEX_SHADER; } else if (mType == GPT_FRAGMENT_PROGRAM) { shaderType = GL_FRAGMENT_SHADER; } OGRE_CHECK_GL_ERROR(mGLShaderHandle = glCreateShader(shaderType)); #if OGRE_PLATFORM != OGRE_PLATFORM_NACL if(getGLES2SupportRef()->checkExtension("GL_EXT_debug_label")) { OGRE_IF_IOS_VERSION_IS_GREATER_THAN(5.0) glLabelObjectEXT(GL_SHADER_OBJECT_EXT, mGLShaderHandle, 0, mName.c_str()); } #endif if(Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS)) { OGRE_CHECK_GL_ERROR(mGLProgramHandle = glCreateProgram()); #if OGRE_PLATFORM != OGRE_PLATFORM_NACL if(getGLES2SupportRef()->checkExtension("GL_EXT_debug_label")) { OGRE_IF_IOS_VERSION_IS_GREATER_THAN(5.0) glLabelObjectEXT(GL_PROGRAM_OBJECT_EXT, mGLProgramHandle, 0, mName.c_str()); } #endif } } // Add preprocessor extras and main source if (!mSource.empty()) { // Fix up the source in case someone forgot to redeclare gl_Position if(Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS) && mType == GPT_VERTEX_PROGRAM) { size_t versionPos = mSource.find("#version"); int shaderVersion = StringConverter::parseInt(mSource.substr(versionPos+9, 3)); // Check that it's missing and that this shader has a main function, ie. not a child shader. if(mSource.find("out highp vec4 gl_Position") == String::npos) { if(shaderVersion >= 300) mSource.insert(versionPos+16, "out highp vec4 gl_Position;\nout highp float gl_PointSize;\n"); } if(mSource.find("#extension GL_EXT_separate_shader_objects : require") == String::npos) { if(shaderVersion >= 300) mSource.insert(versionPos+16, "#extension GL_EXT_separate_shader_objects : require\n"); } } #if !OGRE_NO_GLES2_GLSL_OPTIMISER const char *source = (getOptimiserEnabled() && getIsOptimised()) ? mOptimisedSource.c_str() : mSource.c_str(); #else const char *source = mSource.c_str(); #endif OGRE_CHECK_GL_ERROR(glShaderSource(mGLShaderHandle, 1, &source, NULL)); } if (checkErrors) logObjectInfo("GLSL ES compiling: " + mName, mGLShaderHandle); OGRE_CHECK_GL_ERROR(glCompileShader(mGLShaderHandle)); // Check for compile errors OGRE_CHECK_GL_ERROR(glGetShaderiv(mGLShaderHandle, GL_COMPILE_STATUS, &mCompiled)); if(!mCompiled && checkErrors) { String message = logObjectInfo("GLSL ES compile log: " + mName, mGLShaderHandle); checkAndFixInvalidDefaultPrecisionError(message); } // Log a message that the shader compiled successfully. if (mCompiled && checkErrors) logObjectInfo("GLSL ES compiled: " + mName, mGLShaderHandle); if(!mCompiled) { OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, ((mType == GPT_VERTEX_PROGRAM) ? "Vertex Program " : "Fragment Program ") + mName + " failed to compile. See compile log above for details.", "GLSLESProgram::compile"); } return (mCompiled == 1); }
void GL3PlusRenderToVertexBuffer::bindVerticesOutput(Pass* pass) { VertexDeclaration* declaration = mVertexData->vertexDeclaration; size_t elemCount = declaration->getElementCount(); if (elemCount == 0) return; // Get program object ID. GLuint programId = 0; if (Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS)) { GLSLSeparableProgram* separableProgram = GLSLSeparableProgramManager::getSingleton().getCurrentSeparableProgram(); GLSLShader* glslGpuProgram = 0; if ((glslGpuProgram = separableProgram->getGeometryShader())) programId = glslGpuProgram->getGLProgramHandle(); //TODO include tessellation stages else // vertex program programId = separableProgram->getVertexShader()->getGLProgramHandle(); } else { GLSLMonolithicProgram* monolithicProgram = GLSLMonolithicProgramManager::getSingleton().getActiveMonolithicProgram(); programId = monolithicProgram->getGLProgramHandle(); } // Store the output in a buffer. The buffer has the same // structure as the shader output vertex data. // Note: 64 is the minimum number of interleaved // attributes allowed by GL_EXT_transform_feedback so we // are using it. Otherwise we could query during // rendersystem initialisation and use a dynamic sized // array. But that would require C99. size_t sourceBufferIndex = mTargetBufferIndex == 0 ? 1 : 0; // Bind and fill vertex arrays + buffers. reallocateBuffer(sourceBufferIndex); reallocateBuffer(mTargetBufferIndex); // GL3PlusHardwareVertexBuffer* sourceVertexBuffer = static_cast<GL3PlusHardwareVertexBuffer*>(mVertexBuffers[mSourceBufferIndex].getPointer()); // GL3PlusHardwareVertexBuffer* targetVertexBuffer = static_cast<GL3PlusHardwareVertexBuffer*>(mVertexBuffers[mTargetBufferIndex].getPointer()); //TODO GL4+ glBindTransformFeedback // Dynamically determine shader output variable names. std::vector<String> nameStrings; std::vector<const GLchar*> names; for (uint e = 0; e < elemCount; e++) { const VertexElement* element = declaration->getElement(e); String name = getSemanticVaryingName(element->getSemantic(), element->getIndex()); nameStrings.push_back(name); } // Convert to const char * for GL for (uint e = 0; e < elemCount; e++) { names.push_back(nameStrings[e].c_str()); } //TODO replace glTransformFeedbackVaryings with in-shader specification (GL 4.4) OGRE_CHECK_GL_ERROR(glTransformFeedbackVaryings(programId, elemCount, &names[0], GL_INTERLEAVED_ATTRIBS)); if (Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS)) { GLSLSeparableProgram* separableProgram = GLSLSeparableProgramManager::getSingleton().getCurrentSeparableProgram(); separableProgram->activate(); } else { OGRE_CHECK_GL_ERROR(glLinkProgram(programId)); } #if OGRE_DEBUG_MODE // Check if program linking was successful. GLint didLink = 0; OGRE_CHECK_GL_ERROR(glGetProgramiv(programId, GL_LINK_STATUS, &didLink)); logObjectInfo(String("RVB GLSL link result : "), programId); if (glIsProgram(programId)) { glValidateProgram(programId); } logObjectInfo(String("RVB GLSL validation result : "), programId); // Check if varyings were successfully set. GLchar Name[64]; GLsizei Length(0); GLsizei Size(0); GLenum Type(0); // bool Validated = false; for (size_t i = 0; i < elemCount; i++) { OGRE_CHECK_GL_ERROR(glGetTransformFeedbackVarying( programId, i, 64, &Length, &Size, &Type, Name )); std::cout << "Varying " << i << ": " << Name <<" "<< Length <<" "<< Size <<" "<< Type << std::endl; // Validated = (Size == 1) && (Type == GL_FLOAT_VEC3); // std::cout << Validated << " " << GL_FLOAT_VEC3 << std::endl; } #endif }
bool GLSLESProgram::compile(const bool checkErrors) { if (mCompiled == 1) { return true; } // Only create a shader object if glsl es is supported if (isSupported()) { GL_CHECK_ERROR // Create shader object GLenum shaderType = 0x0000; if (mType == GPT_VERTEX_PROGRAM) { shaderType = GL_VERTEX_SHADER; } else if (mType == GPT_FRAGMENT_PROGRAM) { shaderType = GL_FRAGMENT_SHADER; } mGLShaderHandle = glCreateShader(shaderType); GL_CHECK_ERROR #if GL_EXT_debug_label && OGRE_PLATFORM != OGRE_PLATFORM_NACL glLabelObjectEXT(GL_SHADER_OBJECT_EXT, mGLShaderHandle, 0, mName.c_str()); #endif if(Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS)) { mGLProgramHandle = glCreateProgram(); GL_CHECK_ERROR #if GL_EXT_debug_label && OGRE_PLATFORM != OGRE_PLATFORM_NACL glLabelObjectEXT(GL_PROGRAM_OBJECT_EXT, mGLProgramHandle, 0, mName.c_str()); #endif } } // Add preprocessor extras and main source if (!mSource.empty()) { const char *source = mSource.c_str(); glShaderSource(mGLShaderHandle, 1, &source, NULL); // Check for load errors GL_CHECK_ERROR } if (checkErrors) logObjectInfo("GLSL ES compiling: " + mName, mGLShaderHandle); glCompileShader(mGLShaderHandle); GL_CHECK_ERROR // Check for compile errors glGetShaderiv(mGLShaderHandle, GL_COMPILE_STATUS, &mCompiled); if(!mCompiled && checkErrors) { String message = logObjectInfo("GLSL ES compile log: " + mName, mGLShaderHandle); checkAndFixInvalidDefaultPrecisionError(message); } // Log a message that the shader compiled successfully. if (mCompiled && checkErrors) logObjectInfo("GLSL ES compiled: " + mName, mGLShaderHandle); if(!mCompiled) OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, ((mType == GPT_VERTEX_PROGRAM) ? "Vertex Program " : "Fragment Program ") + mName + " failed to compile. See compile log above for details.", "GLSLESProgram::compile"); return (mCompiled == 1); }
void GLSLESProgramPipeline::compileAndLink() { #if GL_EXT_separate_shader_objects GLint linkStatus = 0; glGenProgramPipelinesEXT(1, &mGLProgramPipelineHandle); GL_CHECK_ERROR glBindProgramPipelineEXT(mGLProgramPipelineHandle); GL_CHECK_ERROR // Compile and attach Vertex Program if(mVertexProgram && !mVertexProgram->isLinked()) { if (!mVertexProgram->getGLSLProgram()->compile(true)) { mTriedToLinkAndFailed = true; return; } GLuint programHandle = mVertexProgram->getGLSLProgram()->getGLProgramHandle(); glProgramParameteriEXT(programHandle, GL_PROGRAM_SEPARABLE_EXT, GL_TRUE); GL_CHECK_ERROR mVertexProgram->getGLSLProgram()->attachToProgramObject(programHandle); glLinkProgram(programHandle); GL_CHECK_ERROR glGetProgramiv(programHandle, GL_LINK_STATUS, &linkStatus); GL_CHECK_ERROR if(linkStatus) { mVertexProgram->setLinked(linkStatus); mLinked |= VERTEX_PROGRAM_LINKED; } GL_CHECK_ERROR // TODO: Just fail out here if the program doesn't link? mTriedToLinkAndFailed = !linkStatus; logObjectInfo( getCombinedName() + String("GLSL vertex program result : "), programHandle ); setSkeletalAnimationIncluded(mVertexProgram->isSkeletalAnimationIncluded()); } // Compile and attach Fragment Program if(mFragmentProgram && !mFragmentProgram->isLinked()) { if (!mFragmentProgram->getGLSLProgram()->compile(true)) { mTriedToLinkAndFailed = true; return; } GLuint programHandle = mFragmentProgram->getGLSLProgram()->getGLProgramHandle(); glProgramParameteriEXT(programHandle, GL_PROGRAM_SEPARABLE_EXT, GL_TRUE); GL_CHECK_ERROR mFragmentProgram->getGLSLProgram()->attachToProgramObject(programHandle); glLinkProgram(programHandle); GL_CHECK_ERROR glGetProgramiv(programHandle, GL_LINK_STATUS, &linkStatus); GL_CHECK_ERROR if(linkStatus) { mFragmentProgram->setLinked(linkStatus); mLinked |= FRAGMENT_PROGRAM_LINKED; } mTriedToLinkAndFailed = !linkStatus; logObjectInfo( getCombinedName() + String("GLSL fragment program result : "), programHandle ); } if(mLinked) { if ( GpuProgramManager::getSingleton().getSaveMicrocodesToCache() ) { // Add to the microcode to the cache String name; name = getCombinedName(); // Get buffer size GLint binaryLength = 0; #if GL_OES_get_program_binary glGetProgramiv(mGLHandle, GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength); GL_CHECK_ERROR; #endif // Create microcode GpuProgramManager::Microcode newMicrocode = GpuProgramManager::getSingleton().createMicrocode((unsigned long)binaryLength + sizeof(GLenum)); #if GL_OES_get_program_binary // Get binary glGetProgramBinaryOES(mGLHandle, binaryLength, NULL, (GLenum *)newMicrocode->getPtr(), newMicrocode->getPtr() + sizeof(GLenum)); GL_CHECK_ERROR; #endif // Add to the microcode to the cache GpuProgramManager::getSingleton().addMicrocodeToCache(name, newMicrocode); } if(mVertexProgram && mVertexProgram->isLinked()) { glUseProgramStagesEXT(mGLProgramPipelineHandle, GL_VERTEX_SHADER_BIT_EXT, mVertexProgram->getGLSLProgram()->getGLProgramHandle()); GL_CHECK_ERROR } if(mFragmentProgram && mFragmentProgram->isLinked()) { glUseProgramStagesEXT(mGLProgramPipelineHandle, GL_FRAGMENT_SHADER_BIT_EXT, mFragmentProgram->getGLSLProgram()->getGLProgramHandle()); GL_CHECK_ERROR }
//----------------------------------------------------------------------- void GLSLLinkProgram::compileAndLink() { mVertexArrayObject = new GL3PlusVertexArrayObject(); mVertexArrayObject->bind(); // Compile and attach Vertex Program if (mVertexProgram) { if (!mVertexProgram->getGLSLProgram()->compile(true)) { mTriedToLinkAndFailed = true; return; } mVertexProgram->getGLSLProgram()->attachToProgramObject(mGLProgramHandle); setSkeletalAnimationIncluded(mVertexProgram->isSkeletalAnimationIncluded()); } // Compile and attach Fragment Program if (mFragmentProgram) { if (!mFragmentProgram->getGLSLProgram()->compile(true)) { mTriedToLinkAndFailed = true; return; } mFragmentProgram->getGLSLProgram()->attachToProgramObject(mGLProgramHandle); } // Compile and attach Geometry Program if (mGeometryProgram) { if (!mGeometryProgram->getGLSLProgram()->compile(true)) { return; } mGeometryProgram->getGLSLProgram()->attachToProgramObject(mGLProgramHandle); } // Compile and attach Tessellation Control Program if (mHullProgram) { if (!mHullProgram->getGLSLProgram()->compile(true)) { return; } mHullProgram->getGLSLProgram()->attachToProgramObject(mGLProgramHandle); } // Compile and attach Tessellation Evaluation Program if (mDomainProgram) { if (!mDomainProgram->getGLSLProgram()->compile(true)) { return; } mDomainProgram->getGLSLProgram()->attachToProgramObject(mGLProgramHandle); } // Compile and attach Compute Program if (mComputeProgram) { if (!mComputeProgram->getGLSLProgram()->compile(true)) { return; } mComputeProgram->getGLSLProgram()->attachToProgramObject(mGLProgramHandle); } // the link OGRE_CHECK_GL_ERROR(glLinkProgram( mGLProgramHandle )); OGRE_CHECK_GL_ERROR(glGetProgramiv( mGLProgramHandle, GL_LINK_STATUS, &mLinked )); mTriedToLinkAndFailed = !mLinked; logObjectInfo( getCombinedName() + String(" GLSL link result : "), mGLProgramHandle ); if(glIsProgram(mGLProgramHandle)) { OGRE_CHECK_GL_ERROR(glValidateProgram(mGLProgramHandle)); } logObjectInfo( getCombinedName() + String(" GLSL validation result : "), mGLProgramHandle ); if(mLinked) { if ( GpuProgramManager::getSingleton().getSaveMicrocodesToCache() ) { // add to the microcode to the cache String name; name = getCombinedName(); // get buffer size GLint binaryLength = 0; OGRE_CHECK_GL_ERROR(glGetProgramiv(mGLProgramHandle, GL_PROGRAM_BINARY_LENGTH, &binaryLength)); // create microcode GpuProgramManager::Microcode newMicrocode = GpuProgramManager::getSingleton().createMicrocode(binaryLength + sizeof(GLenum)); // get binary OGRE_CHECK_GL_ERROR(glGetProgramBinary(mGLProgramHandle, binaryLength, NULL, (GLenum *)newMicrocode->getPtr(), newMicrocode->getPtr() + sizeof(GLenum))); // add to the microcode to the cache GpuProgramManager::getSingleton().addMicrocodeToCache(name, newMicrocode); } } }
//--------------------------------------------------------------------------- bool GLSLProgram::compile(const bool checkErrors) { if (mCompiled == 1) { return true; } // only create a shader object if glsl is supported if (isSupported()) { // create shader object GLenum shaderType = 0x0000; switch (mType) { case GPT_VERTEX_PROGRAM: shaderType = GL_VERTEX_SHADER; break; case GPT_FRAGMENT_PROGRAM: shaderType = GL_FRAGMENT_SHADER; break; case GPT_GEOMETRY_PROGRAM: shaderType = GL_GEOMETRY_SHADER; break; case GPT_DOMAIN_PROGRAM: shaderType = GL_TESS_EVALUATION_SHADER; break; case GPT_HULL_PROGRAM: shaderType = GL_TESS_CONTROL_SHADER; break; case GPT_COMPUTE_PROGRAM: shaderType = GL_COMPUTE_SHADER; break; } OGRE_CHECK_GL_ERROR(mGLShaderHandle = glCreateShader(shaderType)); // if(getGLSupport()->checkExtension("GL_KHR_debug") || gl3wIsSupported(4, 3)) // glObjectLabel(GL_SHADER, mGLShaderHandle, 0, mName.c_str()); if(Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS)) { OGRE_CHECK_GL_ERROR(mGLProgramHandle = glCreateProgram()); // if(getGLSupport()->checkExtension("GL_KHR_debug") || gl3wIsSupported(4, 3)) // glObjectLabel(GL_PROGRAM, mGLProgramHandle, 0, mName.c_str()); } } // Add preprocessor extras and main source if (!mSource.empty()) { // Fix up the source in case someone forgot to redeclare gl_Position if(Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS) && mType == GPT_VERTEX_PROGRAM) { // Check that it's missing and that this shader has a main function, ie. not a child shader. if(mSource.find("vec4 gl_Position") == String::npos) { size_t mainPos = mSource.find("void main"); if(mainPos != String::npos) { size_t versionPos = mSource.find("#version"); int shaderVersion = StringConverter::parseInt(mSource.substr(versionPos+9, 3)); if(shaderVersion >= 150) mSource.insert(mainPos, "out gl_PerVertex\n{\nvec4 gl_Position;\nfloat gl_PointSize;\nfloat gl_ClipDistance[];\n};\n"); } } } const char *source = mSource.c_str(); OGRE_CHECK_GL_ERROR(glShaderSource(mGLShaderHandle, 1, &source, NULL)); } OGRE_CHECK_GL_ERROR(glCompileShader(mGLShaderHandle)); // Check for compile errors OGRE_CHECK_GL_ERROR(glGetShaderiv(mGLShaderHandle, GL_COMPILE_STATUS, &mCompiled)); if(!mCompiled && checkErrors) { String message = logObjectInfo("GLSL compile log: " + mName, mGLShaderHandle); checkAndFixInvalidDefaultPrecisionError(message); } // Log a message that the shader compiled successfully. if (mCompiled && checkErrors) logObjectInfo("GLSL compiled: " + mName, mGLShaderHandle); if(!mCompiled) { String progType = "Fragment"; if (mType == GPT_VERTEX_PROGRAM) { progType = "Vertex"; } else if (mType == GPT_GEOMETRY_PROGRAM) { progType = "Geometry"; } else if (mType == GPT_DOMAIN_PROGRAM) { progType = "Tesselation Evaluation"; } else if (mType == GPT_HULL_PROGRAM) { progType = "Tesselation Control"; } else if (mType == GPT_COMPUTE_PROGRAM) { progType = "Compute"; } OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, progType + " Program " + mName + " failed to compile. See compile log above for details.", "GLSLProgram::compile"); } return (mCompiled == 1); }
void GLSLESProgramPipeline::compileAndLink() { #if GL_EXT_separate_shader_objects && OGRE_PLATFORM != OGRE_PLATFORM_NACL GLint linkStatus = 0; OGRE_CHECK_GL_ERROR(glGenProgramPipelinesEXT(1, &mGLProgramPipelineHandle)); OGRE_CHECK_GL_ERROR(glBindProgramPipelineEXT(mGLProgramPipelineHandle)); // Compile and attach Vertex Program if(mVertexProgram && !mVertexProgram->isLinked()) { try { mVertexProgram->getGLSLProgram()->compile(true); } catch (Exception& e) { LogManager::getSingleton().stream() << e.getDescription(); mTriedToLinkAndFailed = true; return; } GLuint programHandle = mVertexProgram->getGLSLProgram()->getGLProgramHandle(); OGRE_CHECK_GL_ERROR(glProgramParameteriEXT(programHandle, GL_PROGRAM_SEPARABLE_EXT, GL_TRUE)); mVertexProgram->getGLSLProgram()->attachToProgramObject(programHandle); OGRE_CHECK_GL_ERROR(glLinkProgram(programHandle)); OGRE_CHECK_GL_ERROR(glGetProgramiv(programHandle, GL_LINK_STATUS, &linkStatus)); if(linkStatus) { mVertexProgram->setLinked(linkStatus); mLinked |= VERTEX_PROGRAM_LINKED; } mTriedToLinkAndFailed = !linkStatus; logObjectInfo( getCombinedName() + String("GLSL vertex program result : "), programHandle ); setSkeletalAnimationIncluded(mVertexProgram->isSkeletalAnimationIncluded()); } // Compile and attach Fragment Program if(mFragmentProgram && !mFragmentProgram->isLinked()) { try { mFragmentProgram->getGLSLProgram()->compile(true); } catch (Exception& e) { LogManager::getSingleton().stream() << e.getDescription(); mTriedToLinkAndFailed = true; return; } GLuint programHandle = mFragmentProgram->getGLSLProgram()->getGLProgramHandle(); OGRE_CHECK_GL_ERROR(glProgramParameteriEXT(programHandle, GL_PROGRAM_SEPARABLE_EXT, GL_TRUE)); mFragmentProgram->getGLSLProgram()->attachToProgramObject(programHandle); OGRE_CHECK_GL_ERROR(glLinkProgram(programHandle)); OGRE_CHECK_GL_ERROR(glGetProgramiv(programHandle, GL_LINK_STATUS, &linkStatus)); if(linkStatus) { mFragmentProgram->setLinked(linkStatus); mLinked |= FRAGMENT_PROGRAM_LINKED; } mTriedToLinkAndFailed = !linkStatus; logObjectInfo( getCombinedName() + String("GLSL fragment program result : "), programHandle ); } if(mLinked) { if(mVertexProgram && mVertexProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStagesEXT(mGLProgramPipelineHandle, GL_VERTEX_SHADER_BIT_EXT, mVertexProgram->getGLSLProgram()->getGLProgramHandle())); } if(mFragmentProgram && mFragmentProgram->isLinked()) { OGRE_CHECK_GL_ERROR(glUseProgramStagesEXT(mGLProgramPipelineHandle, GL_FRAGMENT_SHADER_BIT_EXT, mFragmentProgram->getGLSLProgram()->getGLProgramHandle())); } // Validate pipeline logObjectInfo( getCombinedName() + String("GLSL program pipeline result : "), mGLProgramPipelineHandle ); #if GL_EXT_debug_label && OGRE_PLATFORM != OGRE_PLATFORM_NACL if(mVertexProgram && mFragmentProgram) OGRE_IF_IOS_VERSION_IS_GREATER_THAN(5.0) glLabelObjectEXT(GL_PROGRAM_PIPELINE_OBJECT_EXT, mGLProgramPipelineHandle, 0, (mVertexProgram->getName() + "/" + mFragmentProgram->getName()).c_str()); #endif } #endif }