Evas gl: Enable texture atlasses with ETC1/2

We prefer ETC2 textures when ETC2 support has been detected.
According to the spec, glCompressedTexSubImage2D should work
for ETC2.

Try even with ETC1. This may fail at runtime. The fallback path
is very dubious right now but without a proper test case I'm
not sure which approach to take.

We can also imagine cases where the GPU supports TexSubImage for
ETC1 but ETC2 is not supported at all. This will need testing, as
this case is not handled.

@feature
This commit is contained in:
Jean-Philippe Andre 2014-06-12 14:44:28 +09:00
parent 90985d2282
commit dbd576b858
5 changed files with 69 additions and 14 deletions

View File

@ -378,6 +378,7 @@ struct _Evas_GL_Shared
Eina_Bool unpack_row_length : 1;
Eina_Bool etc1 : 1;
Eina_Bool etc2 : 1;
Eina_Bool etc1_subimage : 1;
// tuning params - per gpu/cpu combo?
#define MAX_CUTOUT 512
#define DEF_CUTOUT 512
@ -575,6 +576,7 @@ struct _Evas_GL_Texture_Pool
Eina_Bool render : 1;
Eina_Bool native : 1;
Eina_Bool dynamic : 1;
Eina_Bool comptex_ready : 1;
};
struct _Evas_GL_Texture_Alloca

View File

@ -740,6 +740,10 @@ evas_gl_common_context_new(void)
shared->info.etc2 = (cnt == 2);
free(texFormats);
// Note: If we support ETC2 we'll try to always use ETC2 even when the
// image has colorspace ETC1 (backwards compatibility).
shared->info.etc1_subimage = shared->info.etc2;
// 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

View File

@ -218,6 +218,9 @@ _evas_gl_common_image(Evas_Engine_GL_Context *gc, RGBA_Image *im_im, Evas_Image_
}
cspace = im_im->cache_entry.cspaces[i];
// ETC2 is backwards compatible with ETC1 but we prefer ETC2
if (cspace == EVAS_COLORSPACE_ETC1 && gc->shared->info.etc2)
cspace = EVAS_COLORSPACE_RGB8_ETC2;
im_im->cache_entry.space = cspace;
}

View File

@ -299,9 +299,7 @@ _pool_tex_new(Evas_Engine_GL_Context *gc, int w, int h, GLenum intformat, GLenum
pt = calloc(1, sizeof(Evas_GL_Texture_Pool));
if (!pt) return NULL;
if ((intformat == etc1_fmt) ||
(intformat == etc2_rgb_fmt) ||
(intformat == etc2_rgba_fmt))
if (!gc->shared->info.etc1_subimage && (intformat == etc1_fmt))
no_rounding = EINA_TRUE;
if (!no_rounding)
@ -416,9 +414,7 @@ _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 == etc2_rgb_fmt) ||
(intformat == etc2_rgba_fmt))
(!gc->shared->info.etc1_subimage && (intformat == etc1_fmt)))
{
pt = _pool_tex_new(gc, w, h, intformat, format);
if (!pt) return NULL;
@ -1107,11 +1103,14 @@ evas_gl_common_texture_update(Evas_GL_Texture *tex, RGBA_Image *im)
all.
*/
GLsizei width, height;
GLint x, y;
int etc_block_size = 8;
if (im->cache_entry.space == EVAS_COLORSPACE_RGBA8_ETC2_EAC)
etc_block_size = 16;
x = tex->x - 1;
y = tex->y - 1;
width = im->cache_entry.w + 2;
height = im->cache_entry.h + 2;
width = ((width >> 2) + (width & 0x3 ? 1 : 0)) << 2;
@ -1120,11 +1119,52 @@ evas_gl_common_texture_update(Evas_GL_Texture *tex, RGBA_Image *im)
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) * etc_block_size,
im->image.data);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
if ((tex->gc->shared->info.etc1_subimage ||
(im->cache_entry.space != EVAS_COLORSPACE_ETC1))
&& (tex->pt->w != width || tex->pt->h != height))
{
int glerr;
glerr = glGetError();
if (!tex->pt->comptex_ready)
{
GLsizei tw, th;
tw = ((tex->pt->w >> 2) + (tex->pt->w & 0x3 ? 1 : 0)) << 2;
th = ((tex->pt->h >> 2) + (tex->pt->h & 0x3 ? 1 : 0)) << 2;
glCompressedTexImage2D(GL_TEXTURE_2D, 0, tex->pt->format,
tw, th, 0,
((tw * th) >> 4) * etc_block_size,
NULL);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
tex->pt->comptex_ready = EINA_TRUE;
}
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0,
x, y, width, height,
tex->pt->format,
((width * height) >> 4) * etc_block_size,
im->image.data);
glerr = glGetError();
if (glerr != GL_NO_ERROR)
{
ERR("glCompressedTexSubImage2D failed with ETC1/2: %d", glerr);
// FIXME: Changing settings on the fly.
// The first texture will be black.
// How to fallback? We need a whole texture now.
if (im->cache_entry.space == EVAS_COLORSPACE_ETC1)
tex->gc->shared->info.etc1_subimage = EINA_FALSE;
}
}
else
{
glCompressedTexImage2D(GL_TEXTURE_2D, 0, tex->pt->format,
width, height, 0,
((width * height) >> 4) * etc_block_size,
im->image.data);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
}
if (tex->pt->texture != tex->gc->pipe[0].shader.cur_tex)
{

View File

@ -270,7 +270,7 @@ evas_image_load_file_data_tgv(void *loader_data,
const char *m;
unsigned int *p = pixels;
unsigned char *p_etc = pixels;
char *buffer;
char *buffer = NULL;
Eina_Rectangle master;
unsigned int block_length;
unsigned int length, offset;
@ -326,12 +326,18 @@ evas_image_load_file_data_tgv(void *loader_data,
default: abort();
}
if (prop->cspace != EVAS_COLORSPACE_ARGB8888 && prop->cspace != loader->cspace)
{
if (!((prop->cspace == EVAS_COLORSPACE_RGB8_ETC2) &&
(loader->cspace == EVAS_COLORSPACE_ETC1)))
goto on_error;
// else: ETC2 is compatible with ETC1 and is preferred
}
// Allocate space for each ETC block (8 or 16 bytes per 4 * 4 pixels group)
block_count = loader->block.width * loader->block.height / (4 * 4);
if (loader->compress)
buffer = alloca(etc_block_size * block_count);
else
buffer = NULL;
for (y = 0; y < loader->size.height + 2; y += loader->block.height)
for (x = 0; x < loader->size.width + 2; x += loader->block.width)