summaryrefslogtreecommitdiff
path: root/src/static_libs/rg_etc
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2014-06-09 18:39:39 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2014-06-10 14:58:28 +0900
commit90f58b2a578ee8420ca0fee617b15cd29435a9ed (patch)
tree05b187a7c10ecfffa7121d3cc5425877c7c8525b /src/static_libs/rg_etc
parent173b6bebf9dc079f96d1e434e5506a7d98ec6011 (diff)
Evas ETC2: Implement Planar mode
And this completes the first version of this ETC2 encoder. It's pretty slow and not exhaustive. Color selection for T and H modes could probably be optimized for both performance and quality. As for the planar mode, there is no selection to speak of, as we just take the values of the pixels directly (no scan, very fast) On a sample image with lots of blue, white and noisy gradients, T+H+Planar mode boost the PNSR from 41.22dB to 42.01dB. Without planar mode, the PSNR was 41.94dB. @feature
Diffstat (limited to 'src/static_libs/rg_etc')
-rw-r--r--src/static_libs/rg_etc/etc2_encoder.c212
1 files changed, 191 insertions, 21 deletions
diff --git a/src/static_libs/rg_etc/etc2_encoder.c b/src/static_libs/rg_etc/etc2_encoder.c
index 042667f187..6ac84e89a6 100644
--- a/src/static_libs/rg_etc/etc2_encoder.c
+++ b/src/static_libs/rg_etc/etc2_encoder.c
@@ -535,6 +535,22 @@ _color_reduce_444(uint32_t color)
535 return BGRA(R, G, B, 255); 535 return BGRA(R, G, B, 255);
536} 536}
537 537
538static uint32_t
539_color_reduce_676(uint32_t color)
540{
541 int R = R_VAL(&color);
542 int G = G_VAL(&color);
543 int B = B_VAL(&color);
544 int R1, G1, B1;
545
546 // FIXME: Do we have better candidates to try?
547 R1 = (R & 0xFC) | (R >> 6);
548 G1 = (G & 0xFE) | (G >> 7);
549 B1 = (B & 0xFC) | (B >> 6);
550
551 return BGRA(R1, G1, B1, 255);
552}
553
538static int 554static int
539_block_main_colors_find(uint32_t *color1_out, uint32_t *color2_out, 555_block_main_colors_find(uint32_t *color1_out, uint32_t *color2_out,
540 uint32_t color1, uint32_t color2, const uint32_t *bgra, 556 uint32_t color1, uint32_t color2, const uint32_t *bgra,
@@ -757,6 +773,150 @@ found:
757 return err; 773 return err;
758} 774}
759 775
776static inline Eina_Bool
777_etc2_planar_mode_header_pack(uint8_t *etc2,
778 uint32_t RO, uint32_t RH, uint32_t RV,
779 uint32_t GO, uint32_t GH, uint32_t GV,
780 uint32_t BO, uint32_t BH, uint32_t BV)
781{
782 int R, dR;
783 int G, dG;
784 int B, dB;
785
786 // RO_6 [2..5]
787 R = BITS(RO >> 2, 2, 5);
788 // RO_6 [0..1] + GO_7[6]
789 dR = (BITS(RO >> 2, 0, 1) << 1) | BIT(GO >> 1, 6);
790
791 if (!((R + kSigned3bit[dR] >= 0) && (R + kSigned3bit[dR] <= 31)))
792 R |= 1 << 4;
793
794 // GO_7[2..5]
795 G = BITS(GO >> 1, 2, 5);
796 // GO_7[0..1] + BO_6[5]
797 dG = (BITS(GO >> 1, 0, 1) << 1) | BIT(BO >> 2, 5);
798
799 if (!((G + kSigned3bit[dG] >= 0) && (G + kSigned3bit[dG] <= 31)))
800 G |= 1 << 4;
801
802 // BO_6[3..4]
803 B = BITS(BO >> 2, 3, 4);
804 // BO_6[1..2]
805 dB = BITS(BO >> 2, 1, 2);
806
807 // B + dB must be outside the range.
808 for (int Bx = 0; Bx < 8; Bx++)
809 for (int dBx = 0; dBx < 2; dBx++)
810 {
811 int Btry = B | (Bx << 2);
812 int dBtry = dB | (dBx << 2);
813 if ((Btry + kSigned3bit[dBtry]) < 0 || (Btry + kSigned3bit[dBtry] > 31))
814 {
815 B = Btry;
816 dB = dBtry;
817 break;
818 }
819 }
820
821 if (!((R + kSigned3bit[dR] >= 0) && (R + kSigned3bit[dR] <= 31)))
822 return EINA_FALSE;
823
824 if (!((G + kSigned3bit[dG] >= 0) && (G + kSigned3bit[dG] <= 31)))
825 return EINA_FALSE;
826
827 if ((B + kSigned3bit[dB] >= 0) && (B + kSigned3bit[dB] <= 31))
828 return EINA_FALSE;
829
830 // Write everything
831 etc2[0] = (R << 3) | dR;
832 etc2[1] = (G << 3) | dG;
833 etc2[2] = (B << 3) | dB;
834 etc2[3] = (BIT(BO >> 2, 0) << 7) | (BITS(RH >> 2, 1, 5) << 2) | 0x2 | BIT(RH >> 2, 0);
835 etc2[4] = ((GH >> 1) << 1) | BIT(BH >> 2, 5);
836 etc2[5] = (BITS(BH >> 2, 0, 4) << 3) | BITS(RV >> 2, 3, 5);
837 etc2[6] = (BITS(RV >> 2, 0, 2) << 5) | BITS(GV >> 1, 2, 6);
838 etc2[7] = (BITS(GV >> 1, 0, 1) << 6) | (BV >> 2);
839
840 return EINA_TRUE;
841}
842
843static unsigned int
844_etc2_planar_mode_block_pack(uint8_t *etc2,
845 uint32_t Ocol, uint32_t Hcol, uint32_t Vcol,
846 const uint32_t *bgra, Eina_Bool write)
847{
848 unsigned int err = 0;
849 uint32_t RO, RH, RV, GO, GH, GV, BO, BH, BV;
850
851 RO = R_VAL(&Ocol);
852 RH = R_VAL(&Hcol);
853 RV = R_VAL(&Vcol);
854 GO = G_VAL(&Ocol);
855 GH = G_VAL(&Hcol);
856 GV = G_VAL(&Vcol);
857 BO = B_VAL(&Ocol);
858 BH = B_VAL(&Hcol);
859 BV = B_VAL(&Vcol);
860
861 if (write)
862 {
863 if (!_etc2_planar_mode_header_pack(etc2, RO, RH, RV, GO, GH, GV, BO, BH, BV))
864 return INT_MAX;
865 }
866
867 // Compute MSE, that's all we need to do
868
869 for (int y = 0; y < 4; y++)
870 for (int x = 0; x < 4; x++)
871 {
872 const int R = CLAMP(((x * (RH - RO)) + y * (RV - RO) + 4 * RO + 2) >> 2);
873 const int G = CLAMP(((x * (GH - GO)) + y * (GV - GO) + 4 * GO + 2) >> 2);
874 const int B = CLAMP(((x * (BH - BO)) + y * (BV - BO) + 4 * BO + 2) >> 2);
875 uint32_t color = BGRA(R, G, B, 255);
876
877 err += _rgb_distance_euclid(color, bgra[x + y * 4]);
878 }
879
880 return err;
881}
882
883static unsigned int
884_etc2_planar_mode_block_encode(uint8_t *etc2, const uint32_t *bgra,
885 const rg_etc1_pack_params *params EINA_UNUSED)
886{
887 unsigned int err;
888 unsigned int Ocol, Hcol, Vcol, RO, GO, BO, Rx, Gx, Bx;
889
890 // TODO: Scan a broader range to avoid artifacts when the
891 // points O, H or V are exceptions
892
893 /* O is at (0,0)
894 * H is at (4,0)
895 * V is at (0,4)
896 * So, H and V are outside the block.
897 * We extrapolate the values from (0,3) and (3,0).
898 */
899
900 RO = R_VAL(&(bgra[0]));
901 GO = G_VAL(&(bgra[0]));
902 BO = B_VAL(&(bgra[0]));
903 Ocol = _color_reduce_676(bgra[0]);
904
905 Rx = CLAMP(RO + (4 * (R_VAL(&(bgra[3])) - RO)) / 3);
906 Gx = CLAMP(GO + (4 * (G_VAL(&(bgra[3])) - GO)) / 3);
907 Bx = CLAMP(BO + (4 * (B_VAL(&(bgra[3])) - BO)) / 3);
908 Hcol = _color_reduce_676(BGRA(Rx, Gx, Bx, 0xFF));
909
910 Rx = CLAMP(RO + (4 * (R_VAL(&(bgra[12])) - RO)) / 3);
911 Gx = CLAMP(GO + (4 * (G_VAL(&(bgra[12])) - GO)) / 3);
912 Bx = CLAMP(BO + (4 * (B_VAL(&(bgra[12])) - BO)) / 3);
913 Vcol = _color_reduce_676(BGRA(Rx, Gx, Bx, 0xFF));
914
915 err = _etc2_planar_mode_block_pack(etc2, Ocol, Hcol, Vcol, bgra, EINA_TRUE);
916
917 return err;
918}
919
760static unsigned int 920static unsigned int
761_block_error_calc(const uint32_t *enc, const uint32_t *orig, Eina_Bool perceptual) 921_block_error_calc(const uint32_t *enc, const uint32_t *orig, Eina_Bool perceptual)
762{ 922{
@@ -778,34 +938,39 @@ etc2_rgba8_block_pack(unsigned char *etc2, const unsigned int *bgra,
778 rg_etc1_pack_params *params) 938 rg_etc1_pack_params *params)
779{ 939{
780 rg_etc1_pack_params safe_params; 940 rg_etc1_pack_params safe_params;
781 unsigned int errors[2], minErr = INT_MAX; 941 unsigned int errors[3] = { INT_MAX, INT_MAX, INT_MAX };
782 uint8_t etc2_try[2][8]; 942 unsigned int minErr = INT_MAX;
943 uint8_t etc2_try[3][8];
783 int bestSolution = 0; 944 int bestSolution = 0;
784 945
946#ifdef DEBUG
947 static int cnt [3] = {0};
948#endif
949
785 safe_params.m_dithering = !!params->m_dithering; 950 safe_params.m_dithering = !!params->m_dithering;
786 safe_params.m_quality = MINMAX(params->m_quality, 0, 2); 951 safe_params.m_quality = MINMAX(params->m_quality, 0, 2);
787 952
788 // TODO: H mode, Planar mode
789
790 errors[0] = rg_etc1_pack_block(etc2_try[0], bgra, &safe_params); 953 errors[0] = rg_etc1_pack_block(etc2_try[0], bgra, &safe_params);
791 errors[1] = _etc2_th_mode_block_encode(etc2_try[1], bgra, &safe_params); 954 errors[1] = _etc2_th_mode_block_encode(etc2_try[1], bgra, &safe_params);
955 errors[2] = _etc2_planar_mode_block_encode(etc2_try[2], bgra, &safe_params);
792 956
793#ifdef DEBUG 957#ifdef DEBUG
794 if (errors[1] < INT_MAX) 958 for (int i = 1; i < 3; i++)
795 for (unsigned k = 0; k < sizeof(errors) / sizeof(*errors); k++) 959 {
796 { 960 const char *mode = (i == 1) ? "T or H" : "Planar";
797 uint32_t decoded[16]; 961 if (errors[i] < INT_MAX)
798 unsigned int real_errors[2]; 962 for (unsigned k = 0; k < sizeof(errors) / sizeof(*errors); k++)
799 rg_etc2_rgb8_decode_block(etc2_try[1], decoded);
800 real_errors[0] = _block_error_calc(decoded, bgra, EINA_FALSE);
801 real_errors[1] = _block_error_calc(decoded, bgra, EINA_TRUE);
802
803 if (real_errors[0] != errors[1])
804 { 963 {
805 DBG("Invalid error calc in T or H mode"); 964 uint32_t decoded[16];
806 //errors[1] = real_errors[0]; 965 unsigned int real_errors[2];
966 rg_etc2_rgb8_decode_block(etc2_try[i], decoded);
967 real_errors[0] = _block_error_calc(decoded, bgra, EINA_FALSE);
968 real_errors[1] = _block_error_calc(decoded, bgra, EINA_TRUE);
969
970 if (real_errors[0] != errors[i])
971 DBG("Invalid error calc in %s mode", mode);
807 } 972 }
808 } 973 }
809#endif 974#endif
810 975
811 for (unsigned k = 0; k < sizeof(errors) / sizeof(*errors); k++) 976 for (unsigned k = 0; k < sizeof(errors) / sizeof(*errors); k++)
@@ -819,6 +984,11 @@ etc2_rgba8_block_pack(unsigned char *etc2, const unsigned int *bgra,
819 984
820 minErr += _etc2_alpha_encode(etc2, bgra, &safe_params); 985 minErr += _etc2_alpha_encode(etc2, bgra, &safe_params);
821 986
987#ifdef DEBUG
988 cnt[bestSolution]++;
989 DBG("Block count by mode: ETC1: %d T/H: %d Planar: %d", cnt[0], cnt[1], cnt[2]);
990#endif
991
822 return minErr; 992 return minErr;
823} 993}
824 994
@@ -827,17 +997,17 @@ etc2_rgb8_block_pack(unsigned char *etc2, const unsigned int *bgra,
827 rg_etc1_pack_params *params) 997 rg_etc1_pack_params *params)
828{ 998{
829 rg_etc1_pack_params safe_params; 999 rg_etc1_pack_params safe_params;
830 unsigned int errors[2], minErr = INT_MAX; 1000 unsigned int errors[3] = { INT_MAX, INT_MAX, INT_MAX };
831 uint8_t etc2_try[8][2]; 1001 unsigned int minErr = INT_MAX;
1002 uint8_t etc2_try[3][8];
832 int bestSolution = 0; 1003 int bestSolution = 0;
833 1004
834 safe_params.m_dithering = !!params->m_dithering; 1005 safe_params.m_dithering = !!params->m_dithering;
835 safe_params.m_quality = MINMAX(params->m_quality, 0, 2); 1006 safe_params.m_quality = MINMAX(params->m_quality, 0, 2);
836 1007
837 // TODO: Planar mode
838
839 errors[0] = rg_etc1_pack_block(etc2_try[0], bgra, &safe_params); 1008 errors[0] = rg_etc1_pack_block(etc2_try[0], bgra, &safe_params);
840 errors[1] = _etc2_th_mode_block_encode(etc2_try[1], bgra, &safe_params); 1009 errors[1] = _etc2_th_mode_block_encode(etc2_try[1], bgra, &safe_params);
1010 errors[2] = _etc2_planar_mode_block_encode(etc2_try[2], bgra, &safe_params);
841 1011
842 for (unsigned k = 0; k < sizeof(errors) / sizeof(*errors); k++) 1012 for (unsigned k = 0; k < sizeof(errors) / sizeof(*errors); k++)
843 if (errors[k] < minErr) 1013 if (errors[k] < minErr)