Skip to content

Instantly share code, notes, and snippets.

@zeux
Last active December 8, 2018 06:25
Show Gist options
  • Save zeux/a47210f82406e760f7971f136c3d0c82 to your computer and use it in GitHub Desktop.
Save zeux/a47210f82406e760f7971f136c3d0c82 to your computer and use it in GitHub Desktop.
8-bit (unsigned) floating point encoding that is designed to be very efficient to decode on DX9/GLES2 class GPUs
// Can be used to efficiently encode floating point values from a limited range ([0..65k]) into a byte
// edgeDecode is optimized for GPUs (native exp2)
// edgeEncode1 is optimized for GPUs (native log2)
// edgeEncode2 is optimized for CPUs but is an approximation
// edgeEncode3 is optimized for CPUs
float edgeDecode(int e)
{
return exp2f(float(e) * (1 / 16.f)) - 1;
}
// max relative error 4.3% on [1, 2048] range
int edgeEncode1(float f)
{
return log2f(f + 1) * 16 + 0.5f;
}
// max relative error 12% on [1, 2048] range
int edgeEncode2(float f)
{
// This is an approximation of log2(f + 1) * 16 + 0.5
// Instead of computing log2 precisely, we compute integer part by taking the floating point exponent
// and take the fractional part as is (rounded)
union { float f; uint32_t ui; } u;
u.f = f + 1;
uint32_t v = u.ui;
return (v - (127 << 23) + (1 << 18)) >> 19;
}
// precompute this table with:
// for (size_t i = 0; i < 128; ++i) edgeEncode3Table[i] = int(log2f(1 + float(i) / 128) * 16 + 0.5f);
uint8_t edgeEncode3Table[128];
// max relative error 4.5% on [1, 2048] range
int edgeEncode3(float f)
{
// This is an approximation of log2(f + 1) * 16 + 0.5 that refines edgeEncode2 with a table lookup
union { float f; uint32_t ui; } u;
u.f = f + 1;
uint32_t v = u.ui;
return (((v >> 23) - 127) << 4) + edgeEncode3Table[(v >> 16) & 127];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment