inline void VL_glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary) { if (glGetProgramBinary) glGetProgramBinary(program, bufSize, length, binaryFormat, binary); else VL_UNSUPPORTED_FUNC(); }
void gfx::ShaderProgram::SaveProgramBinary(){ if(m_Handle <= 0){ return; } GLint formatCount; glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS,&formatCount); GLint* formats = new GLint[formatCount]; glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, formats); GLint length; glGetProgramiv(m_Handle,GL_PROGRAM_BINARY_LENGTH, &length); GLenum* binaryFormats = new GLenum(); GLbyte* programBinary = new GLbyte[length]; glGetProgramBinary(m_Handle,length,nullptr, binaryFormats,programBinary); ShaderProgramBinary header; header.Size = length; strcpy(header.Version,(char*)glGetString(GL_VERSION)); std::stringstream ss; ss << m_Filename; ss << ".bin"; FILE* file = fopen(ss.str().c_str(),"wb"); fwrite(&header,sizeof(ShaderProgramBinary),1,file); fwrite(programBinary,length,1,file); fclose(file); Logger::Log("Saved program binary", "ShaderProgram", LogSeverity::INFO_MSG); delete [] programBinary; delete binaryFormats; delete formats; }
static void linkAndCheck(GLuint program) { GLint programBinaryLength; glLinkProgram(program); if (!checkProgram(program, "render")) { exit(1); } programBinaryLength = 0; glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programBinaryLength); if (programBinaryLength > 0) { void* buf; GLenum format; GLsizei length; FILE* file; printf("programBinaryLength: %d.\n", programBinaryLength); buf = malloc(programBinaryLength); glGetProgramBinary(program, programBinaryLength, &length, &format, buf); printf("programBinaryFormat: %x.\n", format); file = fopen("p_binary.dat", "wb"); if (file) { printf("write binary to p_binary.dat, length: %d.\n", length); fwrite(buf, 1, length, file); fclose(file); } } }
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_GL41_nglGetProgramBinary(JNIEnv *env, jclass clazz, jint program, jint bufSize, jlong length, jlong binaryFormat, jlong binary, jlong function_pointer) { GLsizei *length_address = (GLsizei *)(intptr_t)length; GLenum *binaryFormat_address = (GLenum *)(intptr_t)binaryFormat; GLvoid *binary_address = (GLvoid *)(intptr_t)binary; glGetProgramBinaryPROC glGetProgramBinary = (glGetProgramBinaryPROC)((intptr_t)function_pointer); glGetProgramBinary(program, bufSize, length_address, binaryFormat_address, binary_address); }
void Shader::exportAssembly(const string & fileName) { if(!glGetProgramBinary) { LOG("glGetProgramBinary not supported"); return; } // Max file size const size_t MAX_SIZE = 1 << 24; // Get binary program char *binary = new char[MAX_SIZE]; GLenum format; GLint length; glGetProgramBinary(m_id, MAX_SIZE, &length, &format, binary); // Copy to string string content; content.resize(length); memcpy(&content[0], binary, length); // Write to file FileSystem::WriteFile(fileName, content); // Clean up delete[] binary; }
std::pair<GLenum,std::vector<char>> Program::getBinary() const { GLint binaryLength(0); glGetProgramiv( getGLId(), GL_PROGRAM_BINARY_LENGTH, &binaryLength ); GLenum binaryFormat(0); std::vector<char> binary(binaryLength); glGetProgramBinary( getGLId(), binaryLength, nullptr, &binaryFormat, binary.data() ); return( std::make_pair( binaryFormat, binary ) ); }
static void cache_program_binary(GLuint program, const SCP_string& hash) { if (!do_shader_caching()) { return; } GR_DEBUG_SCOPE("Saving shader binary"); GLint size; glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &size); if (size <= 0) { // No binary available (I'm looking at you Mesa...) return; } SCP_vector<uint8_t> binary; binary.resize((size_t) size); GLenum binary_fmt; GLsizei length; glGetProgramBinary(program, (GLsizei) binary.size(), &length, &binary_fmt, binary.data()); if (length == 0) { return; } auto base_filename = SCP_string("ogl_shader-") + hash; auto metadata_name = base_filename + ".json"; auto binary_name = base_filename + ".bin"; auto metadata_fp = cfopen(metadata_name.c_str(), "wb", CFILE_NORMAL, CF_TYPE_CACHE, false, CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT); if (!metadata_fp) { mprintf(("Could not open shader cache metadata file!\n")); return; } auto metadata = json_pack("{sI}", "format", (json_int_t)binary_fmt); if (json_dump_callback(metadata, json_write_callback, metadata_fp, 0) != 0) { mprintf(("Failed to write shader cache metadata file!\n")); cfclose(metadata_fp); return; } cfclose(metadata_fp); json_decref(metadata); auto binary_fp = cfopen(binary_name.c_str(), "wb", CFILE_NORMAL, CF_TYPE_CACHE, false, CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT); if (!binary_fp) { mprintf(("Could not open shader cache binary file!\n")); return; } cfwrite(binary.data(), 1, (int) binary.size(), binary_fp); cfclose(binary_fp); }
void ProgramShaderCache::Shutdown() { // store all shaders in cache on disk if (g_ogl_config.bSupportsGLSLCache && !g_Config.bEnableShaderDebugging) { for (auto& entry : pshaders) { // Clear any prior error code glGetError(); if (entry.second.in_cache) { continue; } GLint link_status = GL_FALSE, delete_status = GL_TRUE, binary_size = 0; glGetProgramiv(entry.second.shader.glprogid, GL_LINK_STATUS, &link_status); glGetProgramiv(entry.second.shader.glprogid, GL_DELETE_STATUS, &delete_status); glGetProgramiv(entry.second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size); if (glGetError() != GL_NO_ERROR || link_status == GL_FALSE || delete_status == GL_TRUE || !binary_size) { continue; } std::vector<u8> data(binary_size + sizeof(GLenum)); u8* binary = &data[sizeof(GLenum)]; GLenum* prog_format = (GLenum*)&data[0]; glGetProgramBinary(entry.second.shader.glprogid, binary_size, nullptr, prog_format, binary); if (glGetError() != GL_NO_ERROR) { continue; } g_program_disk_cache.Append(entry.first, &data[0], binary_size + sizeof(GLenum)); } g_program_disk_cache.Sync(); g_program_disk_cache.Close(); } glUseProgram(0); for (auto& entry : pshaders) { entry.second.Destroy(); } pshaders.clear(); pixel_uid_checker.Invalidate(); vertex_uid_checker.Invalidate(); delete s_buffer; s_buffer = nullptr; }
/* * * Core in: * OpenGL : 4.1 * OpenGLES : 3.1 */ void rglGetProgramBinary( GLuint program, GLsizei bufsize, GLsizei *length, GLenum *binaryFormat, void *binary) { #if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3) glGetProgramBinary(program, bufsize, length, binaryFormat, binary); #else printf("WARNING! Not implemented.\n"); #endif }
// This function will get the binary program. Normally it must be used a caching // solution but Nvidia also incorporates the ASM dump. Asm is nice because it allow // to have an overview of the program performance based on the instruction number // Note: initially I was using cg offline compiler but it doesn't support latest // GLSL improvement (unfortunately). int GSShaderOGL::DumpAsm(const std::string& file, GLuint p) { if (!GLLoader::nvidia_buggy_driver) return 0; GLint binaryLength; glGetProgramiv(p, GL_PROGRAM_BINARY_LENGTH, &binaryLength); char* binary = new char[binaryLength+4]; GLenum binaryFormat; glGetProgramBinary(p, binaryLength, NULL, &binaryFormat, binary); FILE* outfile = fopen(file.c_str(), "w"); ASSERT(outfile); // Search the magic number "!!" int asm_ = 0; while (asm_ < binaryLength && (binary[asm_] != '!' || binary[asm_+1] != '!')) { asm_ += 1; } int instructions = -1; if (asm_ < binaryLength) { // Now print asm as text char* asm_txt = strtok(&binary[asm_], "\n"); while (asm_txt != NULL && (strncmp(asm_txt, "END", 3) || !strncmp(asm_txt, "ENDIF", 5))) { if (!strncmp(asm_txt, "OUT", 3) || !strncmp(asm_txt, "TEMP", 4) || !strncmp(asm_txt, "LONG", 4)) { instructions = 0; } else if (instructions >= 0) { if (instructions == 0) fprintf(outfile, "\n"); instructions++; } fprintf(outfile, "%s\n", asm_txt); asm_txt = strtok(NULL, "\n"); } fprintf(outfile, "\nFound %d instructions\n", instructions); } fclose(outfile); if (instructions < 0) { // RAW dump in case of error fprintf(stderr, "Error: failed to find the number of instructions!\n"); outfile = fopen(file.c_str(), "wb"); fwrite(binary, binaryLength, 1, outfile); fclose(outfile); ASSERT(0); } delete[] binary; return instructions; }
bool saveProgram(GLuint ProgramName, std::string const & String) { GLint Size(0); GLenum Format(0); glGetProgramiv(ProgramName, GL_PROGRAM_BINARY_LENGTH, &Size); std::vector<glm::byte> Data(Size); glGetProgramBinary(ProgramName, Size, nullptr, &Format, &Data[0]); saveBinary(String, Format, Data, Size); return this->checkError("saveProgram"); }
static void fgm_program_to_binary(GLuint program, fe_iov *binfile) { #ifndef FE_TARGET_EMSCRIPTEN GLsizei binlen; glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binlen); binfile->len = HEADER_SIZE + binlen; binfile->base = fe_mem_heapalloc(binfile->len, char, "fe_gl prog binary"); GLenum binfmt; glGetProgramBinary(program, binlen, NULL, &binfmt, ((char*)binfile->base)+HEADER_SIZE); // >= ES 3.0 *(fe_timestamp*)binfile->base = fe_hw_swap64_host_to_net(fe_timestamp_get_now()); *(GLenum*)(((char*)binfile->base)+sizeof(fe_timestamp)) = fe_hw_swap32_host_to_net(binfmt); fe_logv(TAG, "Saved binary with format 0x%x.\n", binfmt); #endif /* FE_TARGET_EMSCRIPTEN */ }
ProgramBinary * ProgramBinaryImplementation_GetProgramBinaryARB::getProgramBinary(const Program * program) const { int length = program->get(GL_PROGRAM_BINARY_LENGTH); if (length == 0) return nullptr; GLenum format; std::vector<char> binary(length); glGetProgramBinary(program->id(), length, nullptr, &format, binary.data()); return new ProgramBinary(format, binary); }
std::pair<GLenum, std::unique_ptr<char[]>> ShaderProgram::getBinary() const { if(ext::programBinary()) { GLenum format = 0; std::unique_ptr<char[]> binary(new char[getBinarySize()]); glCheck(glGetProgramBinary(program_, getBinarySize(), nullptr, &format, void_cast(binary))); return std::make_pair(format, std::move(binary)); } else return std::make_pair(0, nullptr); }
void ProgramShaderCache::Shutdown() { // store all shaders in cache on disk if (g_ogl_config.bSupportsGLSLCache && !g_Config.bEnableShaderDebugging) { for (auto& entry : pshaders) { if (entry.second.in_cache) { continue; } GLint binary_size; glGetProgramiv(entry.second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size); if (!binary_size) { continue; } u8 *data = new u8[binary_size+sizeof(GLenum)]; u8 *binary = data + sizeof(GLenum); GLenum *prog_format = (GLenum*)data; glGetProgramBinary(entry.second.shader.glprogid, binary_size, nullptr, prog_format, binary); g_program_disk_cache.Append(entry.first, data, binary_size+sizeof(GLenum)); delete [] data; } g_program_disk_cache.Sync(); g_program_disk_cache.Close(); } glUseProgram(0); for (auto& entry : pshaders) { entry.second.Destroy(); } pshaders.clear(); pixel_uid_checker.Invalidate(); vertex_uid_checker.Invalidate(); delete s_buffer; s_buffer = nullptr; }
void ProgramShaderCache::Shutdown(void) { // store all shaders in cache on disk if (g_ogl_config.bSupportsGLSLCache) { PCache::iterator iter = pshaders.begin(); for (; iter != pshaders.end(); ++iter) { if(iter->second.in_cache) continue; GLint binary_size; glGetProgramiv(iter->second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size); if(!binary_size) continue; u8 *data = new u8[binary_size+sizeof(GLenum)]; u8 *binary = data + sizeof(GLenum); GLenum *prog_format = (GLenum*)data; glGetProgramBinary(iter->second.shader.glprogid, binary_size, NULL, prog_format, binary); g_program_disk_cache.Append(iter->first, data, binary_size+sizeof(GLenum)); delete [] data; } g_program_disk_cache.Sync(); g_program_disk_cache.Close(); } glUseProgram(0); PCache::iterator iter = pshaders.begin(); for (; iter != pshaders.end(); ++iter) iter->second.Destroy(); pshaders.clear(); pixel_uid_checker.Invalidate(); vertex_uid_checker.Invalidate(); if (g_ActiveConfig.backend_info.bSupportsGLSLUBO) { delete s_buffer; s_buffer = 0; delete [] s_ubo_buffer; s_ubo_buffer = 0; } }
int gl_GetProgramBinary(State & state){ GLuint program = (GLuint)state.stack->to<int>(1); GLint maxLength; GLsizei length; glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &maxLength); GLenum binaryFormat; GLchar * binary = new char[maxLength]; glGetProgramBinary(program, maxLength, &length, &binaryFormat, binary); state.stack->push<int>(binaryFormat); state.stack->pushLString(binary, length); delete[] binary; return 2; }
ByteArray Shader::GetBinary() const { ByteArray byteArray; Context::EnsureContext(); GLint binaryLength = 0; glGetProgramiv(m_program, GL_PROGRAM_BINARY_LENGTH, &binaryLength); if (binaryLength > 0) { byteArray.Reserve(sizeof(UInt64) + binaryLength); UInt8* buffer = byteArray.GetBuffer(); GLenum binaryFormat; glGetProgramBinary(m_program, binaryLength, nullptr, &binaryFormat, &buffer[sizeof(UInt64)]); // On stocke le format au début du binaire *reinterpret_cast<UInt64*>(&buffer[0]) = binaryFormat; } return byteArray; }
bool HdStGLSLProgram::Link() { HD_TRACE_FUNCTION(); HF_MALLOC_TAG_FUNCTION(); if (!glLinkProgram) return false; // glew initialized GLuint program = _program.GetId(); if (program == 0) { TF_CODING_ERROR("At least one shader has to be compiled before linking."); return false; } bool dumpShaderBinary = TfDebug::IsEnabled(HD_DUMP_SHADER_BINARY); if (dumpShaderBinary) { // set RETRIEVABLE_HINT to true for getting program binary length. // note: Actually the GL driver may recompile the program dynamically on // some state changes, so the size of program could be inaccurate. glProgramParameteri(program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); } // link glLinkProgram(program); std::string logString; bool success = true; if (!HdStGLUtils::GetProgramLinkStatus(program, &logString)) { // XXX:validation TF_WARN("Failed to link shader: %s", logString.c_str()); success = false; } // initial program size GLint size; glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &size); // update the program resource allocation _program.SetAllocation(program, size); // create an uniform buffer GLuint uniformBuffer = _uniformBuffer.GetId(); if (uniformBuffer == 0) { glGenBuffers(1, &uniformBuffer); _uniformBuffer.SetAllocation(uniformBuffer, 0); } // binary dump out if (dumpShaderBinary) { std::vector<char> bin(size); GLsizei len; GLenum format; glGetProgramBinary(program, size, &len, &format, &bin[0]); static int id = 0; std::stringstream fname; fname << "program" << id++ << ".bin"; std::fstream output(fname.str().c_str(), std::ios::out|std::ios::binary); output.write(&bin[0], size); output.close(); std::cout << "Write " << fname.str() << " (size=" << size << ")\n"; } return success; }
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::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 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); } } }
/*! adds a shader object */ shader_object* shader::add_shader_src(const string& identifier, const string& option, ext::GLSL_VERSION glsl_version, const char* vs_text, const char* gs_text, const char* fs_text) { // success flag (if it's 1 (true), we successfully created a shader object) int success; GLchar info_log[A2E_SHADER_LOG_SIZE]; if(gs_text != nullptr && strcmp(gs_text, "") == 0) gs_text = nullptr; // create a new shader object if none exists for this identifier if(shaders.count(identifier) == 0) { shaders[identifier] = new shader_object(identifier); } // add a new program object to this shader shaders[identifier]->programs.push_back(new shader_object::internal_shader_object()); if(option != "") { shaders[identifier]->options[option] = shaders[identifier]->programs.back(); } shader_object::internal_shader_object& shd_obj = *shaders[identifier]->programs.back(); shaders[identifier]->glsl_version = std::max(shaders[identifier]->glsl_version, glsl_version); // create the vertex shader object shd_obj.vertex_shader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(shd_obj.vertex_shader, 1, (GLchar const**)&vs_text, nullptr); glCompileShader(shd_obj.vertex_shader); glGetShaderiv(shd_obj.vertex_shader, GL_COMPILE_STATUS, &success); if(!success) { glGetShaderInfoLog(shd_obj.vertex_shader, A2E_SHADER_LOG_SIZE, nullptr, info_log); log_error("Error in vertex shader \"%s/%s\" compilation!", identifier, option); log_pretty_print(info_log, vs_text); return 0; } #if !defined(FLOOR_IOS) // create the geometry shader object if(gs_text != nullptr && strcmp(gs_text, "") != 0) { shd_obj.geometry_shader = glCreateShader(GL_GEOMETRY_SHADER); glShaderSource(shd_obj.geometry_shader, 1, (GLchar const**)&gs_text, nullptr); glCompileShader(shd_obj.geometry_shader); glGetShaderiv(shd_obj.geometry_shader, GL_COMPILE_STATUS, &success); if(!success) { glGetShaderInfoLog(shd_obj.geometry_shader, A2E_SHADER_LOG_SIZE, nullptr, info_log); log_error("Error in geometry shader \"%s/%s\" compilation!", identifier, option); log_pretty_print(info_log, gs_text); return 0; } } else shd_obj.geometry_shader = 0; #else if(gs_text != nullptr && strcmp(gs_text, "") != 0) { log_error("geometry shaders are not supported in OpenGL ES 2.0 or 3.0!"); } shd_obj.geometry_shader = 0; #endif // create the fragment shader object shd_obj.fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(shd_obj.fragment_shader, 1, (GLchar const**)&fs_text, nullptr); glCompileShader(shd_obj.fragment_shader); glGetShaderiv(shd_obj.fragment_shader, GL_COMPILE_STATUS, &success); if(!success) { glGetShaderInfoLog(shd_obj.fragment_shader, A2E_SHADER_LOG_SIZE, nullptr, info_log); log_error("Error in fragment shader \"%s/%s\" compilation!", identifier, option); log_pretty_print(info_log, fs_text); return 0; } // create the program object shd_obj.program = glCreateProgram(); // attach the vertex and fragment shader progam to it glAttachShader(shd_obj.program, shd_obj.vertex_shader); glAttachShader(shd_obj.program, shd_obj.fragment_shader); if(gs_text != nullptr) { glAttachShader(shd_obj.program, shd_obj.geometry_shader); } // WIP: program binary #if defined(A2E_DEBUG_PROGRAM_BINARY) #if defined(__APPLE__) { fstream progcode_vs("/tmp/a2e_shd_code_vs.glsl", fstream::out); progcode_vs << vs_text << endl; progcode_vs.close(); if(shd_obj.geometry_shader != 0) { fstream progcode_gs("/tmp/a2e_shd_code_gs.glsl", fstream::out); progcode_gs << gs_text << endl; progcode_gs.close(); } fstream progcode_fs("/tmp/a2e_shd_code_fs.glsl", fstream::out); progcode_fs << fs_text << endl; progcode_fs.close(); string output_vs = "", output_gs = "", output_fs = ""; core::system("cgc -profile gp4vp -strict -oglsl /tmp/a2e_shd_code_vs.glsl 2>&1", output_vs); if(shd_obj.geometry_shader != 0) { core::system("cgc -profile gp4gp -strict -oglsl -po POINT /tmp/a2e_shd_code_gs.glsl 2>&1", output_gs); } core::system("cgc -profile gp4fp -strict -oglsl /tmp/a2e_shd_code_fs.glsl 2>&1", output_fs); system("rm /tmp/a2e_shd_code_vs.glsl"); if(shd_obj.geometry_shader != 0) { system("rm /tmp/a2e_shd_code_gs.glsl"); } system("rm /tmp/a2e_shd_code_fs.glsl"); // shader_debug::add(identifier, option, output_vs, output_gs, output_fs); } #else if(exts->is_ext_supported("GL_ARB_get_program_binary")) glProgramParameteri(shd_obj.program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); #endif #endif // now link the program object glLinkProgram(shd_obj.program); glGetProgramiv(shd_obj.program, GL_LINK_STATUS, &success); if(!success) { glGetProgramInfoLog(shd_obj.program, A2E_SHADER_LOG_SIZE, nullptr, info_log); log_error("Error in program \"%s/%s\" linkage!\nInfo log: %s", identifier, option, info_log); return 0; } glUseProgram(shd_obj.program); // bind frag data locations (frag_color, frag_color_2, frag_color_3, ...) bool fd_relink = false; #if !defined(FLOOR_IOS) const unsigned int max_draw_buffers = exts->get_max_draw_buffers(); for(unsigned int i = 0; i < max_draw_buffers; i++) { string name = "frag_color"; if(i >= 1) name += "_"+to_string(i+1); const GLint location = glGetFragDataLocation(shd_obj.program, name.c_str()); // check if the frag color exists and must be bound to a different location if(location >= 0 && i != (GLuint)location) { // if so, bind it to the correct location glBindFragDataLocation(shd_obj.program, i, name.c_str()); fd_relink = true; } } #else // NOTE: MRTs are not support in OpenGL ES 2.0 // in OpenGL ES 3.0 the locations are already set in the shader #endif if(fd_relink) { // program must be linked again after the frag data locations were modified // (double-linkage sucks, but there's no other way in opengl 3.2 ...) glLinkProgram(shd_obj.program); } // WIP: program binary #if defined(A2E_DEBUG_PROGRAM_BINARY) #if !defined(__APPLE__) if(exts->is_ext_supported("GL_ARB_get_program_binary")) { GLint binary_length = 0; glGetProgramiv(shd_obj.program, GL_PROGRAM_BINARY_LENGTH, &binary_length); unsigned char* binary = new unsigned char[binary_length]; GLenum binary_format = 0; glGetProgramBinary(shd_obj.program, binary_length, nullptr, &binary_format, binary); string binary_fname = "shader_binary_"+identifier+"_"+to_string(shaders[identifier]->programs.size()-1)+".dat"; f->open_file(binary_fname.c_str(), file_io::OT_WRITE_BINARY); f->write_block((const char*)binary, binary_length, false); f->close_file(); delete [] binary; } #endif #endif // grab number and names of all attributes and uniforms and get their locations (needs to be done before validation, b/c we have to set sampler locations) GLint attr_count = 0, uni_count = 0, max_attr_len = 0, max_uni_len = 0; GLint var_location = 0; GLint var_size = 0; GLenum var_type = 0; glGetProgramiv(shd_obj.program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attr_len); glGetProgramiv(shd_obj.program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uni_len); glGetProgramiv(shd_obj.program, GL_ACTIVE_ATTRIBUTES, &attr_count); glGetProgramiv(shd_obj.program, GL_ACTIVE_UNIFORMS, &uni_count); max_attr_len+=2; max_uni_len+=2; #if !defined(FLOOR_IOS) || defined(PLATFORM_X64) GLint uni_block_count = 0, max_uni_block_len = 0; glGetProgramiv(shd_obj.program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_uni_block_len); glGetProgramiv(shd_obj.program, GL_ACTIVE_UNIFORM_BLOCKS, &uni_block_count); max_uni_block_len+=2; #endif // note: this may report weird attribute/uniform names (and locations), if uniforms/attributes are optimized away by the compiler bool print_debug_info = false; //if(identifier == "SIMPLE") { /*if(identifier == "FONT") { print_debug_info = true; cout << endl << "## " << identifier << "::" << option << endl; }*/ GLchar* attr_name = new GLchar[(size_t)max_attr_len]; if(print_debug_info) log_undecorated("## shader: %s", identifier); if(print_debug_info) log_undecorated("GL_ACTIVE_ATTRIBUTES: %u", attr_count); for(GLuint attr = 0; attr < (GLuint)attr_count; attr++) { memset(attr_name, 0, (size_t)max_attr_len); glGetActiveAttrib(shd_obj.program, attr, max_attr_len-1, nullptr, &var_size, &var_type, attr_name); var_location = glGetAttribLocation(shd_obj.program, attr_name); if(var_location < 0) { if(print_debug_info) log_error("Warning: could not get location for attribute \"%s\" in shader #%s/%s!", attr_name, identifier, option); continue; } if(print_debug_info) log_undecorated("attribute #%u: %s", var_location, attr_name); string attribute_name = attr_name; if(attribute_name.find("[") != string::npos) attribute_name = attribute_name.substr(0, attribute_name.find("[")); shd_obj.attributes.insert(make_pair(attribute_name, shader_object::internal_shader_object::shader_variable((size_t)var_location, (size_t)var_size, var_type))); } delete [] attr_name; GLchar* uni_name = new GLchar[(size_t)max_uni_len]; if(print_debug_info) log_undecorated("GL_ACTIVE_UNIFORMS: %u", uni_count); for(GLuint uniform = 0; uniform < (GLuint)uni_count; uniform++) { memset(uni_name, 0, (size_t)max_uni_len); glGetActiveUniform(shd_obj.program, uniform, max_uni_len-1, nullptr, &var_size, &var_type, uni_name); var_location = glGetUniformLocation(shd_obj.program, uni_name); if(var_location < 0) { if(print_debug_info) log_error("Warning: could not get location for uniform \"%s\" in shader #%s/%s!", uni_name, identifier, option); continue; } if(print_debug_info) log_undecorated("uniform #%u: %s", var_location, uni_name); string uniform_name = uni_name; if(uniform_name.find("[") != string::npos) uniform_name = uniform_name.substr(0, uniform_name.find("[")); shd_obj.uniforms.insert(make_pair(uniform_name, shader_object::internal_shader_object::shader_variable((size_t)var_location, (size_t)var_size, var_type))); // if the uniform is a sampler, add it to the sampler mapping (with increasing id/num) if(shader_class::is_gl_sampler_type(var_type)) { shd_obj.samplers.insert(make_pair(uniform_name, shd_obj.samplers.size())); // while we are at it, also set the sampler location to a dummy value (this has to be done to satisfy program validation) glUniform1i(var_location, (GLint)shd_obj.samplers.size()-1); } } delete [] uni_name; #if !defined(FLOOR_IOS) || defined(PLATFORM_X64) GLchar* uni_block_name = new GLchar[(size_t)max_uni_block_len]; if(print_debug_info) log_undecorated("GL_ACTIVE_UNIFORM_BLOCKS: %u", uni_block_count); for(GLuint block = 0; block < (GLuint)uni_block_count; block++) { memset(uni_block_name, 0, (size_t)max_uni_block_len); glGetActiveUniformBlockName(shd_obj.program, (GLuint)block, max_uni_block_len-1, nullptr, uni_block_name); GLuint block_index = glGetUniformBlockIndex(shd_obj.program, uni_block_name); if(block_index == GL_INVALID_INDEX) { if(print_debug_info) log_error("Warning: could not get index for uniform block \"%s\" in shader #%s/%s!", uni_block_name, identifier, option); continue; } GLint data_size = 0; glGetActiveUniformBlockiv(shd_obj.program, block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &data_size); if(print_debug_info) log_undecorated("uniform block #%u (size: %u): %s", block_index, data_size, uni_block_name); const string uniform_block_name = uni_block_name; shd_obj.blocks.insert(make_pair(uniform_block_name, shader_object::internal_shader_object::shader_variable(block_index, (size_t)data_size, GL_UNIFORM_BUFFER))); // TODO: handle samplers? } delete [] uni_block_name; #endif // validate the program object glValidateProgram(shd_obj.program); glGetProgramiv(shd_obj.program, GL_VALIDATE_STATUS, &success); if(!success) { glGetProgramInfoLog(shd_obj.program, A2E_SHADER_LOG_SIZE, nullptr, info_log); log_error("Error in program \"%s/%s\" validation!\nInfo log: %s", identifier, option, info_log); return 0; } else { glGetProgramInfoLog(shd_obj.program, A2E_SHADER_LOG_SIZE, nullptr, info_log); // check if shader will run in software (if so, print out a debug message) if(strstr((const char*)info_log, (const char*)"software") != nullptr) { log_debug("program \"%s/%s\" validation: %s", identifier, option, info_log); } } // glUseProgram(0); return shaders[identifier]; }
int JNICALL Java_com_gomdev_gles_GLESShader_nRetrieveProgramBinary (JNIEnv * env, jobject obj, jint program, jstring str) { GLint binaryLength; GLvoid* binary; FILE* outfile; GLenum binaryFormat; const char* fileName = env->GetStringUTFChars(str, NULL); if(fileName != NULL) { glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binaryLength); checkGLError("retrieve() glGetProgramiv"); #ifdef DEBUG LOGI("retrieve() binaryLength=%d", binaryLength); #endif binary = (GLvoid*)malloc(binaryLength); if(binary == NULL) { LOGE("nRetrieveProgramBinary() malloc fail"); } // if (glGetProgramBinaryOES == NULL) { // glGetProgramBinaryOES = (PFNGLGETPROGRAMBINARYOESPROC) eglGetProcAddress("glGetProgramBinaryOES"); // } glGetProgramBinary(program, binaryLength, NULL, &binaryFormat, binary); checkGLError("retrieve() glGetProgramBinaryOES"); outfile = fopen(fileName, "wb"); if(outfile == NULL) { LOGE("nRetrieveProgramBinary() fileName=%s", fileName); LOGE("nRetrieveProgramBinary() fopen error"); free(binary); return 0; } fwrite(binary, binaryLength, 1, outfile); fclose(outfile); // if binary is already cached, remove cached binary char* name = copyFileName(fileName); BinaryInfo* info = find(name); if (info != NULL) { removeBinaryFromList(info, true); } BinaryInfo* binaryInfo = (BinaryInfo*)malloc(sizeof(BinaryInfo)); if (binaryInfo != NULL ) { binaryInfo->name = name; binaryInfo->length = binaryLength; binaryInfo->binary = binary; add(binaryInfo); } env->ReleaseStringUTFChars(str, fileName); } sBinaryFormat = binaryFormat; return binaryFormat; }
static inline void dumpProgram(StateWriter &writer, Context &context, GLint program) { if (program <= 0) { return; } GLint attached_shaders = 0; glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders); if (!attached_shaders) { return; } ShaderMap shaderMap; GLuint *shaders = new GLuint[attached_shaders]; GLsizei count = 0; glGetAttachedShaders(program, attached_shaders, &count, shaders); std::sort(shaders, shaders + count); for (GLsizei i = 0; i < count; ++ i) { getShaderSource(shaderMap, shaders[i]); } delete [] shaders; for (ShaderMap::const_iterator it = shaderMap.begin(); it != shaderMap.end(); ++it) { writer.beginMember(it->first); writer.writeString(it->second); writer.endMember(); } // Dump NVIDIA GPU programs via GL_ARB_get_program_binary if (context.ARB_get_program_binary) { GLint binaryLength = 0; glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binaryLength); if (binaryLength > 0) { std::vector<char> binary(binaryLength); GLenum format = GL_NONE; glGetProgramBinary(program, binaryLength, NULL, &format, &binary[0]); if (format == 0x8e21) { if (0) { FILE *fp = fopen("program.bin", "wb"); if (fp) { fwrite(&binary[0], 1, binaryLength, fp); fclose(fp); } } // Extract NVIDIA GPU programs std::string str(binary.begin(), binary.end()); size_t end = 0; while (true) { // Each program starts with a !!NV header token size_t start = str.find("!!NV", end); if (start == std::string::npos) { break; } // And is preceeded by a length DWORD assert(start >= end + 4); if (start < end + 4) { break; } uint32_t length; str.copy(reinterpret_cast<char *>(&length), 4, start - 4); assert(start + length <= binaryLength); if (start + length > binaryLength) { break; } std::string nvProg = str.substr(start, length); size_t eol = nvProg.find('\n'); std::string nvHeader = nvProg.substr(2, eol - 2); writer.beginMember(nvHeader); writer.writeString(nvProg); writer.endMember(); end = start + length; } } } } }
/*!**************************************************************************** @Function saveBinaryProgram @Return bool True if save 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 save the binary program to. The function will save out a file storing the binary shader program, and the enum value determining its format. ******************************************************************************/ bool OGLES3BinaryShader::saveBinaryProgram(const char* Filename, GLuint &ProgramObjectID) { //Quick check to make sure that the program actually exists. GLint linked; glGetProgramiv(ProgramObjectID, GL_LINK_STATUS, &linked); if (!linked) { //Shaders not linked correctly, no binary to retrieve. return false; } // Get the length of the shader binary program in memory. // Doing this ensures that a sufficient amount of memory is allocated for storing the binary program you retrieve. GLsizei length=0; glGetProgramiv(ProgramObjectID,GL_PROGRAM_BINARY_LENGTH, &length); // Pointer to the binary shader program in memory, needs to be allocated with the right size. GLvoid* ShaderBinary = (GLvoid*)malloc(length); // The format that the binary is retrieved in. GLenum binaryFormat=0; // Error checking variable - this should be greater than 0 after glGetProgramBinaryOES, otherwise there was an error. GLsizei lengthWritten=0; // Get the program binary from GL and save it out. glGetProgramBinary(ProgramObjectID,length,&lengthWritten,&binaryFormat,ShaderBinary); if(!lengthWritten) { // Save failed. Insufficient memory allocated to write binary shader. return false; } // Cache the program binary for future runs FILE* outfile = fopen(Filename, "wb"); if(!outfile) { PVRShellOutputDebug("Failed to open %s for writing to.\n", Filename); return false; } // Save the binary format. if(!fwrite((void*)&binaryFormat,sizeof(GLenum),1,outfile)) { fclose(outfile); return false; // Couldn't write binary format to file. } // Save the actual binary program. if(!fwrite(ShaderBinary, length,1,outfile)) { fclose(outfile); return false; // Couldn't write binary data to file. } // Close the file. fclose(outfile); // Free the memory used by Shader Binary. free(ShaderBinary); return true; }