From 115fff8ae08b0d6fcc4212c588dab09bd6c4bed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Madar=C3=A1sz?= Date: Mon, 15 Apr 2024 07:21:15 +0200 Subject: [PATCH] gfx: shader instance caching --- engine/joint/v4k.h | 69 ++++++++++++++++++++++++--------------- engine/split/v4k_font.c | 6 ++-- engine/split/v4k_gui.c | 4 +-- engine/split/v4k_render.c | 57 ++++++++++++++++++++------------ engine/split/v4k_sprite.c | 2 +- engine/v4k.c | 69 ++++++++++++++++++++++++--------------- 6 files changed, 126 insertions(+), 81 deletions(-) diff --git a/engine/joint/v4k.h b/engine/joint/v4k.h index ada02d4..7fc2f3e 100644 --- a/engine/joint/v4k.h +++ b/engine/joint/v4k.h @@ -376022,7 +376022,7 @@ void font_face_from_mem(const char *tag, const void *ttf_data, unsigned ttf_len, glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); // upload constant uniforms - glUseProgram(f->program); + shader_bind(f->program); glUniform1i(glGetUniformLocation(f->program, "sampler_font"), 0); glUniform1i(glGetUniformLocation(f->program, "sampler_meta"), 1); glUniform1i(glGetUniformLocation(f->program, "sampler_colors"), 2); @@ -376084,7 +376084,7 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact glBindVertexArray(f->vao); // update uniforms - glUseProgram(f->program); + shader_bind(f->program); glUniform1f(glGetUniformLocation(f->program, "scale_factor"), factor); glUniform2fv(glGetUniformLocation(f->program, "string_offset"), 1, &offset.x); glUniform1f(glGetUniformLocation(f->program, "offset_firstline"), f->ascent*f->factor); @@ -376104,7 +376104,7 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact glDrawArraysInstanced(GL_TRIANGLES, 0, 6, glyph_idx); // Restore modified GL state - glUseProgram(last_program); + shader_bind(last_program); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, last_texture0); @@ -376707,7 +376707,7 @@ void gui_drawrect( texture_t texture, vec2 tex_start, vec2 tex_end, int rgba, ve renderstate_apply(&rect_rs); GLenum texture_type = texture.flags & TEXTURE_ARRAY ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; - glUseProgram( program ); + shader_bind( program ); glBindVertexArray( vao ); @@ -376756,7 +376756,7 @@ void gui_drawrect( texture_t texture, vec2 tex_start, vec2 tex_end, int rgba, ve glDisableVertexAttribArray(1); glBindVertexArray( 0 ); glBindBuffer(GL_ARRAY_BUFFER, 0); - glUseProgram( 0 ); + shader_bind( 0 ); } // ---------------------------------------------------------------------------- @@ -382845,6 +382845,8 @@ unsigned shader(const char *vs, const char *fs, const char *attribs, const char return shader_geom(NULL, vs, fs, attribs, fragcolor, defines); } +static __thread map(unsigned, unsigned) shader_instances; + static inline char *shader_preprocess(const char *src, const char *defines) { if (!src) return NULL; @@ -382862,6 +382864,18 @@ char *shader_preprocess(const char *src, const char *defines) { } unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines) { + do_once { + map_init(shader_instances, less_int, hash_int); + } + + // Hash shader input and check if we already have an instance made + unsigned shader_hash = hash_str(va("%s%s%s%s%s%s", gs, vs, fs, attribs, fragcolor, defines)); + unsigned *existing = map_find(shader_instances, shader_hash); + if (existing) { + PRINTF("Shader instance reused\n"); + return *existing; + } + PRINTF(/*"!"*/"Compiling shader\n"); char *glsl_defines = ""; @@ -382981,6 +382995,8 @@ unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char for( int i = 0; i < array_count(props); ++i ) shader_apply_param(program, i); } + map_insert(shader_instances, shader_hash, program); + return program; } @@ -383032,14 +383048,14 @@ void shader_apply_param(unsigned shader, unsigned param_no) { if( strchr("ibfv", type[0]) ) { GLint shader_bak; glGetIntegerv(GL_CURRENT_PROGRAM, &shader_bak); - glUseProgram(shader); + shader_bind(shader); /**/ if(type[0] == 'i') glUniform1i(glGetUniformLocation(shader, name), setv.x); else if(type[0] == 'b') glUniform1i(glGetUniformLocation(shader, name), !!setv.x); else if(type[0] == 'f') glUniform1f(glGetUniformLocation(shader, name), setv.x); else if(type[3] == '2') glUniform2fv(glGetUniformLocation(shader, name), 1, &setv.x); else if(type[3] == '3') glUniform3fv(glGetUniformLocation(shader, name), 1, &setv.x); else if(type[3] == '4') glUniform4fv(glGetUniformLocation(shader, name), 1, &setv.x); - glUseProgram(shader_bak); + shader_bind(shader_bak); } } } @@ -383297,7 +383313,7 @@ int shader_uniform(const char *name) { return *map_find(names, name_hash); } unsigned shader_get_active() { return last_shader; } -unsigned shader_bind(unsigned program) { unsigned ret = last_shader; return glUseProgram(last_shader = program), ret; } +unsigned shader_bind(unsigned program) { if (program == last_shader) return last_shader; unsigned ret = last_shader; return glUseProgram(last_shader = program), ret; } void shader_int(const char *uniform, int i) { glUniform1i(shader_uniform(uniform), i); } void shader_float(const char *uniform, float f) { glUniform1f(shader_uniform(uniform), f); } void shader_vec2(const char *uniform, vec2 v) { glUniform2fv(shader_uniform(uniform), 1, &v.x); } @@ -384111,7 +384127,7 @@ void fullscreen_quad_rgb( texture_t texture ) { GLenum texture_type = texture.flags & TEXTURE_ARRAY ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; renderstate_apply(&fullscreen_quad_rs); - glUseProgram( program ); + shader_bind( program ); float gamma = 1; glUniform1f( u_inv_gamma, gamma ); @@ -384126,7 +384142,7 @@ void fullscreen_quad_rgb( texture_t texture ) { glBindTexture( texture_type, 0 ); glBindVertexArray( 0 ); - glUseProgram( 0 ); + shader_bind( 0 ); // glDisable( GL_BLEND ); } @@ -384144,7 +384160,7 @@ void fullscreen_quad_rgb_flipped( texture_t texture ) { GLenum texture_type = texture.flags & TEXTURE_ARRAY ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; renderstate_apply(&fullscreen_quad_rs); - glUseProgram( program ); + shader_bind( program ); float gamma = 1; glUniform1f( u_inv_gamma, gamma ); @@ -384159,7 +384175,7 @@ void fullscreen_quad_rgb_flipped( texture_t texture ) { glBindTexture( texture_type, 0 ); glBindVertexArray( 0 ); - glUseProgram( 0 ); + shader_bind( 0 ); // glDisable( GL_BLEND ); } @@ -384181,7 +384197,7 @@ void fullscreen_quad_ycbcr( texture_t textureYCbCr[3] ) { } renderstate_apply(&fullscreen_quad_rs); - glUseProgram( program ); + shader_bind( program ); // glUniform1f( u_gamma, gamma ); glBindVertexArray( vao ); @@ -384204,7 +384220,7 @@ void fullscreen_quad_ycbcr( texture_t textureYCbCr[3] ) { glBindTexture( GL_TEXTURE_2D, 0 ); glBindVertexArray( 0 ); - glUseProgram( 0 ); + shader_bind( 0 ); // glDisable( GL_BLEND ); } @@ -384226,7 +384242,7 @@ void fullscreen_quad_ycbcr_flipped( texture_t textureYCbCr[3] ) { } renderstate_apply(&fullscreen_quad_rs); - glUseProgram( program ); + shader_bind( program ); // glUniform1f( u_gamma, gamma ); glBindVertexArray( vao ); @@ -384249,7 +384265,7 @@ void fullscreen_quad_ycbcr_flipped( texture_t textureYCbCr[3] ) { glBindTexture( GL_TEXTURE_2D, 0 ); glBindVertexArray( 0 ); - glUseProgram( 0 ); + shader_bind( 0 ); // glDisable( GL_BLEND ); } @@ -384554,7 +384570,7 @@ void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity) { for(int i = 0; i < 6; ++i) { glBindFramebuffer(GL_FRAMEBUFFER, sky->framebuffers[i]); glViewport(0, 0, WIDTH, HEIGHT); - glUseProgram(sky->program); + shader_bind(sky->program); mat44 proj; perspective44(proj, 90.0f, WIDTH / (float)HEIGHT, 0.1f, 500.f); mat44 view; lookat44(view, vec3(0,0,0), directions[i], vec3(0,-1,0)); @@ -385105,7 +385121,7 @@ int postfx_load_from_mem( postfx *fx, const char *name, const char *fs ) { p->program = shader(vs, fs2, "vtexcoord", "fragColor" , NULL); - glUseProgram(p->program); // needed? + shader_bind(p->program); // needed? for( int i = 0; i < countof(p->uniforms); ++i ) p->uniforms[i] = -1; @@ -385267,7 +385283,7 @@ bool postfx_end(postfx *fx) { passfx *pass = &fx->pass[i]; if( pass->enabled ) { if( !pass->program ) { --num_active_passes; continue; } - glUseProgram(pass->program); + shader_bind(pass->program); // bind texture to texture unit 0 // shader_texture_unit(fx->diffuse[frame], 0); @@ -385306,7 +385322,7 @@ bool postfx_end(postfx *fx) { if (bound) fbo_unbind(); } } - glUseProgram(0); + shader_bind(0); // restore clear color: needed in case transparent window is being used (alpha != 0) glClearColor(0,0,0,1); // @transparent @@ -385417,7 +385433,7 @@ static void brdf_load() { glDisable(GL_BLEND); handle old_shader = last_shader; - glUseProgram( program ); + shader_bind( program ); glViewport(0, 0, 512, 512); @@ -385431,7 +385447,7 @@ static void brdf_load() { glBindVertexArray( 0 ); - glUseProgram( last_shader ); + shader_bind( last_shader ); fbo_unbind(); fbo_destroy(lut_fbo); @@ -385553,7 +385569,7 @@ shadertoy_t* shadertoy_render(shadertoy_t *s, float delta) { struct tm *tm = localtime(&tmsec); s->t += delta * 1000; - glUseProgram(s->program); + shader_bind(s->program); glUniform1f(s->uniforms[iGlobalTime], s->t / 1000.f ); glUniform1f(s->uniforms[iGlobalFrame], s->frame++); glUniform1f(s->uniforms[iGlobalDelta], delta / 1000.f ); @@ -385728,7 +385744,7 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view, if(!m.iqm) return; iqm_t *q = m.iqm; - glUseProgram(shader); + shader_bind(shader); int loc; //if( (loc = glGetUniformLocation(shader, "M")) >= 0 ) glUniformMatrix4fv( loc, 1, GL_FALSE/*GL_TRUE*/, m); // RIM if( (loc = glGetUniformLocation(shader, "MV")) >= 0 ) { @@ -386664,7 +386680,6 @@ void model_draw_call(model_t m, int shader) { glUniform4f(loc, m.materials[i].layer[0].map.color.r, m.materials[i].layer[0].map.color.g, m.materials[i].layer[0].map.color.b, m.materials[i].layer[0].map.color.a); } } - } else { const material_t *material = &m.materials[i]; shader_colormap( "map_diffuse", material->layer[MATERIAL_CHANNEL_DIFFUSE].map ); @@ -386722,7 +386737,7 @@ void model_shading(model_t *m, int shading) { // rebind shader // @fixme: app crashes rn - // glUseProgram(0); + // shader_bind(0); // glDeleteProgram(m->program); const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_3322_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, @@ -388795,7 +388810,7 @@ void sprite_flush() { glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); glDepthFunc(GL_LESS); - glUseProgram(0); + shader_bind(0); } } diff --git a/engine/split/v4k_font.c b/engine/split/v4k_font.c index 79b81c6..15d271f 100644 --- a/engine/split/v4k_font.c +++ b/engine/split/v4k_font.c @@ -1886,7 +1886,7 @@ void font_face_from_mem(const char *tag, const void *ttf_data, unsigned ttf_len, glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); // upload constant uniforms - glUseProgram(f->program); + shader_bind(f->program); glUniform1i(glGetUniformLocation(f->program, "sampler_font"), 0); glUniform1i(glGetUniformLocation(f->program, "sampler_meta"), 1); glUniform1i(glGetUniformLocation(f->program, "sampler_colors"), 2); @@ -1948,7 +1948,7 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact glBindVertexArray(f->vao); // update uniforms - glUseProgram(f->program); + shader_bind(f->program); glUniform1f(glGetUniformLocation(f->program, "scale_factor"), factor); glUniform2fv(glGetUniformLocation(f->program, "string_offset"), 1, &offset.x); glUniform1f(glGetUniformLocation(f->program, "offset_firstline"), f->ascent*f->factor); @@ -1968,7 +1968,7 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact glDrawArraysInstanced(GL_TRIANGLES, 0, 6, glyph_idx); // Restore modified GL state - glUseProgram(last_program); + shader_bind(last_program); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, last_texture0); diff --git a/engine/split/v4k_gui.c b/engine/split/v4k_gui.c index 8cc9ad1..2a2915d 100644 --- a/engine/split/v4k_gui.c +++ b/engine/split/v4k_gui.c @@ -39,7 +39,7 @@ void gui_drawrect( texture_t texture, vec2 tex_start, vec2 tex_end, int rgba, ve renderstate_apply(&rect_rs); GLenum texture_type = texture.flags & TEXTURE_ARRAY ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; - glUseProgram( program ); + shader_bind( program ); glBindVertexArray( vao ); @@ -88,7 +88,7 @@ void gui_drawrect( texture_t texture, vec2 tex_start, vec2 tex_end, int rgba, ve glDisableVertexAttribArray(1); glBindVertexArray( 0 ); glBindBuffer(GL_ARRAY_BUFFER, 0); - glUseProgram( 0 ); + shader_bind( 0 ); } // ---------------------------------------------------------------------------- diff --git a/engine/split/v4k_render.c b/engine/split/v4k_render.c index 23119fe..d78f790 100644 --- a/engine/split/v4k_render.c +++ b/engine/split/v4k_render.c @@ -240,6 +240,8 @@ unsigned shader(const char *vs, const char *fs, const char *attribs, const char return shader_geom(NULL, vs, fs, attribs, fragcolor, defines); } +static __thread map(unsigned, unsigned) shader_instances; + static inline char *shader_preprocess(const char *src, const char *defines) { if (!src) return NULL; @@ -257,6 +259,18 @@ char *shader_preprocess(const char *src, const char *defines) { } unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines) { + do_once { + map_init(shader_instances, less_int, hash_int); + } + + // Hash shader input and check if we already have an instance made + unsigned shader_hash = hash_str(va("%s%s%s%s%s%s", gs, vs, fs, attribs, fragcolor, defines)); + unsigned *existing = map_find(shader_instances, shader_hash); + if (existing) { + PRINTF("Shader instance reused\n"); + return *existing; + } + PRINTF(/*"!"*/"Compiling shader\n"); char *glsl_defines = ""; @@ -376,6 +390,8 @@ unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char for( int i = 0; i < array_count(props); ++i ) shader_apply_param(program, i); } + map_insert(shader_instances, shader_hash, program); + return program; } @@ -427,14 +443,14 @@ void shader_apply_param(unsigned shader, unsigned param_no) { if( strchr("ibfv", type[0]) ) { GLint shader_bak; glGetIntegerv(GL_CURRENT_PROGRAM, &shader_bak); - glUseProgram(shader); + shader_bind(shader); /**/ if(type[0] == 'i') glUniform1i(glGetUniformLocation(shader, name), setv.x); else if(type[0] == 'b') glUniform1i(glGetUniformLocation(shader, name), !!setv.x); else if(type[0] == 'f') glUniform1f(glGetUniformLocation(shader, name), setv.x); else if(type[3] == '2') glUniform2fv(glGetUniformLocation(shader, name), 1, &setv.x); else if(type[3] == '3') glUniform3fv(glGetUniformLocation(shader, name), 1, &setv.x); else if(type[3] == '4') glUniform4fv(glGetUniformLocation(shader, name), 1, &setv.x); - glUseProgram(shader_bak); + shader_bind(shader_bak); } } } @@ -692,7 +708,7 @@ int shader_uniform(const char *name) { return *map_find(names, name_hash); } unsigned shader_get_active() { return last_shader; } -unsigned shader_bind(unsigned program) { unsigned ret = last_shader; return glUseProgram(last_shader = program), ret; } +unsigned shader_bind(unsigned program) { if (program == last_shader) return last_shader; unsigned ret = last_shader; return glUseProgram(last_shader = program), ret; } void shader_int(const char *uniform, int i) { glUniform1i(shader_uniform(uniform), i); } void shader_float(const char *uniform, float f) { glUniform1f(shader_uniform(uniform), f); } void shader_vec2(const char *uniform, vec2 v) { glUniform2fv(shader_uniform(uniform), 1, &v.x); } @@ -1506,7 +1522,7 @@ void fullscreen_quad_rgb( texture_t texture ) { GLenum texture_type = texture.flags & TEXTURE_ARRAY ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; renderstate_apply(&fullscreen_quad_rs); - glUseProgram( program ); + shader_bind( program ); float gamma = 1; glUniform1f( u_inv_gamma, gamma ); @@ -1521,7 +1537,7 @@ void fullscreen_quad_rgb( texture_t texture ) { glBindTexture( texture_type, 0 ); glBindVertexArray( 0 ); - glUseProgram( 0 ); + shader_bind( 0 ); // glDisable( GL_BLEND ); } @@ -1539,7 +1555,7 @@ void fullscreen_quad_rgb_flipped( texture_t texture ) { GLenum texture_type = texture.flags & TEXTURE_ARRAY ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; renderstate_apply(&fullscreen_quad_rs); - glUseProgram( program ); + shader_bind( program ); float gamma = 1; glUniform1f( u_inv_gamma, gamma ); @@ -1554,7 +1570,7 @@ void fullscreen_quad_rgb_flipped( texture_t texture ) { glBindTexture( texture_type, 0 ); glBindVertexArray( 0 ); - glUseProgram( 0 ); + shader_bind( 0 ); // glDisable( GL_BLEND ); } @@ -1576,7 +1592,7 @@ void fullscreen_quad_ycbcr( texture_t textureYCbCr[3] ) { } renderstate_apply(&fullscreen_quad_rs); - glUseProgram( program ); + shader_bind( program ); // glUniform1f( u_gamma, gamma ); glBindVertexArray( vao ); @@ -1599,7 +1615,7 @@ void fullscreen_quad_ycbcr( texture_t textureYCbCr[3] ) { glBindTexture( GL_TEXTURE_2D, 0 ); glBindVertexArray( 0 ); - glUseProgram( 0 ); + shader_bind( 0 ); // glDisable( GL_BLEND ); } @@ -1621,7 +1637,7 @@ void fullscreen_quad_ycbcr_flipped( texture_t textureYCbCr[3] ) { } renderstate_apply(&fullscreen_quad_rs); - glUseProgram( program ); + shader_bind( program ); // glUniform1f( u_gamma, gamma ); glBindVertexArray( vao ); @@ -1644,7 +1660,7 @@ void fullscreen_quad_ycbcr_flipped( texture_t textureYCbCr[3] ) { glBindTexture( GL_TEXTURE_2D, 0 ); glBindVertexArray( 0 ); - glUseProgram( 0 ); + shader_bind( 0 ); // glDisable( GL_BLEND ); } @@ -1949,7 +1965,7 @@ void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity) { for(int i = 0; i < 6; ++i) { glBindFramebuffer(GL_FRAMEBUFFER, sky->framebuffers[i]); glViewport(0, 0, WIDTH, HEIGHT); - glUseProgram(sky->program); + shader_bind(sky->program); mat44 proj; perspective44(proj, 90.0f, WIDTH / (float)HEIGHT, 0.1f, 500.f); mat44 view; lookat44(view, vec3(0,0,0), directions[i], vec3(0,-1,0)); @@ -2500,7 +2516,7 @@ int postfx_load_from_mem( postfx *fx, const char *name, const char *fs ) { p->program = shader(vs, fs2, "vtexcoord", "fragColor" , NULL); - glUseProgram(p->program); // needed? + shader_bind(p->program); // needed? for( int i = 0; i < countof(p->uniforms); ++i ) p->uniforms[i] = -1; @@ -2662,7 +2678,7 @@ bool postfx_end(postfx *fx) { passfx *pass = &fx->pass[i]; if( pass->enabled ) { if( !pass->program ) { --num_active_passes; continue; } - glUseProgram(pass->program); + shader_bind(pass->program); // bind texture to texture unit 0 // shader_texture_unit(fx->diffuse[frame], 0); @@ -2701,7 +2717,7 @@ bool postfx_end(postfx *fx) { if (bound) fbo_unbind(); } } - glUseProgram(0); + shader_bind(0); // restore clear color: needed in case transparent window is being used (alpha != 0) glClearColor(0,0,0,1); // @transparent @@ -2812,7 +2828,7 @@ static void brdf_load() { glDisable(GL_BLEND); handle old_shader = last_shader; - glUseProgram( program ); + shader_bind( program ); glViewport(0, 0, 512, 512); @@ -2826,7 +2842,7 @@ static void brdf_load() { glBindVertexArray( 0 ); - glUseProgram( last_shader ); + shader_bind( last_shader ); fbo_unbind(); fbo_destroy(lut_fbo); @@ -2948,7 +2964,7 @@ shadertoy_t* shadertoy_render(shadertoy_t *s, float delta) { struct tm *tm = localtime(&tmsec); s->t += delta * 1000; - glUseProgram(s->program); + shader_bind(s->program); glUniform1f(s->uniforms[iGlobalTime], s->t / 1000.f ); glUniform1f(s->uniforms[iGlobalFrame], s->frame++); glUniform1f(s->uniforms[iGlobalDelta], delta / 1000.f ); @@ -3123,7 +3139,7 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view, if(!m.iqm) return; iqm_t *q = m.iqm; - glUseProgram(shader); + shader_bind(shader); int loc; //if( (loc = glGetUniformLocation(shader, "M")) >= 0 ) glUniformMatrix4fv( loc, 1, GL_FALSE/*GL_TRUE*/, m); // RIM if( (loc = glGetUniformLocation(shader, "MV")) >= 0 ) { @@ -4059,7 +4075,6 @@ void model_draw_call(model_t m, int shader) { glUniform4f(loc, m.materials[i].layer[0].map.color.r, m.materials[i].layer[0].map.color.g, m.materials[i].layer[0].map.color.b, m.materials[i].layer[0].map.color.a); } } - } else { const material_t *material = &m.materials[i]; shader_colormap( "map_diffuse", material->layer[MATERIAL_CHANNEL_DIFFUSE].map ); @@ -4117,7 +4132,7 @@ void model_shading(model_t *m, int shading) { // rebind shader // @fixme: app crashes rn - // glUseProgram(0); + // shader_bind(0); // glDeleteProgram(m->program); const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_3322_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, diff --git a/engine/split/v4k_sprite.c b/engine/split/v4k_sprite.c index 2aa3ef4..8d79156 100644 --- a/engine/split/v4k_sprite.c +++ b/engine/split/v4k_sprite.c @@ -339,7 +339,7 @@ void sprite_flush() { glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); glDepthFunc(GL_LESS); - glUseProgram(0); + shader_bind(0); } } diff --git a/engine/v4k.c b/engine/v4k.c index ec238ee..fc6d9aa 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -10591,7 +10591,7 @@ void font_face_from_mem(const char *tag, const void *ttf_data, unsigned ttf_len, glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); // upload constant uniforms - glUseProgram(f->program); + shader_bind(f->program); glUniform1i(glGetUniformLocation(f->program, "sampler_font"), 0); glUniform1i(glGetUniformLocation(f->program, "sampler_meta"), 1); glUniform1i(glGetUniformLocation(f->program, "sampler_colors"), 2); @@ -10653,7 +10653,7 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact glBindVertexArray(f->vao); // update uniforms - glUseProgram(f->program); + shader_bind(f->program); glUniform1f(glGetUniformLocation(f->program, "scale_factor"), factor); glUniform2fv(glGetUniformLocation(f->program, "string_offset"), 1, &offset.x); glUniform1f(glGetUniformLocation(f->program, "offset_firstline"), f->ascent*f->factor); @@ -10673,7 +10673,7 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact glDrawArraysInstanced(GL_TRIANGLES, 0, 6, glyph_idx); // Restore modified GL state - glUseProgram(last_program); + shader_bind(last_program); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, last_texture0); @@ -11276,7 +11276,7 @@ void gui_drawrect( texture_t texture, vec2 tex_start, vec2 tex_end, int rgba, ve renderstate_apply(&rect_rs); GLenum texture_type = texture.flags & TEXTURE_ARRAY ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; - glUseProgram( program ); + shader_bind( program ); glBindVertexArray( vao ); @@ -11325,7 +11325,7 @@ void gui_drawrect( texture_t texture, vec2 tex_start, vec2 tex_end, int rgba, ve glDisableVertexAttribArray(1); glBindVertexArray( 0 ); glBindBuffer(GL_ARRAY_BUFFER, 0); - glUseProgram( 0 ); + shader_bind( 0 ); } // ---------------------------------------------------------------------------- @@ -17414,6 +17414,8 @@ unsigned shader(const char *vs, const char *fs, const char *attribs, const char return shader_geom(NULL, vs, fs, attribs, fragcolor, defines); } +static __thread map(unsigned, unsigned) shader_instances; + static inline char *shader_preprocess(const char *src, const char *defines) { if (!src) return NULL; @@ -17431,6 +17433,18 @@ char *shader_preprocess(const char *src, const char *defines) { } unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines) { + do_once { + map_init(shader_instances, less_int, hash_int); + } + + // Hash shader input and check if we already have an instance made + unsigned shader_hash = hash_str(va("%s%s%s%s%s%s", gs, vs, fs, attribs, fragcolor, defines)); + unsigned *existing = map_find(shader_instances, shader_hash); + if (existing) { + PRINTF("Shader instance reused\n"); + return *existing; + } + PRINTF(/*"!"*/"Compiling shader\n"); char *glsl_defines = ""; @@ -17550,6 +17564,8 @@ unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char for( int i = 0; i < array_count(props); ++i ) shader_apply_param(program, i); } + map_insert(shader_instances, shader_hash, program); + return program; } @@ -17601,14 +17617,14 @@ void shader_apply_param(unsigned shader, unsigned param_no) { if( strchr("ibfv", type[0]) ) { GLint shader_bak; glGetIntegerv(GL_CURRENT_PROGRAM, &shader_bak); - glUseProgram(shader); + shader_bind(shader); /**/ if(type[0] == 'i') glUniform1i(glGetUniformLocation(shader, name), setv.x); else if(type[0] == 'b') glUniform1i(glGetUniformLocation(shader, name), !!setv.x); else if(type[0] == 'f') glUniform1f(glGetUniformLocation(shader, name), setv.x); else if(type[3] == '2') glUniform2fv(glGetUniformLocation(shader, name), 1, &setv.x); else if(type[3] == '3') glUniform3fv(glGetUniformLocation(shader, name), 1, &setv.x); else if(type[3] == '4') glUniform4fv(glGetUniformLocation(shader, name), 1, &setv.x); - glUseProgram(shader_bak); + shader_bind(shader_bak); } } } @@ -17866,7 +17882,7 @@ int shader_uniform(const char *name) { return *map_find(names, name_hash); } unsigned shader_get_active() { return last_shader; } -unsigned shader_bind(unsigned program) { unsigned ret = last_shader; return glUseProgram(last_shader = program), ret; } +unsigned shader_bind(unsigned program) { if (program == last_shader) return last_shader; unsigned ret = last_shader; return glUseProgram(last_shader = program), ret; } void shader_int(const char *uniform, int i) { glUniform1i(shader_uniform(uniform), i); } void shader_float(const char *uniform, float f) { glUniform1f(shader_uniform(uniform), f); } void shader_vec2(const char *uniform, vec2 v) { glUniform2fv(shader_uniform(uniform), 1, &v.x); } @@ -18680,7 +18696,7 @@ void fullscreen_quad_rgb( texture_t texture ) { GLenum texture_type = texture.flags & TEXTURE_ARRAY ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; renderstate_apply(&fullscreen_quad_rs); - glUseProgram( program ); + shader_bind( program ); float gamma = 1; glUniform1f( u_inv_gamma, gamma ); @@ -18695,7 +18711,7 @@ void fullscreen_quad_rgb( texture_t texture ) { glBindTexture( texture_type, 0 ); glBindVertexArray( 0 ); - glUseProgram( 0 ); + shader_bind( 0 ); // glDisable( GL_BLEND ); } @@ -18713,7 +18729,7 @@ void fullscreen_quad_rgb_flipped( texture_t texture ) { GLenum texture_type = texture.flags & TEXTURE_ARRAY ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; renderstate_apply(&fullscreen_quad_rs); - glUseProgram( program ); + shader_bind( program ); float gamma = 1; glUniform1f( u_inv_gamma, gamma ); @@ -18728,7 +18744,7 @@ void fullscreen_quad_rgb_flipped( texture_t texture ) { glBindTexture( texture_type, 0 ); glBindVertexArray( 0 ); - glUseProgram( 0 ); + shader_bind( 0 ); // glDisable( GL_BLEND ); } @@ -18750,7 +18766,7 @@ void fullscreen_quad_ycbcr( texture_t textureYCbCr[3] ) { } renderstate_apply(&fullscreen_quad_rs); - glUseProgram( program ); + shader_bind( program ); // glUniform1f( u_gamma, gamma ); glBindVertexArray( vao ); @@ -18773,7 +18789,7 @@ void fullscreen_quad_ycbcr( texture_t textureYCbCr[3] ) { glBindTexture( GL_TEXTURE_2D, 0 ); glBindVertexArray( 0 ); - glUseProgram( 0 ); + shader_bind( 0 ); // glDisable( GL_BLEND ); } @@ -18795,7 +18811,7 @@ void fullscreen_quad_ycbcr_flipped( texture_t textureYCbCr[3] ) { } renderstate_apply(&fullscreen_quad_rs); - glUseProgram( program ); + shader_bind( program ); // glUniform1f( u_gamma, gamma ); glBindVertexArray( vao ); @@ -18818,7 +18834,7 @@ void fullscreen_quad_ycbcr_flipped( texture_t textureYCbCr[3] ) { glBindTexture( GL_TEXTURE_2D, 0 ); glBindVertexArray( 0 ); - glUseProgram( 0 ); + shader_bind( 0 ); // glDisable( GL_BLEND ); } @@ -19123,7 +19139,7 @@ void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity) { for(int i = 0; i < 6; ++i) { glBindFramebuffer(GL_FRAMEBUFFER, sky->framebuffers[i]); glViewport(0, 0, WIDTH, HEIGHT); - glUseProgram(sky->program); + shader_bind(sky->program); mat44 proj; perspective44(proj, 90.0f, WIDTH / (float)HEIGHT, 0.1f, 500.f); mat44 view; lookat44(view, vec3(0,0,0), directions[i], vec3(0,-1,0)); @@ -19674,7 +19690,7 @@ int postfx_load_from_mem( postfx *fx, const char *name, const char *fs ) { p->program = shader(vs, fs2, "vtexcoord", "fragColor" , NULL); - glUseProgram(p->program); // needed? + shader_bind(p->program); // needed? for( int i = 0; i < countof(p->uniforms); ++i ) p->uniforms[i] = -1; @@ -19836,7 +19852,7 @@ bool postfx_end(postfx *fx) { passfx *pass = &fx->pass[i]; if( pass->enabled ) { if( !pass->program ) { --num_active_passes; continue; } - glUseProgram(pass->program); + shader_bind(pass->program); // bind texture to texture unit 0 // shader_texture_unit(fx->diffuse[frame], 0); @@ -19875,7 +19891,7 @@ bool postfx_end(postfx *fx) { if (bound) fbo_unbind(); } } - glUseProgram(0); + shader_bind(0); // restore clear color: needed in case transparent window is being used (alpha != 0) glClearColor(0,0,0,1); // @transparent @@ -19986,7 +20002,7 @@ static void brdf_load() { glDisable(GL_BLEND); handle old_shader = last_shader; - glUseProgram( program ); + shader_bind( program ); glViewport(0, 0, 512, 512); @@ -20000,7 +20016,7 @@ static void brdf_load() { glBindVertexArray( 0 ); - glUseProgram( last_shader ); + shader_bind( last_shader ); fbo_unbind(); fbo_destroy(lut_fbo); @@ -20122,7 +20138,7 @@ shadertoy_t* shadertoy_render(shadertoy_t *s, float delta) { struct tm *tm = localtime(&tmsec); s->t += delta * 1000; - glUseProgram(s->program); + shader_bind(s->program); glUniform1f(s->uniforms[iGlobalTime], s->t / 1000.f ); glUniform1f(s->uniforms[iGlobalFrame], s->frame++); glUniform1f(s->uniforms[iGlobalDelta], delta / 1000.f ); @@ -20297,7 +20313,7 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view, if(!m.iqm) return; iqm_t *q = m.iqm; - glUseProgram(shader); + shader_bind(shader); int loc; //if( (loc = glGetUniformLocation(shader, "M")) >= 0 ) glUniformMatrix4fv( loc, 1, GL_FALSE/*GL_TRUE*/, m); // RIM if( (loc = glGetUniformLocation(shader, "MV")) >= 0 ) { @@ -21233,7 +21249,6 @@ void model_draw_call(model_t m, int shader) { glUniform4f(loc, m.materials[i].layer[0].map.color.r, m.materials[i].layer[0].map.color.g, m.materials[i].layer[0].map.color.b, m.materials[i].layer[0].map.color.a); } } - } else { const material_t *material = &m.materials[i]; shader_colormap( "map_diffuse", material->layer[MATERIAL_CHANNEL_DIFFUSE].map ); @@ -21291,7 +21306,7 @@ void model_shading(model_t *m, int shading) { // rebind shader // @fixme: app crashes rn - // glUseProgram(0); + // shader_bind(0); // glDeleteProgram(m->program); const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_3322_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs, @@ -23364,7 +23379,7 @@ void sprite_flush() { glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); glDepthFunc(GL_LESS); - glUseProgram(0); + shader_bind(0); } }