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);
	}
Пример #2
0
    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());
        }
    }
Пример #4
0
    //-----------------------------------------------------------------------------
    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 );
		}
	}
Пример #6
0
	//-----------------------------------------------------------------------
	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;
		}
	}
Пример #7
0
    //---------------------------------------------------------------------------
	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);

	}
Пример #8
0
	//-----------------------------------------------------------------------
	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);
            }
        }
    }
Пример #13
0
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);
}
Пример #14
0
    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
    }
Пример #15
0
	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);
			}
		}
	}
Пример #18
0
    //---------------------------------------------------------------------------
	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
}