summaryrefslogtreecommitdiff
path: root/basegfx
diff options
context:
space:
mode:
authorArmin Le Grand (allotropia) <armin.le.grand.extern@allotropia.de>2023-04-04 14:57:06 +0200
committerArmin Le Grand <Armin.Le.Grand@me.com>2023-04-04 18:55:49 +0200
commit4b5203ebf4ca5894f4d7dd37a141832df26e8b9a (patch)
treee3f3497bdc121eade2d9c812ae26c3d8d0c8d718 /basegfx
parent37928bef1c23f30df04bc7e95fcbc202c8cb4299 (diff)
MCGR: Improve performance for texture-mapped MCGR processing
Change-Id: I20b32e7c272112c6c3d9f7ee0ef59c6d4d006d94 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150020 Tested-by: Jenkins Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Diffstat (limited to 'basegfx')
-rw-r--r--basegfx/source/tools/gradienttools.cxx100
1 files changed, 57 insertions, 43 deletions
diff --git a/basegfx/source/tools/gradienttools.cxx b/basegfx/source/tools/gradienttools.cxx
index dc6e4dc3f66a..fdc8dd189531 100644
--- a/basegfx/source/tools/gradienttools.cxx
+++ b/basegfx/source/tools/gradienttools.cxx
@@ -607,7 +607,8 @@ namespace basegfx
BColor modifyBColor(
const ColorStops& rColorStops,
double fScaler,
- sal_uInt32 nRequestedSteps)
+ sal_uInt32 nRequestedSteps,
+ ColorStopRange& rLastColorStopRange)
{
// no color at all, done
if (rColorStops.empty())
@@ -650,56 +651,69 @@ namespace basegfx
nSteps > 1 ? floor(fScaler * nSteps) / double(nSteps - 1) : fScaler);
}
- // access needed spot in sorted array using binary search
- // NOTE: This *seems* slow(er) when developing compared to just
- // looping/accessing, but that's just due to the extensive
- // debug test code created by the stl. In a pro version,
- // all is good/fast as expected
- const auto upperBound(
- std::upper_bound(
- rColorStops.begin(),
- rColorStops.end(),
- ColorStop(fScaler),
- [](const ColorStop& x, const ColorStop& y) { return x.getStopOffset() < y.getStopOffset(); }));
-
- // no upper bound, done
- if (rColorStops.end() == upperBound)
- return rColorStops.back().getStopColor();
-
- // lower bound is one entry back
- const auto lowerBound(upperBound - 1);
-
- // no lower bound, done
- if (rColorStops.end() == lowerBound)
- return rColorStops.back().getStopColor();
-
- // we have lower and upper bound, get colors
- const BColor aCStart(lowerBound->getStopColor());
- const BColor aCEnd(upperBound->getStopColor());
+ // check if we need to newly populate the needed interpolation data
+ // or if we can re-use from last time.
+ // If this scope is not entered, we do not need the binary search. It's
+ // only a single buffered entry, and only used when more than three
+ // ColorStops exist, but makes a huge difference compared with acessing
+ // the sorted ColorStop vector each time.
+ // NOTE: with this simple change I get very high hit rates, e.g. rotating
+ // a donut with gradient test '1' hit rate is at 0.99909440357755486
+ if (rLastColorStopRange.mfOffsetStart == rLastColorStopRange.mfOffsetEnd
+ || fScaler < rLastColorStopRange.mfOffsetStart
+ || fScaler > rLastColorStopRange.mfOffsetEnd)
+ {
+ // access needed spot in sorted array using binary search
+ // NOTE: This *seems* slow(er) when developing compared to just
+ // looping/accessing, but that's just due to the extensive
+ // debug test code created by the stl. In a pro version,
+ // all is good/fast as expected
+ const auto upperBound(
+ std::upper_bound(
+ rColorStops.begin(),
+ rColorStops.end(),
+ ColorStop(fScaler),
+ [](const ColorStop& x, const ColorStop& y) { return x.getStopOffset() < y.getStopOffset(); }));
+
+ // no upper bound, done
+ if (rColorStops.end() == upperBound)
+ return rColorStops.back().getStopColor();
+
+ // lower bound is one entry back, access that
+ const auto lowerBound(upperBound - 1);
+
+ // no lower bound, done
+ if (rColorStops.end() == lowerBound)
+ return rColorStops.back().getStopColor();
+
+ // when there are just two color steps this cannot happen, but when using
+ // a range of colors this *may* be used inside the range to represent
+ // single-colored regions inside a ColorRange. Use that color & done
+ if (lowerBound->getStopColor() == upperBound->getStopColor())
+ return rLastColorStopRange.maColorStart;
+
+ // we have lower and upper bound, get colors and offsets
+ rLastColorStopRange.maColorStart = lowerBound->getStopColor();
+ rLastColorStopRange.maColorEnd = upperBound->getStopColor();
+ rLastColorStopRange.mfOffsetStart = lowerBound->getStopOffset();
+ rLastColorStopRange.mfOffsetEnd = upperBound->getStopOffset();
+ }
- // when there are just two color steps this cannot happen, but when using
- // a range of colors this *may* be used inside the range to represent
- // single-colored regions inside a ColorRange. Use that color & done
- if (aCStart == aCEnd)
- return aCStart;
- // calculate number of steps
+ // calculate number of steps and adapted proportinal
+ // range for scaler in [0.0 .. 1.0]
+ const double fAdaptedScaler((fScaler - rLastColorStopRange.mfOffsetStart) /
+ (rLastColorStopRange.mfOffsetEnd - rLastColorStopRange.mfOffsetStart));
const sal_uInt32 nSteps(
calculateNumberOfSteps(
nRequestedSteps,
- aCStart,
- aCEnd));
-
- // get offsets and scale to new [0.0 .. 1.0] relative range for
- // partial outer range
- const double fOffsetStart(lowerBound->getStopOffset());
- const double fOffsetEnd(upperBound->getStopOffset());
- const double fAdaptedScaler((fScaler - fOffsetStart) / (fOffsetEnd - fOffsetStart));
+ rLastColorStopRange.maColorStart,
+ rLastColorStopRange.maColorEnd));
// interpolate & evtl. apply steps
return interpolate(
- aCStart,
- aCEnd,
+ rLastColorStopRange.maColorStart,
+ rLastColorStopRange.maColorEnd,
nSteps > 1 ? floor(fAdaptedScaler * nSteps) / double(nSteps - 1) : fAdaptedScaler);
}