basegfx/source/color/bcolormodifier.cxx |   31 ++++++++++++++++++++++++++++---
 1 file changed, 28 insertions(+), 3 deletions(-)

New commits:
commit 23e158e4c35a9f548010827adfccccd70d1928f6
Author:     Noel Grandin <noelgran...@gmail.com>
AuthorDate: Fri Apr 25 08:06:05 2025 +0200
Commit:     Noel Grandin <noelgran...@gmail.com>
CommitDate: Fri Apr 25 09:35:36 2025 +0200

    tdf#165595 speedup BColorModifier_gamma
    
    which shows up heavily on this profile. In this case we don't
    need perfection and we can use a fast approximation for std::pow.
    Thanks to the binary representation of float numbers, this new
    code reduces to some basic bit-twiddling.
    
    Change-Id: I064588f65cf8f5973ba45545fba9c5fe66500e37
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184602
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/basegfx/source/color/bcolormodifier.cxx 
b/basegfx/source/color/bcolormodifier.cxx
index e0e0ebbd6203..360a41db9285 100644
--- a/basegfx/source/color/bcolormodifier.cxx
+++ b/basegfx/source/color/bcolormodifier.cxx
@@ -324,14 +324,39 @@ namespace basegfx
         return mfValue == pCompare->mfValue;
     }
 
+    /**
+      A fast and approximate std::pow(), good enough for gamma calculations.
+
+      std::pow() is basically implemented using log's:
+          pow(a,b) = x^(logx(a) * b)
+      So we need a fast log and fast exponent - it doesn't matter what x is so 
we use 2.
+          pow(a,b) = 2^(log2(a) * b)
+      The trick is that a floating point number is already in a log style 
format:
+          a = M * 2^E
+      Taking the log of both sides gives:
+          log2(a) = log2(M) + E
+      or more simply:
+          log2(a) ~= E
+      In other words if we take the floating point representation of a number,
+      and extract the Exponent we've got something that's a good starting 
point as its log.
+      And then we can do:
+          pow(a,b) = 2^(E * b)
+    */
+    static double fast_pow(double a, double b)
+    {
+        int a_exp;
+        std::frexp(a, &a_exp);
+        return std::exp2(a_exp * b);
+    }
+
     ::basegfx::BColor BColorModifier_gamma::getModifiedColor(const 
::basegfx::BColor& aSourceColor) const
     {
         if(mbUseIt)
         {
             ::basegfx::BColor aRetval(
-                pow(aSourceColor.getRed(), mfInvValue),
-                pow(aSourceColor.getGreen(), mfInvValue),
-                pow(aSourceColor.getBlue(), mfInvValue));
+                fast_pow(aSourceColor.getRed(), mfInvValue),
+                fast_pow(aSourceColor.getGreen(), mfInvValue),
+                fast_pow(aSourceColor.getBlue(), mfInvValue));
 
             aRetval.clamp();
             return aRetval;

Reply via email to