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
This commit is contained in:
Jean-Philippe Andre 2014-04-25 14:51:42 +09:00
parent ef3a36626f
commit 86ce491a86
7 changed files with 126 additions and 24 deletions

View File

@ -1056,6 +1056,11 @@ typedef signed long int GLsizeiptr; // Changed khronos_ssize_t
/* GL_OES_compressed_ETC1_RGB8_texture */ /* GL_OES_compressed_ETC1_RGB8_texture */
#define GL_ETC1_RGB8_OES 0x8D64 #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 */ /* GL_OES_compressed_paletted_texture */
#define GL_PALETTE4_RGB8_OES 0x8B90 #define GL_PALETTE4_RGB8_OES 0x8B90
#define GL_PALETTE4_RGBA8_OES 0x8B91 #define GL_PALETTE4_RGBA8_OES 0x8B91

View File

@ -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_GRY8: siz = w * h * sizeof(DATA8); break;
case EVAS_COLORSPACE_AGRY88: siz = w * h * sizeof(DATA16); break; case EVAS_COLORSPACE_AGRY88: siz = w * h * sizeof(DATA16); break;
case EVAS_COLORSPACE_ETC1: case EVAS_COLORSPACE_ETC1:
case EVAS_COLORSPACE_RGB8_ETC2:
// Need to round width and height independently // Need to round width and height independently
w += 2; h += 2; // We do duplicate border in ETC1 to have better rendering on GPU. w += 2; h += 2; // We do duplicate border in ETC1 to have better rendering on GPU.
siz = (w / 4 + (w % 4 ? 1 : 0)) * siz = (w / 4 + (w % 4 ? 1 : 0)) * (h / 4 + (h % 4 ? 1 : 0)) * 8;
(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; break;
default: default:
case EVAS_COLORSPACE_ARGB8888: siz = w * h * sizeof(DATA32); break; case EVAS_COLORSPACE_ARGB8888: siz = w * h * sizeof(DATA32); break;

View File

@ -114,6 +114,12 @@
#ifndef GL_ETC1_RGB8_OES #ifndef GL_ETC1_RGB8_OES
# define GL_ETC1_RGB8_OES 0x8D64 # define GL_ETC1_RGB8_OES 0x8D64
#endif #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 #ifndef GL_UNPACK_ROW_LENGTH
@ -363,6 +369,7 @@ struct _Evas_GL_Shared
Eina_Bool bin_program : 1; Eina_Bool bin_program : 1;
Eina_Bool unpack_row_length : 1; Eina_Bool unpack_row_length : 1;
Eina_Bool etc1 : 1; Eina_Bool etc1 : 1;
Eina_Bool etc2 : 1;
// tuning params - per gpu/cpu combo? // tuning params - per gpu/cpu combo?
#define MAX_CUTOUT 512 #define MAX_CUTOUT 512
#define DEF_CUTOUT 512 #define DEF_CUTOUT 512

View File

@ -724,6 +724,39 @@ evas_gl_common_context_new(void)
if (atoi(s) == 0) shared->info.bin_program = 0; 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")) if (getenv("EVAS_GL_INFO"))
fprintf(stderr, fprintf(stderr,
"max tex size %ix%i\n" "max tex size %ix%i\n"
@ -732,6 +765,7 @@ evas_gl_common_context_new(void)
"rect tex %i\n" "rect tex %i\n"
"bgra : %i\n" "bgra : %i\n"
"etc1 : %i\n" "etc1 : %i\n"
"etc2 : %i%s\n"
"max ansiotropic filtering: %3.3f\n" "max ansiotropic filtering: %3.3f\n"
"egl sec map image: %i\n" "egl sec map image: %i\n"
"max vertex count: %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.tex_rect,
(int)shared->info.bgra, (int)shared->info.bgra,
(int)shared->info.etc1, (int)shared->info.etc1,
(int)shared->info.etc2, shared->info.etc2 ? " (GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_RGBA8_ETC2_EAC)" : "",
(double)shared->info.anisotropic, (double)shared->info.anisotropic,
(int)shared->info.sec_image_map, (int)shared->info.sec_image_map,
(int)shared->info.max_vertex_elements, (int)shared->info.max_vertex_elements,

View File

@ -135,6 +135,15 @@ static const Evas_Colorspace known_etc1_cspace[] = {
EVAS_COLORSPACE_ARGB8888 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 * static Evas_GL_Image *
_evas_gl_common_image(Evas_Engine_GL_Context *gc, RGBA_Image *im_im, Evas_Image_Load_Opts *lo, int *error) _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; const Evas_Colorspace *cspaces;
unsigned int i; 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; cspaces = known_etc1_cspace;
else else
cspaces = known_cspace; 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: case EVAS_COLORSPACE_AGRY88:
break; break;
case EVAS_COLORSPACE_ETC1: 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."); ERR("We don't know what to do with ETC1 on this hardware. You need to add a software converter here.");
break; 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_YCBCR422P601_PL:
case EVAS_COLORSPACE_YCBCR422P709_PL: case EVAS_COLORSPACE_YCBCR422P709_PL:
if (im->tex) evas_gl_common_texture_free(im->tex, EINA_TRUE); 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: case EVAS_COLORSPACE_AGRY88:
break; break;
case EVAS_COLORSPACE_ETC1: 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."); ERR("We don't know what to do with ETC1 on this hardware. You need to add a software converter here.");
break; 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_YCBCR422P601_PL:
case EVAS_COLORSPACE_YCBCR422P709_PL: case EVAS_COLORSPACE_YCBCR422P709_PL:
if (im->tex) evas_gl_common_texture_free(im->tex, EINA_TRUE); 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: case EVAS_COLORSPACE_AGRY88:
break; break;
case EVAS_COLORSPACE_ETC1: 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."); ERR("We don't know what to do with ETC1 on this hardware. You need to add a software converter here.");
break; 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_YCBCR422P601_PL:
case EVAS_COLORSPACE_YCBCR422P709_PL: case EVAS_COLORSPACE_YCBCR422P709_PL:
case EVAS_COLORSPACE_YCBCR422601_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 && if (im->cs.space != EVAS_COLORSPACE_ARGB8888 &&
im->cs.space != EVAS_COLORSPACE_GRY8 && im->cs.space != EVAS_COLORSPACE_GRY8 &&
im->cs.space != EVAS_COLORSPACE_AGRY88 && 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->content_hint == EVAS_IMAGE_CONTENT_HINT_DYNAMIC)
{ {
if (im->cs.data) 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_GRY8:
case EVAS_COLORSPACE_AGRY88: case EVAS_COLORSPACE_AGRY88:
case EVAS_COLORSPACE_ETC1: case EVAS_COLORSPACE_ETC1:
case EVAS_COLORSPACE_RGB8_ETC2:
case EVAS_COLORSPACE_RGBA8_ETC2_EAC:
if ((im->tex) && if ((im->tex) &&
((im->dirty) || (ie->animated.animated) || (ie->flags.updated_data))) ((im->dirty) || (ie->animated.animated) || (ie->flags.updated_data)))
{ {

View File

@ -32,7 +32,12 @@ static const GLenum lum_alpha_ifmt = GL_LUMINANCE_ALPHA;
static const GLenum rgba8_ifmt = GL_RGBA; static const GLenum rgba8_ifmt = GL_RGBA;
static const GLenum rgba8_fmt = GL_BGRA; 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 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 { static struct {
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_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_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 }; 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; atlas_w = gc->shared->info.max_texture_size;
if ((w > gc->shared->info.tune.atlas.max_w) || 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)) (intformat == etc1_fmt) ||
(intformat == etc2_rgb_fmt) ||
(intformat == etc2_rgba_fmt))
{ {
pt = _pool_tex_new(gc, w, h, intformat, format); pt = _pool_tex_new(gc, w, h, intformat, format);
if (!pt) return NULL; 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; Evas_GL_Texture *tex;
GLsizei w, h; GLsizei w, h;
int u = 0, v = 0; int u = 0, v = 0, yoffset = 0;
int lformat; int lformat;
tex = evas_gl_common_texture_alloc(gc, im->cache_entry.w, im->cache_entry.h, im->cache_entry.flags.alpha); 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 #define TEX_VREP 1
lformat = _evas_gl_texture_search_format(im->cache_entry.flags.alpha, gc->shared->info.bgra, im->cache_entry.space); 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; w = im->cache_entry.w + 2;
h = im->cache_entry.h + 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; w = ((w >> 2) + (w & 0x3 ? 1 : 0)) << 2;
h = ((h >> 2) + (h & 0x3 ? 1 : 0)) << 2; h = ((h >> 2) + (h & 0x3 ? 1 : 0)) << 2;
} break;
else
{ default:
/* This need to be adjusted if we do something else than strip allocation */ /* 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 */ 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 */ 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->apt->tex = tex;
tex->x = u + 1; tex->x = u + 1;
tex->y = v; tex->y = v + yoffset;
if (im->cache_entry.space == EVAS_COLORSPACE_ETC1)
tex->y++;
tex->pt->references++; tex->pt->references++;
evas_gl_common_texture_update(tex, im); 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_GRY8: bytes_count = 1; break;
case EVAS_COLORSPACE_AGRY88: bytes_count = 2; break; case EVAS_COLORSPACE_AGRY88: bytes_count = 2; break;
case EVAS_COLORSPACE_ETC1: 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 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 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 upload the compressed data, there is no need to use the normal path at
all. all.
*/ */
GLsizei width, height; 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; width = im->cache_entry.w + 2;
height = im->cache_entry.h + 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, glCompressedTexImage2D(GL_TEXTURE_2D, 0, tex->pt->format,
width, height, 0, width, height, 0,
((width * height) >> 4) * 8, im->image.data); ((width * height) >> 4) * etc_block_size,
im->image.data);
GLERR(__FUNCTION__, __FILE__, __LINE__, ""); GLERR(__FUNCTION__, __FILE__, __LINE__, "");
if (tex->pt->texture != tex->gc->pipe[0].shader.cur_tex) if (tex->pt->texture != tex->gc->pipe[0].shader.cur_tex)

View File

@ -2870,8 +2870,10 @@ eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data, i
*image_data = im->cs.data; *image_data = im->cs.data;
break; break;
case EVAS_COLORSPACE_ETC1: case EVAS_COLORSPACE_ETC1:
ERR("This image is encoded in ETC1, not returning any data"); case EVAS_COLORSPACE_RGB8_ETC2:
*err = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; 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; *image_data = NULL;
break; break;
default: default: