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 e5b46321f7..f35d9c94d0 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_common.h +++ b/src/modules/evas/engines/gl_common/evas_gl_common.h @@ -111,6 +111,10 @@ #ifndef GL_LUMINANCE16_ALPHA16 # define GL_LUMINANCE16_ALPHA16 0x8048 #endif +#ifndef GL_ETC1_RGB8_OES +# define GL_ETC1_RGB8_OES 0x8D64 +#endif + #ifndef GL_UNPACK_ROW_LENGTH # define GL_UNPACK_ROW_LENGTH 0x0cf2 @@ -358,6 +362,7 @@ struct _Evas_GL_Shared Eina_Bool sec_image_map : 1; Eina_Bool bin_program : 1; Eina_Bool unpack_row_length : 1; + Eina_Bool etc1 : 1; // tuning params - per gpu/cpu combo? #define MAX_CUTOUT 512 #define DEF_CUTOUT 512 @@ -839,7 +844,14 @@ extern void (*glsym_glProgramParameteri) (GLuint a, GLuint b, GLint d); extern void (*glsym_glReleaseShaderCompiler)(void); extern void *(*glsym_glMapBuffer) (GLenum a, GLenum b); extern GLboolean (*glsym_glUnmapBuffer) (GLenum a); - +extern void (*glsym_glCompressedTexImage2d) (GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLsizei imageSize, + const GLvoid * data); #ifdef GL_GLES extern void *(*secsym_eglCreateImage) (void *a, void *b, GLenum c, void *d, const int *e); extern unsigned int (*secsym_eglDestroyImage) (void *a, void *b); diff --git a/src/modules/evas/engines/gl_common/evas_gl_context.c b/src/modules/evas/engines/gl_common/evas_gl_context.c index cb02c6e6df..7bee00cdd6 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_context.c +++ b/src/modules/evas/engines/gl_common/evas_gl_context.c @@ -30,6 +30,10 @@ GLboolean (*glsym_glUnmapBuffer) (GLenum a) = NULL; void (*glsym_glStartTiling) (GLuint a, GLuint b, GLuint c, GLuint d, GLuint e) = NULL; void (*glsym_glEndTiling) (GLuint a) = NULL; +void (*glsym_glCompressedTexImage2d) (GLenum target, GLint level, GLenum internalformat, + GLsizei width, GLsizei height, GLint border, GLsizei imageSize, + const GLvoid * data) = NULL; + #ifdef GL_GLES // just used for finding symbols :) typedef void (*_eng_fn) (void); @@ -211,6 +215,7 @@ gl_symbols(void) FINDSYM(secsym_eglGetImageAttribSEC, "eglGetImageAttribSEC", secsym_func_uint); #endif + FINDSYM(glsym_glCompressedTexImage2d, "glCompressedTexImage2D", glsym_func_void); } static void shader_array_flush(Evas_Engine_GL_Context *gc); @@ -623,6 +628,8 @@ evas_gl_common_context_new(void) (strstr((char *)ext, "GL_EXT_texture_format_BGRA8888"))) shared->info.bgra = 1; #endif + if (glsym_glCompressedTexImage2d && strstr((char *)ext, "OES_compressed_ETC1_RGB8_texture")) + shared->info.etc1 = 1; #ifdef GL_GLES // FIXME: there should be an extension name/string to check for // not just symbols in the lib diff --git a/src/modules/evas/engines/gl_common/evas_gl_image.c b/src/modules/evas/engines/gl_common/evas_gl_image.c index a89d79deca..a74f45a396 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_image.c +++ b/src/modules/evas/engines/gl_common/evas_gl_image.c @@ -128,6 +128,13 @@ static const Evas_Colorspace known_cspace[] = { EVAS_COLORSPACE_ARGB8888 }; +static const Evas_Colorspace known_etc1_cspace[] = { + EVAS_COLORSPACE_ETC1, + EVAS_COLORSPACE_GRY8, + EVAS_COLORSPACE_AGRY88, + EVAS_COLORSPACE_ARGB8888 +}; + static Evas_GL_Image * _evas_gl_common_image(Evas_Engine_GL_Context *gc, RGBA_Image *im_im, Evas_Image_Load_Opts *lo, int *error) { @@ -177,19 +184,25 @@ _evas_gl_common_image(Evas_Engine_GL_Context *gc, RGBA_Image *im_im, Evas_Image_ } if (im_im->cache_entry.cspaces) { + const Evas_Colorspace *cspaces; unsigned int i; + if (gc->shared->info.etc1) + cspaces = known_etc1_cspace; + else + cspaces = known_cspace; + for (i = 0; im_im->cache_entry.cspaces[i] != EVAS_COLORSPACE_ARGB8888; i++) { unsigned int j; for (j = 0; - known_cspace[j] != EVAS_COLORSPACE_ARGB8888; + cspaces[j] != EVAS_COLORSPACE_ARGB8888; j++) - if (known_cspace[j] == im_im->cache_entry.cspaces[i]) + if (cspaces[j] == im_im->cache_entry.cspaces[i]) break; - if (known_cspace[j] == im_im->cache_entry.cspaces[i]) + if (cspaces[j] == im_im->cache_entry.cspaces[i]) break; } @@ -318,6 +331,10 @@ evas_gl_common_image_new_from_data(Evas_Engine_GL_Context *gc, unsigned int w, u case EVAS_COLORSPACE_GRY8: case EVAS_COLORSPACE_AGRY88: break; + case EVAS_COLORSPACE_ETC1: + if (gc->shared->info.etc1) break; + ERR("We don't know what to do with ETC1 on this hardware. You need to add a software converter here."); + break; case EVAS_COLORSPACE_YCBCR422P601_PL: case EVAS_COLORSPACE_YCBCR422P709_PL: if (im->tex) evas_gl_common_texture_free(im->tex, EINA_TRUE); @@ -362,6 +379,10 @@ evas_gl_common_image_new_from_copied_data(Evas_Engine_GL_Context *gc, unsigned i case EVAS_COLORSPACE_GRY8: case EVAS_COLORSPACE_AGRY88: break; + case EVAS_COLORSPACE_ETC1: + if (gc->shared->info.etc1) break; + ERR("We don't know what to do with ETC1 on this hardware. You need to add a software converter here."); + break; case EVAS_COLORSPACE_YCBCR422P601_PL: case EVAS_COLORSPACE_YCBCR422P709_PL: if (im->tex) evas_gl_common_texture_free(im->tex, EINA_TRUE); @@ -413,6 +434,10 @@ evas_gl_common_image_new(Evas_Engine_GL_Context *gc, unsigned int w, unsigned in case EVAS_COLORSPACE_GRY8: case EVAS_COLORSPACE_AGRY88: break; + case EVAS_COLORSPACE_ETC1: + if (gc->shared->info.etc1) break; + ERR("We don't know what to do with ETC1 on this hardware. You need to add a software converter here."); + break; case EVAS_COLORSPACE_YCBCR422P601_PL: case EVAS_COLORSPACE_YCBCR422P709_PL: case EVAS_COLORSPACE_YCBCR422601_PL: @@ -546,9 +571,10 @@ evas_gl_common_image_content_hint_set(Evas_GL_Image *im, int hint) if (!im->gc->shared->info.sec_image_map) return; if (!im->gc->shared->info.bgra) return; // does not handle yuv yet. - if (im->cs.space != EVAS_COLORSPACE_ARGB8888 || - im->cs.space != EVAS_COLORSPACE_GRY8 || - im->cs.space != EVAS_COLORSPACE_AGRY88) return; + if (im->cs.space != EVAS_COLORSPACE_ARGB8888 && + im->cs.space != EVAS_COLORSPACE_GRY8 && + im->cs.space != EVAS_COLORSPACE_AGRY88 && + im->cs.space != EVAS_COLORSPACE_ETC1) return; if (im->content_hint == EVAS_IMAGE_CONTENT_HINT_DYNAMIC) { if (im->cs.data) @@ -725,6 +751,7 @@ evas_gl_common_image_update(Evas_Engine_GL_Context *gc, Evas_GL_Image *im) case EVAS_COLORSPACE_ARGB8888: case EVAS_COLORSPACE_GRY8: case EVAS_COLORSPACE_AGRY88: + case EVAS_COLORSPACE_ETC1: if ((im->tex) && ((im->dirty) || (ie->animated.animated) || (ie->flags.updated_data))) { diff --git a/src/modules/evas/engines/gl_common/evas_gl_texture.c b/src/modules/evas/engines/gl_common/evas_gl_texture.c index baa27a2686..c43a924173 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_texture.c +++ b/src/modules/evas/engines/gl_common/evas_gl_texture.c @@ -32,6 +32,8 @@ static const GLenum lum_alpha_ifmt = GL_LUMINANCE_ALPHA; static const GLenum rgba8_ifmt = GL_RGBA; static const GLenum rgba8_fmt = GL_BGRA; +static const GLenum etc1_fmt = GL_ETC1_RGB8_OES; + static struct { struct { int num, pix; @@ -58,7 +60,9 @@ static const struct { { EINA_FALSE, EINA_FALSE, EVAS_COLORSPACE_GRY8, &lum_fmt, &lum_ifmt }, { EINA_FALSE, EINA_TRUE, EVAS_COLORSPACE_GRY8, &lum_fmt, &lum_ifmt }, { EINA_TRUE, EINA_FALSE, EVAS_COLORSPACE_AGRY88, &lum_alpha_fmt, &lum_alpha_ifmt }, - { EINA_TRUE, EINA_TRUE, EVAS_COLORSPACE_AGRY88, &lum_alpha_fmt, &lum_alpha_ifmt } + { EINA_TRUE, EINA_TRUE, EVAS_COLORSPACE_AGRY88, &lum_alpha_fmt, &lum_alpha_ifmt }, + { EINA_FALSE, EINA_FALSE, EVAS_COLORSPACE_ETC1, &etc1_fmt, &etc1_fmt }, + { EINA_FALSE, EINA_TRUE, EVAS_COLORSPACE_ETC1, &etc1_fmt, &etc1_fmt } }; static const GLenum matching_rgba[] = { GL_RGBA4, GL_RGBA8, GL_RGBA12, GL_RGBA16, 0x0 }; @@ -380,7 +384,7 @@ _pool_tex_alloc(Evas_GL_Texture_Pool *pt, int w, int h EINA_UNUSED, int *u, int static Evas_GL_Texture_Pool * _pool_tex_find(Evas_Engine_GL_Context *gc, int w, int h, - int intformat, int format, int *u, int *v, + GLenum intformat, GLenum format, int *u, int *v, Evas_GL_Texture_Alloca **apt, int atlas_w) { Evas_GL_Texture_Pool *pt = NULL; @@ -390,7 +394,8 @@ _pool_tex_find(Evas_Engine_GL_Context *gc, int w, int h, if (atlas_w > gc->shared->info.max_texture_size) atlas_w = gc->shared->info.max_texture_size; if ((w > gc->shared->info.tune.atlas.max_w) || - (h > gc->shared->info.tune.atlas.max_h)) + (h > gc->shared->info.tune.atlas.max_h) || + (intformat == etc1_fmt)) { pt = _pool_tex_new(gc, w, h, intformat, format); if (!pt) return NULL; @@ -432,6 +437,7 @@ Evas_GL_Texture * evas_gl_common_texture_new(Evas_Engine_GL_Context *gc, RGBA_Image *im) { Evas_GL_Texture *tex; + GLsizei w, h; int u = 0, v = 0; int lformat; @@ -442,9 +448,24 @@ evas_gl_common_texture_new(Evas_Engine_GL_Context *gc, RGBA_Image *im) #define TEX_VREP 1 lformat = _evas_gl_texture_search_format(im->cache_entry.flags.alpha, gc->shared->info.bgra, im->cache_entry.space); - tex->pt = _pool_tex_find(gc, - im->cache_entry.w + TEX_HREP + 2, - im->cache_entry.h + TEX_VREP, + if (im->cache_entry.space == EVAS_COLORSPACE_ETC1) + { + // Add border for avoiding artifact + w = im->cache_entry.w + 2; + h = im->cache_entry.h + 2; + + // Adjust w and h for etc1 format (multiple of 4 pixels on both axis) + w = ((w >> 2) + (w & 0x3 ? 1 : 0)) << 2; + h = ((h >> 2) + (h & 0x3 ? 1 : 0)) << 2; + } + else + { + /* This need to be adjusted if we do something else than strip allocation */ + w = im->cache_entry.w + TEX_HREP + 2; /* one pixel stop gap and two pixels for the border */ + h = im->cache_entry.h + TEX_VREP; /* only one added border for security down */ + } + + tex->pt = _pool_tex_find(gc, w, h, *matching_format[lformat].intformat, *matching_format[lformat].format, &u, &v, &tex->apt, @@ -457,6 +478,10 @@ evas_gl_common_texture_new(Evas_Engine_GL_Context *gc, RGBA_Image *im) tex->apt->tex = tex; tex->x = u + 1; tex->y = v; + + if (im->cache_entry.space == EVAS_COLORSPACE_ETC1) + tex->y++; + tex->pt->references++; evas_gl_common_texture_update(tex, im); @@ -1032,7 +1057,7 @@ evas_gl_common_texture_update(Evas_GL_Texture *tex, RGBA_Image *im) tex->alpha = im->cache_entry.flags.alpha; lformat = _evas_gl_texture_search_format(tex->alpha, tex->gc->shared->info.bgra, im->cache_entry.space); - // FIXME: why a 'render' new here ??? + // FIXME: why a 'render' new here ??? Should already have been allocated, quite a weird path. tex->pt = _pool_tex_render_new(tex->gc, tex->w, tex->h, *matching_format[lformat].intformat, *matching_format[lformat].format); @@ -1046,7 +1071,41 @@ evas_gl_common_texture_update(Evas_GL_Texture *tex, RGBA_Image *im) case EVAS_COLORSPACE_ARGB8888: bytes_count = 4; break; case EVAS_COLORSPACE_GRY8: bytes_count = 1; break; case EVAS_COLORSPACE_AGRY88: bytes_count = 2; break; - default: return; + case EVAS_COLORSPACE_ETC1: + { + /* + ETC1 can't be scaled down on the fly and interpolated, like it is + required for preloading, so we don't take that path. Also as the content + already have duplicated border and we use a specific function to + upload the compressed data, there is no need to use the normal path at + all. + */ + GLsizei width, height; + + width = im->cache_entry.w + 2; + height = im->cache_entry.h + 2; + width = ((width >> 2) + (width & 0x3 ? 1 : 0)) << 2; + height = ((height >> 2) + (height & 0x3 ? 1 : 0)) << 2; + + glBindTexture(GL_TEXTURE_2D, tex->pt->texture); + GLERR(__FUNCTION__, __FILE__, __LINE__, ""); + + glCompressedTexImage2D(GL_TEXTURE_2D, 0, tex->pt->format, + width, height, 0, + ((width * height) >> 4) * 8, im->image.data); + GLERR(__FUNCTION__, __FILE__, __LINE__, ""); + + if (tex->pt->texture != tex->gc->pipe[0].shader.cur_tex) + { + glBindTexture(GL_TEXTURE_2D, tex->gc->pipe[0].shader.cur_tex); + GLERR(__FUNCTION__, __FILE__, __LINE__, ""); + } + + return; + } + default: + ERR("Don't know how to upload texture in colorspace %i.", im->cache_entry.space); + return; } // if preloaded, then async push it in after uploading a miniature of it