Skip to content

Commit

Permalink
Fixed Rgb9E5F decoding. Removed union cast in favor of bx::bitCast.
Browse files Browse the repository at this point in the history
  • Loading branch information
bkaradzic committed Nov 20, 2024
1 parent 98b36f4 commit 04464c4
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 76 deletions.
11 changes: 5 additions & 6 deletions include/bx/inline/allocator.inl
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@ namespace bx

inline void* alignPtr(void* _ptr, size_t _extra, size_t _align)
{
union { void* ptr; uintptr_t addr; } un;
un.ptr = _ptr;
uintptr_t unaligned = un.addr + _extra; // space for header
uintptr_t aligned = bx::alignUp(unaligned, int32_t(_align) );
un.addr = aligned;
return un.ptr;
const uintptr_t addr = bitCast<uintptr_t>(_ptr);
const uintptr_t unaligned = addr + _extra; // space for header
const uintptr_t aligned = bx::alignUp(unaligned, int32_t(_align) );

return bitCast<void*>(aligned);
}

inline void* alloc(AllocatorI* _allocator, size_t _size, size_t _align, const Location& _location)
Expand Down
43 changes: 22 additions & 21 deletions include/bx/inline/pixelformat.inl
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ namespace bx

inline int32_t toSnorm(float _value, float _scale)
{
return int32_t(round(
clamp(_value, -1.0f, 1.0f) * _scale)
);
return int32_t(round(clamp(_value, -1.0f, 1.0f) * _scale) );
}

inline float fromSnorm(int32_t _value, float _scale)
Expand Down Expand Up @@ -721,46 +719,49 @@ namespace bx
memCopy(_dst, _src, 8);
}

template<int32_t MantissaBits, int32_t ExpBits>
template<int32_t MantissaBitsT, int32_t ExpBitsT>
inline void encodeRgbE(float* _dst, const float* _src)
{
// Reference(s):
// - https://web.archive.org/web/20181126040035/https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_shared_exponent.txt
//
const int32_t expMax = (1<<ExpBits) - 1;
const int32_t expBias = (1<<(ExpBits - 1) ) - 1;
const int32_t expMax = (1<< ExpBitsT ) - 1;
const int32_t expBias = (1<<(ExpBitsT - 1) ) - 1;
const float sharedExpMax = float(expMax) / float(expMax + 1) * float(1 << (expMax - expBias) );

const float rr = clamp(_src[0], 0.0f, sharedExpMax);
const float gg = clamp(_src[1], 0.0f, sharedExpMax);
const float bb = clamp(_src[2], 0.0f, sharedExpMax);
const float mm = max(rr, gg, bb);
union { float ff; uint32_t ui; } cast = { mm };
int32_t expShared = int32_t(uint32_imax(uint32_t(-expBias-1), ( ( (cast.ui>>23) & 0xff) - 127) ) ) + 1 + expBias;
float denom = pow(2.0f, float(expShared - expBias - MantissaBits) );
const uint32_t mm_as_ui = bitCast<uint32_t>(mm);

if ( (1<<MantissaBits) == int32_t(round(mm/denom) ) )
int32_t expShared = int32_t(max(uint32_t(-expBias-1), ( ( (mm_as_ui>>23) & 0xff) - 127) ) ) + 1 + expBias;
float denom = pow(2.0f, float(expShared - expBias - MantissaBitsT) );

if ( (1<<MantissaBitsT) == int32_t(round(mm/denom) ) )
{
denom *= 2.0f;
++expShared;
}

const float invDenom = 1.0f/denom;
const float invDenom = rcpSafe(denom);
_dst[0] = round(rr * invDenom);
_dst[1] = round(gg * invDenom);
_dst[2] = round(bb * invDenom);
_dst[3] = float(expShared);
}

template<int32_t MantissaBits, int32_t ExpBits>
template<int32_t MantissaBitsT, int32_t ExpBitsT>
inline void decodeRgbE(float* _dst, const float* _src)
{
const int32_t expBias = (1<<(ExpBits - 1) ) - 1;
const float exponent = _src[3]-float(expBias-MantissaBits);
const int32_t expBias = (1<<(ExpBitsT - 1) ) - 1;
const float exponent = _src[3]-float(expBias-MantissaBitsT);
const float scale = pow(2.0f, exponent);
_dst[0] = _src[0] * scale;
_dst[1] = _src[1] * scale;
_dst[2] = _src[2] * scale;
const float invScale = rcpSafe(scale);

_dst[0] = _src[0] * invScale;
_dst[1] = _src[1] * invScale;
_dst[2] = _src[2] * invScale;
}

// RGB9E5F
Expand All @@ -779,12 +780,12 @@ namespace bx

