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); }
static bool printNextDebugMessage() { if (!hasPendingDebugMessage()) { return false; } GLint msgLen = 0; glGetIntegerv(GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB, &msgLen); SCP_vector<GLchar> msg; msg.resize(msgLen + 1); // Includes null character, needs to be removed later GLenum source; GLenum type; GLenum severity; GLuint id; GLsizei length; GLuint numFound = glGetDebugMessageLogARB(1, static_cast<GLsizei>(msg.size()), &source, &type, &id, &severity, &length, &msg[0]); if (numFound < 1) { return false; } debug_callback(source, type, id, severity, length, msg.data(), nullptr); return true; }
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; }
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; }