Add evenly spaced stops and unify gradient contexts
Change-Id: I17ac13b9d1ea6765e2c1a2b53aa6975eab408856
Reviewed-on: https://skia-review.googlesource.com/16713
Commit-Queue: Herb Derby <herb@google.com>
Reviewed-by: Mike Klein <mtklein@chromium.org>
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 042ad45..038bea6 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -5,6 +5,7 @@
* found in the LICENSE file.
*/
+#include <algorithm>
#include "Sk4fLinearGradient.h"
#include "SkColorSpace_XYZ.h"
#include "SkGradientShaderPriv.h"
@@ -14,6 +15,8 @@
#include "SkRadialGradient.h"
#include "SkSweepGradient.h"
#include "SkTwoPointConicalGradient.h"
+#include "../../jumper/SkJumper.h"
+
enum GradientSerializationFlags {
// Bits 29:31 used for various boolean flags
@@ -406,51 +409,58 @@
p->append(SkRasterPipeline::evenly_spaced_2_stop_gradient, f_and_b);
} else {
-
- struct Stop { float t; SkPM4f f, b; };
- struct Ctx { size_t n; Stop* stops; SkPM4f start; };
-
- auto* ctx = alloc->make<Ctx>();
- ctx->start = prepareColor(0);
-
- // For each stop we calculate a bias B and a scale factor F, such that
- // for any t between stops n and n+1, the color we want is B[n] + F[n]*t.
- auto init_stop = [](float t_l, float t_r, SkPM4f c_l, SkPM4f c_r, Stop *stop) {
- auto F = SkPM4f::From4f((c_r.to4f() - c_l.to4f()) / (t_r - t_l));
- auto B = SkPM4f::From4f(c_l.to4f() - (F.to4f() * t_l));
- *stop = {t_l, F, B};
+ auto* ctx = alloc->make<SkJumper_GradientCtx>();
+ auto add_stop_color = [&](size_t stop, SkPM4f Fs, SkPM4f Bs) {
+ (ctx->fs[0])[stop] = Fs.r();
+ (ctx->fs[1])[stop] = Fs.g();
+ (ctx->fs[2])[stop] = Fs.b();
+ (ctx->fs[3])[stop] = Fs.a();
+ (ctx->bs[0])[stop] = Bs.r();
+ (ctx->bs[1])[stop] = Bs.g();
+ (ctx->bs[2])[stop] = Bs.b();
+ (ctx->bs[3])[stop] = Bs.a();
};
+ auto add_const_color = [&](size_t stop, SkPM4f color) {
+ add_stop_color(stop, SkPM4f::FromPremulRGBA(0,0,0,0), color);
+ };
+
+ // Note: In order to handle clamps in search, the search assumes a stop conceptully placed
+ // at -inf. Therefore, the max number of stops is fColorCount+1.
+ for (int i = 0; i < 4; i++) {
+ // Allocate at least at for the AVX2 gather from a YMM register.
+ ctx->fs[i] = alloc->makeArray<float>(std::max(fColorCount+1, 8));
+ ctx->bs[i] = alloc->makeArray<float>(std::max(fColorCount+1, 8));
+ }
+
if (fOrigPos == nullptr) {
// Handle evenly distributed stops.
- float dt = 1.0f / (fColorCount - 1);
- // In the evenly distributed case, fColorCount is the number of stops. There are no
- // dummy entries.
- auto* stopsArray = alloc->makeArrayDefault<Stop>(fColorCount);
+ size_t stopCount = fColorCount;
+ float gapCount = stopCount - 1;
+ // Calculate a factor F and a bias B so that color = F*t + B when t is in range of
+ // the stop. Assume that the distance between stops is 1/gapCount.
+ auto init_stop = [&](size_t stop, SkPM4f c_l, SkPM4f c_r) {
+ auto Fs = SkPM4f::From4f((c_r.to4f() - c_l.to4f()) * gapCount);
+ auto Bs = SkPM4f::From4f(c_l.to4f() - (Fs.to4f() * (stop/gapCount)));
+ add_stop_color(stop, Fs, Bs);
+ };
- float t_l = 0;
- SkPM4f c_l = ctx->start;
- for (int i = 0; i < fColorCount - 1; i++) {
- // Use multiply instead of accumulating error using repeated addition.
- float t_r = (i + 1) * dt;
+ SkPM4f c_l = prepareColor(0);
+ for (size_t i = 0; i < stopCount - 1; i++) {
SkPM4f c_r = prepareColor(i + 1);
- init_stop(t_l, t_r, c_l, c_r, &stopsArray[i]);
-
- t_l = t_r;
+ init_stop(i, c_l, c_r);
c_l = c_r;
}
+ add_const_color(stopCount - 1, c_l);
- // Force the last stop.
- stopsArray[fColorCount - 1].t = 1;
- stopsArray[fColorCount - 1].f = SkPM4f::From4f(Sk4f{0});
- stopsArray[fColorCount - 1].b = prepareColor(fColorCount - 1);
-
- ctx->n = fColorCount;
- ctx->stops = stopsArray;
+ ctx->stopCount = stopCount;
+ p->append(SkRasterPipeline::evenly_spaced_gradient, ctx);
} else {
// Handle arbitrary stops.
+ ctx->ts = alloc->makeArray<float>(fColorCount+1);
+
// Remove the dummy stops inserted by SkGradientShaderBase::SkGradientShaderBase
// because they are naturally handled by the search method.
int firstStop;
@@ -463,37 +473,38 @@
firstStop = 0;
lastStop = 1;
}
- int realCount = lastStop - firstStop + 1;
- // This is the maximum number of stops. There may be fewer stops because the duplicate
- // points of hard stops are removed.
- auto* stopsArray = alloc->makeArrayDefault<Stop>(realCount);
+ // For each stop we calculate a bias B and a scale factor F, such that
+ // for any t between stops n and n+1, the color we want is B[n] + F[n]*t.
+ auto init_stop = [&](size_t stop, float t_l, float t_r, SkPM4f c_l, SkPM4f c_r) {
+ auto Fs = SkPM4f::From4f((c_r.to4f() - c_l.to4f()) / (t_r - t_l));
+ auto Bs = SkPM4f::From4f(c_l.to4f() - (Fs.to4f() * t_l));
+ ctx->ts[stop] = t_l;
+ add_stop_color(stop, Fs, Bs);
+ };
size_t stopCount = 0;
float t_l = fOrigPos[firstStop];
SkPM4f c_l = prepareColor(firstStop);
+ add_const_color(stopCount++, c_l);
// N.B. lastStop is the index of the last stop, not one after.
for (int i = firstStop; i < lastStop; i++) {
float t_r = fOrigPos[i + 1];
SkPM4f c_r = prepareColor(i + 1);
if (t_l < t_r) {
- init_stop(t_l, t_r, c_l, c_r, &stopsArray[stopCount]);
+ init_stop(stopCount, t_l, t_r, c_l, c_r);
stopCount += 1;
}
t_l = t_r;
c_l = c_r;
}
- stopsArray[stopCount].t = fOrigPos[lastStop];
- stopsArray[stopCount].f = SkPM4f::From4f(Sk4f{0});
- stopsArray[stopCount].b = prepareColor(lastStop);
- stopCount += 1;
+ ctx->ts[stopCount] = t_l;
+ add_const_color(stopCount++, c_l);
- ctx->n = stopCount;
- ctx->stops = stopsArray;
+ ctx->stopCount = stopCount;
+ p->append(SkRasterPipeline::gradient, ctx);
}
-
- p->append(SkRasterPipeline::gradient, ctx);
}
if (!premulGrad && !this->colorsAreOpaque()) {