diff options
author | Jean-Philippe Andre <jp.andre@samsung.com> | 2014-07-01 19:10:11 +0900 |
---|---|---|
committer | Jean-Philippe Andre <jp.andre@samsung.com> | 2014-07-03 11:37:48 +0900 |
commit | 81929e34045b9fe95af6b0be76d069fb5b71b885 (patch) | |
tree | c83dda6ef222dd80bd5084a8b7747fdeb9e02846 | |
parent | 79ed3c45168d66245654acabd5ef9f3e714b15a7 (diff) | |
download | efl-81929e34045b9fe95af6b0be76d069fb5b71b885.tar.gz |
Evas: Complete DDS loader with direct S3TC data load
This requires block flip (could be repeat, but flip is just as fast).
-rw-r--r-- | src/modules/evas/loaders/dds/evas_image_load_dds.c | 145 | ||||
-rw-r--r-- | src/modules/evas/loaders/dds/s3tc.h | 6 | ||||
-rw-r--r-- | src/modules/evas/loaders/dds/s3tc_decoder.c | 101 |
3 files changed, 236 insertions, 16 deletions
diff --git a/src/modules/evas/loaders/dds/evas_image_load_dds.c b/src/modules/evas/loaders/dds/evas_image_load_dds.c index dc4fd629ba..cd3f87fb66 100644 --- a/src/modules/evas/loaders/dds/evas_image_load_dds.c +++ b/src/modules/evas/loaders/dds/evas_image_load_dds.c @@ -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); } diff --git a/src/modules/evas/loaders/dds/s3tc.h b/src/modules/evas/loaders/dds/s3tc.h index 91f05f0b5a..3bc965db48 100644 --- a/src/modules/evas/loaders/dds/s3tc.h +++ b/src/modules/evas/loaders/dds/s3tc.h @@ -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 diff --git a/src/modules/evas/loaders/dds/s3tc_decoder.c b/src/modules/evas/loaders/dds/s3tc_decoder.c index a3e09dc98e..f934fbd4a3 100644 --- a/src/modules/evas/loaders/dds/s3tc_decoder.c +++ b/src/modules/evas/loaders/dds/s3tc_decoder.c @@ -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); +} |