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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « src/effects/gradients/SkLinearGradient.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2012 Google Inc. 2 * Copyright 2012 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkLinearGradient.h" 8 #include "SkLinearGradient.h"
9 9
10 static inline int repeat_bits(int x, const int bits) { 10 static inline int repeat_bits(int x, const int bits) {
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; 93 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
94 if ((fDstToIndex.getType() & ~mask) == 0) { 94 if ((fDstToIndex.getType() & ~mask) == 0) {
95 // when we dither, we are (usually) not const-in-Y 95 // when we dither, we are (usually) not const-in-Y
96 if ((fFlags & SkShader::kHasSpan16_Flag) && !rec.fPaint->isDither()) { 96 if ((fFlags & SkShader::kHasSpan16_Flag) && !rec.fPaint->isDither()) {
97 // only claim this if we do have a 16bit mode (i.e. none of our 97 // only claim this if we do have a 16bit mode (i.e. none of our
98 // colors have alpha), and if we are not dithering (which obviously 98 // colors have alpha), and if we are not dithering (which obviously
99 // is not const in Y). 99 // is not const in Y).
100 fFlags |= SkShader::kConstInY16_Flag; 100 fFlags |= SkShader::kConstInY16_Flag;
101 } 101 }
102 } 102 }
103
104 // setup for Sk4f
105 int count = shader.fColorCount;
106 fColorCount = count;
107 fColors4 = new Sk4f[count];
108 fPos = new float[count * 2];
109 fPosScale = fPos + count;
110 if (shader.fOrigPos) {
111 fPos[0] = 0;
112 fPosScale[0] = 0; // should never get used
113 for (int i = 1; i < count; ++i) {
114 fPos[i] = SkTMin(SkTMax(fPos[i - 1], shader.fOrigPos[i]), 1.0f);
115 fPosScale[i] = 1.0f / (fPos[i] - fPos[i - 1]);
116 }
117 fPos[count - 1] = 1; // overwrite the last value just to be sure we e nd at 1.0
118 } else {
119 float invScale = 1.0f / (count - 1);
120 for (int i = 0; i < count; ++i) {
121 fPos[i] = i * invScale;
122 fPosScale[i] = count - 1;
123 }
124 }
125 for (int i = 0; i < count; ++i) {
126 SkPMColor pmc = SkPreMultiplyColor(shader.fOrigColors[i]);
127 fColors4[i] = Sk4f::FromBytes((const uint8_t*)&pmc);
128 if (i > 0) {
129 SkASSERT(fPos[i - 1] <= fPos[i]);
130 }
131 }
103 } 132 }
104 133
134 SkLinearGradient::LinearGradientContext::~LinearGradientContext() {
135 delete[] fPos;
136 delete[] fColors4;
137 }
138
105 #define NO_CHECK_ITER \ 139 #define NO_CHECK_ITER \
106 do { \ 140 do { \
107 unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache32Shift; \ 141 unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache32Shift; \
108 SkASSERT(fi <= 0xFF); \ 142 SkASSERT(fi <= 0xFF); \
109 fx += dx; \ 143 fx += dx; \
110 *dstC++ = cache[toggle + fi]; \ 144 *dstC++ = cache[toggle + fi]; \
111 toggle = next_dither_toggle(toggle); \ 145 toggle = next_dither_toggle(toggle); \
112 } while (0) 146 } while (0)
113 147
114 namespace { 148 namespace {
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 fx += dx; 238 fx += dx;
205 *dstC++ = cache[toggle + fi]; 239 *dstC++ = cache[toggle + fi];
206 toggle = next_dither_toggle(toggle); 240 toggle = next_dither_toggle(toggle);
207 } while (--count != 0); 241 } while (--count != 0);
208 } 242 }
209 243
210 } 244 }
211 245
212 void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, 246 void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
213 int count) { 247 int count) {
248 if (true) {
249 this->shadeSpan4(x, y, dstC, count);
250 return;
251 }
252
214 SkASSERT(count > 0); 253 SkASSERT(count > 0);
215 254
216 const SkLinearGradient& linearGradient = static_cast<const SkLinearGradient& >(fShader); 255 const SkLinearGradient& linearGradient = static_cast<const SkLinearGradient& >(fShader);
217 256
218 SkPoint srcPt; 257 SkPoint srcPt;
219 SkMatrix::MapXYProc dstProc = fDstToIndexProc; 258 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
220 TileProc proc = linearGradient.fTileProc; 259 TileProc proc = linearGradient.fTileProc;
221 const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); 260 const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
222 int toggle = init_dither_toggle(x, y); 261 int toggle = init_dither_toggle(x, y);
223 262
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after
569 str->append("SkLinearGradient ("); 608 str->append("SkLinearGradient (");
570 609
571 str->appendf("start: (%f, %f)", fStart.fX, fStart.fY); 610 str->appendf("start: (%f, %f)", fStart.fX, fStart.fY);
572 str->appendf(" end: (%f, %f) ", fEnd.fX, fEnd.fY); 611 str->appendf(" end: (%f, %f) ", fEnd.fX, fEnd.fY);
573 612
574 this->INHERITED::toString(str); 613 this->INHERITED::toString(str);
575 614
576 str->append(")"); 615 str->append(")");
577 } 616 }
578 #endif 617 #endif
618
619 //////////////////////////////////////////////////////////////////////////////// ///////////////////
620
621 #include "SkNx.h"
622
623 #if 0
624 static Sk4f premul(const Sk4f& x) {
625 return x * scale_rgb(x.kth<SK_A32_SHIFT/8>());
626 }
627
628 static Sk4f unpremul(const Sk4f& x) {
629 return x * scale_rgb(1 / x.kth<SK_A32_SHIFT/8>()); // TODO: fast/approx inv ert?
630 }
631
632 static Sk4f clamp_0_1(const Sk4f& x) {
633 return Sk4f::Max(Sk4f::Min(x, Sk4f(1)), Sk4f(0));
634 }
635 #endif
636
637 static SkPMColor round_from_255(const Sk4f& x) {
638 SkPMColor c;
639 (x + Sk4f(0.5f)).toBytes((uint8_t*)&c);
640 return c;
641 }
642
643 static Sk4f lerp(Sk4f a, Sk4f b, float t) {
644 return a + Sk4f(t) * (b - a);
645 }
646
647 static int find(float tiledX, const float pos[], int count) {
648 SkASSERT(count > 1);
649 SkASSERT(0 == pos[0]);
650 SkASSERT(1 == pos[count - 1]);
651 SkASSERT(tiledX >= 0 && tiledX <= 1);
652
653 int i = 1;
654 while (pos[i] < tiledX) {
655 i += 1;
656 }
657 return i - 1;
658 }
659
660 /*
661 * TODOs
662 *
663 * - tilemodes
664 * - interp before or after premul
665 * - apply paint's alpha (available when we create the context
666 * - perspective
667 * - dithering
668 * - optimizations
669 * - even spacing (how common is that?)
670 * - use fixed (32bit or 16bit) instead of floats?
671 */
672 void SkLinearGradient::LinearGradientContext::shadeSpan4(int x, int y, SkPMColor * SK_RESTRICT dstC,
673 int count) {
674 SkASSERT(count > 0);
675
676 const Sk4f* colors4 = fColors4;
677 const float* pos = fPos;
678 const float* posScale = fPosScale;
679
680 SkPoint srcPt;
681 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
682 // int toggle = init_dither_toggle(x, y);
683
684 float dx, fx;
685 if (fDstToIndexClass != kPerspective_MatrixClass || true) {
686 dstProc(fDstToIndex, x + SK_ScalarHalf, y + SK_ScalarHalf, &srcPt);
687 fx = srcPt.x();
688
689 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
690 SkFixed dxStorage[1];
691 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, nullptr) ;
692 // todo: do we need a real/high-precision value for dx here?
693 dx = SkFixedToFloat(dxStorage[0]);
694 } else {
695 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
696 dx = fDstToIndex.getScaleX();
697 }
698 }
699
700 int prevIndex = 0;
701 for (int i = 0; i < count; ++i) {
702 float tiledX = fx;
703
704 // Apply the TileMode
705 if (tiledX < 0) {
706 tiledX = 0;
707 }
708 if (tiledX > 1) {
709 tiledX = 1;
710 }
711
712 // Are we in the same relative interval, or do we need to search
713 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
714 prevIndex = find(tiledX, pos, fColorCount);
715 }
716
717 // Compute the color
718 float t = (fx - pos[prevIndex]) * posScale[prevIndex + 1];
719 Sk4f c = lerp(colors4[prevIndex], colors4[prevIndex + 1], t);
720 dstC[i] = round_from_255(c);
721
722 fx += dx;
723 }
724 }
725
OLDNEW
« 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