Home | History | Annotate | Download | only in tests
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "Test.h"
      9 #include "SkColor.h"
     10 #include "SkColorPriv.h"
     11 #include "SkMathPriv.h"
     12 #include "SkRandom.h"
     13 #include "SkUnPreMultiply.h"
     14 
     15 #define GetPackedR16As32(packed)    (SkGetPackedR16(dc) << (8 - SK_R16_BITS))
     16 #define GetPackedG16As32(packed)    (SkGetPackedG16(dc) << (8 - SK_G16_BITS))
     17 #define GetPackedB16As32(packed)    (SkGetPackedB16(dc) << (8 - SK_B16_BITS))
     18 
     19 static inline bool S32A_D565_Blend_0(SkPMColor sc, uint16_t dc, U8CPU alpha) {
     20     unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha);
     21     unsigned dr = SkMulS16(SkPacked32ToR16(sc), alpha) + SkMulS16(SkGetPackedR16(dc), dst_scale);
     22     unsigned dg = SkMulS16(SkPacked32ToG16(sc), alpha) + SkMulS16(SkGetPackedG16(dc), dst_scale);
     23 
     24     unsigned rr = SkDiv255Round(dr);
     25     unsigned rg = SkDiv255Round(dg);
     26 
     27     if (rr <= 31 && rg <= 63) {
     28         return true;
     29     }
     30     return false;
     31 }
     32 
     33 static inline bool S32A_D565_Blend_01(SkPMColor sc, uint16_t dc, U8CPU alpha) {
     34     unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha);
     35     unsigned dr = SkMulS16(SkGetPackedR32(sc), alpha) + SkMulS16(SkGetPackedR16(dc) << 3, dst_scale);
     36     unsigned dg = SkMulS16(SkGetPackedG32(sc), alpha) + SkMulS16(SkGetPackedG16(dc) << 2, dst_scale);
     37 
     38     unsigned rr = SkDiv255Round(dr) >> 3;
     39     unsigned rg = SkDiv255Round(dg) >> 2;
     40 
     41     if (rr <= 31 && rg <= 63) {
     42         return true;
     43     }
     44     return false;
     45 }
     46 
     47 static inline bool S32A_D565_Blend_02(SkPMColor sc, uint16_t dc, U8CPU alpha) {
     48     unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha);
     49     unsigned dr = SkMulS16(SkGetPackedR32(sc), alpha) + SkMulS16(GetPackedR16As32(dc), dst_scale);
     50     unsigned dg = SkMulS16(SkGetPackedG32(sc), alpha) + SkMulS16(GetPackedG16As32(dc), dst_scale);
     51     unsigned db = SkMulS16(SkGetPackedB32(sc), alpha) + SkMulS16(GetPackedB16As32(dc), dst_scale);
     52     int rc = SkPack888ToRGB16(SkDiv255Round(dr),
     53                               SkDiv255Round(dg),
     54                               SkDiv255Round(db));
     55 
     56     unsigned rr = SkGetPackedR16(rc);
     57     unsigned rg = SkGetPackedG16(rc);
     58 
     59     if (rr <= 31 && rg <= 63) {
     60         return true;
     61     }
     62     return false;
     63 }
     64 
     65 static inline bool S32A_D565_Blend_1(SkPMColor sc, uint16_t dc, U8CPU alpha) {
     66     unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha);
     67     unsigned dr = (SkMulS16(SkGetPackedR32(sc), alpha) >> 3) + SkMulS16(SkGetPackedR16(dc), dst_scale);
     68     unsigned dg = (SkMulS16(SkGetPackedG32(sc), alpha) >> 2) + SkMulS16(SkGetPackedG16(dc), dst_scale);
     69 
     70     unsigned rr = SkDiv255Round(dr);
     71     unsigned rg = SkDiv255Round(dg);
     72 
     73     if (rr <= 31 && rg <= 63) {
     74         return true;
     75     }
     76     return false;
     77 }
     78 
     79 static inline int SkDiv65025Round(int x) {
     80     return (x + 65025/2) / 65025;
     81 //    return x / 65025;
     82 }
     83 static inline bool S32A_D565_Blend_2(SkPMColor sc, uint16_t dc, U8CPU alpha) {
     84     unsigned dst_scale = 255*255 - SkGetPackedA32(sc) * alpha;
     85     alpha *= 255;
     86     unsigned dr = (SkGetPackedR32(sc) >> 3) * alpha + SkGetPackedR16(dc) * dst_scale;
     87     unsigned dg = (SkGetPackedG32(sc) >> 2) * alpha + SkGetPackedG16(dc) * dst_scale;
     88 
     89     unsigned rr = SkDiv65025Round(dr);
     90     unsigned rg = SkDiv65025Round(dg);
     91 
     92     if (rr <= 31 && rg <= 63) {
     93         return true;
     94     }
     95     return false;
     96 }
     97 
     98 static inline void test_565blend() {
     99     int total_failures = 0;
    100     for (int global_alpha = 0; global_alpha <= 255; ++global_alpha) {
    101         int failures = 0;
    102         int total = 0;
    103         for (int src_a = 0; src_a <= 255; ++src_a) {
    104             for (int src_c = 0; src_c <= src_a; ++src_c) {
    105                 SkPMColor sc = SkPackARGB32(src_a, src_c, src_c, src_c);
    106                 for (int dst_r = 0; dst_r <= 31; ++dst_r) {
    107                     for (int dst_g = 0; dst_g <= 63; ++dst_g) {
    108                         uint16_t dc = SkPackRGB16(dst_r, dst_g, dst_r);
    109                         failures += !S32A_D565_Blend_0(sc, dc, global_alpha);
    110                         total += 1;
    111                     }
    112                 }
    113             }
    114         }
    115         SkDebugf("global_alpha=%d failures=%d total=%d %g\n", global_alpha, failures, total, failures * 100.0 / total);
    116         total_failures += failures;
    117     }
    118     SkDebugf("total failures %d\n", total_failures);
    119 }
    120 
    121 static inline void test_premul(skiatest::Reporter* reporter) {
    122     for (int a = 0; a <= 255; a++) {
    123         for (int x = 0; x <= 255; x++) {
    124             SkColor c0 = SkColorSetARGB(a, x, x, x);
    125             SkPMColor p0 = SkPreMultiplyColor(c0);
    126 
    127             SkColor c1 = SkUnPreMultiply::PMColorToColor(p0);
    128             SkPMColor p1 = SkPreMultiplyColor(c1);
    129 
    130             // we can't promise that c0 == c1, since c0 -> p0 is a many to one
    131             // function, however, we can promise that p0 -> c1 -> p1 : p0 == p1
    132             REPORTER_ASSERT(reporter, p0 == p1);
    133 
    134             {
    135                 int ax = SkMulDiv255Ceiling(x, a);
    136                 REPORTER_ASSERT(reporter, ax <= a);
    137             }
    138         }
    139     }
    140 }
    141 
    142 /**
    143   This test fails: SkFourByteInterp does *not* preserve opaque destinations.
    144   SkAlpha255To256 implemented as (alpha + 1) is faster than
    145   (alpha + (alpha >> 7)), but inaccurate, and Skia intends to phase it out.
    146 */
    147 /*
    148 static void test_interp(skiatest::Reporter* reporter) {
    149     SkMWCRandom r;
    150 
    151     U8CPU a0 = 0;
    152     U8CPU a255 = 255;
    153     for (int i = 0; i < 200; i++) {
    154         SkColor colorSrc = r.nextU();
    155         SkColor colorDst = r.nextU();
    156         SkPMColor src = SkPreMultiplyColor(colorSrc);
    157         SkPMColor dst = SkPreMultiplyColor(colorDst);
    158 
    159         REPORTER_ASSERT(reporter, SkFourByteInterp(src, dst, a0) == dst);
    160         REPORTER_ASSERT(reporter, SkFourByteInterp(src, dst, a255) == src);
    161     }
    162 }
    163 */
    164 
    165 static inline void test_fast_interp(skiatest::Reporter* reporter) {
    166     SkMWCRandom r;
    167 
    168     U8CPU a0 = 0;
    169     U8CPU a255 = 255;
    170     for (int i = 0; i < 200; i++) {
    171         SkColor colorSrc = r.nextU();
    172         SkColor colorDst = r.nextU();
    173         SkPMColor src = SkPreMultiplyColor(colorSrc);
    174         SkPMColor dst = SkPreMultiplyColor(colorDst);
    175 
    176         REPORTER_ASSERT(reporter, SkFastFourByteInterp(src, dst, a0) == dst);
    177         REPORTER_ASSERT(reporter, SkFastFourByteInterp(src, dst, a255) == src);
    178     }
    179 }
    180 
    181 static void TestColor(skiatest::Reporter* reporter) {
    182     test_premul(reporter);
    183     //test_interp(reporter);
    184     test_fast_interp(reporter);
    185 //    test_565blend();
    186 }
    187 
    188 #include "TestClassDef.h"
    189 DEFINE_TESTCLASS("Color", ColorTestClass, TestColor)
    190