Merge pull request #698 from mapbox/cache-shaders
Add caching of compiled shaders
This commit is contained in:
@@ -32,6 +32,7 @@
|
||||
'hard_dependency': 1,
|
||||
'sources': [
|
||||
'../platform/ios/cache_database_library.mm',
|
||||
'../platform/ios/shader_cache_library.mm',
|
||||
'../platform/darwin/log_nslog.mm',
|
||||
'../platform/darwin/string_nsstring.mm',
|
||||
'../platform/darwin/http_request_baton_cocoa.mm',
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
},
|
||||
'sources': [
|
||||
'../platform/default/cache_database_tmp.cpp',
|
||||
'../platform/default/shader_cache_tmp.cpp',
|
||||
'../platform/default/log_stderr.cpp',
|
||||
'../platform/default/string_stdlib.cpp',
|
||||
'../platform/default/http_request_baton_curl.cpp',
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
'hard_dependency': 1,
|
||||
'sources': [
|
||||
'../platform/osx/cache_database_application_support.mm',
|
||||
'../platform/osx/shader_cache_application_support.mm',
|
||||
'../platform/darwin/log_nslog.mm',
|
||||
'../platform/darwin/string_nsstring.mm',
|
||||
'../platform/darwin/http_request_baton_cocoa.mm',
|
||||
|
||||
@@ -118,6 +118,7 @@ typedef void (* PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei
|
||||
extern PFNGLLABELOBJECTEXTPROC LabelObjectEXT;
|
||||
extern PFNGLGETOBJECTLABELEXTPROC GetObjectLabelEXT;
|
||||
|
||||
// GL_ARB_vertex_array_object / GL_OES_vertex_array_object
|
||||
#define GL_VERTEX_ARRAY_BINDING 0x85B5
|
||||
typedef void (* PFNGLBINDVERTEXARRAYPROC) (GLuint array);
|
||||
typedef void (* PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint* arrays);
|
||||
@@ -128,6 +129,17 @@ extern PFNGLDELETEVERTEXARRAYSPROC DeleteVertexArrays;
|
||||
extern PFNGLGENVERTEXARRAYSPROC GenVertexArrays;
|
||||
extern PFNGLISVERTEXARRAYPROC IsVertexArray;
|
||||
|
||||
// GL_ARB_get_program_binary / GL_OES_get_program_binary
|
||||
#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257
|
||||
#define GL_PROGRAM_BINARY_LENGTH 0x8741
|
||||
#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
|
||||
#define GL_PROGRAM_BINARY_FORMATS 0x87FF
|
||||
typedef void (* PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
|
||||
typedef void (* PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);
|
||||
typedef void (* PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value);
|
||||
extern PFNGLGETPROGRAMBINARYPROC GetProgramBinary;
|
||||
extern PFNGLPROGRAMBINARYPROC ProgramBinary;
|
||||
extern PFNGLPROGRAMPARAMETERIPROC ProgramParameteri;
|
||||
|
||||
// Debug group markers, useful for debugging on iOS
|
||||
#if defined(DEBUG)
|
||||
|
||||
@@ -20,6 +20,9 @@ std::string lowercase(const std::string &string);
|
||||
// Returns the path to the default cache database on this system.
|
||||
std::string defaultCacheDatabase();
|
||||
|
||||
// Returns the path to the default shader cache on this system.
|
||||
std::string defaultShaderCache();
|
||||
|
||||
// Shows an alpha image with the specified dimensions in a named window.
|
||||
void show_debug_image(std::string name, const char *data, size_t width, size_t height);
|
||||
|
||||
|
||||
@@ -82,6 +82,17 @@ void GLFWView::initialize(mbgl::Map *map_) {
|
||||
gl::GetObjectLabel = (gl::PFNGLGETOBJECTLABELPROC)glfwGetProcAddress("glGetObjectLabel");
|
||||
gl::ObjectPtrLabel = (gl::PFNGLOBJECTPTRLABELPROC)glfwGetProcAddress("glObjectPtrLabel");
|
||||
gl::GetObjectPtrLabel = (gl::PFNGLGETOBJECTPTRLABELPROC)glfwGetProcAddress("glGetObjectPtrLabel");
|
||||
assert(gl::DebugMessageControl != nullptr);
|
||||
assert(gl::DebugMessageInsert != nullptr);
|
||||
assert(gl::DebugMessageCallback != nullptr);
|
||||
assert(gl::GetDebugMessageLog != nullptr);
|
||||
assert(gl::GetPointerv != nullptr);
|
||||
assert(gl::PushDebugGroup != nullptr);
|
||||
assert(gl::PopDebugGroup != nullptr);
|
||||
assert(gl::ObjectLabel != nullptr);
|
||||
assert(gl::GetObjectLabel != nullptr);
|
||||
assert(gl::ObjectPtrLabel != nullptr);
|
||||
assert(gl::GetObjectPtrLabel != nullptr);
|
||||
} else {
|
||||
if (extensions.find("GL_ARB_debug_output") != std::string::npos) {
|
||||
gl::DebugMessageControl = (gl::PFNGLDEBUGMESSAGECONTROLPROC)glfwGetProcAddress("glDebugMessageControlARB");
|
||||
@@ -89,17 +100,27 @@ void GLFWView::initialize(mbgl::Map *map_) {
|
||||
gl::DebugMessageCallback = (gl::PFNGLDEBUGMESSAGECALLBACKPROC)glfwGetProcAddress("glDebugMessageCallbackARB");
|
||||
gl::GetDebugMessageLog = (gl::PFNGLGETDEBUGMESSAGELOGPROC)glfwGetProcAddress("glGetDebugMessageLogARB");
|
||||
gl::GetPointerv = (gl::PFNGLGETPOINTERVPROC)glfwGetProcAddress("glGetPointerv");
|
||||
assert(gl::DebugMessageControl != nullptr);
|
||||
assert(gl::DebugMessageInsert != nullptr);
|
||||
assert(gl::DebugMessageCallback != nullptr);
|
||||
assert(gl::GetDebugMessageLog != nullptr);
|
||||
assert(gl::GetPointerv != nullptr);
|
||||
}
|
||||
|
||||
if (extensions.find("GL_EXT_debug_marker") != std::string::npos) {
|
||||
gl::InsertEventMarkerEXT = (gl::PFNGLINSERTEVENTMARKEREXTPROC)glfwGetProcAddress("glInsertEventMarkerEXT");
|
||||
gl::PushGroupMarkerEXT = (gl::PFNGLPUSHGROUPMARKEREXTPROC)glfwGetProcAddress("glPushGroupMarkerEXT");
|
||||
gl::PopGroupMarkerEXT = (gl::PFNGLPOPGROUPMARKEREXTPROC)glfwGetProcAddress("glPopGroupMarkerEXT");
|
||||
assert(gl::InsertEventMarkerEXT != nullptr);
|
||||
assert(gl::PushGroupMarkerEXT != nullptr);
|
||||
assert(gl::PopGroupMarkerEXT != nullptr);
|
||||
}
|
||||
|
||||
if (extensions.find("GL_EXT_debug_label") != std::string::npos) {
|
||||
gl::LabelObjectEXT = (gl::PFNGLLABELOBJECTEXTPROC)glfwGetProcAddress("glLabelObjectEXT");
|
||||
gl::GetObjectLabelEXT = (gl::PFNGLGETOBJECTLABELEXTPROC)glfwGetProcAddress("glGetObjectLabelEXT");
|
||||
assert(gl::LabelObjectEXT != nullptr);
|
||||
assert(gl::GetObjectLabelEXT != nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,11 +129,28 @@ void GLFWView::initialize(mbgl::Map *map_) {
|
||||
gl::DeleteVertexArrays = (gl::PFNGLDELETEVERTEXARRAYSPROC)glfwGetProcAddress("glDeleteVertexArrays");
|
||||
gl::GenVertexArrays = (gl::PFNGLGENVERTEXARRAYSPROC)glfwGetProcAddress("glGenVertexArrays");
|
||||
gl::IsVertexArray = (gl::PFNGLISVERTEXARRAYPROC)glfwGetProcAddress("glIsVertexArray");
|
||||
assert(gl::BindVertexArray != nullptr);
|
||||
assert(gl::DeleteVertexArrays != nullptr);
|
||||
assert(gl::GenVertexArrays != nullptr);
|
||||
assert(gl::IsVertexArray != nullptr);
|
||||
} else if (extensions.find("GL_APPLE_vertex_array_object") != std::string::npos) {
|
||||
gl::BindVertexArray = (gl::PFNGLBINDVERTEXARRAYPROC)glfwGetProcAddress("glBindVertexArrayAPPLE");
|
||||
gl::DeleteVertexArrays = (gl::PFNGLDELETEVERTEXARRAYSPROC)glfwGetProcAddress("glDeleteVertexArraysAPPLE");
|
||||
gl::GenVertexArrays = (gl::PFNGLGENVERTEXARRAYSPROC)glfwGetProcAddress("glGenVertexArraysAPPLE");
|
||||
gl::IsVertexArray = (gl::PFNGLISVERTEXARRAYPROC)glfwGetProcAddress("glIsVertexArrayAPPLE");
|
||||
assert(gl::BindVertexArray != nullptr);
|
||||
assert(gl::DeleteVertexArrays != nullptr);
|
||||
assert(gl::GenVertexArrays != nullptr);
|
||||
assert(gl::IsVertexArray != nullptr);
|
||||
}
|
||||
|
||||
if (extensions.find("GL_ARB_get_program_binary") != std::string::npos) {
|
||||
gl::GetProgramBinary = (gl::PFNGLGETPROGRAMBINARYPROC)glfwGetProcAddress("glGetProgramBinary");
|
||||
gl::ProgramBinary = (gl::PFNGLPROGRAMBINARYPROC)glfwGetProcAddress("glProgramBinary");
|
||||
gl::ProgramParameteri = (gl::PFNGLPROGRAMPARAMETERIPROC)glfwGetProcAddress("glProgramParameteri");
|
||||
assert(gl::GetProgramBinary != nullptr);
|
||||
assert(gl::ProgramBinary != nullptr);
|
||||
assert(gl::ProgramParameteri != nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
12
platform/default/shader_cache_tmp.cpp
Normal file
12
platform/default/shader_cache_tmp.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace platform {
|
||||
|
||||
// Returns the path to the default shader cache on this system.
|
||||
std::string defaultShaderCache() {
|
||||
return "/tmp/mbgl-shader-cache-";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
21
platform/ios/shader_cache_library.mm
Normal file
21
platform/ios/shader_cache_library.mm
Normal file
@@ -0,0 +1,21 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace platform {
|
||||
|
||||
// Returns the path to the default shader cache on this system.
|
||||
std::string defaultShaderCache() {
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
|
||||
if ([paths count] == 0) {
|
||||
// Disable the cache if we don't have a location to write.
|
||||
return "";
|
||||
}
|
||||
|
||||
NSString *libraryDirectory = [paths objectAtIndex:0];
|
||||
return [[libraryDirectory stringByAppendingPathComponent:@"shader-cache-"] UTF8String];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
31
platform/osx/shader_cache_application_support.mm
Normal file
31
platform/osx/shader_cache_application_support.mm
Normal file
@@ -0,0 +1,31 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace platform {
|
||||
|
||||
// Returns the path to the default shader cache on this system.
|
||||
std::string defaultShaderCache() {
|
||||
NSArray *paths =
|
||||
NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
if ([paths count] == 0) {
|
||||
// Disable the cache if we don't have a location to write.
|
||||
return "";
|
||||
}
|
||||
|
||||
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Mapbox GL"];
|
||||
|
||||
if (![[NSFileManager defaultManager] createDirectoryAtPath:path
|
||||
withIntermediateDirectories:YES
|
||||
attributes:nil
|
||||
error:nil]) {
|
||||
// Disable the cache if we couldn't create the directory.
|
||||
return "";
|
||||
}
|
||||
|
||||
return [[path stringByAppendingPathComponent:@"shader-cache-"] UTF8String];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,10 @@ PFNGLDELETEVERTEXARRAYSPROC DeleteVertexArrays = nullptr;
|
||||
PFNGLGENVERTEXARRAYSPROC GenVertexArrays = nullptr;
|
||||
PFNGLISVERTEXARRAYPROC IsVertexArray = nullptr;
|
||||
|
||||
PFNGLGETPROGRAMBINARYPROC GetProgramBinary = nullptr;
|
||||
PFNGLPROGRAMBINARYPROC ProgramBinary = nullptr;
|
||||
PFNGLPROGRAMPARAMETERIPROC ProgramParameteri = nullptr;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
#include <mbgl/platform/gl.hpp>
|
||||
#include <mbgl/util/stopwatch.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
@@ -14,49 +16,97 @@ Shader::Shader(const char *name_, const GLchar *vertSource, const GLchar *fragSo
|
||||
program(0) {
|
||||
util::stopwatch stopwatch("shader compilation", Event::Shader);
|
||||
|
||||
GLuint vertShader;
|
||||
if (!compileShader(&vertShader, GL_VERTEX_SHADER, vertSource)) {
|
||||
Log::Error(Event::Shader, "Vertex shader failed to compile: %s", vertSource);
|
||||
return;
|
||||
}
|
||||
|
||||
GLuint fragShader;
|
||||
if (!compileShader(&fragShader, GL_FRAGMENT_SHADER, fragSource)) {
|
||||
Log::Error(Event::Shader, "Fragment shader failed to compile: %s", fragSource);
|
||||
return;
|
||||
}
|
||||
|
||||
program = glCreateProgram();
|
||||
|
||||
// Attach shaders
|
||||
glAttachShader(program, vertShader);
|
||||
glAttachShader(program, fragShader);
|
||||
if (!mbgl::platform::defaultShaderCache().empty()) {
|
||||
binaryFileName = mbgl::platform::defaultShaderCache() + name + ".bin";
|
||||
}
|
||||
|
||||
// Load binary shader if it exists
|
||||
bool skipCompile = false;
|
||||
if (!binaryFileName.empty() && (gl::ProgramBinary != nullptr)) {
|
||||
FILE *binaryFile = fopen(binaryFileName.c_str(), "rb");
|
||||
if (binaryFile != nullptr) {
|
||||
GLsizei binaryLength;
|
||||
GLenum binaryFormat;
|
||||
bool lengthOk = fread(&binaryLength, sizeof(binaryLength), 1, binaryFile) == 1;
|
||||
bool formatOk = fread(&binaryFormat, sizeof(binaryFormat), 1, binaryFile) == 1;
|
||||
|
||||
{
|
||||
// Link program
|
||||
GLint status;
|
||||
glLinkProgram(program);
|
||||
if (lengthOk && formatOk && binaryLength > 0) {
|
||||
std::unique_ptr<char[]> binary = mbgl::util::make_unique<char[]>(binaryLength);
|
||||
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||
if (status == 0) {
|
||||
GLint logLength;
|
||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
|
||||
if (logLength > 0) {
|
||||
GLchar *log = (GLchar *)malloc(logLength);
|
||||
glGetProgramInfoLog(program, logLength, &logLength, log);
|
||||
Log::Error(Event::Shader, "Program failed to link: %s", log);
|
||||
free(log);
|
||||
if (binary != nullptr) {
|
||||
bool binaryOk = fread(binary.get(), binaryLength, 1, binaryFile) == 1;
|
||||
|
||||
if (binaryOk) {
|
||||
gl::ProgramBinary(program, binaryFormat, binary.get(), binaryLength);
|
||||
|
||||
// Check if the binary was valid
|
||||
GLint status;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||
if (status == GL_TRUE) {
|
||||
skipCompile = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glDeleteShader(vertShader);
|
||||
vertShader = 0;
|
||||
glDeleteShader(fragShader);
|
||||
fragShader = 0;
|
||||
fclose(binaryFile);
|
||||
binaryFile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint vertShader = 0;
|
||||
GLuint fragShader = 0;
|
||||
if (!skipCompile) {
|
||||
if (!compileShader(&vertShader, GL_VERTEX_SHADER, vertSource)) {
|
||||
Log::Error(Event::Shader, "Vertex shader %s failed to compile: %s", name, vertSource);
|
||||
glDeleteProgram(program);
|
||||
program = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!compileShader(&fragShader, GL_FRAGMENT_SHADER, fragSource)) {
|
||||
Log::Error(Event::Shader, "Fragment shader %s failed to compile: %s", name, fragSource);
|
||||
glDeleteShader(vertShader);
|
||||
vertShader = 0;
|
||||
glDeleteProgram(program);
|
||||
program = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Attach shaders
|
||||
glAttachShader(program, vertShader);
|
||||
glAttachShader(program, fragShader);
|
||||
|
||||
{
|
||||
if (!binaryFileName.empty() && (gl::ProgramParameteri != nullptr)) {
|
||||
gl::ProgramParameteri(program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
|
||||
}
|
||||
|
||||
// Link program
|
||||
GLint status;
|
||||
glLinkProgram(program);
|
||||
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||
if (status == 0) {
|
||||
GLint logLength;
|
||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
|
||||
if (logLength > 0) {
|
||||
std::unique_ptr<GLchar[]> log = mbgl::util::make_unique<GLchar[]>(logLength);
|
||||
glGetProgramInfoLog(program, logLength, &logLength, log.get());
|
||||
Log::Error(Event::Shader, "Program failed to link: %s", log.get());
|
||||
}
|
||||
|
||||
glDeleteShader(vertShader);
|
||||
vertShader = 0;
|
||||
glDeleteShader(fragShader);
|
||||
fragShader = 0;
|
||||
glDeleteProgram(program);
|
||||
program = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@@ -69,10 +119,9 @@ Shader::Shader(const char *name_, const GLchar *vertSource, const GLchar *fragSo
|
||||
GLint logLength;
|
||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
|
||||
if (logLength > 0) {
|
||||
GLchar *log = (GLchar *)malloc(logLength);
|
||||
glGetProgramInfoLog(program, logLength, &logLength, log);
|
||||
Log::Error(Event::Shader, "Program failed to validate: %s", log);
|
||||
free(log);
|
||||
std::unique_ptr<GLchar[]> log = mbgl::util::make_unique<GLchar[]>(logLength);
|
||||
glGetProgramInfoLog(program, logLength, &logLength, log.get());
|
||||
Log::Error(Event::Shader, "Program failed to validate: %s", log.get());
|
||||
}
|
||||
|
||||
glDeleteShader(vertShader);
|
||||
@@ -82,14 +131,15 @@ Shader::Shader(const char *name_, const GLchar *vertSource, const GLchar *fragSo
|
||||
glDeleteProgram(program);
|
||||
program = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Remove the compiled shaders; they are now part of the program.
|
||||
glDetachShader(program, vertShader);
|
||||
glDeleteShader(vertShader);
|
||||
glDetachShader(program, fragShader);
|
||||
glDeleteShader(fragShader);
|
||||
if (!skipCompile) {
|
||||
// Remove the compiled shaders; they are now part of the program.
|
||||
glDetachShader(program, vertShader);
|
||||
glDeleteShader(vertShader);
|
||||
glDetachShader(program, fragShader);
|
||||
glDeleteShader(fragShader);
|
||||
}
|
||||
|
||||
valid = true;
|
||||
}
|
||||
@@ -100,7 +150,7 @@ bool Shader::compileShader(GLuint *shader, GLenum type, const GLchar *source) {
|
||||
|
||||
*shader = glCreateShader(type);
|
||||
const GLchar *strings[] = { source };
|
||||
const GLint lengths[] = { (GLint)strlen(source) };
|
||||
const GLsizei lengths[] = { (GLsizei)strlen(source) };
|
||||
glShaderSource(*shader, 1, strings, lengths);
|
||||
|
||||
glCompileShader(*shader);
|
||||
@@ -110,10 +160,9 @@ bool Shader::compileShader(GLuint *shader, GLenum type, const GLchar *source) {
|
||||
GLint logLength;
|
||||
glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
|
||||
if (logLength > 0) {
|
||||
GLchar *log = (GLchar *)malloc(logLength);
|
||||
glGetShaderInfoLog(*shader, logLength, &logLength, log);
|
||||
Log::Error(Event::Shader, "Shader failed to compile: %s", log);
|
||||
free(log);
|
||||
std::unique_ptr<GLchar[]> log = mbgl::util::make_unique<GLchar[]>(logLength);
|
||||
glGetShaderInfoLog(*shader, logLength, &logLength, log.get());
|
||||
Log::Error(Event::Shader, "Shader failed to compile: %s", log.get());
|
||||
}
|
||||
|
||||
glDeleteShader(*shader);
|
||||
@@ -121,10 +170,41 @@ bool Shader::compileShader(GLuint *shader, GLenum type, const GLchar *source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
|
||||
if (status == GL_FALSE) {
|
||||
Log::Error(Event::Shader, "Shader %s failed to compile.", name, type);
|
||||
glDeleteShader(*shader);
|
||||
*shader = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Shader::~Shader() {
|
||||
if (!binaryFileName.empty() && (gl::GetProgramBinary != nullptr)) {
|
||||
// Retrieve the program binary
|
||||
GLsizei binaryLength;
|
||||
GLenum binaryFormat;
|
||||
glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
|
||||
if (binaryLength > 0) {
|
||||
std::unique_ptr<char[]> binary = mbgl::util::make_unique<char[]>(binaryLength);
|
||||
if (binary != nullptr) {
|
||||
gl::GetProgramBinary(program, binaryLength, NULL, &binaryFormat, binary.get());
|
||||
|
||||
// Write the binary to a file
|
||||
FILE *binaryFile = fopen(binaryFileName.c_str(), "wb");
|
||||
if (binaryFile != nullptr) {
|
||||
fwrite(&binaryLength, sizeof(binaryLength), 1, binaryFile);
|
||||
fwrite(&binaryFormat, sizeof(binaryFormat), 1, binaryFile);
|
||||
fwrite(binary.get(), binaryLength, 1, binaryFile);
|
||||
fclose(binaryFile);
|
||||
binaryFile = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (program) {
|
||||
glDeleteProgram(program);
|
||||
program = 0;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
@@ -21,6 +22,8 @@ public:
|
||||
|
||||
private:
|
||||
bool compileShader(uint32_t *shader, uint32_t type, const char *source);
|
||||
|
||||
std::string binaryFileName;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user