diff options
-rw-r--r-- | src/core/SkBitmap.cpp | 4 | ||||
-rw-r--r-- | src/core/SkHalf.h | 107 | ||||
-rw-r--r-- | src/core/SkLinearBitmapPipeline_sample.h | 2 | ||||
-rw-r--r-- | src/core/SkMipMap.cpp | 4 | ||||
-rw-r--r-- | src/core/SkSpanProcs.cpp | 2 | ||||
-rw-r--r-- | src/core/SkXfermodeF16.cpp | 42 | ||||
-rw-r--r-- | src/effects/gradients/Sk4fGradientPriv.h | 4 | ||||
-rw-r--r-- | src/opts/SkNx_neon.h | 23 | ||||
-rw-r--r-- | src/opts/SkNx_sse.h | 30 | ||||
-rw-r--r-- | tests/Float16Test.cpp | 24 | ||||
-rw-r--r-- | tests/SkNxTest.cpp | 19 |
11 files changed, 108 insertions, 153 deletions
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp index fb7f691c93..863169c458 100644 --- a/src/core/SkBitmap.cpp +++ b/src/core/SkBitmap.cpp @@ -601,7 +601,7 @@ SkColor SkBitmap::getColor(int x, int y) const { } case kRGBA_F16_SkColorType: { const uint64_t* addr = (const uint64_t*)fPixels + y * (fRowBytes >> 3) + x; - Sk4f p4 = SkHalfToFloat_finite(addr[0]); + Sk4f p4 = SkHalfToFloat_01(addr[0]); if (p4[3]) { float inva = 1 / p4[3]; p4 = p4 * Sk4f(inva, inva, inva, 1); @@ -1145,7 +1145,7 @@ bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) { SkImageInfo info; info.unflatten(*buffer); - // If there was an error reading "info" or if it is bogus, + // If there was an error reading "info" or if it is bogus, // don't use it to compute minRowBytes() if (!buffer->validate(SkColorTypeValidateAlphaType(info.colorType(), info.alphaType()))) { diff --git a/src/core/SkHalf.h b/src/core/SkHalf.h index 2f2ed66c6a..5f5575ae1a 100644 --- a/src/core/SkHalf.h +++ b/src/core/SkHalf.h @@ -24,10 +24,10 @@ typedef uint16_t SkHalf; float SkHalfToFloat(SkHalf h); SkHalf SkFloatToHalf(float f); -// Convert between half and single precision floating point, -// assuming inputs and outputs are both finite. -static inline Sk4f SkHalfToFloat_finite(uint64_t); -static inline uint64_t SkFloatToHalf_finite(const Sk4f&); +// Convert between half and single precision floating point, but pull any dirty +// trick we can to make it faster as long as it's correct enough for values in [0,1]. +static inline Sk4f SkHalfToFloat_01(uint64_t); +static inline uint64_t SkFloatToHalf_01(const Sk4f&); // ~~~~~~~~~~~ impl ~~~~~~~~~~~~~~ // @@ -36,7 +36,7 @@ static inline uint64_t SkFloatToHalf_finite(const Sk4f&); // GCC 4.9 lacks the intrinsics to use ARMv8 f16<->f32 instructions, so we use inline assembly. -static inline Sk4f SkHalfToFloat_finite(uint64_t hs) { +static inline Sk4f SkHalfToFloat_01(uint64_t hs) { #if !defined(SKNX_NO_SIMD) && defined(SK_CPU_ARM64) float32x4_t fs; asm ("fmov %d[fs], %[hs] \n" // vcreate_f16(hs) @@ -44,28 +44,53 @@ static inline Sk4f SkHalfToFloat_finite(uint64_t hs) { : [fs] "=w" (fs) // =w: write-only NEON register : [hs] "r" (hs)); // r: read-only 64-bit general register return fs; + +#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON) + // NEON makes this pretty easy: + // - denormals are 10-bit * 2^-14 == 24-bit fixed point; + // - handle normals the same way as in SSE: align mantissa, then rebias exponent. + uint32x4_t h = vmovl_u16(vcreate_u16(hs)), + is_denorm = vcltq_u32(h, vdupq_n_u32(1<<10)); + float32x4_t denorm = vcvtq_n_f32_u32(h, 24), + norm = vreinterpretq_f32_u32(vaddq_u32(vshlq_n_u32(h, 13), + vdupq_n_u32((127-15) << 23))); + return vbslq_f32(is_denorm, denorm, norm); + +#elif !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 + // If our input is a normal 16-bit float, things are pretty easy: + // - shift left by 13 to put the mantissa in the right place; + // - the exponent is wrong, but it just needs to be rebiased; + // - re-bias the exponent from 15-bias to 127-bias by adding (127-15). + + // If our input is denormalized, we're going to do the same steps, plus a few more fix ups: + // - the input is h = K*2^-14, for some 10-bit fixed point K in [0,1); + // - by shifting left 13 and adding (127-15) to the exponent, we constructed the float value + // 2^-15*(1+K); + // - we'd need to subtract 2^-15 and multiply by 2 to get back to K*2^-14, or equivallently + // multiply by 2 then subtract 2^-14. + // + // - We'll work that multiply by 2 into the rebias, by adding 1 more to the exponent. + // - Conveniently, this leaves that rebias constant 2^-14, exactly what we want to subtract. + + __m128i h = _mm_unpacklo_epi16(_mm_loadl_epi64((const __m128i*)&hs), _mm_setzero_si128()); + const __m128i is_denorm = _mm_cmplt_epi32(h, _mm_set1_epi32(1<<10)); + + __m128i rebias = _mm_set1_epi32((127-15) << 23); + rebias = _mm_add_epi32(rebias, _mm_and_si128(is_denorm, _mm_set1_epi32(1<<23))); + + __m128i f = _mm_add_epi32(_mm_slli_epi32(h, 13), rebias); + return _mm_sub_ps(_mm_castsi128_ps(f), + _mm_castsi128_ps(_mm_and_si128(is_denorm, rebias))); #else - Sk4i bits = SkNx_cast<int>(Sk4h::Load(&hs)), // Expand to 32 bit. - sign = bits & 0x00008000, // Save the sign bit for later... - positive = bits ^ sign, // ...but strip it off for now. - is_denorm = positive < (1<<10); // Exponent == 0? - - // For normal half floats, extend the mantissa by 13 zero bits, - // then adjust the exponent from 15 bias to 127 bias. - Sk4i norm = (positive << 13) + ((127 - 15) << 23); - - // For denorm half floats, mask in the exponent-only float K that turns our - // denorm value V*2^-14 into a normalized float K + V*2^-14. Then subtract off K. - const Sk4i K = ((127-15) + (23-10) + 1) << 23; - Sk4i mask_K = positive | K; - Sk4f denorm = Sk4f::Load(&mask_K) - Sk4f::Load(&K); - - Sk4i merged = (sign << 16) | is_denorm.thenElse(Sk4i::Load(&denorm), norm); - return Sk4f::Load(&merged); + float fs[4]; + for (int i = 0; i < 4; i++) { + fs[i] = SkHalfToFloat(hs >> (i*16)); + } + return Sk4f::Load(fs); #endif } -static inline uint64_t SkFloatToHalf_finite(const Sk4f& fs) { +static inline uint64_t SkFloatToHalf_01(const Sk4f& fs) { uint64_t r; #if !defined(SKNX_NO_SIMD) && defined(SK_CPU_ARM64) float32x4_t vec = fs.fVec; @@ -73,25 +98,25 @@ static inline uint64_t SkFloatToHalf_finite(const Sk4f& fs) { "fmov %[r], %d[vec] \n" // vst1_f16(&r, ...) : [r] "=r" (r) // =r: write-only 64-bit general register , [vec] "+w" (vec)); // +w: read-write NEON register + +// TODO: ARMv7 NEON float->half? + +#elif !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 + // Scale down from 127-bias to 15-bias, then cut off bottom 13 mantissa bits. + // This doesn't round, so it can be 1 bit too small. + const __m128 rebias = _mm_castsi128_ps(_mm_set1_epi32((127 - (127-15)) << 23)); + __m128i h = _mm_srli_epi32(_mm_castps_si128(_mm_mul_ps(fs.fVec, rebias)), 13); + _mm_storel_epi64((__m128i*)&r, _mm_packs_epi32(h,h)); + #else - Sk4i bits = Sk4i::Load(&fs), - sign = bits & 0x80000000, // Save the sign bit for later... - positive = bits ^ sign, // ...but strip it off for now. - will_be_denorm = positive < ((127-15+1) << 23); // positve < smallest normal half? - - // For normal half floats, adjust the exponent from 127 bias to 15 bias, - // then drop the bottom 13 mantissa bits. - Sk4i norm = (positive - ((127 - 15) << 23)) >> 13; - - // This mechanically inverts the denorm half -> normal float conversion above. - // Knowning that and reading its explanation will leave you feeling more confident - // than reading my best attempt at explaining this directly. - const Sk4i K = ((127-15) + (23-10) + 1) << 23; - Sk4f plus_K = Sk4f::Load(&positive) + Sk4f::Load(&K); - Sk4i denorm = Sk4i::Load(&plus_K) ^ K; - - Sk4i merged = (sign >> 16) | will_be_denorm.thenElse(denorm, norm); - SkNx_cast<uint16_t>(merged).store(&r); + SkHalf hs[4]; + for (int i = 0; i < 4; i++) { + hs[i] = SkFloatToHalf(fs[i]); + } + r = (uint64_t)hs[3] << 48 + | (uint64_t)hs[2] << 32 + | (uint64_t)hs[1] << 16 + | (uint64_t)hs[0] << 0; #endif return r; } diff --git a/src/core/SkLinearBitmapPipeline_sample.h b/src/core/SkLinearBitmapPipeline_sample.h index e957ae7e4d..39400f6750 100644 --- a/src/core/SkLinearBitmapPipeline_sample.h +++ b/src/core/SkLinearBitmapPipeline_sample.h @@ -198,7 +198,7 @@ public: PixelConverter(const SkPixmap& srcPixmap) { } Sk4f toSk4f(const Element pixel) const { - return SkHalfToFloat_finite(pixel); + return SkHalfToFloat_01(pixel); } }; diff --git a/src/core/SkMipMap.cpp b/src/core/SkMipMap.cpp index 4811c9e073..f469762eba 100644 --- a/src/core/SkMipMap.cpp +++ b/src/core/SkMipMap.cpp @@ -85,10 +85,10 @@ struct ColorTypeFilter_8 { struct ColorTypeFilter_F16 { typedef uint64_t Type; // SkHalf x4 static Sk4f Expand(uint64_t x) { - return SkHalfToFloat_finite(x); + return SkHalfToFloat_01(x); } static uint64_t Compact(const Sk4f& x) { - return SkFloatToHalf_finite(x); + return SkFloatToHalf_01(x); } }; diff --git a/src/core/SkSpanProcs.cpp b/src/core/SkSpanProcs.cpp index 87dcbc0ee7..dddf7419e2 100644 --- a/src/core/SkSpanProcs.cpp +++ b/src/core/SkSpanProcs.cpp @@ -42,7 +42,7 @@ static void load_f16(const SkPixmap& src, int x, int y, SkPM4f span[], int count SkASSERT(src.addr64(x + count - 1, y)); for (int i = 0; i < count; ++i) { - SkHalfToFloat_finite(addr[i]).store(span[i].fVec); + SkHalfToFloat_01(addr[i]).store(span[i].fVec); } } diff --git a/src/core/SkXfermodeF16.cpp b/src/core/SkXfermodeF16.cpp index 63058f9dce..6ca5519afb 100644 --- a/src/core/SkXfermodeF16.cpp +++ b/src/core/SkXfermodeF16.cpp @@ -22,16 +22,16 @@ static void xfer_1(const SkXfermode* xfer, uint64_t dst[], const SkPM4f* src, in SkPM4f d; if (aa) { for (int i = 0; i < count; ++i) { - Sk4f d4 = SkHalfToFloat_finite(dst[i]); + Sk4f d4 = SkHalfToFloat_01(dst[i]); d4.store(d.fVec); Sk4f r4 = Sk4f::Load(proc(*src, d).fVec); - dst[i] = SkFloatToHalf_finite(lerp_by_coverage(r4, d4, aa[i])); + dst[i] = SkFloatToHalf_01(lerp_by_coverage(r4, d4, aa[i])); } } else { for (int i = 0; i < count; ++i) { - SkHalfToFloat_finite(dst[i]).store(d.fVec); + SkHalfToFloat_01(dst[i]).store(d.fVec); Sk4f r4 = Sk4f::Load(proc(*src, d).fVec); - dst[i] = SkFloatToHalf_finite(r4); + dst[i] = SkFloatToHalf_01(r4); } } } @@ -42,16 +42,16 @@ static void xfer_n(const SkXfermode* xfer, uint64_t dst[], const SkPM4f src[], i SkPM4f d; if (aa) { for (int i = 0; i < count; ++i) { - Sk4f d4 = SkHalfToFloat_finite(dst[i]); + Sk4f d4 = SkHalfToFloat_01(dst[i]); d4.store(d.fVec); Sk4f r4 = Sk4f::Load(proc(src[i], d).fVec); - dst[i] = SkFloatToHalf_finite(lerp_by_coverage(r4, d4, aa[i])); + dst[i] = SkFloatToHalf_01(lerp_by_coverage(r4, d4, aa[i])); } } else { for (int i = 0; i < count; ++i) { - SkHalfToFloat_finite(dst[i]).store(d.fVec); + SkHalfToFloat_01(dst[i]).store(d.fVec); Sk4f r4 = Sk4f::Load(proc(src[i], d).fVec); - dst[i] = SkFloatToHalf_finite(r4); + dst[i] = SkFloatToHalf_01(r4); } } } @@ -64,8 +64,8 @@ static void clear(const SkXfermode*, uint64_t dst[], const SkPM4f*, int count, c if (aa) { for (int i = 0; i < count; ++i) { if (aa[i]) { - const Sk4f d4 = SkHalfToFloat_finite(dst[i]); - dst[i] = SkFloatToHalf_finite(d4 * Sk4f((255 - aa[i]) * 1.0f/255)); + const Sk4f d4 = SkHalfToFloat_01(dst[i]); + dst[i] = SkFloatToHalf_01(d4 * Sk4f((255 - aa[i]) * 1.0f/255)); } } } else { @@ -82,11 +82,11 @@ static void src_1(const SkXfermode*, uint64_t dst[], const SkPM4f* src, int coun const Sk4f s4 = Sk4f::Load(src->fVec); if (aa) { for (int i = 0; i < count; ++i) { - const Sk4f d4 = SkHalfToFloat_finite(dst[i]); - dst[i] = SkFloatToHalf_finite(lerp_by_coverage(s4, d4, aa[i])); + const Sk4f d4 = SkHalfToFloat_01(dst[i]); + dst[i] = SkFloatToHalf_01(lerp_by_coverage(s4, d4, aa[i])); } } else { - sk_memset64(dst, SkFloatToHalf_finite(s4), count); + sk_memset64(dst, SkFloatToHalf_01(s4), count); } } @@ -95,13 +95,13 @@ static void src_n(const SkXfermode*, uint64_t dst[], const SkPM4f src[], int cou if (aa) { for (int i = 0; i < count; ++i) { const Sk4f s4 = Sk4f::Load(src[i].fVec); - const Sk4f d4 = SkHalfToFloat_finite(dst[i]); - dst[i] = SkFloatToHalf_finite(lerp_by_coverage(s4, d4, aa[i])); + const Sk4f d4 = SkHalfToFloat_01(dst[i]); + dst[i] = SkFloatToHalf_01(lerp_by_coverage(s4, d4, aa[i])); } } else { for (int i = 0; i < count; ++i) { const Sk4f s4 = Sk4f::Load(src[i].fVec); - dst[i] = SkFloatToHalf_finite(s4); + dst[i] = SkFloatToHalf_01(s4); } } } @@ -121,12 +121,12 @@ static void srcover_1(const SkXfermode*, uint64_t dst[], const SkPM4f* src, int const Sk4f s4 = Sk4f::Load(src->fVec); const Sk4f dst_scale = Sk4f(1 - get_alpha(s4)); for (int i = 0; i < count; ++i) { - const Sk4f d4 = SkHalfToFloat_finite(dst[i]); + const Sk4f d4 = SkHalfToFloat_01(dst[i]); const Sk4f r4 = s4 + d4 * dst_scale; if (aa) { - dst[i] = SkFloatToHalf_finite(lerp_by_coverage(r4, d4, aa[i])); + dst[i] = SkFloatToHalf_01(lerp_by_coverage(r4, d4, aa[i])); } else { - dst[i] = SkFloatToHalf_finite(r4); + dst[i] = SkFloatToHalf_01(r4); } } } @@ -135,12 +135,12 @@ static void srcover_n(const SkXfermode*, uint64_t dst[], const SkPM4f src[], int const SkAlpha aa[]) { for (int i = 0; i < count; ++i) { Sk4f s = Sk4f::Load(src+i), - d = SkHalfToFloat_finite(dst[i]), + d = SkHalfToFloat_01(dst[i]), r = s + d*(1.0f - SkNx_shuffle<3,3,3,3>(s)); if (aa) { r = lerp_by_coverage(r, d, aa[i]); } - dst[i] = SkFloatToHalf_finite(r); + dst[i] = SkFloatToHalf_01(r); } } diff --git a/src/effects/gradients/Sk4fGradientPriv.h b/src/effects/gradients/Sk4fGradientPriv.h index 68e95a63d9..ae6fe7ce46 100644 --- a/src/effects/gradients/Sk4fGradientPriv.h +++ b/src/effects/gradients/Sk4fGradientPriv.h @@ -143,11 +143,11 @@ struct DstTraits<DstType::F16, premul> { } static void store(const Sk4f& c, Type* dst) { - *dst = SkFloatToHalf_finite(PM::apply(c)); + *dst = SkFloatToHalf_01(PM::apply(c)); } static void store(const Sk4f& c, Type* dst, int n) { - sk_memset64(dst, SkFloatToHalf_finite(PM::apply(c)), n); + sk_memset64(dst, SkFloatToHalf_01(PM::apply(c)), n); } static void store4x(const Sk4f& c0, const Sk4f& c1, diff --git a/src/opts/SkNx_neon.h b/src/opts/SkNx_neon.h index 2f73e0368d..91cd104482 100644 --- a/src/opts/SkNx_neon.h +++ b/src/opts/SkNx_neon.h @@ -388,28 +388,13 @@ public: SkNx operator & (const SkNx& o) const { return vandq_s32(fVec, o.fVec); } SkNx operator | (const SkNx& o) const { return vorrq_s32(fVec, o.fVec); } - SkNx operator ^ (const SkNx& o) const { return veorq_s32(fVec, o.fVec); } SkNx operator << (int bits) const { SHIFT32(vshlq_n_s32, fVec, bits); } SkNx operator >> (int bits) const { SHIFT32(vshrq_n_s32, fVec, bits); } - SkNx operator == (const SkNx& o) const { - return vreinterpretq_s32_u32(vceqq_s32(fVec, o.fVec)); - } - SkNx operator < (const SkNx& o) const { - return vreinterpretq_s32_u32(vcltq_s32(fVec, o.fVec)); - } - SkNx operator > (const SkNx& o) const { - return vreinterpretq_s32_u32(vcgtq_s32(fVec, o.fVec)); - } - static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_s32(a.fVec, b.fVec); } // TODO as needed - SkNx thenElse(const SkNx& t, const SkNx& e) const { - return vbslq_s32(vreinterpretq_u32_s32(fVec), t.fVec, e.fVec); - } - int32x4_t fVec; }; @@ -471,14 +456,6 @@ template<> inline Sk4b SkNx_cast<uint8_t, int>(const Sk4i& src) { return vqmovn_u16(vcombine_u16(_16, _16)); } -template<> inline Sk4i SkNx_cast<int, uint16_t>(const Sk4h& src) { - return vreinterpretq_s32_u32(vmovl_u16(src.fVec)); -} - -template<> inline Sk4h SkNx_cast<uint16_t, int>(const Sk4i& src) { - return vmovn_u32(vreinterpretq_u32_s32(src.fVec)); -} - static inline Sk4i Sk4f_round(const Sk4f& x) { return vcvtq_s32_f32((x + 0.5f).fVec); } diff --git a/src/opts/SkNx_sse.h b/src/opts/SkNx_sse.h index a8a415fd37..78cea3b3d8 100644 --- a/src/opts/SkNx_sse.h +++ b/src/opts/SkNx_sse.h @@ -152,30 +152,16 @@ public: SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); } SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); } - SkNx operator ^ (const SkNx& o) const { return _mm_xor_si128(fVec, o.fVec); } SkNx operator << (int bits) const { return _mm_slli_epi32(fVec, bits); } SkNx operator >> (int bits) const { return _mm_srai_epi32(fVec, bits); } - SkNx operator == (const SkNx& o) const { return _mm_cmpeq_epi32 (fVec, o.fVec); } - SkNx operator < (const SkNx& o) const { return _mm_cmplt_epi32 (fVec, o.fVec); } - SkNx operator > (const SkNx& o) const { return _mm_cmpgt_epi32 (fVec, o.fVec); } - int operator[](int k) const { SkASSERT(0 <= k && k < 4); union { __m128i v; int is[4]; } pun = {fVec}; return pun.is[k&3]; } - SkNx thenElse(const SkNx& t, const SkNx& e) const { - #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 - return _mm_blendv_epi8(e.fVec, t.fVec, fVec); - #else - return _mm_or_si128(_mm_and_si128 (fVec, t.fVec), - _mm_andnot_si128(fVec, e.fVec)); - #endif - } - __m128i fVec; }; @@ -386,21 +372,7 @@ template<> /*static*/ inline Sk4b SkNx_cast<uint8_t, uint16_t>(const Sk4h& src) return _mm_packus_epi16(src.fVec, src.fVec); } -template<> /*static*/ inline Sk4i SkNx_cast<int, uint16_t>(const Sk4h& src) { - return _mm_unpacklo_epi16(src.fVec, _mm_setzero_si128()); -} - -template<> /*static*/ inline Sk4h SkNx_cast<uint16_t, int>(const Sk4i& src) { -#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 - return _mm_packus_epi32(src.fVec, src.fVec); -#else - // Sign extend to trick _mm_packs_epi32() into doing the pack we want. - __m128i x = _mm_srai_epi32(_mm_slli_epi32(src.fVec, 16), 16); - return _mm_packs_epi32(x,x); -#endif -} - -template<> /*static*/ inline Sk4b SkNx_cast<uint8_t, int>(const Sk4i& src) { +template<> inline Sk4b SkNx_cast<uint8_t, int>(const Sk4i& src) { return _mm_packus_epi16(_mm_packus_epi16(src.fVec, src.fVec), src.fVec); } diff --git a/tests/Float16Test.cpp b/tests/Float16Test.cpp index 2091652522..cc5efedae6 100644 --- a/tests/Float16Test.cpp +++ b/tests/Float16Test.cpp @@ -61,26 +61,26 @@ static uint32_t u(float f) { return x; } -DEF_TEST(HalfToFloat_finite, r) { - for (uint32_t h = 0; h <= 0xffff; h++) { +DEF_TEST(HalfToFloat_01, r) { + for (uint16_t h = 0; h < 0x8000; h++) { float f = SkHalfToFloat(h); - if (isfinite(f)) { - float got = SkHalfToFloat_finite(h)[0]; + if (f >= 0 && f <= 1) { + float got = SkHalfToFloat_01(h)[0]; if (got != f) { SkDebugf("0x%04x -> 0x%08x (%g), want 0x%08x (%g)\n", h, u(got), got, u(f), f); } - REPORTER_ASSERT(r, SkHalfToFloat_finite(h)[0] == f); - REPORTER_ASSERT(r, SkFloatToHalf_finite(SkHalfToFloat_finite(h)) == h); + REPORTER_ASSERT(r, SkHalfToFloat_01(h)[0] == f); + REPORTER_ASSERT(r, SkFloatToHalf_01(SkHalfToFloat_01(h)) == h); } } } -DEF_TEST(FloatToHalf_finite, r) { +DEF_TEST(FloatToHalf_01, r) { #if 0 - for (uint64_t bits = 0; bits <= 0xffffffff; bits++) { + for (uint32_t bits = 0; bits < 0x80000000; bits++) { #else SkRandom rand; for (int i = 0; i < 1000000; i++) { @@ -88,14 +88,14 @@ DEF_TEST(FloatToHalf_finite, r) { #endif float f; memcpy(&f, &bits, 4); - if (isfinite(f) && isfinite(SkHalfToFloat(SkFloatToHalf(f)))) { - uint16_t h1 = (uint16_t)SkFloatToHalf_finite(Sk4f(f,0,0,0)), + if (f >= 0 && f <= 1) { + uint16_t h1 = (uint16_t)SkFloatToHalf_01(Sk4f(f,0,0,0)), h2 = SkFloatToHalf(f); bool ok = (h1 == h2 || h1 == h2-1); REPORTER_ASSERT(r, ok); if (!ok) { - SkDebugf("%08x (%g) -> %04x, want %04x (%g)\n", - bits, f, h1, h2, SkHalfToFloat(h2)); + SkDebugf("%08x (%d) -> %04x (%d), want %04x (%d)\n", + bits, bits>>23, h1, h1>>10, h2, h2>>10); break; } } diff --git a/tests/SkNxTest.cpp b/tests/SkNxTest.cpp index 51d937dd4d..5509814c07 100644 --- a/tests/SkNxTest.cpp +++ b/tests/SkNxTest.cpp @@ -288,22 +288,3 @@ DEF_TEST(SkNx_u16_float, r) { REPORTER_ASSERT(r, !memcmp(s16, d16, sizeof(s16))); } } - -// The SSE2 implementation of SkNx_cast<uint16_t>(Sk4i) is non-trivial, so worth a test. -DEF_TEST(SkNx_int_u16, r) { - // These are pretty hard to get wrong. - for (int i = 0; i <= 0x7fff; i++) { - uint16_t expected = (uint16_t)i; - uint16_t actual = SkNx_cast<uint16_t>(Sk4i(i))[0]; - - REPORTER_ASSERT(r, expected == actual); - } - - // A naive implementation with _mm_packs_epi32 would succeed up to 0x7fff but fail here: - for (int i = 0x8000; (1) && i <= 0xffff; i++) { - uint16_t expected = (uint16_t)i; - uint16_t actual = SkNx_cast<uint16_t>(Sk4i(i))[0]; - - REPORTER_ASSERT(r, expected == actual); - } -} |