inline void VL_glProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length)
 {
   if (glProgramBinary)
     glProgramBinary(program, binaryFormat, binary, length);
   else
     VL_UNSUPPORTED_FUNC();
 }
示例#2
0
	bool Shader::LoadFromBinary(const void* buffer, unsigned int size)
	{
		#if NAZARA_RENDERER_SAFE
		if (!glProgramBinary)
		{
			NazaraError("GL_ARB_get_program_binary not supported");
			return false;
		}

		if (!buffer || size < sizeof(UInt64))
		{
			NazaraError("Invalid buffer");
			return false;
		}
		#endif

		Context::EnsureContext();

		const UInt8* ptr = reinterpret_cast<const UInt8*>(buffer);

		// On récupère le format au début du binaire
		///TODO: ByteStream ?
		GLenum binaryFormat = static_cast<GLenum>(*reinterpret_cast<const UInt64*>(&ptr[0]));
		ptr += sizeof(UInt64);

		glProgramBinary(m_program, binaryFormat, ptr, size - sizeof(UInt64));

		return PostLinkage();
	}
int JNICALL Java_com_gomdev_gles_GLESShader_nLoadProgramBinary
(JNIEnv * env, jobject obj, jint program, jint binaryFormat, jstring str)
{
    char* fileName = (char*)env->GetStringUTFChars(str, NULL);

#ifdef DEBUG
    dump("before");
#endif

    if(fileName != NULL)
    {
        BinaryInfo* binaryInfo = find(fileName);
        if(binaryInfo != NULL) {
#ifdef DEBUG
            LOGI("Load() cache hit!!! - %s", fileName);
#endif
            removeBinaryFromList(binaryInfo, false);
            add(binaryInfo);
        } else {
#ifdef DEBUG
            LOGI("Load() cache miss!! - %s", fileName);
#endif
            binaryInfo = readFile(fileName);
            if(binaryInfo == NULL) {
                LOGE("Load() binaryInfo is NULL");
                return 0;
            }

            add(binaryInfo);
        }

//        if (glProgramBinaryOES == NULL) {
//            glProgramBinaryOES = (PFNGLPROGRAMBINARYOESPROC) eglGetProcAddress("glProgramBinaryOES");
//        }
        glProgramBinary(program,
                sBinaryFormat,
                binaryInfo->binary,
                binaryInfo->length);

        GLint success;
        glGetProgramiv(program, GL_LINK_STATUS, &success);

        env->ReleaseStringUTFChars(str, fileName);

        if (!success)
        {
            LOGE("nLoadProgramBinary() link fail");
            return 0;
        }

#ifdef DEBUG
        dump("after");
#endif
        return 1;
    }
    else {
        LOGE("nLoadProgramBinary() fileName is NULL");
        return 0;
    }
}
示例#4
0
void gfx::ShaderProgram::LoadProgramBinary(const rString& filename)
{
	std::stringstream ss;
	ss << filename;
	ss << ".bin";
	FILE* fp = fopen(ss.str().c_str(), "rb");
	//header
	ShaderProgramBinary header;
	fseek(fp, 0, SEEK_SET);
	fread(&header, sizeof(ShaderProgramBinary),1,fp);
	//shader prog
	GLbyte* binary = new GLbyte[header.Size];
	fseek(fp, sizeof(ShaderProgramBinary), SEEK_SET);
	fread(binary, header.Size, 1, fp);
	fclose(fp);

	GLint formats = 0;
	glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &formats);
	GLint *binaryFormats = new GLint[formats];
	glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, binaryFormats);

	m_Handle = glCreateProgram();

	glProgramBinary(m_Handle,(GLenum)(*binaryFormats),binary,header.Size);
	GLint succes;
	glGetProgramiv(m_Handle, GL_LINK_STATUS, &succes);

	if(!succes)
	{
		Logger::Log("Failed to load shader program binary", "ShaderProgram", LogSeverity::ERROR_MSG);
	}
	delete [] binary;
	delete [] binaryFormats;
}
示例#5
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();
    }
