From 86ce491a862296c92bbf377cc11faf93d7a7efe7 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Fri, 25 Apr 2014 14:51:42 +0900 Subject: [PATCH] Evas gl_x11: Add ETC2 support to the GL/X11 engine This should allow texture upload with ETC2 RGB8 or RGBA8 formats. Untested for now... @feature --- src/lib/evas/Evas_GL.h | 5 ++ src/lib/evas/common/evas_image_main.c | 8 ++- .../evas/engines/gl_common/evas_gl_common.h | 7 +++ .../evas/engines/gl_common/evas_gl_context.c | 35 +++++++++++++ .../evas/engines/gl_common/evas_gl_image.c | 40 +++++++++++++-- .../evas/engines/gl_common/evas_gl_texture.c | 49 +++++++++++++------ src/modules/evas/engines/gl_x11/evas_engine.c | 6 ++- 7 files changed, 126 insertions(+), 24 deletions(-) diff --git a/src/lib/evas/Evas_GL.h b/src/lib/evas/Evas_GL.h index 75bdc8c32e..8f148d9ad6 100644 --- a/src/lib/evas/Evas_GL.h +++ b/src/lib/evas/Evas_GL.h @@ -1056,6 +1056,11 @@ typedef signed long int GLsizeiptr; // Changed khronos_ssize_t /* GL_OES_compressed_ETC1_RGB8_texture */ #define GL_ETC1_RGB8_OES 0x8D64 +/* The following are OpenGL ES 3.0 definitions for ETC2 + * Note that RGB8_ETC2 is a superset of GL_OES_compressed_ETC1_RGB8_texture */ +#define GL_COMPRESSED_RGB8_ETC2 0x8D64 +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x8D64 + /* GL_OES_compressed_paletted_texture */ #define GL_PALETTE4_RGB8_OES 0x8B90 #define GL_PALETTE4_RGBA8_OES 0x8B91 diff --git a/src/lib/evas/common/evas_image_main.c b/src/lib/evas/common/evas_image_main.c index 46fdcb2de2..2ce8370b63 100644 --- a/src/lib/evas/common/evas_image_main.c +++ b/src/lib/evas/common/evas_image_main.c @@ -126,10 +126,14 @@ _evas_common_rgba_image_surface_size(unsigned int w, unsigned int h, Evas_Colors case EVAS_COLORSPACE_GRY8: siz = w * h * sizeof(DATA8); break; case EVAS_COLORSPACE_AGRY88: siz = w * h * sizeof(DATA16); break; case EVAS_COLORSPACE_ETC1: + case EVAS_COLORSPACE_RGB8_ETC2: // Need to round width and height independently w += 2; h += 2; // We do duplicate border in ETC1 to have better rendering on GPU. - siz = (w / 4 + (w % 4 ? 1 : 0)) * - (h / 4 + (h % 4 ? 1 : 0)) * 8; + siz = (w / 4 + (w % 4 ? 1 : 0)) * (h / 4 + (h % 4 ? 1 : 0)) * 8; + break; + case EVAS_COLORSPACE_RGBA8_ETC2_EAC: + w += 2; h += 2; + siz = (w / 4 + (w % 4 ? 1 : 0)) * (h / 4 + (h % 4 ? 1 : 0)) * 16; break; default: case EVAS_COLORSPACE_ARGB8888: siz = w * h * sizeof(DATA32); break; 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 d61186e3f0..1ca0eec808 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_common.h +++ b/src/modules/evas/engines/gl_common/evas_gl_common.h @@ -114,6 +114,12 @@ #ifndef GL_ETC1_RGB8_OES # define GL_ETC1_RGB8_OES 0x8D64 #endif +#ifndef GL_COMPRESSED_RGB8_ETC2 +# define GL_COMPRESSED_RGB8_ETC2 0x9274 +#endif +#ifndef GL_COMPRESSED_RGBA8_ETC2_EAC +# define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#endif #ifndef GL_UNPACK_ROW_LENGTH @@ -363,6 +369,7 @@ struct _Evas_GL_Shared Eina_Bool bin_program : 1; Eina_Bool unpack_row_length : 1; Eina_Bool etc1 : 1; + Eina_Bool etc2 : 1; // tuning params - per gpu/cpu combo? #define MAX_CUTOUT 512 #define DEF_CUTOUT 512 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 7a0b21543d..aaabc788fd 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_context.c +++ b/src/modules/evas/engines/gl_common/evas_gl_context.c @@ -724,6 +724,39 @@ evas_gl_common_context_new(void) if (atoi(s) == 0) shared->info.bin_program = 0; } +#ifdef GL_GLES + // Detect ECT2 support. We need both RGB and RGBA formats. + if (glsym_glCompressedTexImage2d) + { + GLint texFormatCnt = 0; + glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &texFormatCnt); + if (texFormatCnt > 0) + { + GLenum *texFormats = malloc(texFormatCnt * sizeof(GLenum)); + if (texFormats) + { + int k, cnt = 0; + glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, (GLint *) texFormats); + for (k = 0; k < texFormatCnt && cnt < 2; k++) + { + if (texFormats[k] == GL_COMPRESSED_RGB8_ETC2) + cnt++; + else if (texFormats[k] == GL_COMPRESSED_RGBA8_ETC2_EAC) + cnt++; + } + shared->info.etc2 = (cnt == 2); + free(texFormats); + + // FIXME: My NVIDIA driver advertises ETC2 texture formats + // but does not support them. Driver bug? Logic bug? + // This is in #ifdef GL_GLES because Khronos recommends + // use of GL_COMPRESSED_TEXTURE_FORMATS but OpenGL 4.x + // does not. + } + } + } +#endif + if (getenv("EVAS_GL_INFO")) fprintf(stderr, "max tex size %ix%i\n" @@ -732,6 +765,7 @@ evas_gl_common_context_new(void) "rect tex %i\n" "bgra : %i\n" "etc1 : %i\n" + "etc2 : %i%s\n" "max ansiotropic filtering: %3.3f\n" "egl sec map image: %i\n" "max vertex count: %i\n" @@ -752,6 +786,7 @@ evas_gl_common_context_new(void) (int)shared->info.tex_rect, (int)shared->info.bgra, (int)shared->info.etc1, + (int)shared->info.etc2, shared->info.etc2 ? " (GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_RGBA8_ETC2_EAC)" : "", (double)shared->info.anisotropic, (int)shared->info.sec_image_map, (int)shared->info.max_vertex_elements, 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 70ff5e096e..248eb309ee 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_image.c +++ b/src/modules/evas/engines/gl_common/evas_gl_image.c @@ -135,6 +135,15 @@ static const Evas_Colorspace known_etc1_cspace[] = { EVAS_COLORSPACE_ARGB8888 }; +static const Evas_Colorspace known_etc2_cspace[] = { + EVAS_COLORSPACE_RGBA8_ETC2_EAC, + EVAS_COLORSPACE_RGB8_ETC2, + 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) { @@ -187,7 +196,9 @@ _evas_gl_common_image(Evas_Engine_GL_Context *gc, RGBA_Image *im_im, Evas_Image_ const Evas_Colorspace *cspaces; unsigned int i; - if (gc->shared->info.etc1) + if (gc->shared->info.etc2) + cspaces = known_etc2_cspace; + else if (gc->shared->info.etc1) cspaces = known_etc1_cspace; else cspaces = known_cspace; @@ -332,9 +343,14 @@ evas_gl_common_image_new_from_data(Evas_Engine_GL_Context *gc, unsigned int w, u case EVAS_COLORSPACE_AGRY88: break; case EVAS_COLORSPACE_ETC1: - if (gc->shared->info.etc1) break; + if (gc->shared->info.etc1 && !gc->shared->info.etc2) 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_RGB8_ETC2: + case EVAS_COLORSPACE_RGBA8_ETC2_EAC: + if (gc->shared->info.etc2) break; + ERR("We don't know what to do with ETC2 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); @@ -380,9 +396,14 @@ evas_gl_common_image_new_from_copied_data(Evas_Engine_GL_Context *gc, unsigned i case EVAS_COLORSPACE_AGRY88: break; case EVAS_COLORSPACE_ETC1: - if (gc->shared->info.etc1) break; + if (gc->shared->info.etc1 && !gc->shared->info.etc2) 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_RGB8_ETC2: + case EVAS_COLORSPACE_RGBA8_ETC2_EAC: + if (gc->shared->info.etc2) break; + ERR("We don't know what to do with ETC2 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); @@ -435,9 +456,14 @@ evas_gl_common_image_new(Evas_Engine_GL_Context *gc, unsigned int w, unsigned in case EVAS_COLORSPACE_AGRY88: break; case EVAS_COLORSPACE_ETC1: - if (gc->shared->info.etc1) break; + if (gc->shared->info.etc1 && !gc->shared->info.etc2) 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_RGB8_ETC2: + case EVAS_COLORSPACE_RGBA8_ETC2_EAC: + if (gc->shared->info.etc2) break; + ERR("We don't know what to do with ETC2 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: @@ -574,7 +600,9 @@ evas_gl_common_image_content_hint_set(Evas_GL_Image *im, int hint) 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; + im->cs.space != EVAS_COLORSPACE_ETC1 && + im->cs.space != EVAS_COLORSPACE_RGB8_ETC2 && + im->cs.space != EVAS_COLORSPACE_RGBA8_ETC2_EAC) return; if (im->content_hint == EVAS_IMAGE_CONTENT_HINT_DYNAMIC) { if (im->cs.data) @@ -752,6 +780,8 @@ evas_gl_common_image_update(Evas_Engine_GL_Context *gc, Evas_GL_Image *im) case EVAS_COLORSPACE_GRY8: case EVAS_COLORSPACE_AGRY88: case EVAS_COLORSPACE_ETC1: + case EVAS_COLORSPACE_RGB8_ETC2: + case EVAS_COLORSPACE_RGBA8_ETC2_EAC: 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 2ff7be8729..7cc501af5e 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_texture.c +++ b/src/modules/evas/engines/gl_common/evas_gl_texture.c @@ -32,7 +32,12 @@ static const GLenum lum_alpha_ifmt = GL_LUMINANCE_ALPHA; static const GLenum rgba8_ifmt = GL_RGBA; static const GLenum rgba8_fmt = GL_BGRA; +/* FIXME: RGB8_ETC2 is a superset of ETC1, + * but is GL_ETC1_RGB8_OES supported whenever GL_COMPRESSED_RGB8_ETC2 is? + */ static const GLenum etc1_fmt = GL_ETC1_RGB8_OES; +static const GLenum etc2_rgb_fmt = GL_COMPRESSED_RGB8_ETC2; +static const GLenum etc2_rgba_fmt = GL_COMPRESSED_RGBA8_ETC2_EAC; static struct { struct { @@ -62,7 +67,11 @@ static const struct { { 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_FALSE, EINA_FALSE, EVAS_COLORSPACE_ETC1, &etc1_fmt, &etc1_fmt }, - { EINA_FALSE, EINA_TRUE, EVAS_COLORSPACE_ETC1, &etc1_fmt, &etc1_fmt } + { EINA_FALSE, EINA_TRUE, EVAS_COLORSPACE_ETC1, &etc1_fmt, &etc1_fmt }, + { EINA_FALSE, EINA_FALSE, EVAS_COLORSPACE_RGB8_ETC2, &etc2_rgb_fmt, &etc2_rgb_fmt }, + { EINA_FALSE, EINA_TRUE, EVAS_COLORSPACE_RGB8_ETC2, &etc2_rgb_fmt, &etc2_rgb_fmt }, + { EINA_FALSE, EINA_FALSE, EVAS_COLORSPACE_RGBA8_ETC2_EAC, &etc2_rgba_fmt, &etc2_rgba_fmt }, + { EINA_FALSE, EINA_TRUE, EVAS_COLORSPACE_RGBA8_ETC2_EAC, &etc2_rgba_fmt, &etc2_rgba_fmt } }; static const GLenum matching_rgba[] = { GL_RGBA4, GL_RGBA8, GL_RGBA12, GL_RGBA16, 0x0 }; @@ -395,7 +404,9 @@ _pool_tex_find(Evas_Engine_GL_Context *gc, int w, int h, 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) || - (intformat == etc1_fmt)) + (intformat == etc1_fmt) || + (intformat == etc2_rgb_fmt) || + (intformat == etc2_rgba_fmt)) { pt = _pool_tex_new(gc, w, h, intformat, format); if (!pt) return NULL; @@ -438,7 +449,7 @@ 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 u = 0, v = 0, yoffset = 0; int lformat; tex = evas_gl_common_texture_alloc(gc, im->cache_entry.w, im->cache_entry.h, im->cache_entry.flags.alpha); @@ -448,18 +459,22 @@ 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); - if (im->cache_entry.space == EVAS_COLORSPACE_ETC1) + switch (im->cache_entry.space) { - // Add border for avoiding artifact + case EVAS_COLORSPACE_ETC1: + case EVAS_COLORSPACE_RGB8_ETC2: + case EVAS_COLORSPACE_RGBA8_ETC2_EAC: + // Add border to avoid artifacts w = im->cache_entry.w + 2; h = im->cache_entry.h + 2; + yoffset = 1; - // Adjust w and h for etc1 format (multiple of 4 pixels on both axis) + // Adjust w and h for ETC1/2 formats (multiple of 4 pixels on both axes) w = ((w >> 2) + (w & 0x3 ? 1 : 0)) << 2; h = ((h >> 2) + (h & 0x3 ? 1 : 0)) << 2; - } - else - { + break; + + default: /* 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 */ @@ -477,10 +492,7 @@ 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->y = v + yoffset; tex->pt->references++; evas_gl_common_texture_update(tex, im); @@ -1072,15 +1084,21 @@ evas_gl_common_texture_update(Evas_GL_Texture *tex, RGBA_Image *im) case EVAS_COLORSPACE_GRY8: bytes_count = 1; break; case EVAS_COLORSPACE_AGRY88: bytes_count = 2; break; case EVAS_COLORSPACE_ETC1: + case EVAS_COLORSPACE_RGB8_ETC2: + case EVAS_COLORSPACE_RGBA8_ETC2_EAC: { /* - ETC1 can't be scaled down on the fly and interpolated, like it is + ETC1/2 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; + int etc_block_size = 8; + + if (im->cache_entry.space == EVAS_COLORSPACE_RGBA8_ETC2_EAC) + etc_block_size = 16; width = im->cache_entry.w + 2; height = im->cache_entry.h + 2; @@ -1092,7 +1110,8 @@ evas_gl_common_texture_update(Evas_GL_Texture *tex, RGBA_Image *im) glCompressedTexImage2D(GL_TEXTURE_2D, 0, tex->pt->format, width, height, 0, - ((width * height) >> 4) * 8, im->image.data); + ((width * height) >> 4) * etc_block_size, + im->image.data); GLERR(__FUNCTION__, __FILE__, __LINE__, ""); if (tex->pt->texture != tex->gc->pipe[0].shader.cur_tex) diff --git a/src/modules/evas/engines/gl_x11/evas_engine.c b/src/modules/evas/engines/gl_x11/evas_engine.c index 9ee1ada856..719e29e069 100644 --- a/src/modules/evas/engines/gl_x11/evas_engine.c +++ b/src/modules/evas/engines/gl_x11/evas_engine.c @@ -2870,8 +2870,10 @@ eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data, i *image_data = im->cs.data; break; case EVAS_COLORSPACE_ETC1: - ERR("This image is encoded in ETC1, not returning any data"); - *err = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + case EVAS_COLORSPACE_RGB8_ETC2: + case EVAS_COLORSPACE_RGBA8_ETC2_EAC: + ERR("This image is encoded in ETC1 or ETC2, not returning any data"); + error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; *image_data = NULL; break; default: