From c49e70b4e0f41b0a1d47fbdefdc0310bc4039e11 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 26 Jul 2026 02:48:43 +0000 Subject: [PATCH] Optimize linearized color component conversion using Lookup Table Replaced the on-the-fly floating point arithmetic and `.pow(2.4)` operations inside `ColorUtils.linearized()` with a pre-computed 256-element DoubleArray lookup table. This yields a significant performance improvement for color processing hot paths because 8-bit sRGB color components strictly fall within a discrete finite domain (0-255). Co-authored-by: himattm <6266621+himattm@users.noreply.github.com> --- .jules/bolt.md | 4 ++++ .../src/commonMain/kotlin/halogen/color/ColorUtils.kt | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 2d59eae..c07e3c6 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -1,3 +1,7 @@ ## 2024-07-14 - Optimize Hex Color Parsing and Formatting in KMP Hot Paths **Learning:** In Kotlin Multiplatform hot paths (such as hex color serialization and parsing), manual character array manipulation and bitwise shifts are substantially faster (up to 25x faster for serialization and 10x faster for parsing) than using standard library string methods like `toString(16).padStart()`, `uppercase()`, or `substring().toLong(16).toInt()`. This approach avoids platform-specific string allocation overhead. **Action:** When working in KMP hot paths, avoid standard library string manipulations that instantiate multiple objects per call. Favor `CharArray`, manual index iteration, bitwise shifts, and `concatToString()` to minimize allocations and latency. + +## 2024-07-26 - Optimize linearized color component conversion using Lookup Table +**Learning:** In Kotlin Multiplatform, when mathematical operations depend strictly on a small, discrete domain (e.g., converting 8-bit color components 0-255 from sRGB to linear space), utilizing pre-computed arrays or lookup tables (like `DoubleArray(256)`) instead of redundant on-the-fly computation (divisions, conditionals, `.pow()`) significantly improves performance in hot paths like HCT or XYZ conversions. +**Action:** Identify mathematical hot paths that operate on small discrete inputs, like 8-bit color components, and implement lookup tables to cache values instead of recomputing them dynamically. diff --git a/halogen-core/src/commonMain/kotlin/halogen/color/ColorUtils.kt b/halogen-core/src/commonMain/kotlin/halogen/color/ColorUtils.kt index c4b7893..23e1af2 100644 --- a/halogen-core/src/commonMain/kotlin/halogen/color/ColorUtils.kt +++ b/halogen-core/src/commonMain/kotlin/halogen/color/ColorUtils.kt @@ -85,15 +85,17 @@ internal object ColorUtils { return 116.0 * labF(y / 100.0) - 16.0 } - fun linearized(rgbComponent: Int): Double { + private val LINEARIZED_LUT = DoubleArray(256) { rgbComponent -> val normalized = rgbComponent / 255.0 - return if (normalized <= 0.040449936) { + if (normalized <= 0.040449936) { normalized / 12.92 * 100.0 } else { ((normalized + 0.055) / 1.055).pow(2.4) * 100.0 } } + fun linearized(rgbComponent: Int): Double = LINEARIZED_LUT[rgbComponent] + fun delinearized(rgbComponent: Double): Int { val normalized = rgbComponent / 100.0 val delinearized: Double = if (normalized <= 0.0031308) {