Evas: Complete DDS loader with direct S3TC data load

This requires block flip (could be repeat, but flip is just as fast).
This commit is contained in:
Jean-Philippe Andre 2014-07-01 19:10:11 +09:00
parent 79ed3c4516
commit 81929e3404
3 changed files with 236 additions and 16 deletions

View File

@ -214,7 +214,7 @@ evas_image_load_file_head_dds(void *loader_data,
height = _dword_read(&m);
width = _dword_read(&m);
pitchOrLinearSize = _dword_read(&m);
if (!width || !height || (width & 0x3) || (height & 0x3))
if (!width || !height)
FAIL();
// Skip depth & mipmap count + reserved[11]
@ -302,6 +302,10 @@ evas_image_load_file_head_dds(void *loader_data,
prop->h = height;
prop->w = width;
prop->borders.l = 4;
prop->borders.t = 4;
prop->borders.r = 4 - (prop->w & 0x3);
prop->borders.b = 4 - (prop->h & 0x3);
*error = EVAS_LOAD_ERROR_NONE;
on_error:
@ -309,6 +313,134 @@ on_error:
return (*error == EVAS_LOAD_ERROR_NONE);
}
static Eina_Bool
_dds_data_load(Evas_Loader_Internal *loader, Evas_Image_Property *prop,
unsigned char *map, void *pixels, int *error)
{
const unsigned char *src;
int bsize = 16, srcstride, dststride, w, h;
unsigned char *dst;
void (* flip) (unsigned char *, const unsigned char *, int) = NULL;
*error = EVAS_LOAD_ERROR_GENERIC;
if (loader->format != prop->cspace)
FAIL();
switch (loader->format)
{
case EVAS_COLORSPACE_RGB_S3TC_DXT1:
case EVAS_COLORSPACE_RGBA_S3TC_DXT1:
flip = s3tc_encode_dxt1_flip;
bsize = 8;
break;
case EVAS_COLORSPACE_RGBA_S3TC_DXT2:
flip = s3tc_encode_dxt2_rgba_flip;
bsize = 16;
break;
case EVAS_COLORSPACE_RGBA_S3TC_DXT3:
flip = s3tc_encode_dxt3_rgba_flip;
bsize = 16;
break;
case EVAS_COLORSPACE_RGBA_S3TC_DXT4:
flip = s3tc_encode_dxt4_rgba_flip;
bsize = 16;
break;
case EVAS_COLORSPACE_RGBA_S3TC_DXT5:
flip = s3tc_encode_dxt5_rgba_flip;
bsize = 16;
break;
default: FAIL();
}
src = map + DDS_HEADER_SIZE;
w = prop->w;
h = prop->h;
srcstride = ((prop->w + 3) / 4) * bsize;
dststride = ((prop->w + prop->borders.l + prop->borders.r) / 4) * bsize;
// asserts
EINA_SAFETY_ON_FALSE_GOTO(prop->borders.l == 4, on_error);
EINA_SAFETY_ON_FALSE_GOTO(prop->borders.t == 4, on_error);
EINA_SAFETY_ON_FALSE_GOTO(prop->borders.r == (4 - (w & 0x3)), on_error);
EINA_SAFETY_ON_FALSE_GOTO(prop->borders.b == (4 - (h & 0x3)), on_error);
if (eina_file_size_get(loader->f) <
(size_t) (DDS_HEADER_SIZE + srcstride * h / 4))
{
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
goto on_error;
}
// First, copy the real data
for (int y = 0; y < h; y += 4)
{
dst = ((unsigned char *) pixels) + ((y / 4) + 1) * dststride + bsize;
memcpy(dst, src, srcstride);
src += srcstride;
}
// Top
for (int x = 0; x < w; x += 4)
{
src = map + DDS_HEADER_SIZE + (x / 4) * bsize;
dst = ((unsigned char *) pixels) + ((x / 4) + 1) * bsize;
flip(dst, src, EINA_TRUE);
}
// Left
for (int y = 0; y < h; y += 4)
{
src = map + DDS_HEADER_SIZE + (y / 4) * srcstride;
dst = ((unsigned char *) pixels) + ((y / 4) + 1) * dststride;
flip(dst, src, EINA_FALSE);
}
// Top-left
dst = pixels;
src = dst + bsize;
flip(dst, src, EINA_FALSE);
// Right
if ((prop->w & 0x3) == 0)
{
for (int y = 0; y < h; y += 4)
{
src = map + DDS_HEADER_SIZE + ((y / 4) + 1) * srcstride - bsize;
dst = ((unsigned char *) pixels) + ((y / 4) + 2) * dststride - bsize;
flip(dst, src, EINA_FALSE);
}
// Top-right
dst = ((unsigned char *) pixels) + dststride - bsize;
src = dst - bsize;
flip(dst, src, EINA_FALSE);
}
// Bottom
if ((prop->h & 0x3) == 0)
{
for (int x = 0; x < w; x += 4)
{
src = map + DDS_HEADER_SIZE + ((h / 4) - 1) * srcstride + (x / 4) * bsize;
dst = ((unsigned char *) pixels) + ((h / 4) + 1) * dststride + ((x / 4) + 1) * bsize;
flip(dst, src, EINA_TRUE);
}
// Bottom-left
dst = ((unsigned char *) pixels) + ((h / 4) + 1) * dststride;
src = dst + bsize;
flip(dst, src, EINA_FALSE);
if ((prop->w & 0x3) == 0)
{
// Bottom-right
dst = ((unsigned char *) pixels) + ((h / 4) + 2) * dststride - bsize;
src = dst - bsize;
flip(dst, src, EINA_FALSE);
}
}
*error = EVAS_LOAD_ERROR_NONE;
on_error:
eina_file_map_free(loader->f, (void *) map);
return (*error == EVAS_LOAD_ERROR_NONE);
}
Eina_Bool
evas_image_load_file_data_dds(void *loader_data,
Evas_Image_Property *prop,
@ -332,14 +464,7 @@ evas_image_load_file_data_dds(void *loader_data,
FAIL();
if (prop->cspace != EVAS_COLORSPACE_ARGB8888)
{
if (loader->format != prop->cspace)
FAIL();
memcpy(pixels, src, loader->data_size);
*error = EVAS_LOAD_ERROR_NONE;
eina_file_map_free(loader->f, (void *) src);
return EINA_TRUE;
}
return _dds_data_load(loader, prop, map, pixels, error);
// Decode to BGRA
switch (loader->format)
@ -399,7 +524,7 @@ evas_image_load_file_data_dds(void *loader_data,
*error = EVAS_LOAD_ERROR_NONE;
on_error:
eina_file_map_free(loader->f, (void *) src);
eina_file_map_free(loader->f, (void *) map);
return (*error == EVAS_LOAD_ERROR_NONE);
}

View File

@ -8,4 +8,10 @@ void s3tc_decode_dxt3_rgba(unsigned int *bgra, const unsigned char *s3tc);
void s3tc_decode_dxt4_rgba(unsigned int *bgra, const unsigned char *s3tc);
void s3tc_decode_dxt5_rgba(unsigned int *bgra, const unsigned char *s3tc);
void s3tc_encode_dxt1_flip(unsigned char *dest, const unsigned char *orig, int vflip);
void s3tc_encode_dxt2_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip);
void s3tc_encode_dxt3_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip);
void s3tc_encode_dxt4_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip);
void s3tc_encode_dxt5_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip);
#endif // EFL_S3TC_H

