FastLED 3.9.15
Loading...
Searching...
No Matches

◆ Gamma8Impl() [1/2]

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

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

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

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

+ Here is the call graph for this function: