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 "SkFloatingPoint.h"
     10 #include "SkMath.h"
     11 #include "SkPoint.h"
     12 #include "SkRandom.h"
     13 #include "SkColorPriv.h"
     14 
     15 static float float_blend(int src, int dst, float unit) {
     16     return dst + (src - dst) * unit;
     17 }
     18 
     19 static int blend31(int src, int dst, int a31) {
     20     return dst + ((src - dst) * a31 * 2114 >> 16);
     21     //    return dst + ((src - dst) * a31 * 33 >> 10);
     22 }
     23 
     24 static int blend31_slow(int src, int dst, int a31) {
     25     int prod = src * a31 + (31 - a31) * dst + 16;
     26     prod = (prod + (prod >> 5)) >> 5;
     27     return prod;
     28 }
     29 
     30 static int blend31_round(int src, int dst, int a31) {
     31     int prod = (src - dst) * a31 + 16;
     32     prod = (prod + (prod >> 5)) >> 5;
     33     return dst + prod;
     34 }
     35 
     36 static int blend31_old(int src, int dst, int a31) {
     37     a31 += a31 >> 4;
     38     return dst + ((src - dst) * a31 >> 5);
     39 }
     40 
     41 static void test_blend31() {
     42     int failed = 0;
     43     int death = 0;
     44     for (int src = 0; src <= 255; src++) {
     45         for (int dst = 0; dst <= 255; dst++) {
     46             for (int a = 0; a <= 31; a++) {
     47 //                int r0 = blend31(src, dst, a);
     48 //                int r0 = blend31_round(src, dst, a);
     49 //                int r0 = blend31_old(src, dst, a);
     50                 int r0 = blend31_slow(src, dst, a);
     51 
     52                 float f = float_blend(src, dst, a / 31.f);
     53                 int r1 = (int)f;
     54                 int r2 = SkScalarRoundToInt(SkFloatToScalar(f));
     55 
     56                 if (r0 != r1 && r0 != r2) {
     57                     printf("src:%d dst:%d a:%d result:%d float:%g\n",
     58                                  src, dst, a, r0, f);
     59                     failed += 1;
     60                 }
     61                 if (r0 > 255) {
     62                     death += 1;
     63                     printf("death src:%d dst:%d a:%d result:%d float:%g\n",
     64                            src, dst, a, r0, f);
     65                 }
     66             }
     67         }
     68     }
     69     SkDebugf("---- failed %d death %d\n", failed, death);
     70 }
     71 
     72 static void test_blend(skiatest::Reporter* reporter) {
     73     for (int src = 0; src <= 255; src++) {
     74         for (int dst = 0; dst <= 255; dst++) {
     75             for (int a = 0; a <= 255; a++) {
     76                 int r0 = SkAlphaBlend255(src, dst, a);
     77                 float f1 = float_blend(src, dst, a / 255.f);
     78                 int r1 = SkScalarRoundToInt(SkFloatToScalar(f1));
     79 
     80                 if (r0 != r1) {
     81                     float diff = sk_float_abs(f1 - r1);
     82                     diff = sk_float_abs(diff - 0.5f);
     83                     if (diff > (1 / 255.f)) {
     84 #ifdef SK_DEBUG
     85                         SkDebugf("src:%d dst:%d a:%d result:%d float:%g\n",
     86                                  src, dst, a, r0, f1);
     87 #endif
     88                         REPORTER_ASSERT(reporter, false);
     89                     }
     90                 }
     91             }
     92         }
     93     }
     94 }
     95 
     96 #if defined(SkLONGLONG)
     97 static int symmetric_fixmul(int a, int b) {
     98     int sa = SkExtractSign(a);
     99     int sb = SkExtractSign(b);
    100 
    101     a = SkApplySign(a, sa);
    102     b = SkApplySign(b, sb);
    103 
    104 #if 1
    105     int c = (int)(((SkLONGLONG)a * b) >> 16);
    106 
    107     return SkApplySign(c, sa ^ sb);
    108 #else
    109     SkLONGLONG ab = (SkLONGLONG)a * b;
    110     if (sa ^ sb) {
    111         ab = -ab;
    112     }
    113     return ab >> 16;
    114 #endif
    115 }
    116 #endif
    117 
    118 static void check_length(skiatest::Reporter* reporter,
    119                          const SkPoint& p, SkScalar targetLen) {
    120 #ifdef SK_CAN_USE_FLOAT
    121     float x = SkScalarToFloat(p.fX);
    122     float y = SkScalarToFloat(p.fY);
    123     float len = sk_float_sqrt(x*x + y*y);
    124 
    125     len /= SkScalarToFloat(targetLen);
    126 
    127     REPORTER_ASSERT(reporter, len > 0.999f && len < 1.001f);
    128 #endif
    129 }
    130 
    131 #if defined(SK_CAN_USE_FLOAT)
    132 
    133 static float nextFloat(SkRandom& rand) {
    134     SkFloatIntUnion data;
    135     data.fSignBitInt = rand.nextU();
    136     return data.fFloat;
    137 }
    138 
    139 /*  returns true if a == b as resulting from (int)x. Since it is undefined
    140  what to do if the float exceeds 2^32-1, we check for that explicitly.
    141  */
    142 static bool equal_float_native_skia(float x, uint32_t ni, uint32_t si) {
    143     if (!(x == x)) {    // NAN
    144         return si == SK_MaxS32 || si == SK_MinS32;
    145     }
    146     // for out of range, C is undefined, but skia always should return NaN32
    147     if (x > SK_MaxS32) {
    148         return si == SK_MaxS32;
    149     }
    150     if (x < -SK_MaxS32) {
    151         return si == SK_MinS32;
    152     }
    153     return si == ni;
    154 }
    155 
    156 static void assert_float_equal(skiatest::Reporter* reporter, const char op[],
    157                                float x, uint32_t ni, uint32_t si) {
    158     if (!equal_float_native_skia(x, ni, si)) {
    159         SkString desc;
    160         desc.printf("%s float %g bits %x native %x skia %x\n", op, x, ni, si);
    161         reporter->reportFailed(desc);
    162     }
    163 }
    164 
    165 static void test_float_cast(skiatest::Reporter* reporter, float x) {
    166     int ix = (int)x;
    167     int iix = SkFloatToIntCast(x);
    168     assert_float_equal(reporter, "cast", x, ix, iix);
    169 }
    170 
    171 static void test_float_floor(skiatest::Reporter* reporter, float x) {
    172     int ix = (int)floor(x);
    173     int iix = SkFloatToIntFloor(x);
    174     assert_float_equal(reporter, "floor", x, ix, iix);
    175 }
    176 
    177 static void test_float_round(skiatest::Reporter* reporter, float x) {
    178     double xx = x + 0.5;    // need intermediate double to avoid temp loss
    179     int ix = (int)floor(xx);
    180     int iix = SkFloatToIntRound(x);
    181     assert_float_equal(reporter, "round", x, ix, iix);
    182 }
    183 
    184 static void test_float_ceil(skiatest::Reporter* reporter, float x) {
    185     int ix = (int)ceil(x);
    186     int iix = SkFloatToIntCeil(x);
    187     assert_float_equal(reporter, "ceil", x, ix, iix);
    188 }
    189 
    190 static void test_float_conversions(skiatest::Reporter* reporter, float x) {
    191     test_float_cast(reporter, x);
    192     test_float_floor(reporter, x);
    193     test_float_round(reporter, x);
    194     test_float_ceil(reporter, x);
    195 }
    196 
    197 static void test_int2float(skiatest::Reporter* reporter, int ival) {
    198     float x0 = (float)ival;
    199     float x1 = SkIntToFloatCast(ival);
    200     float x2 = SkIntToFloatCast_NoOverflowCheck(ival);
    201     REPORTER_ASSERT(reporter, x0 == x1);
    202     REPORTER_ASSERT(reporter, x0 == x2);
    203 }
    204 
    205 static void unittest_fastfloat(skiatest::Reporter* reporter) {
    206     SkRandom rand;
    207     size_t i;
    208 
    209     static const float gFloats[] = {
    210         0.f, 1.f, 0.5f, 0.499999f, 0.5000001f, 1.f/3,
    211         0.000000001f, 1000000000.f,     // doesn't overflow
    212         0.0000000001f, 10000000000.f    // does overflow
    213     };
    214     for (i = 0; i < SK_ARRAY_COUNT(gFloats); i++) {
    215         test_float_conversions(reporter, gFloats[i]);
    216         test_float_conversions(reporter, -gFloats[i]);
    217     }
    218 
    219     for (int outer = 0; outer < 100; outer++) {
    220         rand.setSeed(outer);
    221         for (i = 0; i < 100000; i++) {
    222             float x = nextFloat(rand);
    223             test_float_conversions(reporter, x);
    224         }
    225 
    226         test_int2float(reporter, 0);
    227         test_int2float(reporter, 1);
    228         test_int2float(reporter, -1);
    229         for (i = 0; i < 100000; i++) {
    230             // for now only test ints that are 24bits or less, since we don't
    231             // round (down) large ints the same as IEEE...
    232             int ival = rand.nextU() & 0xFFFFFF;
    233             test_int2float(reporter, ival);
    234             test_int2float(reporter, -ival);
    235         }
    236     }
    237 }
    238 
    239 #ifdef SK_SCALAR_IS_FLOAT
    240 static float make_zero() {
    241     return sk_float_sin(0);
    242 }
    243 #endif
    244 
    245 static void unittest_isfinite(skiatest::Reporter* reporter) {
    246 #ifdef SK_SCALAR_IS_FLOAT
    247     float nan = sk_float_asin(2);
    248     float inf = 1.0 / make_zero();
    249     float big = 3.40282e+038;
    250 
    251     REPORTER_ASSERT(reporter, !SkScalarIsNaN(inf));
    252     REPORTER_ASSERT(reporter, !SkScalarIsNaN(-inf));
    253     REPORTER_ASSERT(reporter, !SkScalarIsFinite(inf));
    254     REPORTER_ASSERT(reporter, !SkScalarIsFinite(-inf));
    255 #else
    256     SkFixed nan = SK_FixedNaN;
    257     SkFixed big = SK_FixedMax;
    258 #endif
    259 
    260     REPORTER_ASSERT(reporter,  SkScalarIsNaN(nan));
    261     REPORTER_ASSERT(reporter, !SkScalarIsNaN(big));
    262     REPORTER_ASSERT(reporter, !SkScalarIsNaN(-big));
    263     REPORTER_ASSERT(reporter, !SkScalarIsNaN(0));
    264 
    265     REPORTER_ASSERT(reporter, !SkScalarIsFinite(nan));
    266     REPORTER_ASSERT(reporter,  SkScalarIsFinite(big));
    267     REPORTER_ASSERT(reporter,  SkScalarIsFinite(-big));
    268     REPORTER_ASSERT(reporter,  SkScalarIsFinite(0));
    269 }
    270 
    271 #endif
    272 
    273 static void test_muldiv255(skiatest::Reporter* reporter) {
    274 #ifdef SK_CAN_USE_FLOAT
    275     for (int a = 0; a <= 255; a++) {
    276         for (int b = 0; b <= 255; b++) {
    277             int ab = a * b;
    278             float s = ab / 255.0f;
    279             int round = (int)floorf(s + 0.5f);
    280             int trunc = (int)floorf(s);
    281 
    282             int iround = SkMulDiv255Round(a, b);
    283             int itrunc = SkMulDiv255Trunc(a, b);
    284 
    285             REPORTER_ASSERT(reporter, iround == round);
    286             REPORTER_ASSERT(reporter, itrunc == trunc);
    287 
    288             REPORTER_ASSERT(reporter, itrunc <= iround);
    289             REPORTER_ASSERT(reporter, iround <= a);
    290             REPORTER_ASSERT(reporter, iround <= b);
    291         }
    292     }
    293 #endif
    294 }
    295 
    296 static void test_muldiv255ceiling(skiatest::Reporter* reporter) {
    297     for (int c = 0; c <= 255; c++) {
    298         for (int a = 0; a <= 255; a++) {
    299             int product = (c * a + 255);
    300             int expected_ceiling = (product + (product >> 8)) >> 8;
    301             int webkit_ceiling = (c * a + 254) / 255;
    302             REPORTER_ASSERT(reporter, expected_ceiling == webkit_ceiling);
    303             int skia_ceiling = SkMulDiv255Ceiling(c, a);
    304             REPORTER_ASSERT(reporter, skia_ceiling == webkit_ceiling);
    305         }
    306     }
    307 }
    308 
    309 static void test_copysign(skiatest::Reporter* reporter) {
    310     static const int32_t gTriples[] = {
    311         // x, y, expected result
    312         0, 0, 0,
    313         0, 1, 0,
    314         0, -1, 0,
    315         1, 0, 1,
    316         1, 1, 1,
    317         1, -1, -1,
    318         -1, 0, 1,
    319         -1, 1, 1,
    320         -1, -1, -1,
    321     };
    322     for (size_t i = 0; i < SK_ARRAY_COUNT(gTriples); i += 3) {
    323         REPORTER_ASSERT(reporter,
    324                         SkCopySign32(gTriples[i], gTriples[i+1]) == gTriples[i+2]);
    325 #ifdef SK_CAN_USE_FLOAT
    326         float x = (float)gTriples[i];
    327         float y = (float)gTriples[i+1];
    328         float expected = (float)gTriples[i+2];
    329         REPORTER_ASSERT(reporter, sk_float_copysign(x, y) == expected);
    330 #endif
    331     }
    332 
    333     SkRandom rand;
    334     for (int j = 0; j < 1000; j++) {
    335         int ix = rand.nextS();
    336         REPORTER_ASSERT(reporter, SkCopySign32(ix, ix) == ix);
    337         REPORTER_ASSERT(reporter, SkCopySign32(ix, -ix) == -ix);
    338         REPORTER_ASSERT(reporter, SkCopySign32(-ix, ix) == ix);
    339         REPORTER_ASSERT(reporter, SkCopySign32(-ix, -ix) == -ix);
    340 
    341         SkScalar sx = rand.nextSScalar1();
    342         REPORTER_ASSERT(reporter, SkScalarCopySign(sx, sx) == sx);
    343         REPORTER_ASSERT(reporter, SkScalarCopySign(sx, -sx) == -sx);
    344         REPORTER_ASSERT(reporter, SkScalarCopySign(-sx, sx) == sx);
    345         REPORTER_ASSERT(reporter, SkScalarCopySign(-sx, -sx) == -sx);
    346     }
    347 }
    348 
    349 static void TestMath(skiatest::Reporter* reporter) {
    350     int         i;
    351     int32_t     x;
    352     SkRandom    rand;
    353 
    354     // these should assert
    355 #if 0
    356     SkToS8(128);
    357     SkToS8(-129);
    358     SkToU8(256);
    359     SkToU8(-5);
    360 
    361     SkToS16(32768);
    362     SkToS16(-32769);
    363     SkToU16(65536);
    364     SkToU16(-5);
    365 
    366     if (sizeof(size_t) > 4) {
    367         SkToS32(4*1024*1024);
    368         SkToS32(-4*1024*1024);
    369         SkToU32(5*1024*1024);
    370         SkToU32(-5);
    371     }
    372 #endif
    373 
    374     test_muldiv255(reporter);
    375     test_muldiv255ceiling(reporter);
    376     test_copysign(reporter);
    377 
    378     {
    379         SkScalar x = SK_ScalarNaN;
    380         REPORTER_ASSERT(reporter, SkScalarIsNaN(x));
    381     }
    382 
    383     for (i = 1; i <= 10; i++) {
    384         x = SkCubeRootBits(i*i*i, 11);
    385         REPORTER_ASSERT(reporter, x == i);
    386     }
    387 
    388     x = SkFixedSqrt(SK_Fixed1);
    389     REPORTER_ASSERT(reporter, x == SK_Fixed1);
    390     x = SkFixedSqrt(SK_Fixed1/4);
    391     REPORTER_ASSERT(reporter, x == SK_Fixed1/2);
    392     x = SkFixedSqrt(SK_Fixed1*4);
    393     REPORTER_ASSERT(reporter, x == SK_Fixed1*2);
    394 
    395     x = SkFractSqrt(SK_Fract1);
    396     REPORTER_ASSERT(reporter, x == SK_Fract1);
    397     x = SkFractSqrt(SK_Fract1/4);
    398     REPORTER_ASSERT(reporter, x == SK_Fract1/2);
    399     x = SkFractSqrt(SK_Fract1/16);
    400     REPORTER_ASSERT(reporter, x == SK_Fract1/4);
    401 
    402     for (i = 1; i < 100; i++) {
    403         x = SkFixedSqrt(SK_Fixed1 * i * i);
    404         REPORTER_ASSERT(reporter, x == SK_Fixed1 * i);
    405     }
    406 
    407     for (i = 0; i < 1000; i++) {
    408         int value = rand.nextS16();
    409         int max = rand.nextU16();
    410 
    411         int clamp = SkClampMax(value, max);
    412         int clamp2 = value < 0 ? 0 : (value > max ? max : value);
    413         REPORTER_ASSERT(reporter, clamp == clamp2);
    414     }
    415 
    416     for (i = 0; i < 10000; i++) {
    417         SkPoint p;
    418 
    419         p.setLength(rand.nextS(), rand.nextS(), SK_Scalar1);
    420         check_length(reporter, p, SK_Scalar1);
    421         p.setLength(rand.nextS() >> 13, rand.nextS() >> 13, SK_Scalar1);
    422         check_length(reporter, p, SK_Scalar1);
    423     }
    424 
    425     {
    426         SkFixed result = SkFixedDiv(100, 100);
    427         REPORTER_ASSERT(reporter, result == SK_Fixed1);
    428         result = SkFixedDiv(1, SK_Fixed1);
    429         REPORTER_ASSERT(reporter, result == 1);
    430     }
    431 
    432 #ifdef SK_CAN_USE_FLOAT
    433     unittest_fastfloat(reporter);
    434     unittest_isfinite(reporter);
    435 #endif
    436 
    437 #ifdef SkLONGLONG
    438     for (i = 0; i < 10000; i++) {
    439         SkFixed numer = rand.nextS();
    440         SkFixed denom = rand.nextS();
    441         SkFixed result = SkFixedDiv(numer, denom);
    442         SkLONGLONG check = ((SkLONGLONG)numer << 16) / denom;
    443 
    444         (void)SkCLZ(numer);
    445         (void)SkCLZ(denom);
    446 
    447         REPORTER_ASSERT(reporter, result != (SkFixed)SK_NaN32);
    448         if (check > SK_MaxS32) {
    449             check = SK_MaxS32;
    450         } else if (check < -SK_MaxS32) {
    451             check = SK_MinS32;
    452         }
    453         REPORTER_ASSERT(reporter, result == (int32_t)check);
    454 
    455         result = SkFractDiv(numer, denom);
    456         check = ((SkLONGLONG)numer << 30) / denom;
    457 
    458         REPORTER_ASSERT(reporter, result != (SkFixed)SK_NaN32);
    459         if (check > SK_MaxS32) {
    460             check = SK_MaxS32;
    461         } else if (check < -SK_MaxS32) {
    462             check = SK_MinS32;
    463         }
    464         REPORTER_ASSERT(reporter, result == (int32_t)check);
    465 
    466         // make them <= 2^24, so we don't overflow in fixmul
    467         numer = numer << 8 >> 8;
    468         denom = denom << 8 >> 8;
    469 
    470         result = SkFixedMul(numer, denom);
    471         SkFixed r2 = symmetric_fixmul(numer, denom);
    472         //        SkASSERT(result == r2);
    473 
    474         result = SkFixedMul(numer, numer);
    475         r2 = SkFixedSquare(numer);
    476         REPORTER_ASSERT(reporter, result == r2);
    477 
    478 #ifdef SK_CAN_USE_FLOAT
    479         if (numer >= 0 && denom >= 0) {
    480             SkFixed mean = SkFixedMean(numer, denom);
    481             float prod = SkFixedToFloat(numer) * SkFixedToFloat(denom);
    482             float fm = sk_float_sqrt(sk_float_abs(prod));
    483             SkFixed mean2 = SkFloatToFixed(fm);
    484             int diff = SkAbs32(mean - mean2);
    485             REPORTER_ASSERT(reporter, diff <= 1);
    486         }
    487 
    488         {
    489             SkFixed mod = SkFixedMod(numer, denom);
    490             float n = SkFixedToFloat(numer);
    491             float d = SkFixedToFloat(denom);
    492             float m = sk_float_mod(n, d);
    493             // ensure the same sign
    494             REPORTER_ASSERT(reporter, mod == 0 || (mod < 0) == (m < 0));
    495             int diff = SkAbs32(mod - SkFloatToFixed(m));
    496             REPORTER_ASSERT(reporter, (diff >> 7) == 0);
    497         }
    498 #endif
    499     }
    500 #endif
    501 
    502 #ifdef SK_CAN_USE_FLOAT
    503     for (i = 0; i < 10000; i++) {
    504         SkFract x = rand.nextU() >> 1;
    505         double xx = (double)x / SK_Fract1;
    506         SkFract xr = SkFractSqrt(x);
    507         SkFract check = SkFloatToFract(sqrt(xx));
    508         REPORTER_ASSERT(reporter, xr == check ||
    509                                   xr == check-1 ||
    510                                   xr == check+1);
    511 
    512         xr = SkFixedSqrt(x);
    513         xx = (double)x / SK_Fixed1;
    514         check = SkFloatToFixed(sqrt(xx));
    515         REPORTER_ASSERT(reporter, xr == check || xr == check-1);
    516 
    517         xr = SkSqrt32(x);
    518         xx = (double)x;
    519         check = (int32_t)sqrt(xx);
    520         REPORTER_ASSERT(reporter, xr == check || xr == check-1);
    521     }
    522 #endif
    523 
    524 #if !defined(SK_SCALAR_IS_FLOAT) && defined(SK_CAN_USE_FLOAT)
    525     {
    526         SkFixed s, c;
    527         s = SkFixedSinCos(0, &c);
    528         REPORTER_ASSERT(reporter, s == 0);
    529         REPORTER_ASSERT(reporter, c == SK_Fixed1);
    530     }
    531 
    532     int maxDiff = 0;
    533     for (i = 0; i < 1000; i++) {
    534         SkFixed rads = rand.nextS() >> 10;
    535         double frads = SkFixedToFloat(rads);
    536 
    537         SkFixed s, c;
    538         s = SkScalarSinCos(rads, &c);
    539 
    540         double fs = sin(frads);
    541         double fc = cos(frads);
    542 
    543         SkFixed is = SkFloatToFixed(fs);
    544         SkFixed ic = SkFloatToFixed(fc);
    545 
    546         maxDiff = SkMax32(maxDiff, SkAbs32(is - s));
    547         maxDiff = SkMax32(maxDiff, SkAbs32(ic - c));
    548     }
    549     SkDebugf("SinCos: maximum error = %d\n", maxDiff);
    550 #endif
    551 
    552 #ifdef SK_SCALAR_IS_FLOAT
    553     test_blend(reporter);
    554 #endif
    555 
    556     // disable for now
    557 //    test_blend31();
    558 }
    559 
    560 #include "TestClassDef.h"
    561 DEFINE_TESTCLASS("Math", MathTestClass, TestMath)
    562