View File

@ -95,36 +95,125 @@ _decode_dxt_alpha(unsigned int *bgra, const unsigned char *s3tc)
}
}
void s3tc_decode_dxt1_rgb(unsigned int *bgra, const unsigned char *s3tc)
void
s3tc_decode_dxt1_rgb(unsigned int *bgra, const unsigned char *s3tc)
{
_decode_dxt1_rgb(bgra, s3tc, 0xFF000000, EINA_TRUE, EINA_FALSE);
}
void s3tc_decode_dxt1_rgba(unsigned int *bgra, const unsigned char *s3tc)
void
s3tc_decode_dxt1_rgba(unsigned int *bgra, const unsigned char *s3tc)
{
_decode_dxt1_rgb(bgra, s3tc, 0xFF000000, EINA_TRUE, EINA_TRUE);
}
void s3tc_decode_dxt2_rgba(unsigned int *bgra, const unsigned char *s3tc)
void
s3tc_decode_dxt2_rgba(unsigned int *bgra, const unsigned char *s3tc)
{
_decode_dxt1_rgb(bgra, s3tc + 8, 0x0, EINA_FALSE, EINA_FALSE);
_decode_alpha4(bgra, s3tc);
}
void s3tc_decode_dxt3_rgba(unsigned int *bgra, const unsigned char *s3tc)
void
s3tc_decode_dxt3_rgba(unsigned int *bgra, const unsigned char *s3tc)
{
_decode_dxt1_rgb(bgra, s3tc + 8, 0x0, EINA_FALSE, EINA_FALSE);
_decode_alpha4(bgra, s3tc);
}
void s3tc_decode_dxt4_rgba(unsigned int *bgra, const unsigned char *s3tc)
void
s3tc_decode_dxt4_rgba(unsigned int *bgra, const unsigned char *s3tc)
{
_decode_dxt1_rgb(bgra, s3tc + 8, 0x0, EINA_FALSE, EINA_FALSE);
_decode_dxt_alpha(bgra, s3tc);
}
void s3tc_decode_dxt5_rgba(unsigned int *bgra, const unsigned char *s3tc)
void
s3tc_decode_dxt5_rgba(unsigned int *bgra, const unsigned char *s3tc)
{
_decode_dxt1_rgb(bgra, s3tc + 8, 0x0, EINA_FALSE, EINA_FALSE);
_decode_dxt_alpha(bgra, s3tc);
}
/* Fast re-encode functions to flip S3TC blocks */
static inline unsigned char
_byte_2222_flip(unsigned char src)
{
return ((src & (0x3 << 6)) >> 6) |
((src & (0x3 << 4)) >> 2) |
((src & (0x3 << 2)) << 2) |
((src & 0x3) << 6);
}
static inline unsigned char
_byte_44_flip(unsigned char src)
{
return ((src & 0xF0) >> 4) | ((src & 0x0F) << 4);
}
void
s3tc_encode_dxt1_flip(unsigned char *dest, const unsigned char *orig, int vflip)
{
dest[0] = orig[0];
dest[1] = orig[1];
dest[2] = orig[2];
dest[3] = orig[3];
if (vflip)
{
dest[4] = orig[7];
dest[5] = orig[6];
dest[6] = orig[5];
dest[7] = orig[4];
}
else
{
dest[4] = _byte_2222_flip(orig[4]);
dest[5] = _byte_2222_flip(orig[5]);
dest[6] = _byte_2222_flip(orig[6]);
dest[7] = _byte_2222_flip(orig[7]);
}
}
void
s3tc_encode_dxt2_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip)
{
if (vflip)
{
dest[0] = orig[6];
dest[1] = orig[7];
dest[2] = orig[4];
dest[3] = orig[5];
dest[4] = orig[2];
dest[5] = orig[3];
dest[6] = orig[0];
dest[7] = orig[1];
}
else
{
for (int k = 0; k < 8; k += 2)
{
dest[0+k] = _byte_44_flip(orig[1+k]);
dest[1+k] = _byte_44_flip(orig[0+k]);
}
}
s3tc_encode_dxt1_flip(dest + 8, orig + 8, vflip);
}
void
s3tc_encode_dxt3_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip)
{
s3tc_encode_dxt2_rgba_flip(dest, orig, vflip);
}
void s3tc_encode_dxt4_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip)
{
s3tc_encode_dxt1_flip(dest, orig, vflip);
s3tc_encode_dxt1_flip(dest + 8, orig + 8, vflip);
}
void s3tc_encode_dxt5_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip)
{
s3tc_encode_dxt4_rgba_flip(dest, orig, vflip);
}