inline void unpackRgb9E5F(float* _dst, const void* _src)
{
uint32_t packed = *( (const uint32_t*)_src);
const uint32_t packed = *( (const uint32_t*)_src);

float tmp[4];
tmp[0] = float( ( (packed ) & 0x1ff) ) / 511.0f;
tmp[1] = float( ( (packed>> 9) & 0x1ff) ) / 511.0f;
tmp[2] = float( ( (packed>>18) & 0x1ff) ) / 511.0f;
tmp[0] = float( ( (packed ) & 0x1ff) );
tmp[1] = float( ( (packed>> 9) & 0x1ff) );
tmp[2] = float( ( (packed>>18) & 0x1ff) );
tmp[3] = float( ( (packed>>27) & 0x1f) );

decodeRgbE<9, 5>(_dst, tmp);
Expand Down
49 changes: 23 additions & 26 deletions include/bx/inline/uint32_t.inl
Original file line number Diff line number Diff line change
Expand Up @@ -649,15 +649,15 @@ namespace bx
template<typename Ty>
inline BX_CONSTEXPR_FUNC bool isAligned(Ty* _ptr, int32_t _align)
{
union { const void* ptr; uintptr_t addr; } un = { _ptr };
return isAligned(un.addr, _align);
const uintptr_t addr = bitCast<uintptr_t>(_ptr);
return isAligned(addr, _align);
}

template<typename Ty>
inline BX_CONSTEXPR_FUNC bool isAligned(const Ty* _ptr, int32_t _align)
{
union { const void* ptr; uintptr_t addr; } un = { _ptr };
return isAligned(un.addr, _align);
const uintptr_t addr = bitCast<uintptr_t>(_ptr);
return isAligned(addr, _align);
}

template<typename Ty>
Expand All @@ -670,17 +670,17 @@ namespace bx
template<typename Ty>
inline BX_CONSTEXPR_FUNC Ty* alignDown(Ty* _ptr, int32_t _align)
{
union { Ty* ptr; uintptr_t addr; } un = { _ptr };
un.addr = alignDown(un.addr, _align);
return un.ptr;
uintptr_t addr = bitCast<uintptr_t>(_ptr);
addr = alignDown(addr, _align);
return bitCast<Ty*>(addr);
}

template<typename Ty>
inline BX_CONSTEXPR_FUNC const Ty* alignDown(const Ty* _ptr, int32_t _align)
{
union { const Ty* ptr; uintptr_t addr; } un = { _ptr };
un.addr = alignDown(un.addr, _align);
return un.ptr;
uintptr_t addr = bitCast<uintptr_t>(_ptr);
addr = alignDown(addr, _align);
return bitCast<const Ty*>(addr);
}

template<typename Ty>
Expand All @@ -693,23 +693,22 @@ namespace bx
template<typename Ty>
inline BX_CONSTEXPR_FUNC Ty* alignUp(Ty* _ptr, int32_t _align)
{
union { Ty* ptr; uintptr_t addr; } un = { _ptr };
un.addr = alignUp(un.addr, _align);
return un.ptr;
uintptr_t addr = bitCast<uintptr_t>(_ptr);
addr = alignUp(addr, _align);
return bitCast<Ty*>(addr);
}

template<typename Ty>
inline BX_CONSTEXPR_FUNC const Ty* alignUp(const Ty* _ptr, int32_t _align)
{
union { const Ty* ptr; uintptr_t addr; } un = { _ptr };
un.addr = alignUp(un.addr, _align);
return un.ptr;
uintptr_t addr = bitCast<uintptr_t>(_ptr);
addr = alignUp(addr, _align);
return bitCast<const Ty*>(addr);
}

inline BX_CONST_FUNC uint16_t halfFromFloat(float _a)
{
union { uint32_t ui; float flt; } ftou;
ftou.flt = _a;
const uint32_t a_as_ui = bitCast<uint32_t>(_a);

const uint32_t one = uint32_li(0x00000001);
const uint32_t f_s_mask = uint32_li(kFloatSignMask);
Expand All @@ -728,13 +727,13 @@ namespace bx
const uint32_t f_h_m_pos_offset = uint32_li(0x0000000d);
const uint32_t h_nan_min = uint32_li(0x00007c01);
const uint32_t f_h_e_biased_flag = uint32_li(0x0000008f);
const uint32_t f_s = uint32_and(ftou.ui, f_s_mask);
const uint32_t f_e = uint32_and(ftou.ui, f_e_mask);
const uint32_t f_s = uint32_and(a_as_ui, f_s_mask);
const uint32_t f_e = uint32_and(a_as_ui, f_e_mask);
const uint16_t h_s = (uint16_t)uint32_srl(f_s, f_h_s_pos_offset);
const uint32_t f_m = uint32_and(ftou.ui, f_m_mask);
const uint32_t f_m = uint32_and(a_as_ui, f_m_mask);
const uint16_t f_e_amount = (uint16_t)uint32_srl(f_e, f_e_pos);
const uint32_t f_e_half_bias = uint32_sub(f_e_amount, f_h_bias_offset);
const uint32_t f_snan = uint32_and(ftou.ui, f_snan_mask);
const uint32_t f_snan = uint32_and(a_as_ui, f_snan_mask);
const uint32_t f_m_round_mask = uint32_and(f_m, f_m_round_bit);
const uint32_t f_m_round_offset = uint32_sll(f_m_round_mask, one);
const uint32_t f_m_rounded = uint32_add(f_m, f_m_round_offset);
Expand Down Expand Up @@ -770,7 +769,7 @@ namespace bx
const uint32_t h_em_snan_result = uint32_sels(is_f_snan_msb, h_snan_mask, h_em_denorm_result);
const uint32_t h_result = uint32_or(h_s, h_em_snan_result);

return (uint16_t)(h_result);
return uint16_t(h_result);
}

inline BX_CONST_FUNC float halfToFloat(uint16_t _a)
Expand Down Expand Up @@ -817,9 +816,7 @@ namespace bx
const uint32_t f_nan_result = uint32_sels(is_nan_msb, f_em_nan, f_inf_result);
const uint32_t f_result = uint32_or(f_s, f_nan_result);

union { uint32_t ui; float flt; } utof;
utof.ui = f_result;
return utof.flt;
return bitCast<float>(f_result);
}

} // namespace bx
33 changes: 10 additions & 23 deletions src/dtoa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -606,12 +606,6 @@ namespace bx
#define DOUBLE_PLUS_INFINITY UINT64_C(0x7ff0000000000000)
#define DOUBLE_MINUS_INFINITY UINT64_C(0xfff0000000000000)

