FastLED 3.10.8
Loading...
Searching...
No Matches

◆ Gamma8Impl() [1/2]

fl::Gamma8Impl::Gamma8Impl ( float gamma)
inlineexplicit

Definition at line 356 of file ease.cpp.hpp.

356 {
357 // i=0 is mathematically exact regardless of gamma: pow(0, any) = 0.
358 // The s8x24::pow short-circuit covers exact 0 input, but we set it
359 // here directly anyway because (a) the loop below avoids the
360 // round-trip math and (b) `mLut` is otherwise uninitialized.
361 // i=255 used to need a workaround for the log2(1+t) endpoint
362 // residual; that snap is now handled inside s8x24::pow itself
363 // (see #2969).
364 mLut[0] = 0;
365 // Compute the 256-entry u16 gamma LUT in fixed-point so we don't
366 // pull `__ieee754_pow` (libm, ~2.7 KB) into release builds — the
367 // double-precision pow chain dominates the top-9 bytes attributed
368 // to libm in the post-#2908 ESP32-S3 NEOPIXEL Blink audit
369 // (see #2886 / #2910).
370 //
371 // `s8x24` is 8-integer + 24-fractional bits (same 32-bit storage as
372 // s16x16, but 256× the sub-LSB resolution). Both log2_fp/exp2_fp use
373 // the same 4-term minimax polynomial, but s8x24 carries the full
374 // 24-bit intermediate precision end-to-end instead of truncating
375 // back to 16 frac bits at each stage — bringing the runtime output
376 // within ~1 LSB of true float pow() at the u16 output. Combined
377 // with the special-case for gamma=2.8 in Gamma8::getOrCreate(),
378 // this closes the divergence with the precomputed GAMMA_2_8_LUT
379 // (see #2963 audit + ucs7604 "default gamma 2.8" subcase).
380 //
381 // Bit budget check: max intermediate is exp*log2_fp(1/255) =
382 // 16 * -7.994 ≈ -127.9, fits in s8x24's signed [-128, 128) range.
383 // (GammaKey caps user gamma at 16.)
384 //
385 // libm-free: log2_fp/exp2_fp are pure integer-polynomial impls.
386 // The only float kept is the one-shot s8x24(gamma) constructor
387 // call (pulls __mulsf3 / __fixsfsi helpers, both << 100 B).
388 const fl::s8x24 gamma_fp(gamma);
389 constexpr fl::s8x24 inv_255_fp(1.0f / 255.0f);
390 for (int i = 1; i < 256; ++i) {
391 const fl::s8x24 x = static_cast<i32>(i) * inv_255_fp; // (0, 1]
392 const fl::s8x24 r = fl::s8x24::pow(x, gamma_fp); // (0, 1]
393 // r.raw() is the s8x24 raw with FRAC_BITS=24, range [0, 2^24].
394 // Scale to u16 [0, 65535] with round-half-up. 24+16 bit
395 // multiplication needs a u64 intermediate:
396 // result = ((u64)raw * 65535 + (1<<23)) >> 24
397 const fl::u64 scaled =
398 (static_cast<fl::u64>(static_cast<fl::u32>(r.raw())) * 65535ull
399 + (1ull << 23)) >> 24;
400 mLut[i] = static_cast<u16>(scaled > 65535u ? 65535u : scaled);
401 }
402 }
static FASTLED_FORCE_INLINE s8x24 pow(s8x24 base, s8x24 exp) FL_NO_EXCEPT
Definition s8x24.h:216
constexpr i32 raw() const FL_NO_EXCEPT
Definition s8x24.h:59
constexpr u32 gamma(float g) FL_NO_EXCEPT
Definition gamma_lut.h:36

References fl::FL_NO_EXCEPT, fl::gamma(), fl::s8x24::pow(), fl::s8x24::raw(), and fl::x.

+ Here is the call graph for this function: