//-----------------------------------------------------------------------
	void GLSLESLinkProgram::activate(void)
	{
		if (!mLinked && !mTriedToLinkAndFailed)
		{
			glGetError(); // Clean up the error. Otherwise will flood log.
			mGLHandle = glCreateProgram();
			GL_CHECK_ERROR

			if ( GpuProgramManager::getSingleton().canGetCompiledShaderBuffer() &&
				GpuProgramManager::getSingleton().isMicrocodeAvailableInCache(getCombinedName()) )
			{
				getMicrocodeFromCache();
			}
			else
			{
#ifdef OGRE_USE_GLES2_GLSL_OPTIMISER
                // check CmdParams for each shader type to see if we should optimize
                String paramStr = mVertexProgram->getGLSLProgram()->getParameter("use_optimiser");
                if((paramStr == "true") || paramStr.empty())
                {
                    GLSLESLinkProgramManager::getSingleton().optimiseShaderSource(mVertexProgram);
                }
                paramStr = mFragmentProgram->getGLSLProgram()->getParameter("use_optimiser");
                if((paramStr == "true") || paramStr.empty())
                {
                    GLSLESLinkProgramManager::getSingleton().optimiseShaderSource(mFragmentProgram);
                }
#endif
				compileAndLink();
			}

			buildGLUniformReferences();
		}
示例#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());
        }
    }
    //-----------------------------------------------------------------------
	void GLSLESProgramCommon::getMicrocodeFromCache(void)
	{
		GpuProgramManager::Microcode cacheMicrocode =
            GpuProgramManager::getSingleton().getMicrocodeFromCache(getCombinedName());

		// add to the microcode to the cache
		String name;
		name = getCombinedName();

		// turns out we need this param when loading
		GLenum binaryFormat = 0;

		cacheMicrocode->seek(0);

		// get size of binary
		cacheMicrocode->read(&binaryFormat, sizeof(GLenum));

        if(getGLES2SupportRef()->checkExtension("GL_OES_get_program_binary") || gleswIsSupported(3, 0))
        {
            GLint binaryLength = static_cast<GLint>(cacheMicrocode->size() - sizeof(GLenum));

            // load binary
            OGRE_CHECK_GL_ERROR(glProgramBinaryOES(mGLProgramHandle,
                               binaryFormat, 
                               cacheMicrocode->getPtr(),
                               binaryLength));
        }

		GLint success = 0;
		OGRE_CHECK_GL_ERROR(glGetProgramiv(mGLProgramHandle, GL_LINK_STATUS, &success));
		if (!success)
		{
			//
			// 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::activate(void)
	{
		if (!mLinked && !mTriedToLinkAndFailed)
		{            
			if ( GpuProgramManager::getSingleton().canGetCompiledShaderBuffer() &&
				GpuProgramManager::getSingleton().isMicrocodeAvailableInCache(getCombinedName()) )
			{
				getMicrocodeFromCache();
			}
			else
			{
				compileAndLink();
			}

            extractLayoutQualifiers();

			buildGLUniformReferences();
		}

        _useProgram();
	}
    void GLSLESProgramPipeline::compileAndLink()
    {
#if 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(getVertexProgram())
        {
            if(getVertexProgram()->isLinked())
            {
                mLinked |= VERTEX_PROGRAM_LINKED;
            }
            else if(getMicrocodeFromCache(
                    getVertexProgram()->getName(),
                    getVertexProgram()->createGLProgramHandle()))
            {
                getVertexProgram()->setLinked(true);
                mLinked |= VERTEX_PROGRAM_LINKED;
                mTriedToLinkAndFailed = false;
            }
            else
            {
                if(!getVertexProgram()->compile(true)) {
                    LogManager::getSingleton().stream(LML_CRITICAL)
                            << "Vertex Program " << getVertexProgram()->getName()
                            << " failed to compile. See compile log above for details.";
                    mTriedToLinkAndFailed = true;
                    return;
                }
                GLuint programHandle = getVertexProgram()->getGLProgramHandle();

                bindFixedAttributes( programHandle );

                OGRE_CHECK_GL_ERROR(glProgramParameteriEXT(programHandle, GL_PROGRAM_SEPARABLE_EXT, GL_TRUE));
                getVertexProgram()->attachToProgramObject(programHandle);
                OGRE_CHECK_GL_ERROR(glLinkProgram(programHandle));
                OGRE_CHECK_GL_ERROR(glGetProgramiv(programHandle, GL_LINK_STATUS, &linkStatus));
                
                if(linkStatus)
                {
                    getVertexProgram()->setLinked(linkStatus);
                    mLinked |= VERTEX_PROGRAM_LINKED;
                }
                
                mTriedToLinkAndFailed = !linkStatus;
                
                GLSLES::logObjectInfo( getCombinedName() + String("GLSL vertex program result : "), programHandle );

                setSkeletalAnimationIncluded(getVertexProgram()->isSkeletalAnimationIncluded());
            }
        }
        
        // Compile and attach Fragment Program
        if(mFragmentProgram)
        {
            if(mFragmentProgram->isLinked())
            {
                mLinked |= FRAGMENT_PROGRAM_LINKED;
            }
            else if(getMicrocodeFromCache(
                    mFragmentProgram->getName(),
                    mFragmentProgram->createGLProgramHandle()))
            {
                mFragmentProgram->setLinked(true);
                mLinked |= FRAGMENT_PROGRAM_LINKED;
                mTriedToLinkAndFailed = false;
            }
            else
            {
                if(!mFragmentProgram->compile(true)) {
                    LogManager::getSingleton().stream(LML_CRITICAL)
                            << "Fragment Program " << mFragmentProgram->getName()
                            << " failed to compile. See compile log above for details.";
                    mTriedToLinkAndFailed = true;
                    return;
                }

                GLuint programHandle = mFragmentProgram->getGLProgramHandle();
                OGRE_CHECK_GL_ERROR(glProgramParameteriEXT(programHandle, GL_PROGRAM_SEPARABLE_EXT, GL_TRUE));
                mFragmentProgram->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;

                GLSLES::logObjectInfo( getCombinedName() + String("GLSL fragment program result : "), programHandle );
            }
        }
        
        if(mLinked)
        {
            if(getVertexProgram() && getVertexProgram()->isLinked())
            {
                OGRE_CHECK_GL_ERROR(glUseProgramStagesEXT(mGLProgramPipelineHandle, GL_VERTEX_SHADER_BIT_EXT, getVertexProgram()->getGLProgramHandle()));
                _writeToCache(getVertexProgram()->getName(), getVertexProgram()->getGLProgramHandle());
            }
            if(mFragmentProgram && mFragmentProgram->isLinked())
            {
                OGRE_CHECK_GL_ERROR(glUseProgramStagesEXT(mGLProgramPipelineHandle, GL_FRAGMENT_SHADER_BIT_EXT, mFragmentProgram->getGLProgramHandle()));
                _writeToCache(mFragmentProgram->getName(), mFragmentProgram->getGLProgramHandle());
            }

            // Validate pipeline
            GLSLES::logObjectInfo( getCombinedName() + String("GLSL program pipeline result : "), mGLProgramPipelineHandle );
            if(getVertexProgram() && mFragmentProgram && Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_DEBUG))
            {
                glLabelObjectEXT(GL_PROGRAM_PIPELINE_OBJECT_EXT, mGLProgramPipelineHandle, 0,
                             (getVertexProgram()->getName() + "/" + mFragmentProgram->getName()).c_str());
            }
        }
#endif
    }
    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);
            }
        }
    }
    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
            }
        		// 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
            }

            // Validate pipeline
            logObjectInfo( getCombinedName() + String("GLSL program pipeline result : "), mGLProgramPipelineHandle );
#if GL_EXT_debug_label
            glLabelObjectEXT(GL_PROGRAM_PIPELINE_OBJECT_EXT, mGLProgramPipelineHandle, 0,
                             (mVertexProgram->getName() + "/" + mFragmentProgram->getName()).c_str());
#endif
		}
#endif
	}

    void GLSLESProgramPipeline::_useProgram(void)
    {
		if (mLinked)
		{
#if GL_EXT_separate_shader_objects
            GL_CHECK_ERROR
            glBindProgramPipelineEXT(mGLProgramPipelineHandle);
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
}
	//-----------------------------------------------------------------------
	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);
			}
		}
	}
    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());
		}
	}