示例#6
0
文件: mkprog.c 项目: yoanlcq/FATE
static bool fgm_program_from_binary(GLuint program, fe_iov *binfile) {
#ifndef FE_TARGET_EMSCRIPTEN
    GLsizei binlen = binfile->len - HEADER_SIZE;
    char *bin = ((char*)binfile->base) + HEADER_SIZE;
    GLenum binfmt = fe_hw_swap32_net_to_host(
        *(GLenum*)(((char*)binfile->base)+sizeof(fe_timestamp))
    );

    glProgramBinary(program, binfmt, bin, binlen); // >= ES 3.0

    GLint err, status;
    err = glGetError();
    if(err != GL_INVALID_ENUM) {
        glGetProgramiv(program, GL_LINK_STATUS, &status);
        if(status == GL_TRUE) {
            fe_logv(TAG, "Successfully reused the program binary.\n");
            return true;
        }
    }
    fe_logw(TAG, "Could not reuse the program binary : \n");
    if(err != GL_INVALID_ENUM) {
        fe_gl_log_program_info(program, fe_logw);
        fe_logw(TAG, "\n");
    } else
        fe_logw(TAG, "Either 0x%x is an unrecognized binary format, "
                        "or the OpenGL implementation just rejected it. "
                        "See also the context's settings.\n", binfmt);
    return false;
#else /* FE_TARGET_EMSCRIPTEN */
    return true;
#endif
}
bool ProgramBinaryImplementation_GetProgramBinaryARB::updateProgramLinkSource(const Program * program) const
{
    if (program->m_binary)
    {
        glProgramBinary(program->id(), program->m_binary->format(), program->m_binary->data(), program->m_binary->length());
        return true;
    }

    return program->compileAttachedShaders();
}
示例#8
0
/*
 *
 * Core in:
 * OpenGL    : 4.1
 * OpenGLES  : 3.1
 */
void rglProgramBinary(GLuint program,
  	GLenum binaryFormat,
  	const void *binary,
  	GLsizei length)
{
#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3_1)
   glProgramBinary(program, binaryFormat, binary, length);
#else
   printf("WARNING! Not implemented.\n");
#endif
}
示例#9
0
void ProgramShaderCache::ProgramShaderCacheInserter::Read ( const SHADERUID& key, const u8* value, u32 value_size )
{
	const u8 *binary = value+sizeof(GLenum);
	GLenum *prog_format = (GLenum*)value;
	GLint binary_size = value_size-sizeof(GLenum);

	PCacheEntry entry;
	entry.in_cache = 1;
	entry.shader.glprogid = glCreateProgram();
	glProgramBinary(entry.shader.glprogid, *prog_format, binary, binary_size);

	GLint success;
	glGetProgramiv(entry.shader.glprogid, GL_LINK_STATUS, &success);

	if (success)
	{
		pshaders[key] = entry;
		entry.shader.SetProgramVariables();
	}
	else
		glDeleteProgram(entry.shader.glprogid);
}
示例#10
0
    //-----------------------------------------------------------------------
	void GLSLProgramCommon::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));

        GLint binaryLength = static_cast<GLint>(cacheMicrocode->size() - sizeof(GLenum));

        // load binary
		OGRE_CHECK_GL_ERROR(glProgramBinary(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();
		}
	}
