forked from enlightenment/efl
Evas TGV: Add direct copy mode for ETC1/ETC2 data
If the image is already in ETC1 or ETC2, then just copy its data (and LZ4 compress it). @feature
This commit is contained in:
parent
e5f4b032be
commit
947fc3e098
|
@ -25,6 +25,121 @@ _block_size_get(int size)
|
||||||
return MIN(k, MAX_BLOCK);
|
return MIN(k, MAX_BLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_save_direct_tgv(RGBA_Image *im, const char *file, int compress)
|
||||||
|
{
|
||||||
|
// In case we are directly copying ETC1/2 data, we can't properly
|
||||||
|
// duplicate the 1 pixel borders. So we just assume the image contains
|
||||||
|
// them already.
|
||||||
|
|
||||||
|
// TODO: Add block by block compression.
|
||||||
|
|
||||||
|
int image_width, image_height;
|
||||||
|
uint32_t width, height;
|
||||||
|
uint8_t header[8] = "TGV1";
|
||||||
|
int etc_block_size, etc_data_size, buffer_size, data_size, remain;
|
||||||
|
uint8_t *buffer = NULL;
|
||||||
|
uint8_t *data, *ptr;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
image_width = im->cache_entry.w;
|
||||||
|
image_height = im->cache_entry.h;
|
||||||
|
data = im->image.data8;
|
||||||
|
width = htonl(image_width);
|
||||||
|
height = htonl(image_height);
|
||||||
|
compress = !!compress;
|
||||||
|
|
||||||
|
if ((image_width & 0x3) || (image_height & 0x3))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// header[4]: block size info, unused
|
||||||
|
header[4] = 0;
|
||||||
|
|
||||||
|
// header[5]: 0 for ETC1
|
||||||
|
switch (im->cache_entry.space)
|
||||||
|
{
|
||||||
|
case EVAS_COLORSPACE_ETC1:
|
||||||
|
etc_block_size = 8;
|
||||||
|
header[5] = 0;
|
||||||
|
break;
|
||||||
|
case EVAS_COLORSPACE_RGB8_ETC2:
|
||||||
|
etc_block_size = 8;
|
||||||
|
header[5] = 1;
|
||||||
|
break;
|
||||||
|
case EVAS_COLORSPACE_RGBA8_ETC2_EAC:
|
||||||
|
etc_block_size = 16;
|
||||||
|
header[5] = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// header[6]: 0 for raw, 1, for LZ4 compressed, 2 for block-less mode
|
||||||
|
header[6] = compress | 0x2;
|
||||||
|
|
||||||
|
// header[7]: options (unused)
|
||||||
|
header[7] = 0;
|
||||||
|
|
||||||
|
f = fopen(file, "w");
|
||||||
|
if (!f) return 0;
|
||||||
|
|
||||||
|
// Write header
|
||||||
|
if (fwrite(header, sizeof (uint8_t), 8, f) != 8) goto on_error;
|
||||||
|
if (fwrite(&width, sizeof (uint32_t), 1, f) != 1) goto on_error;
|
||||||
|
if (fwrite(&height, sizeof (uint32_t), 1, f) != 1) goto on_error;
|
||||||
|
|
||||||
|
etc_data_size = image_width * image_height * etc_block_size / 16;
|
||||||
|
if (compress)
|
||||||
|
{
|
||||||
|
buffer_size = LZ4_compressBound(etc_data_size);
|
||||||
|
buffer = malloc(buffer_size);
|
||||||
|
if (!buffer) goto on_error;
|
||||||
|
data_size = LZ4_compressHC((char *) data, (char *) buffer, etc_data_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data_size = buffer_size = etc_data_size;
|
||||||
|
buffer = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write block length header -- We keep this even in block-less mode
|
||||||
|
if (data_size > 0)
|
||||||
|
{
|
||||||
|
unsigned int blen = data_size;
|
||||||
|
|
||||||
|
while (blen)
|
||||||
|
{
|
||||||
|
unsigned char plen;
|
||||||
|
|
||||||
|
plen = blen & 0x7F;
|
||||||
|
blen = blen >> 7;
|
||||||
|
|
||||||
|
if (blen) plen = 0x80 | plen;
|
||||||
|
if (fwrite(&plen, 1, 1, f) != 1) goto on_error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write data
|
||||||
|
ptr = buffer;
|
||||||
|
remain = data_size;
|
||||||
|
while (remain > 0)
|
||||||
|
{
|
||||||
|
int written = fwrite(ptr, 1, remain, f);
|
||||||
|
if (written < 0) goto on_error;
|
||||||
|
remain -= written;
|
||||||
|
ptr += written;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compress) free(buffer);
|
||||||
|
fclose(f);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
on_error:
|
||||||
|
if (compress) free(buffer);
|
||||||
|
fclose(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
evas_image_save_file_tgv(RGBA_Image *im,
|
evas_image_save_file_tgv(RGBA_Image *im,
|
||||||
const char *file, const char *key EINA_UNUSED,
|
const char *file, const char *key EINA_UNUSED,
|
||||||
|
@ -43,13 +158,19 @@ evas_image_save_file_tgv(RGBA_Image *im,
|
||||||
if (!im || !im->image.data || !file)
|
if (!im || !im->image.data || !file)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Surface with alpha are not supported
|
switch (im->cache_entry.space)
|
||||||
|
{
|
||||||
|
case EVAS_COLORSPACE_ARGB8888:
|
||||||
if (im->cache_entry.flags.alpha)
|
if (im->cache_entry.flags.alpha)
|
||||||
return 0;
|
return 0;
|
||||||
|
break;
|
||||||
// Only RGBA encoding for now. TODO: Direct copy of ETC1/2 blocks.
|
case EVAS_COLORSPACE_ETC1:
|
||||||
if (im->cache_entry.space != EVAS_COLORSPACE_ARGB8888)
|
case EVAS_COLORSPACE_RGB8_ETC2:
|
||||||
|
case EVAS_COLORSPACE_RGBA8_ETC2_EAC:
|
||||||
|
return _save_direct_tgv(im, file, compress);
|
||||||
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
image_stride = im->cache_entry.w;
|
image_stride = im->cache_entry.w;
|
||||||
image_height = im->cache_entry.h;
|
image_height = im->cache_entry.h;
|
||||||
|
|
Loading…
Reference in New Issue