diff options
author | Jean-Philippe Andre <jp.andre@samsung.com> | 2015-11-06 16:35:41 +0900 |
---|---|---|
committer | Jean-Philippe Andre <jp.andre@samsung.com> | 2015-11-06 17:16:28 +0900 |
commit | f36309f39fa5d9218f5fd6f4e1200cf90956088f (patch) | |
tree | c4faecc70627f6c9de9b93e6c8be966756e25864 | |
parent | e7bae35fe949071e27f7f5fdd627f0c4f0a9f7cb (diff) | |
download | efl-f36309f39fa5d9218f5fd6f4e1200cf90956088f.tar.gz |
Evas GL: Precompile common shaders
The whole list contains 238 shaders. That's a bit too many, but they
really just take up only ~270K on disk (24Mb of uncompressed data).
-rw-r--r-- | src/modules/evas/engines/gl_common/evas_gl_common.h | 1 | ||||
-rw-r--r-- | src/modules/evas/engines/gl_common/evas_gl_shader.c | 356 |
2 files changed, 240 insertions, 117 deletions
diff --git a/src/modules/evas/engines/gl_common/evas_gl_common.h b/src/modules/evas/engines/gl_common/evas_gl_common.h index 0d7b21e07b..342189a952 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_common.h +++ b/src/modules/evas/engines/gl_common/evas_gl_common.h @@ -102,6 +102,7 @@ struct _Evas_GL_Program Eina_Bool reset : 1; Eina_Bool bin_saved : 1; + Eina_Bool delete_me : 1; }; struct _Evas_GL_Shared diff --git a/src/modules/evas/engines/gl_common/evas_gl_shader.c b/src/modules/evas/engines/gl_common/evas_gl_shader.c index 33dc130ffc..5eb8364ab4 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_shader.c +++ b/src/modules/evas/engines/gl_common/evas_gl_shader.c @@ -4,9 +4,12 @@ #define SHADER_FLAG_SAM_BITSHIFT 3 #define SHADER_FLAG_MASKSAM_BITSHIFT 6 -#define SHADER_PROG_NAME_FMT "prog_%08x" +#define SHADER_PROG_NAME_FMT "/shader/%08x" #define SHADER_BINARY_EET_COMPRESS 1 +#define P(i) ((void*)(intptr_t)i) +#define I(p) ((int)(intptr_t)p) + #ifdef WORDS_BIGENDIAN # define BASEFLAG SHADER_FLAG_BIGENDIAN; #else @@ -337,14 +340,226 @@ error: return 0; } -static void -_shaders_hash_free_cb(void *data) +static inline void +_program_del(Evas_GL_Program *p) { - Evas_GL_Program *p = data; if (p->prog) glDeleteProgram(p->prog); free(p); } +static void +_shaders_hash_free_cb(void *data) +{ + _program_del(data); +} + +static char * +evas_gl_common_shader_glsl_get(unsigned int flags, const char *base) +{ + Eina_Strbuf *s = eina_strbuf_new(); + unsigned int k; + char *str; + + for (k = 0; k < SHADER_FLAG_COUNT; k++) + { + if (flags & (1 << k)) + eina_strbuf_append_printf(s, "#define SHD_%s\n", _shader_flags[k]); + } + + eina_strbuf_append(s, base); + str = eina_strbuf_string_steal(s); + eina_strbuf_free(s); + return str; +} + +static Evas_GL_Program * +evas_gl_common_shader_compile(unsigned int flags, const char *vertex, + const char *fragment) +{ + Evas_GL_Program *p; + GLuint vtx, frg, prg; + GLint ok = 0; + + compiler_released = EINA_FALSE; + vtx = glCreateShader(GL_VERTEX_SHADER); + frg = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource(vtx, 1, &vertex, NULL); + glCompileShader(vtx); + glGetShaderiv(vtx, GL_COMPILE_STATUS, &ok); + if (!ok) + { + gl_compile_link_error(vtx, "compile vertex shader"); + ERR("Abort compile of vertex shader:\n%s", vertex); + glDeleteShader(vtx); + return NULL; + } + ok = 0; + + glShaderSource(frg, 1, &fragment, NULL); + glCompileShader(frg); + glGetShaderiv(frg, GL_COMPILE_STATUS, &ok); + if (!ok) + { + gl_compile_link_error(frg, "compile fragment shader"); + ERR("Abort compile of fragment shader:\n%s", fragment); + glDeleteShader(vtx); + glDeleteShader(frg); + return NULL; + } + ok = 0; + + prg = glCreateProgram(); +#ifndef GL_GLES + if ((glsym_glGetProgramBinary) && (glsym_glProgramParameteri)) + glsym_glProgramParameteri(prg, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); +#endif + glAttachShader(prg, vtx); + glAttachShader(prg, frg); + + glBindAttribLocation(prg, SHAD_VERTEX, "vertex"); + glBindAttribLocation(prg, SHAD_COLOR, "color"); + glBindAttribLocation(prg, SHAD_TEXUV, "tex_coord"); + glBindAttribLocation(prg, SHAD_TEXUV2, "tex_coord2"); + glBindAttribLocation(prg, SHAD_TEXUV3, "tex_coord3"); + glBindAttribLocation(prg, SHAD_TEXA, "tex_coorda"); + glBindAttribLocation(prg, SHAD_TEXSAM, "tex_sample"); + glBindAttribLocation(prg, SHAD_MASK, "mask_coord"); + glBindAttribLocation(prg, SHAD_MASKSAM, "tex_masksample"); + + glLinkProgram(prg); + glGetProgramiv(prg, GL_LINK_STATUS, &ok); + if (!ok) + { + gl_compile_link_error(prg, "link fragment and vertex shaders"); + ERR("Abort compile of shader (flags: %08x)", flags); + glDeleteShader(vtx); + glDeleteShader(frg); + glDeleteProgram(prg); + return 0; + } + + p = calloc(1, sizeof(*p)); + p->flags = flags; + p->prog = prg; + p->reset = EINA_TRUE; + + glDeleteShader(vtx); + glDeleteShader(frg); + + return p; +} + +static Eina_List * +evas_gl_common_shader_precompile_list(Evas_GL_Shared *shared) +{ + int bgra, mask, sam, masksam, img, nomul, afill, yuv; + Eina_List *li = NULL; + + if (!shared) return NULL; + + // rect + li = eina_list_append(li, P(BASEFLAG)); + + // text + for (mask = 0; mask <= 1; mask++) + for (masksam = SHD_SAM11; masksam < (mask ? SHD_SAM_LAST : 1); masksam++) + { + int flags = BASEFLAG | SHADER_FLAG_TEX | SHADER_FLAG_ALPHA; + if (mask) flags |= SHADER_FLAG_MASK; + if (masksam) flags |= (1 << (SHADER_FLAG_MASKSAM_BITSHIFT + masksam - 1)); + li = eina_list_append(li, P(flags)); + } + + // images + for (mask = 0; mask <= 1; mask++) + for (masksam = SHD_SAM11; masksam < (mask ? SHD_SAM_LAST : 1); masksam++) + for (sam = SHD_SAM11; sam < SHD_SAM_LAST; sam++) + for (bgra = 0; bgra <= shared->info.bgra; bgra++) + for (img = 0; img <= 1; img++) + for (nomul = 0; nomul <= 1; nomul++) + for (afill = 0; afill <= (mask ? 0 : 1); afill++) + { + int flags = BASEFLAG | SHADER_FLAG_TEX; + if (mask) flags |= SHADER_FLAG_MASK; + if (masksam) flags |= (1 << (SHADER_FLAG_MASKSAM_BITSHIFT + masksam - 1)); + if (sam) flags |= (1 << (SHADER_FLAG_SAM_BITSHIFT + sam - 1)); + if (bgra) flags |= SHADER_FLAG_BGRA; + if (img) flags |= SHADER_FLAG_IMG; + if (nomul) flags |= SHADER_FLAG_NOMUL; + if (afill) flags |= SHADER_FLAG_AFILL; + li = eina_list_append(li, P(flags)); + } + + // yuv + for (yuv = SHADER_FLAG_YUV; yuv <= SHADER_FLAG_YUV_709; yuv *= 2) + for (mask = 0; mask <= 1; mask++) + for (masksam = SHD_SAM11; masksam < (mask ? SHD_SAM_LAST : 1); masksam++) + for (nomul = 0; nomul <= 1; nomul++) + { + int flags = BASEFLAG | SHADER_FLAG_TEX | yuv; + if (mask) flags |= SHADER_FLAG_MASK; + if (masksam) flags |= (1 << (SHADER_FLAG_MASKSAM_BITSHIFT + masksam - 1)); + if (yuv == SHADER_FLAG_YUV_709) flags |= SHADER_FLAG_YUV; + if (nomul) flags |= SHADER_FLAG_NOMUL; + li = eina_list_append(li, P(flags)); + } + + // rgb+a pair, external, and others will not be precompiled. + + DBG("Built list of %d shaders to precompile", eina_list_count(li)); + return li; +} + +static Evas_GL_Program * +evas_gl_common_shader_generate_and_compile(Evas_GL_Shared *shared, unsigned int flags) +{ + char *vertex, *fragment; + Evas_GL_Program *p; + + if (eina_hash_find(shared->shaders_hash, &flags)) + return NULL; + + vertex = evas_gl_common_shader_glsl_get(flags, vertex_glsl); + fragment = evas_gl_common_shader_glsl_get(flags, fragment_glsl); + + p = evas_gl_common_shader_compile(flags, vertex, fragment); + if (p) + { + evas_gl_common_shader_textures_bind(p); + eina_hash_add(shared->shaders_hash, &flags, p); + } + else WRN("Failed to compile a shader (flags: %08x)", flags); + + free(vertex); + free(fragment); + + return p; +} + +static int +evas_gl_common_shader_precompile_all(Evas_GL_Shared *shared) +{ + Eina_List *li = evas_gl_common_shader_precompile_list(shared); + Evas_GL_Program *p; + int total, cnt = 0; + void *data; + + total = eina_list_count(li); + EINA_LIST_FREE(li, data) + { + p = evas_gl_common_shader_generate_and_compile(shared, I(data)); + if (p) + { + p->delete_me = 1; + cnt++; + } + } + + DBG("Precompiled %d/%d shaders!", cnt, total); + return cnt; +} + int evas_gl_common_shader_program_init(Evas_GL_Shared *shared) { @@ -356,6 +571,7 @@ evas_gl_common_shader_program_init(Evas_GL_Shared *shared) /* img1 */ BASEFLAG | SHADER_FLAG_TEX | SHADER_FLAG_IMG | BGRA, /* img2 */ BASEFLAG | SHADER_FLAG_TEX | SHADER_FLAG_IMG | SHADER_FLAG_NOMUL | BGRA, }; + Evas_GL_Program *p; unsigned i; shared->shaders_hash = eina_hash_int32_new(_shaders_hash_free_cb); @@ -363,12 +579,24 @@ evas_gl_common_shader_program_init(Evas_GL_Shared *shared) { for (i = 0; i < (sizeof(autoload) / sizeof(autoload[0])); i++) { - Evas_GL_Program *p; - p = _evas_gl_common_shader_program_binary_load(shared->shaders_cache, autoload[i]); - if (p) eina_hash_add(shared->shaders_hash, &autoload[i], p); + if (p) + { + evas_gl_common_shader_textures_bind(p); + eina_hash_add(shared->shaders_hash, &autoload[i], p); + } } } + else + { + evas_gl_common_shader_precompile_all(shared); + for (i = 0; i < (sizeof(autoload) / sizeof(autoload[0])); i++) + { + p = eina_hash_find(shared->shaders_hash, &autoload[i]); + if (p) p->delete_me = 0; + } + evas_gl_common_shaders_flush(); + } return 1; } @@ -533,103 +761,6 @@ end: return flags; } -static char * -evas_gl_common_shader_glsl_get(unsigned int flags, const char *base) -{ - Eina_Strbuf *s = eina_strbuf_new(); - unsigned int k; - char *str; - - for (k = 0; k < SHADER_FLAG_COUNT; k++) - { - if (flags & (1 << k)) - eina_strbuf_append_printf(s, "#define SHD_%s\n", _shader_flags[k]); - } - - eina_strbuf_append(s, base); - str = eina_strbuf_string_steal(s); - eina_strbuf_free(s); - return str; -} - -static Evas_GL_Program * -evas_gl_common_shader_compile(unsigned int flags, const char *vertex, - const char *fragment) -{ - Evas_GL_Program *p; - GLuint vtx, frg, prg; - GLint ok = 0; - - compiler_released = EINA_FALSE; - vtx = glCreateShader(GL_VERTEX_SHADER); - frg = glCreateShader(GL_FRAGMENT_SHADER); - - glShaderSource(vtx, 1, &vertex, NULL); - glCompileShader(vtx); - glGetShaderiv(vtx, GL_COMPILE_STATUS, &ok); - if (!ok) - { - gl_compile_link_error(vtx, "compile vertex shader"); - ERR("Abort compile of vertex shader:\n%s", vertex); - glDeleteShader(vtx); - return NULL; - } - ok = 0; - - glShaderSource(frg, 1, &fragment, NULL); - glCompileShader(frg); - glGetShaderiv(frg, GL_COMPILE_STATUS, &ok); - if (!ok) - { - gl_compile_link_error(frg, "compile fragment shader"); - ERR("Abort compile of fragment shader:\n%s", fragment); - glDeleteShader(vtx); - glDeleteShader(frg); - return NULL; - } - ok = 0; - - prg = glCreateProgram(); -#ifndef GL_GLES - if ((glsym_glGetProgramBinary) && (glsym_glProgramParameteri)) - glsym_glProgramParameteri(prg, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); -#endif - glAttachShader(prg, vtx); - glAttachShader(prg, frg); - - glBindAttribLocation(prg, SHAD_VERTEX, "vertex"); - glBindAttribLocation(prg, SHAD_COLOR, "color"); - glBindAttribLocation(prg, SHAD_TEXUV, "tex_coord"); - glBindAttribLocation(prg, SHAD_TEXUV2, "tex_coord2"); - glBindAttribLocation(prg, SHAD_TEXUV3, "tex_coord3"); - glBindAttribLocation(prg, SHAD_TEXA, "tex_coorda"); - glBindAttribLocation(prg, SHAD_TEXSAM, "tex_sample"); - glBindAttribLocation(prg, SHAD_MASK, "mask_coord"); - glBindAttribLocation(prg, SHAD_MASKSAM, "tex_masksample"); - - glLinkProgram(prg); - glGetProgramiv(prg, GL_LINK_STATUS, &ok); - if (!ok) - { - gl_compile_link_error(prg, "link fragment and vertex shaders"); - ERR("Abort compile of shader (flags: %#x)", flags); - glDeleteShader(vtx); - glDeleteShader(frg); - glDeleteProgram(prg); - return 0; - } - - p = calloc(1, sizeof(*p)); - p->flags = flags; - p->prog = prg; - p->reset = EINA_TRUE; - - glDeleteShader(vtx); - glDeleteShader(frg); - - return p; -} - void evas_gl_common_shader_textures_bind(Evas_GL_Program *p) { @@ -687,7 +818,7 @@ evas_gl_common_shader_textures_bind(Evas_GL_Program *p) loc = glGetUniformLocation(p->prog, textures[i].name); if (loc < 0) { - ERR("Couldn't find uniform '%s' (shader: %#x)", + ERR("Couldn't find uniform '%s' (shader: %08x)", textures[i].name, p->flags); } glUniform1i(loc, p->tex_count++); @@ -717,8 +848,6 @@ evas_gl_common_shader_program_get(Evas_Engine_GL_Context *gc, p = eina_hash_find(gc->shared->shaders_hash, &flags); if (!p) { - char *vertex, *fragment; - _evas_gl_common_shader_binary_init(gc->shared); if (gc->shared->shaders_cache) { @@ -727,20 +856,13 @@ evas_gl_common_shader_program_get(Evas_Engine_GL_Context *gc, p = _evas_gl_common_shader_program_binary_load(gc->shared->shaders_cache, flags); if (p) { + evas_gl_common_shader_textures_bind(p); eina_hash_add(gc->shared->shaders_hash, &flags, p); goto end; } } - - vertex = evas_gl_common_shader_glsl_get(flags, vertex_glsl); - fragment = evas_gl_common_shader_glsl_get(flags, fragment_glsl); - - p = evas_gl_common_shader_compile(flags, vertex, fragment); - evas_gl_common_shader_textures_bind(p); - eina_hash_add(gc->shared->shaders_hash, &flags, p); - - free(vertex); - free(fragment); + p = evas_gl_common_shader_generate_and_compile(gc->shared, flags); + if (!p) return NULL; } end: if (p->hitcount < PROGRAM_HITCOUNT_MAX) |