diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 7cbce428cbc8..100cb9386f1d 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -34,6 +34,7 @@ #ifdef GLES3_ENABLED #include "core/config/project_settings.h" +#include "core/io/dir_access.h" #include "core/os/os.h" #include "storage/texture_storage.h" @@ -257,6 +258,36 @@ RasterizerGLES3::RasterizerGLES3() { #endif // GLES_OVER_GL #endif // CAN_DEBUG + { + String shader_cache_dir = Engine::get_singleton()->get_shader_cache_path(); + if (shader_cache_dir.is_empty()) { + shader_cache_dir = "user://"; + } + Ref da = DirAccess::open(shader_cache_dir); + if (da.is_null()) { + ERR_PRINT("Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir); + } else { + Error err = da->change_dir("shader_cache"); + if (err != OK) { + err = da->make_dir("shader_cache"); + } + if (err != OK) { + ERR_PRINT("Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir); + } else { + shader_cache_dir = shader_cache_dir.path_join("shader_cache"); + + bool shader_cache_enabled = GLOBAL_GET("rendering/shader_compiler/shader_cache/enabled"); + if (!Engine::get_singleton()->is_editor_hint() && !shader_cache_enabled) { + shader_cache_dir = String(); //disable only if not editor + } + + if (!shader_cache_dir.is_empty()) { + ShaderGLES3::set_shader_cache_dir(shader_cache_dir); + } + } + } + } + // OpenGL needs to be initialized before initializing the Rasterizers config = memnew(GLES3::Config); utilities = memnew(GLES3::Utilities); diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 10f42bf22bb9..ded5793e8f89 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -242,6 +242,41 @@ static void _display_error_with_code(const String &p_error, const String &p_code ERR_PRINT(p_error); } +void ShaderGLES3::_get_uniform_locations(Version::Specialization &spec, Version *p_version) { + glUseProgram(spec.id); + + spec.uniform_location.resize(uniform_count); + for (int i = 0; i < uniform_count; i++) { + spec.uniform_location[i] = glGetUniformLocation(spec.id, uniform_names[i]); + } + + for (int i = 0; i < texunit_pair_count; i++) { + GLint loc = glGetUniformLocation(spec.id, texunit_pairs[i].name); + if (loc >= 0) { + if (texunit_pairs[i].index < 0) { + glUniform1i(loc, max_image_units + texunit_pairs[i].index); + } else { + glUniform1i(loc, texunit_pairs[i].index); + } + } + } + + for (int i = 0; i < ubo_count; i++) { + GLint loc = glGetUniformBlockIndex(spec.id, ubo_pairs[i].name); + if (loc >= 0) { + glUniformBlockBinding(spec.id, loc, ubo_pairs[i].index); + } + } + // textures + for (int i = 0; i < p_version->texture_uniforms.size(); i++) { + String native_uniform_name = _mkid(p_version->texture_uniforms[i]); + GLint location = glGetUniformLocation(spec.id, (native_uniform_name).ascii().get_data()); + glUniform1i(location, i + base_texture_index); + } + + glUseProgram(0); +} + void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_t p_variant, Version *p_version, uint64_t p_specialization) { spec.id = glCreateProgram(); spec.ok = false; @@ -402,40 +437,8 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_ ERR_FAIL(); } - // get uniform locations - - glUseProgram(spec.id); - - spec.uniform_location.resize(uniform_count); - for (int i = 0; i < uniform_count; i++) { - spec.uniform_location[i] = glGetUniformLocation(spec.id, uniform_names[i]); - } - - for (int i = 0; i < texunit_pair_count; i++) { - GLint loc = glGetUniformLocation(spec.id, texunit_pairs[i].name); - if (loc >= 0) { - if (texunit_pairs[i].index < 0) { - glUniform1i(loc, max_image_units + texunit_pairs[i].index); - } else { - glUniform1i(loc, texunit_pairs[i].index); - } - } - } - - for (int i = 0; i < ubo_count; i++) { - GLint loc = glGetUniformBlockIndex(spec.id, ubo_pairs[i].name); - if (loc >= 0) { - glUniformBlockBinding(spec.id, loc, ubo_pairs[i].index); - } - } - // textures - for (int i = 0; i < p_version->texture_uniforms.size(); i++) { - String native_uniform_name = _mkid(p_version->texture_uniforms[i]); - GLint location = glGetUniformLocation(spec.id, (native_uniform_name).ascii().get_data()); - glUniform1i(location, i + base_texture_index); - } + _get_uniform_locations(spec, p_version); - glUseProgram(0); spec.ok = true; } @@ -504,11 +507,20 @@ String ShaderGLES3::_version_get_sha1(Version *p_version) const { return hash_build.as_string().sha1_text(); } -//static const char *shader_file_header = "GLSC"; -//static const uint32_t cache_file_version = 2; +#ifndef WEB_ENABLED // not supported in webgl +static const char *shader_file_header = "GLSC"; +static const uint32_t cache_file_version = 3; +#endif bool ShaderGLES3::_load_from_cache(Version *p_version) { -#if 0 +#ifdef WEB_ENABLED // not supported in webgl + return false; +#else +#ifdef GLES_OVER_GL + if (glProgramBinary == NULL) { // ARB_get_program_binary extension not available + return false; + } +#endif String sha1 = _version_get_sha1(p_version); String path = shader_cache_dir.path_join(name).path_join(base_sha256).path_join(sha1) + ".cache"; @@ -517,7 +529,7 @@ bool ShaderGLES3::_load_from_cache(Version *p_version) { return false; } - char header[5] = { 0, 0, 0, 0, 0 }; + char header[5] = {}; f->get_buffer((uint8_t *)header, 4); ERR_FAIL_COND_V(header != String(shader_file_header), false); @@ -526,70 +538,98 @@ bool ShaderGLES3::_load_from_cache(Version *p_version) { return false; // wrong version } - uint32_t variant_count = f->get_32(); + int cache_variant_count = static_cast(f->get_32()); + ERR_FAIL_COND_V_MSG(cache_variant_count != this->variant_count, false, "shader cache variant count mismatch, expected " + itos(this->variant_count) + " got " + itos(cache_variant_count)); //should not happen but check + + LocalVector> variants; + for (int i = 0; i < cache_variant_count; i++) { + uint32_t cache_specialization_count = f->get_32(); + OAHashMap variant; + for (uint32_t j = 0; j < cache_specialization_count; j++) { + uint64_t specialization_key = f->get_64(); + uint32_t variant_size = f->get_32(); + if (variant_size == 0) { + continue; + } + uint32_t variant_format = f->get_32(); + Vector variant_bytes; + variant_bytes.resize(variant_size); + + uint32_t br = f->get_buffer(variant_bytes.ptrw(), variant_size); - ERR_FAIL_COND_V(variant_count != (uint32_t)variant_count, false); //should not happen but check + ERR_FAIL_COND_V(br != variant_size, false); - for (uint32_t i = 0; i < variant_count; i++) { - uint32_t variant_size = f->get_32(); - ERR_FAIL_COND_V(variant_size == 0 && variants_enabled[i], false); - if (!variants_enabled[i]) { - continue; - } - Vector variant_bytes; - variant_bytes.resize(variant_size); + Version::Specialization specialization; - uint32_t br = f->get_buffer(variant_bytes.ptrw(), variant_size); + specialization.id = glCreateProgram(); + glProgramBinary(specialization.id, variant_format, variant_bytes.ptr(), variant_bytes.size()); - ERR_FAIL_COND_V(br != variant_size, false); + _get_uniform_locations(specialization, p_version); - p_version->variant_data[i] = variant_bytes; - } + specialization.ok = true; - for (uint32_t i = 0; i < variant_count; i++) { - if (!variants_enabled[i]) { - MutexLock lock(variant_set_mutex); - p_version->variants[i] = RID(); - continue; - } - RID shader = GLES3::get_singleton()->shader_create_from_bytecode(p_version->variant_data[i]); - if (shader.is_null()) { - for (uint32_t j = 0; j < i; j++) { - GLES3::get_singleton()->free(p_version->variants[i]); - } - ERR_FAIL_COND_V(shader.is_null(), false); - } - { - MutexLock lock(variant_set_mutex); - p_version->variants[i] = shader; + variant.insert(specialization_key, specialization); } + variants.push_back(variant); } + p_version->variants = variants; - memdelete_arr(p_version->variant_data); //clear stages - p_version->variant_data = nullptr; - p_version->valid = true; return true; -#endif - return false; +#endif // WEB_ENABLED } void ShaderGLES3::_save_to_cache(Version *p_version) { -#if 0 +#ifdef WEB_ENABLED // not supported in webgl + return; +#else +#ifdef GLES_OVER_GL + if (glGetProgramBinary == NULL) { // ARB_get_program_binary extension not available + return; + } +#endif String sha1 = _version_get_sha1(p_version); String path = shader_cache_dir.path_join(name).path_join(base_sha256).path_join(sha1) + ".cache"; - Ref f = FileAccess::open(path, FileAccess::WRITE); + Error error; + Ref f = FileAccess::open(path, FileAccess::WRITE, &error); ERR_FAIL_COND(f.is_null()); f->store_buffer((const uint8_t *)shader_file_header, 4); - f->store_32(cache_file_version); //file version - uint32_t variant_count = variant_count; - f->store_32(variant_count); //variant count + f->store_32(cache_file_version); + f->store_32(variant_count); + + for (int i = 0; i < variant_count; i++) { + int cache_specialization_count = p_version->variants[i].get_num_elements(); + f->store_32(cache_specialization_count); + + for (OAHashMap::Iterator it = p_version->variants[i].iter(); it.valid; it = p_version->variants[i].next_iter(it)) { + const uint64_t specialization_key = *it.key; + f->store_64(specialization_key); - for (uint32_t i = 0; i < variant_count; i++) { - f->store_32(p_version->variant_data[i].size()); //stage count - f->store_buffer(p_version->variant_data[i].ptr(), p_version->variant_data[i].size()); + const Version::Specialization *specialization = it.value; + if (specialization == nullptr) { + f->store_32(0); + continue; + } + GLint program_size = 0; + glGetProgramiv(specialization->id, GL_PROGRAM_BINARY_LENGTH, &program_size); + if (program_size == 0) { + f->store_32(0); + continue; + } + PackedByteArray compiled_program; + compiled_program.resize(program_size); + GLenum binary_format = 0; + glGetProgramBinary(specialization->id, program_size, nullptr, &binary_format, compiled_program.ptrw()); + if (program_size != compiled_program.size()) { + f->store_32(0); + continue; + } + f->store_32(program_size); + f->store_32(binary_format); + f->store_buffer(compiled_program.ptr(), compiled_program.size()); + } } -#endif +#endif // WEB_ENABLED } void ShaderGLES3::_clear_version(Version *p_version) { @@ -613,6 +653,9 @@ void ShaderGLES3::_clear_version(Version *p_version) { void ShaderGLES3::_initialize_version(Version *p_version) { ERR_FAIL_COND(p_version->variants.size() > 0); + if (_load_from_cache(p_version)) { + return; + } p_version->variants.reserve(variant_count); for (int i = 0; i < variant_count; i++) { OAHashMap variant; @@ -621,6 +664,7 @@ void ShaderGLES3::_initialize_version(Version *p_version) { _compile_specialization(spec, i, p_version, specialization_default_mask); p_version->variants[i].insert(specialization_default_mask, spec); } + _save_to_cache(p_version); } void ShaderGLES3::version_set_code(RID p_version, const HashMap &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector &p_custom_defines, const Vector &p_texture_uniforms, bool p_initialize) { diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h index 0b2ecbaca69f..565434bb36ec 100644 --- a/drivers/gles3/shader_gles3.h +++ b/drivers/gles3/shader_gles3.h @@ -98,7 +98,6 @@ class ShaderGLES3 { GLuint frag_id; LocalVector uniform_location; LocalVector texture_uniform_locations; - HashMap custom_uniform_locations; bool build_queued = false; bool ok = false; Specialization() { @@ -113,6 +112,7 @@ class ShaderGLES3 { Mutex variant_set_mutex; + void _get_uniform_locations(Version::Specialization &spec, Version *p_version); void _compile_specialization(Version::Specialization &spec, uint32_t p_variant, Version *p_version, uint64_t p_specialization); void _clear_version(Version *p_version); @@ -209,6 +209,7 @@ class ShaderGLES3 { _compile_specialization(s, p_variant, version, p_specialization); version->variants[p_variant].insert(p_specialization, s); spec = version->variants[p_variant].lookup_ptr(p_specialization); + _save_to_cache(version); } } else if (spec->build_queued) { // Still queued, wait diff --git a/thirdparty/glad/gl.c b/thirdparty/glad/gl.c index 6be716284cf1..8d12541ed490 100644 --- a/thirdparty/glad/gl.c +++ b/thirdparty/glad/gl.c @@ -37,6 +37,7 @@ int GLAD_GL_VERSION_3_2 = 0; int GLAD_GL_VERSION_3_3 = 0; int GLAD_GL_ARB_debug_output = 0; int GLAD_GL_ARB_framebuffer_object = 0; +int GLAD_GL_ARB_get_program_binary = 0; int GLAD_GL_EXT_framebuffer_blit = 0; int GLAD_GL_EXT_framebuffer_multisample = 0; int GLAD_GL_EXT_framebuffer_object = 0; @@ -292,6 +293,7 @@ PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv = NULL; PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv = NULL; PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL; PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple = NULL; +PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary = NULL; PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL; @@ -485,6 +487,8 @@ PFNGLPOPMATRIXPROC glad_glPopMatrix = NULL; PFNGLPOPNAMEPROC glad_glPopName = NULL; PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL; PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures = NULL; +PFNGLPROGRAMBINARYPROC glad_glProgramBinary = NULL; +PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri = NULL; PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL; PFNGLPUSHATTRIBPROC glad_glPushAttrib = NULL; PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib = NULL; @@ -1588,6 +1592,12 @@ static void glad_gl_load_GL_ARB_framebuffer_object( GLADuserptrloadfunc load, vo glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, "glRenderbufferStorage"); glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) load(userptr, "glRenderbufferStorageMultisample"); } +static void glad_gl_load_GL_ARB_get_program_binary( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_GL_ARB_get_program_binary) return; + glad_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC) load(userptr, "glGetProgramBinary"); + glad_glProgramBinary = (PFNGLPROGRAMBINARYPROC) load(userptr, "glProgramBinary"); + glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC) load(userptr, "glProgramParameteri"); +} static void glad_gl_load_GL_EXT_framebuffer_blit( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_EXT_framebuffer_blit) return; glad_glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC) load(userptr, "glBlitFramebufferEXT"); @@ -1729,6 +1739,7 @@ static int glad_gl_find_extensions_gl( int version) { GLAD_GL_ARB_debug_output = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_debug_output"); GLAD_GL_ARB_framebuffer_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_framebuffer_object"); + GLAD_GL_ARB_get_program_binary = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_ARB_get_program_binary"); GLAD_GL_EXT_framebuffer_blit = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_framebuffer_blit"); GLAD_GL_EXT_framebuffer_multisample = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_framebuffer_multisample"); GLAD_GL_EXT_framebuffer_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_framebuffer_object"); @@ -1804,6 +1815,7 @@ int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr) { if (!glad_gl_find_extensions_gl(version)) return 0; glad_gl_load_GL_ARB_debug_output(load, userptr); glad_gl_load_GL_ARB_framebuffer_object(load, userptr); + glad_gl_load_GL_ARB_get_program_binary(load, userptr); glad_gl_load_GL_EXT_framebuffer_blit(load, userptr); glad_gl_load_GL_EXT_framebuffer_multisample(load, userptr); glad_gl_load_GL_EXT_framebuffer_object(load, userptr); diff --git a/thirdparty/glad/glad/gl.h b/thirdparty/glad/glad/gl.h index 98362962266a..b180a2e39136 100644 --- a/thirdparty/glad/glad/gl.h +++ b/thirdparty/glad/glad/gl.h @@ -1,11 +1,11 @@ /** - * Loader generated by glad 2.0.2 on Mon Nov 7 12:17:15 2022 + * Loader generated by glad 2.0.4 on Sat Apr 29 13:24:27 2023 * * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0 * * Generator: C/C++ * Specification: gl - * Extensions: 7 + * Extensions: 8 * * APIs: * - gl:compatibility=3.3 @@ -19,10 +19,10 @@ * - ON_DEMAND = False * * Commandline: - * --api='gl:compatibility=3.3' --extensions='GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_OVR_multiview,GL_OVR_multiview2' c --loader + * --api='gl:compatibility=3.3' --extensions='GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_ARB_get_program_binary,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_OVR_multiview,GL_OVR_multiview2' c --loader * * Online: - * http://glad.sh/#api=gl%3Acompatibility%3D3.3&extensions=GL_ARB_debug_output%2CGL_ARB_framebuffer_object%2CGL_EXT_framebuffer_blit%2CGL_EXT_framebuffer_multisample%2CGL_EXT_framebuffer_object%2CGL_OVR_multiview%2CGL_OVR_multiview2&generator=c&options=LOADER + * http://glad.sh/#api=gl%3Acompatibility%3D3.3&extensions=GL_ARB_debug_output%2CGL_ARB_framebuffer_object%2CGL_ARB_get_program_binary%2CGL_EXT_framebuffer_blit%2CGL_EXT_framebuffer_multisample%2CGL_EXT_framebuffer_object%2CGL_OVR_multiview%2CGL_OVR_multiview2&generator=c&options=LOADER * */ @@ -164,7 +164,7 @@ extern "C" { #define GLAD_VERSION_MAJOR(version) (version / 10000) #define GLAD_VERSION_MINOR(version) (version % 10000) -#define GLAD_GENERATOR_VERSION "2.0.2" +#define GLAD_GENERATOR_VERSION "2.0.4" typedef void (*GLADapiproc)(void); @@ -889,6 +889,7 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define GL_NO_ERROR 0 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_NUM_EXTENSIONS 0x821D +#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE #define GL_OBJECT_LINEAR 0x2401 #define GL_OBJECT_PLANE 0x2501 #define GL_OBJECT_TYPE 0x9112 @@ -981,6 +982,9 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define GL_PRIMITIVES_GENERATED 0x8C87 #define GL_PRIMITIVE_RESTART 0x8F9D #define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define GL_PROGRAM_BINARY_FORMATS 0x87FF +#define GL_PROGRAM_BINARY_LENGTH 0x8741 +#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 #define GL_PROGRAM_POINT_SIZE 0x8642 #define GL_PROJECTION 0x1701 #define GL_PROJECTION_MATRIX 0x0BA7 @@ -1605,6 +1609,8 @@ GLAD_API_CALL int GLAD_GL_VERSION_3_3; GLAD_API_CALL int GLAD_GL_ARB_debug_output; #define GL_ARB_framebuffer_object 1 GLAD_API_CALL int GLAD_GL_ARB_framebuffer_object; +#define GL_ARB_get_program_binary 1 +GLAD_API_CALL int GLAD_GL_ARB_get_program_binary; #define GL_EXT_framebuffer_blit 1 GLAD_API_CALL int GLAD_GL_EXT_framebuffer_blit; #define GL_EXT_framebuffer_multisample 1 @@ -1864,6 +1870,7 @@ typedef void (GLAD_API_PTR *PFNGLGETPIXELMAPUIVPROC)(GLenum map, GLuint * values typedef void (GLAD_API_PTR *PFNGLGETPIXELMAPUSVPROC)(GLenum map, GLushort * values); typedef void (GLAD_API_PTR *PFNGLGETPOINTERVPROC)(GLenum pname, void ** params); typedef void (GLAD_API_PTR *PFNGLGETPOLYGONSTIPPLEPROC)(GLubyte * mask); +typedef void (GLAD_API_PTR *PFNGLGETPROGRAMBINARYPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLenum * binaryFormat, void * binary); typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog); typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 * params); @@ -2057,6 +2064,8 @@ typedef void (GLAD_API_PTR *PFNGLPOPMATRIXPROC)(void); typedef void (GLAD_API_PTR *PFNGLPOPNAMEPROC)(void); typedef void (GLAD_API_PTR *PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index); typedef void (GLAD_API_PTR *PFNGLPRIORITIZETEXTURESPROC)(GLsizei n, const GLuint * textures, const GLfloat * priorities); +typedef void (GLAD_API_PTR *PFNGLPROGRAMBINARYPROC)(GLuint program, GLenum binaryFormat, const void * binary, GLsizei length); +typedef void (GLAD_API_PTR *PFNGLPROGRAMPARAMETERIPROC)(GLuint program, GLenum pname, GLint value); typedef void (GLAD_API_PTR *PFNGLPROVOKINGVERTEXPROC)(GLenum mode); typedef void (GLAD_API_PTR *PFNGLPUSHATTRIBPROC)(GLbitfield mask); typedef void (GLAD_API_PTR *PFNGLPUSHCLIENTATTRIBPROC)(GLbitfield mask); @@ -2860,6 +2869,8 @@ GLAD_API_CALL PFNGLGETPOINTERVPROC glad_glGetPointerv; #define glGetPointerv glad_glGetPointerv GLAD_API_CALL PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple; #define glGetPolygonStipple glad_glGetPolygonStipple +GLAD_API_CALL PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary; +#define glGetProgramBinary glad_glGetProgramBinary GLAD_API_CALL PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; #define glGetProgramInfoLog glad_glGetProgramInfoLog GLAD_API_CALL PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; @@ -3246,6 +3257,10 @@ GLAD_API_CALL PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; #define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex GLAD_API_CALL PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures; #define glPrioritizeTextures glad_glPrioritizeTextures +GLAD_API_CALL PFNGLPROGRAMBINARYPROC glad_glProgramBinary; +#define glProgramBinary glad_glProgramBinary +GLAD_API_CALL PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri; +#define glProgramParameteri glad_glProgramParameteri GLAD_API_CALL PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; #define glProvokingVertex glad_glProvokingVertex GLAD_API_CALL PFNGLPUSHATTRIBPROC glad_glPushAttrib;