static bool load_cached_shader_binary(opengl::ShaderProgram* program, const SCP_string& hash) {
	if (!do_shader_caching()) {
		return false;
	}

	auto base_filename = SCP_string("ogl_shader-") + hash;

	auto metadata = base_filename + ".json";
	auto binary = base_filename + ".bin";

	auto metadata_fp = cfopen(metadata.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE, false,
	                          CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
	if (!metadata_fp) {
		nprintf(("ShaderCache", "Metadata file does not exist.\n"));
		return false;
	}

	auto size = cfilelength(metadata_fp);
	SCP_string metadata_content;
	metadata_content.resize((size_t) size);
	cfread(&metadata_content[0], 1, size, metadata_fp);

	cfclose(metadata_fp);

	auto metadata_root = json_loads(metadata_content.c_str(), 0, nullptr);
	if (!metadata_root) {
		mprintf(("Loading of cache metadata failed! Falling back to GLSL shader...\n"));
		return false;
	}

	json_int_t format;
	if (json_unpack(metadata_root, "{sI}", "format", &format) != 0) {
		mprintf(("Failed to unpack values from metadata JSON! Falling back to GLSL shader...\n"));
		return false;
	}
	auto binary_format = (GLenum) format;
	json_decref(metadata_root);

	bool supported = false;
	for (auto supported_fmt : GL_binary_formats) {
		if ((GLenum)supported_fmt == binary_format) {
			supported = true;
			break;
		}
	}

	if (!supported) {
		// This can happen in case an implementation stops supporting a particular binary format
		nprintf(("ShaderCache", "Unsupported binary format %d encountered in shader cache.\n", binary_format));
		return false;
	}

	auto binary_fp = cfopen(binary.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE, false,
	                        CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
	if (!binary_fp) {
		nprintf(("ShaderCache", "Binary file does not exist.\n"));
		return false;
	}
	
	GR_DEBUG_SCOPE("Loading cached shader");
	
	SCP_vector<uint8_t> buffer;
	int length = cfilelength(binary_fp);
	buffer.resize((size_t) length);
	cfread(&buffer[0], 1, length, binary_fp);

	cfclose(binary_fp);

	// Load the data!
	glProgramBinary(program->getShaderHandle(), binary_format, buffer.data(), (GLsizei) buffer.size());

	// Check the status...
	GLint status;
	glGetProgramiv(program->getShaderHandle(), GL_LINK_STATUS, &status);

	return status == GL_TRUE;
}
    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
/*
	char const * retrieveBinaryCache(char const* Path)
	{
		return 0;
	}

	enum
	{
		PROGRAM_SEPARATE_BIT = (1 << 0),
		PROGRAM_CACHE_BIT = (1 << 1),
		PROGRAM_BYPASS_CACHE_BIT = (1 << 2)
	};

	bool hasProgramBinarySPIRVSupport()
	{
		GLint NumProgramBinaryFormats(0);
		glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &NumProgramBinaryFormats);

		std::vector<GLint> ProgramBinaryFormats(static_cast<std::size_t>(NumProgramBinaryFormats));
		glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, &ProgramBinaryFormats[0]);

		for(std::size_t FormatIndex = 0; FormatIndex < ProgramBinaryFormats.size(); ++FormatIndex)
		{
			if(ProgramBinaryFormats[FormatIndex] == GL_PROGRAM_BINARY_SPIR_V)
				return true;
		}

		return false;
	}

	bool isProgramBinarySPIRV(GLubyte * binary)
	{
		return *reinterpret_cast<GLuint*>(binary) == 0x07230203;
	}

	GLuint createProgram(char const* Path, GLbitfield Flags)
	{
		assert(HasProgramBinarySPIRVSupport());
		assert(Path);

		if(!(Flags & PROGRAM_BYPASS_CACHE_BIT))
			Path = retrieveBinaryCache(Path);

		GLenum Format = 0;
		GLint Size = 0;
		std::vector<glm::byte> Data;
		if(!loadBinary(Path, Format, Data, Size))
			return 0;

		assert((isProgramBinarySPIRV(&Data[0]) && Format == GL_PROGRAM_BINARY_SPIR_V) || Format != GL_PROGRAM_BINARY_SPIR_V);

		GLuint ProgramName = glCreateProgram();
		glProgramParameteri(ProgramName, GL_PROGRAM_SEPARABLE, Flags & PROGRAM_SEPARATE_BIT ? GL_TRUE : GL_FALSE);
		glProgramParameteri(ProgramName, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, Flags & PROGRAM_CACHE_BIT ? GL_TRUE : GL_FALSE);
		glProgramBinary(ProgramName, Format, &Data[0], Size);
		glLinkProgram(ProgramName);

		return ProgramName;
	}
*/
	bool initProgram()
	{
		bool Validated = true;
		GLint Success = 0;

		glGenProgramPipelines(1, &PipelineName);

		ProgramName[program::VERT] = glCreateProgram();
		glProgramParameteri(ProgramName[program::VERT], GL_PROGRAM_SEPARABLE, GL_TRUE);
		glProgramParameteri(ProgramName[program::VERT], GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);

		ProgramName[program::GEOM] = glCreateProgram();
		glProgramParameteri(ProgramName[program::GEOM], GL_PROGRAM_SEPARABLE, GL_TRUE);
		glProgramParameteri(ProgramName[program::GEOM], GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);

		ProgramName[program::FRAG] = glCreateProgram();
		glProgramParameteri(ProgramName[program::FRAG], GL_PROGRAM_SEPARABLE, GL_TRUE);
		glProgramParameteri(ProgramName[program::FRAG], GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);

		{
			GLenum Format = 0;
			GLint Size = 0;
			std::vector<glm::byte> Data;
			if(loadBinary(getDataDirectory() + VERT_PROGRAM_BINARY, Format, Data, Size))
			{
				glProgramBinary(ProgramName[program::VERT], Format, &Data[0], Size);
				glGetProgramiv(ProgramName[program::VERT], GL_LINK_STATUS, &Success);
				Validated = Validated && Success == GL_TRUE;
			}
		}

		{
			GLenum Format = 0;
			GLint Size = 0;
			std::vector<glm::byte> Data;
			if(loadBinary(getDataDirectory() + GEOM_PROGRAM_BINARY, Format, Data, Size))
			{
				glProgramBinary(ProgramName[program::GEOM], Format, &Data[0], Size);
				glGetProgramiv(ProgramName[program::GEOM], GL_LINK_STATUS, &Success);
				Validated = Validated && Success == GL_TRUE;
			}
		}

		{
			GLenum Format = 0;
			GLint Size = 0;
			std::vector<glm::byte> Data;
			if(loadBinary(getDataDirectory() + FRAG_PROGRAM_BINARY, Format, Data, Size))
			{
				glProgramBinary(ProgramName[program::FRAG], Format, &Data[0], Size);
				glGetProgramiv(ProgramName[program::FRAG], GL_LINK_STATUS, &Success);
				Validated = Validated && Success == GL_TRUE;
			}
		}

		compiler Compiler;

		if(Validated && !Success)
		{
			GLuint VertShaderName = Compiler.create(GL_VERTEX_SHADER, getDataDirectory() + VERT_SHADER_SOURCE);

			glAttachShader(ProgramName[program::VERT], VertShaderName);
			glLinkProgram(ProgramName[program::VERT]);
		}

		if(Validated && !Success)
		{
			GLuint GeomShaderName = Compiler.create(GL_GEOMETRY_SHADER, getDataDirectory() + GEOM_SHADER_SOURCE);

			glAttachShader(ProgramName[program::GEOM], GeomShaderName);
			glLinkProgram(ProgramName[program::GEOM]);
		}

		if(Validated && !Success)
		{
			GLuint FragShaderName = Compiler.create(GL_FRAGMENT_SHADER, getDataDirectory() + FRAG_SHADER_SOURCE);

			glAttachShader(ProgramName[program::FRAG], FragShaderName);
			glLinkProgram(ProgramName[program::FRAG]);
		}

		if(Validated)
		{
			glUseProgramStages(PipelineName, GL_VERTEX_SHADER_BIT, ProgramName[program::VERT]);
			glUseProgramStages(PipelineName, GL_GEOMETRY_SHADER_BIT, ProgramName[program::GEOM]);
			glUseProgramStages(PipelineName, GL_FRAGMENT_SHADER_BIT, ProgramName[program::FRAG]);
			Validated = Validated && this->checkError("initProgram - stage");
		}

		if(Validated)
		{
			Validated = Validated && Compiler.checkProgram(ProgramName[program::VERT]);
			Validated = Validated && Compiler.checkProgram(ProgramName[program::GEOM]);
			Validated = Validated && Compiler.checkProgram(ProgramName[program::FRAG]);
		}

		if(Validated)
		{
			UniformMVP = glGetUniformLocation(ProgramName[program::VERT], "MVP");
			UniformDiffuse = glGetUniformLocation(ProgramName[program::FRAG], "Diffuse");
		}

		saveProgram(ProgramName[program::VERT], getDataDirectory() + VERT_PROGRAM_BINARY);
		saveProgram(ProgramName[program::GEOM], getDataDirectory() + GEOM_PROGRAM_BINARY);
		saveProgram(ProgramName[program::FRAG], getDataDirectory() + FRAG_PROGRAM_BINARY);

		return Validated && this->checkError("initProgram");
	}
示例#14
0
 void ShaderProgram::setBinary(GLenum format, const void* binary, GLsizei length)
 {
     if(ext::programBinary())
         glCheck(glProgramBinary(program_, format, binary, length));
 }
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_GL41_nglProgramBinary(JNIEnv *env, jclass clazz, jint program, jint binaryFormat, jlong binary, jint length, jlong function_pointer) {
	const GLvoid *binary_address = (const GLvoid *)(intptr_t)binary;
	glProgramBinaryPROC glProgramBinary = (glProgramBinaryPROC)((intptr_t)function_pointer);
	glProgramBinary(program, binaryFormat, binary_address, length);
}
bool initProgram()
{
	bool Validated = true;
	GLint Success = 0;

	glGenProgramPipelines(1, &PipelineName);

	// Vertex program
	ProgramName[program::VERT] = glCreateProgram();
	glProgramParameteri(ProgramName[program::VERT], GL_PROGRAM_SEPARABLE, GL_TRUE);
	glProgramParameteri(ProgramName[program::VERT], GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);

	{
		GLenum Format = 0;
		GLint Size = 0;
		std::vector<glm::byte> Data;
		if(glf::loadBinary(glf::DATA_DIRECTORY + VERT_PROGRAM_BINARY, Format, Data, Size))
		{
			glProgramBinary(ProgramName[program::VERT], Format, &Data[0], Size);
			glGetProgramiv(ProgramName[program::VERT], GL_LINK_STATUS, &Success);
		}
	}

	// Create program
	if(Validated && !Success)
	{
		GLuint VertShaderName = glf::createShader(GL_VERTEX_SHADER, glf::DATA_DIRECTORY + VERT_SHADER_SOURCE);

		glAttachShader(ProgramName[program::VERT], VertShaderName);
		glDeleteShader(VertShaderName);
		glLinkProgram(ProgramName[program::VERT]);
		Validated = Validated && glf::checkProgram(ProgramName[program::VERT]);
	}

	// Geometry program
	ProgramName[program::GEOM] = glCreateProgram();
	glProgramParameteri(ProgramName[program::GEOM], GL_PROGRAM_SEPARABLE, GL_TRUE);
	glProgramParameteri(ProgramName[program::GEOM], GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);

	{
		GLenum Format = 0;
		GLint Size = 0;
		std::vector<glm::byte> Data;
		if(glf::loadBinary(glf::DATA_DIRECTORY + GEOM_PROGRAM_BINARY, Format, Data, Size))
		{
			glProgramBinary(ProgramName[program::GEOM], Format, &Data[0], Size);
			glGetProgramiv(ProgramName[program::GEOM], GL_LINK_STATUS, &Success);
		}
	}

	// Create program
	if(Validated && !Success)
	{
		GLuint GeomShaderName = glf::createShader(GL_GEOMETRY_SHADER, glf::DATA_DIRECTORY + GEOM_SHADER_SOURCE);

		glAttachShader(ProgramName[program::GEOM], GeomShaderName);
		glDeleteShader(GeomShaderName);
		glLinkProgram(ProgramName[program::GEOM]);
		Validated = Validated && glf::checkProgram(ProgramName[program::GEOM]);
	}

	// Fragment program
	ProgramName[program::FRAG] = glCreateProgram();
	glProgramParameteri(ProgramName[program::FRAG], GL_PROGRAM_SEPARABLE, GL_TRUE);
	glProgramParameteri(ProgramName[program::FRAG], GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);

	{
		GLenum Format = 0;
		GLint Size = 0;
		std::vector<glm::byte> Data;
		if(glf::loadBinary(glf::DATA_DIRECTORY + FRAG_PROGRAM_BINARY, Format, Data, Size))
		{
			glProgramBinary(ProgramName[program::FRAG], Format, &Data[0], Size);
			glGetProgramiv(ProgramName[program::FRAG], GL_LINK_STATUS, &Success);
		}
	}

	// Create program
	if(Validated && !Success)
	{
		GLuint FragShaderName = glf::createShader(GL_FRAGMENT_SHADER, glf::DATA_DIRECTORY + FRAG_SHADER_SOURCE);

		glAttachShader(ProgramName[program::FRAG], FragShaderName);
		glDeleteShader(FragShaderName);
		glLinkProgram(ProgramName[program::FRAG]);
		Validated = Validated && glf::checkProgram(ProgramName[program::FRAG]);
	}

	// Pipeline program
	if(Validated)
	{
		glUseProgramStages(PipelineName, GL_VERTEX_SHADER_BIT, ProgramName[program::VERT]);
		glUseProgramStages(PipelineName, GL_GEOMETRY_SHADER_BIT, ProgramName[program::GEOM]);
		glUseProgramStages(PipelineName, GL_FRAGMENT_SHADER_BIT, ProgramName[program::FRAG]);
		Validated = Validated && glf::checkError("initProgram - stage");
	}

	// Get variables locations
	if(Validated)
	{
		UniformMVP = glGetUniformLocation(ProgramName[program::VERT], "MVP");
		UniformDiffuse = glGetUniformLocation(ProgramName[program::FRAG], "Diffuse");
	}

	return Validated && glf::checkError("initProgram");
}
static bool load_cached_shader_binary(opengl::ShaderProgram* program, SCP_string hash) {
	if (!do_shader_caching()) {
		return false;
	}

	auto base_filename = SCP_string("ogl_shader-") + hash;

	auto metadata = base_filename + ".json";
	auto binary = base_filename + ".bin";

	auto metadata_fp = cfopen(metadata.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE);
	if (!metadata_fp) {
		nprintf(("ShaderCache", "Metadata file does not exist.\n"));
		return false;
	}

	auto size = cfilelength(metadata_fp);
	SCP_string metadata_content;
	metadata_content.resize((size_t) size);
	cfread(&metadata_content[0], 1, size, metadata_fp);

	cfclose(metadata_fp);

	auto metadata_root = json_loads(metadata_content.c_str(), 0, nullptr);
	if (!metadata_root) {
		mprintf(("Loading of cache metadata failed! Falling back to GLSL shader...\n"));
		return false;
	}

	json_int_t format;
	if (json_unpack(metadata_root, "{sI}", "format", &format) != 0) {
		mprintf(("Failed to unpack values from metadata JSON! Falling back to GLSL shader...\n"));
		return false;
	}
	auto binary_format = (GLenum) format;
	json_decref(metadata_root);

	auto binary_fp = cfopen(binary.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE);
	if (!binary_fp) {
		nprintf(("ShaderCache", "Binary file does not exist.\n"));
		return false;
	}
	
	GR_DEBUG_SCOPE("Loading cached shader");
	
	SCP_vector<uint8_t> buffer;
	int length = cfilelength(binary_fp);
	buffer.resize((size_t) length);
	cfread(&buffer[0], 1, length, binary_fp);

	cfclose(binary_fp);

	// Load the data!
	glProgramBinary(program->getShaderHandle(), binary_format, buffer.data(), (GLsizei) buffer.size());

	// Check the status...
	GLint status;
	glGetProgramiv(program->getShaderHandle(), GL_LINK_STATUS, &status);

	return status == GL_TRUE;
}
/*!****************************************************************************
 @Function		loadBinaryProgram
 @Return		bool	True if load succeeded.
 @Description	This function takes as input the ID of a shader program object
				which should have been created prior to calling this function,
				as well as a filename to load the binary program from.
				The function will load in a file storing the binary shader
				program, and the enum value determining its format.
				It will then load the binary into memory.

 @Note:			This function is not able to check if the shaders have changed.
				If you change the shaders then the file this saves out either
				needs to be deleted	or a new file used.
******************************************************************************/
bool OGLES3BinaryShader::loadBinaryProgram(const char* Filename, GLuint &ProgramObjectID)
{
    // Open the file.
    FILE* infile = fopen(Filename, "rb");

	// File open failed, either doesn't exist or is empty.
	if (!infile)
		return false;

	// Find initialise the shader binary.
    fseek(infile, 0, SEEK_END);
    GLsizei length = (GLint)ftell(infile)-sizeof(GLenum);

	if (!length)
	{
		fclose(infile);
		return false;	// File appears empty.
	}

	// Allocate a buffer large enough to store the binary program.
    GLvoid* ShaderBinary = (GLvoid*)malloc(length);

	// Read in the binary format
	GLenum format=0;
    fseek(infile, 0, SEEK_SET);
    fread(&format, sizeof(GLenum), 1, infile);

	// Read in the program binary.
    fread(ShaderBinary, length, 1, infile);
    fclose(infile);

	// Create an empty shader program
	ProgramObjectID = glCreateProgram();

    // Load the binary into the program object -- no need to link!
    glProgramBinary(ProgramObjectID, format, ShaderBinary, length);

	// Delete the binary program from memory.
    free(ShaderBinary);

	// Check that the program was loaded correctly, uses the same checks as when linking with a standard shader.
	GLint loaded;
    glGetProgramiv(ProgramObjectID, GL_LINK_STATUS, &loaded);

    if(!loaded)
    {
        // Something must have changed. Need to recompile shaders.
		int i32InfoLogLength, i32CharsWritten;
		glGetProgramiv(ProgramObjectID, GL_INFO_LOG_LENGTH, &i32InfoLogLength);
		char* pszInfoLog = new char[i32InfoLogLength];
		glGetProgramInfoLog(ProgramObjectID, i32InfoLogLength, &i32CharsWritten, pszInfoLog);
		char* pszMsg = new char[i32InfoLogLength+256];
		strcpy(pszMsg, "Failed to load binary program: ");
		strcat(pszMsg, pszInfoLog);
		PVRShellSet(prefExitMessage, pszMsg);

		delete [] pszMsg;
		delete [] pszInfoLog;
		return false;
    }
	return true;
}