Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(293)

Unified Diff: src/effects/gradients/SkLinearGradient.cpp

Issue 1436663003: Implement multi-color-stops in linear gradients using Sk4f (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/effects/gradients/SkLinearGradient.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/effects/gradients/SkLinearGradient.cpp
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index 11c79f0956248e0a56f891aacdab56c7f4186847..404207e7190268d17c7ecd0d59ad58c6a3c38911 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -100,6 +100,40 @@ SkLinearGradient::LinearGradientContext::LinearGradientContext(
fFlags |= SkShader::kConstInY16_Flag;
}
}
+
+ // setup for Sk4f
+ int count = shader.fColorCount;
+ fColorCount = count;
+ fColors4 = new Sk4f[count];
+ fPos = new float[count * 2];
+ fPosScale = fPos + count;
+ if (shader.fOrigPos) {
+ fPos[0] = 0;
+ fPosScale[0] = 0; // should never get used
+ for (int i = 1; i < count; ++i) {
+ fPos[i] = SkTMin(SkTMax(fPos[i - 1], shader.fOrigPos[i]), 1.0f);
+ fPosScale[i] = 1.0f / (fPos[i] - fPos[i - 1]);
+ }
+ fPos[count - 1] = 1; // overwrite the last value just to be sure we end at 1.0
+ } else {
+ float invScale = 1.0f / (count - 1);
+ for (int i = 0; i < count; ++i) {
+ fPos[i] = i * invScale;
+ fPosScale[i] = count - 1;
+ }
+ }
+ for (int i = 0; i < count; ++i) {
+ SkPMColor pmc = SkPreMultiplyColor(shader.fOrigColors[i]);
+ fColors4[i] = Sk4f::FromBytes((const uint8_t*)&pmc);
+ if (i > 0) {
+ SkASSERT(fPos[i - 1] <= fPos[i]);
+ }
+ }
+}
+
+SkLinearGradient::LinearGradientContext::~LinearGradientContext() {
+ delete[] fPos;
+ delete[] fColors4;
}
#define NO_CHECK_ITER \
@@ -211,6 +245,11 @@ void shadeSpan_linear_repeat(TileProc proc, SkGradFixed dx, SkGradFixed fx,
void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
int count) {
+ if (true) {
+ this->shadeSpan4(x, y, dstC, count);
+ return;
+ }
+
SkASSERT(count > 0);
const SkLinearGradient& linearGradient = static_cast<const SkLinearGradient&>(fShader);
@@ -576,3 +615,111 @@ void SkLinearGradient::toString(SkString* str) const {
str->append(")");
}
#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkNx.h"
+
+#if 0
+static Sk4f premul(const Sk4f& x) {
+ return x * scale_rgb(x.kth<SK_A32_SHIFT/8>());
+}
+
+static Sk4f unpremul(const Sk4f& x) {
+ return x * scale_rgb(1 / x.kth<SK_A32_SHIFT/8>()); // TODO: fast/approx invert?
+}
+
+static Sk4f clamp_0_1(const Sk4f& x) {
+ return Sk4f::Max(Sk4f::Min(x, Sk4f(1)), Sk4f(0));
+}
+#endif
+
+static SkPMColor round_from_255(const Sk4f& x) {
+ SkPMColor c;
+ (x + Sk4f(0.5f)).toBytes((uint8_t*)&c);
+ return c;
+}
+
+static Sk4f lerp(Sk4f a, Sk4f b, float t) {
+ return a + Sk4f(t) * (b - a);
+}
+
+static int find(float tiledX, const float pos[], int count) {
+ SkASSERT(count > 1);
+ SkASSERT(0 == pos[0]);
+ SkASSERT(1 == pos[count - 1]);
+ SkASSERT(tiledX >= 0 && tiledX <= 1);
+
+ int i = 1;
+ while (pos[i] < tiledX) {
+ i += 1;
+ }
+ return i - 1;
+}
+
+/*
+ * TODOs
+ *
+ * - tilemodes
+ * - interp before or after premul
+ * - apply paint's alpha (available when we create the context
+ * - perspective
+ * - dithering
+ * - optimizations
+ * - even spacing (how common is that?)
+ * - use fixed (32bit or 16bit) instead of floats?
+ */
+void SkLinearGradient::LinearGradientContext::shadeSpan4(int x, int y, SkPMColor* SK_RESTRICT dstC,
+ int count) {
+ SkASSERT(count > 0);
+
+ const Sk4f* colors4 = fColors4;
+ const float* pos = fPos;
+ const float* posScale = fPosScale;
+
+ SkPoint srcPt;
+ SkMatrix::MapXYProc dstProc = fDstToIndexProc;
+// int toggle = init_dither_toggle(x, y);
+
+ float dx, fx;
+ if (fDstToIndexClass != kPerspective_MatrixClass || true) {
+ dstProc(fDstToIndex, x + SK_ScalarHalf, y + SK_ScalarHalf, &srcPt);
+ fx = srcPt.x();
+
+ if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
+ SkFixed dxStorage[1];
+ (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, nullptr);
+ // todo: do we need a real/high-precision value for dx here?
+ dx = SkFixedToFloat(dxStorage[0]);
+ } else {
+ SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
+ dx = fDstToIndex.getScaleX();
+ }
+ }
+
+ int prevIndex = 0;
+ for (int i = 0; i < count; ++i) {
+ float tiledX = fx;
+
+ // Apply the TileMode
+ if (tiledX < 0) {
+ tiledX = 0;
+ }
+ if (tiledX > 1) {
+ tiledX = 1;
+ }
+
+ // Are we in the same relative interval, or do we need to search
+ if (pos[prevIndex] > tiledX || tiledX > pos[prevIndex + 1]) {
f(malita) 2015/11/11 05:14:16 What if instead of projecting the span pixels onto
+ prevIndex = find(tiledX, pos, fColorCount);
+ }
+
+ // Compute the color
+ float t = (fx - pos[prevIndex]) * posScale[prevIndex + 1];
+ Sk4f c = lerp(colors4[prevIndex], colors4[prevIndex + 1], t);
+ dstC[i] = round_from_255(c);
+
+ fx += dx;
+ }
+}
+
« no previous file with comments | « src/effects/gradients/SkLinearGradient.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698