summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2014-07-01 19:10:11 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2014-07-03 11:37:48 +0900
commit81929e34045b9fe95af6b0be76d069fb5b71b885 (patch)
treec83dda6ef222dd80bd5084a8b7747fdeb9e02846
parent79ed3c45168d66245654acabd5ef9f3e714b15a7 (diff)
downloadefl-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.c145
-rw-r--r--src/modules/evas/loaders/dds/s3tc.h6
-rw-r--r--src/modules/evas/loaders/dds/s3tc_decoder.c101
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);
+}