UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

3 lines (2 loc) 3.94 kB
declare const _default: "\n\n#if defined(PLATFORM_ANDROID)\n\n // Software pack of one f32 -> f16 (low 16 bits). Ties-to-even, full subnormals.\n uint floatToHalf(float a) {\n uint u = floatBitsToUint(a);\n uint sign = (u >> 16u) & 0x8000u;\n uint absu = u & 0x7FFFFFFFu;\n uint man = u & 0x007FFFFFu;\n int e32 = int((u >> 23u) & 0xFFu) - 127;\n \n // NaN / Inf\n if ((absu & 0x7F800000u) == 0x7F800000u) {\n bool isnan = (man != 0u);\n return sign | (isnan ? 0x7E00u : 0x7C00u);\n }\n \n // Overflow to Inf\n if (e32 > 15) return sign | 0x7C00u;\n \n // Normal half\n if (e32 >= -14) {\n uint he = uint(e32 + 15);\n uint hm = man >> 13u;\n uint rem = man & 0x1FFFu;\n uint add = (rem > 0x1000u || (rem == 0x1000u && (hm & 1u) == 1u)) ? 1u : 0u;\n hm = (hm + add) & 0x3FFu;\n if ((hm & 0x400u) != 0u) {\n hm = 0u; he = he + 1u;\n if (he >= 31u) return sign | 0x7C00u;\n }\n return sign | (he << 10u) | hm;\n }\n \n // Subnormals\n if (e32 >= -24) {\n uint s = uint(-(e32 + 1));\n uint mnorm = 0x00800000u | man;\n uint hm = mnorm >> s;\n uint mask = (1u << s) - 1u;\n uint rem = mnorm & mask;\n uint halfBt = 1u << (s - 1u);\n uint add = (rem > halfBt || (rem == halfBt && (hm & 1u) == 1u)) ? 1u : 0u;\n hm = hm + add;\n if (hm >= 0x400u) return sign | (1u << 10u);\n return sign | hm;\n }\n \n // Underflow to signed zero\n return sign;\n }\n\n // Hybrid pack: software for subnormals, builtin for normal range\n uint packHalf2x16Safe(vec2 v) {\n // Convert the input floats to their 32-bit IEEE-754 bit patterns.\n // We'll inspect the exponent bits directly to determine their numeric range.\n uint u_x = floatBitsToUint(v.x);\n uint u_y = floatBitsToUint(v.y);\n \n // Extract the unbiased exponent for each component (float32 uses bias = 127).\n // e32 = exponent - 127 \u21D2 actual power of two for each value.\n int e32_x = int((u_x >> 23u) & 0xFFu) - 127;\n int e32_y = int((u_y >> 23u) & 0xFFu) - 127;\n \n // -------------------------------------------------------------------------\n // Detect values that would become *subnormal* (or zero) in float16.\n //\n // e32 < -14 \u21D4 |value| < 2^-14 \u2248 6.1035e-5\n //\n // Many mobile GPUs (including Adreno and Mali) mishandle half-precision\n // subnormals\u2014typically flushing them to zero or rounding incorrectly.\n // To preserve correct rounding and sign, we use the software conversion\n // path (floatToHalf) for these small magnitudes.\n //\n // The software branch runs very rarely (<0.1% of typical values for\n // normalized scene data) and costs only a few ALU instructions, so the\n // performance impact is negligible while avoiding visible precision loss.\n // -------------------------------------------------------------------------\n if (e32_x < -14 || e32_y < -14) {\n // Convert both components with the reference software routine\n // and pack into a 32-bit uint: low 16 bits = x, high 16 bits = y.\n return (floatToHalf(v.y) << 16u) | floatToHalf(v.x);\n }\n \n // Normal range: use the fast hardware builtin\n return packHalf2x16(v);\n }\n\n#else\n\n // On non-Android platforms, use builtin directly (no subnormal workaround needed)\n uint packHalf2x16Safe(vec2 v) {\n return packHalf2x16(v);\n }\n\n#endif\n"; export default _default;