union HexDouble
{
double d;
uint64_t u;
};

#define lsr96(s2, s1, s0, d2, d1, d0) \
d0 = ( (s0) >> 1) | ( ( (s1) & 1) << 31); \
d1 = ( (s1) >> 1) | ( ( (s2) & 1) << 31); \
Expand Down Expand Up @@ -932,13 +926,12 @@ namespace bx
static double converter(PrepNumber* _pn)
{
int binexp = 92;
HexDouble hd;
uint32_t s2, s1, s0; /* 96-bit precision integer */
uint32_t q2, q1, q0; /* 96-bit precision integer */
uint32_t r2, r1, r0; /* 96-bit precision integer */
uint32_t mask28 = UINT32_C(0xf) << 28;

hd.u = 0;
uint64_t hdu = 0;

s0 = (uint32_t)(_pn->mantissa & UINT32_MAX);
s1 = (uint32_t)(_pn->mantissa >> 32);
Expand Down Expand Up @@ -1011,18 +1004,18 @@ namespace bx
{
if (_pn->negative)
{
hd.u = DOUBLE_MINUS_INFINITY;
hdu = DOUBLE_MINUS_INFINITY;
}
else
{
hd.u = DOUBLE_PLUS_INFINITY;
hdu = DOUBLE_PLUS_INFINITY;
}
}
else if (binexp < 1)
{
if (_pn->negative)
{
hd.u = DOUBLE_MINUS_ZERO;
hdu = DOUBLE_MINUS_ZERO;
}
}
else if (s2)
Expand All @@ -1039,10 +1032,10 @@ namespace bx
q |= (1ULL << 63);
}

hd.u = q;
hdu = q;
}

return hd.d;
return bitCast<double>(hdu);
}

int32_t toString(char* _out, int32_t _max, bool _value)
Expand Down Expand Up @@ -1074,32 +1067,26 @@ namespace bx
pn.negative = 0;
pn.exponent = 0;

HexDouble hd;
hd.u = DOUBLE_PLUS_ZERO;

switch (parser(_str.getPtr(), _str.getTerm(), &pn) )
{
case PARSER_OK:
*_out = converter(&pn);
break;

case PARSER_PZERO:
*_out = hd.d;
*_out = bitCast<double>(DOUBLE_PLUS_ZERO);
break;

case PARSER_MZERO:
hd.u = DOUBLE_MINUS_ZERO;
*_out = hd.d;
*_out = bitCast<double>(DOUBLE_MINUS_ZERO);
break;

case PARSER_PINF:
hd.u = DOUBLE_PLUS_INFINITY;
*_out = hd.d;
*_out = bitCast<double>(DOUBLE_PLUS_INFINITY);
break;

case PARSER_MINF:
hd.u = DOUBLE_MINUS_INFINITY;
*_out = hd.d;
*_out = bitCast<double>(DOUBLE_MINUS_INFINITY);
break;
}

Expand Down
31 changes: 31 additions & 0 deletions tests/pixelformat_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2024 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bx/blob/master/LICENSE
*/

#include "test.h"
#include <bx/pixelformat.h>

TEST_CASE("pack/unpack Rgba8", "[pixelformat]")
{
float rgba[4] = { 0.1f, 0.3f, 0.8f, 0.9f };
uint32_t encoded;
bx::packRgba8(&encoded, rgba);

float decoded[4];
bx::unpackRgba8(decoded, &encoded);

REQUIRE(bx::isEqual(rgba, decoded, 4, 0.01f) );
}

TEST_CASE("pack/unpack Rgb9E5F", "[pixelformat]")
{
float rgba[3] = { 0.1f, 0.3f, 0.89f };
uint32_t encoded;
bx::packRgb9E5F(&encoded, rgba);

float decoded[3];
bx::unpackRgb9E5F(decoded, &encoded);

REQUIRE(bx::isEqual(rgba, decoded, BX_COUNTOF(rgba), 0.001f) );
}

0 comments on commit 04464c4

Please sign in to comment.