1/* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "Test.h" 9#include "SkColor.h" 10#include "SkHalf.h" 11#include "SkOpts.h" 12#include "SkPixmap.h" 13#include "SkPM4f.h" 14#include "SkRandom.h" 15 16static bool eq_within_half_float(float a, float b) { 17 const float kTolerance = 1.0f / (1 << (8 + 10)); 18 19 SkHalf ha = SkFloatToHalf(a); 20 SkHalf hb = SkFloatToHalf(b); 21 float a2 = SkHalfToFloat(ha); 22 float b2 = SkHalfToFloat(hb); 23 return fabsf(a2 - b2) <= kTolerance; 24} 25 26static bool eq_within_half_float(const SkPM4f& a, const SkPM4f& b) { 27 for (int i = 0; i < 4; ++i) { 28 if (!eq_within_half_float(a.fVec[i], b.fVec[i])) { 29 return false; 30 } 31 } 32 return true; 33} 34 35DEF_TEST(color_half_float, reporter) { 36 const int w = 100; 37 const int h = 100; 38 39 SkImageInfo info = SkImageInfo::Make(w, h, kRGBA_F16_SkColorType, kPremul_SkAlphaType); 40 41 SkAutoPixmapStorage pm; 42 pm.alloc(info); 43 REPORTER_ASSERT(reporter, pm.getSafeSize() == SkToSizeT(w * h * sizeof(uint64_t))); 44 45 SkColor4f c4 { 0.5f, 1, 0.5f, 0.25f }; 46 pm.erase(c4); 47 48 SkPM4f origpm4 = c4.premul(); 49 for (int y = 0; y < pm.height(); ++y) { 50 for (int x = 0; x < pm.width(); ++x) { 51 SkPM4f pm4 = SkPM4f::FromF16(pm.addrF16(x, y)); 52 REPORTER_ASSERT(reporter, eq_within_half_float(origpm4, pm4)); 53 } 54 } 55} 56 57DEF_TEST(float_to_half, reporter) { 58 const float fs[] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 }; 59 const uint16_t hs[] = { 0x3c00, 0x4000, 0x4200, 0x4400, 0x4500, 0x4600, 0x4700 }; 60 61 uint16_t hscratch[7]; 62 SkOpts::float_to_half(hscratch, fs, 7); 63 REPORTER_ASSERT(reporter, 0 == memcmp(hscratch, hs, sizeof(hs))); 64 65 float fscratch[7]; 66 SkOpts::half_to_float(fscratch, hs, 7); 67 REPORTER_ASSERT(reporter, 0 == memcmp(fscratch, fs, sizeof(fs))); 68} 69 70static uint32_t u(float f) { 71 uint32_t x; 72 memcpy(&x, &f, 4); 73 return x; 74} 75 76DEF_TEST(HalfToFloat_01, r) { 77 for (uint16_t h = 0; h < 0x8000; h++) { 78 float f = SkHalfToFloat(h); 79 if (f >= 0 && f <= 1) { 80 float got = SkHalfToFloat_01(h)[0]; 81 if (got != f) { 82 SkDebugf("0x%04x -> 0x%08x (%g), want 0x%08x (%g)\n", 83 h, 84 u(got), got, 85 u(f), f); 86 } 87 REPORTER_ASSERT(r, SkHalfToFloat_01(h)[0] == f); 88 REPORTER_ASSERT(r, SkFloatToHalf_01(SkHalfToFloat_01(h)) == h); 89 } 90 } 91} 92 93DEF_TEST(FloatToHalf_01, r) { 94#if 0 95 for (uint32_t bits = 0; bits < 0x80000000; bits++) { 96#else 97 SkRandom rand; 98 for (int i = 0; i < 1000000; i++) { 99 uint32_t bits = rand.nextU(); 100#endif 101 float f; 102 memcpy(&f, &bits, 4); 103 if (f >= 0 && f <= 1) { 104 uint16_t h1 = (uint16_t)SkFloatToHalf_01(Sk4f(f,0,0,0)), 105 h2 = SkFloatToHalf(f); 106 bool ok = (h1 == h2 || h1 == h2-1); 107 REPORTER_ASSERT(r, ok); 108 if (!ok) { 109 SkDebugf("%08x (%d) -> %04x (%d), want %04x (%d)\n", 110 bits, bits>>23, h1, h1>>10, h2, h2>>10); 111 break; 112 } 113 } 114 } 115} 116