3df7144337502914329ff805b0428ac23cb8f63a
[platform/upstream/libSkiaSharp.git] / src / effects / gradients / SkSweepGradient.cpp
1
2 /*
3  * Copyright 2012 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8
9 #include "SkSweepGradient.h"
10
11 static SkMatrix translate(SkScalar dx, SkScalar dy) {
12     SkMatrix matrix;
13     matrix.setTranslate(dx, dy);
14     return matrix;
15 }
16
17 SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy, const Descriptor& desc)
18     : SkGradientShaderBase(desc, translate(-cx, -cy))
19     , fCenter(SkPoint::Make(cx, cy))
20 {
21     // overwrite the tilemode to a canonical value (since sweep ignores it)
22     fTileMode = SkShader::kClamp_TileMode;
23 }
24
25 SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const {
26     if (info) {
27         commonAsAGradient(info);
28         info->fPoint[0] = fCenter;
29     }
30     return kSweep_GradientType;
31 }
32
33 SkFlattenable* SkSweepGradient::CreateProc(SkReadBuffer& buffer) {
34     DescriptorScope desc;
35     if (!desc.unflatten(buffer)) {
36         return nullptr;
37     }
38     const SkPoint center = buffer.readPoint();
39     return SkGradientShader::CreateSweep(center.x(), center.y(), desc.fColors, desc.fPos,
40                                          desc.fCount, desc.fGradFlags, desc.fLocalMatrix);
41 }
42
43 void SkSweepGradient::flatten(SkWriteBuffer& buffer) const {
44     this->INHERITED::flatten(buffer);
45     buffer.writePoint(fCenter);
46 }
47
48 size_t SkSweepGradient::contextSize() const {
49     return sizeof(SweepGradientContext);
50 }
51
52 SkShader::Context* SkSweepGradient::onCreateContext(const ContextRec& rec, void* storage) const {
53     return new (storage) SweepGradientContext(*this, rec);
54 }
55
56 SkSweepGradient::SweepGradientContext::SweepGradientContext(
57         const SkSweepGradient& shader, const ContextRec& rec)
58     : INHERITED(shader, rec) {}
59
60 //  returns angle in a circle [0..2PI) -> [0..255]
61 static unsigned SkATan2_255(float y, float x) {
62     //    static const float g255Over2PI = 255 / (2 * SK_ScalarPI);
63     static const float g255Over2PI = 40.584510488433314f;
64
65     float result = sk_float_atan2(y, x);
66     if (result < 0) {
67         result += 2 * SK_ScalarPI;
68     }
69     SkASSERT(result >= 0);
70     // since our value is always >= 0, we can cast to int, which is faster than
71     // calling floorf()
72     int ir = (int)(result * g255Over2PI);
73     SkASSERT(ir >= 0 && ir <= 255);
74     return ir;
75 }
76
77 void SkSweepGradient::SweepGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
78                                                       int count) {
79     SkMatrix::MapXYProc proc = fDstToIndexProc;
80     const SkMatrix&     matrix = fDstToIndex;
81     const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
82     int                 toggle = init_dither_toggle(x, y);
83     SkPoint             srcPt;
84
85     if (fDstToIndexClass != kPerspective_MatrixClass) {
86         proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
87                      SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
88         SkScalar dx, fx = srcPt.fX;
89         SkScalar dy, fy = srcPt.fY;
90
91         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
92             SkFixed storage[2];
93             (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
94                                       &storage[0], &storage[1]);
95             dx = SkFixedToScalar(storage[0]);
96             dy = SkFixedToScalar(storage[1]);
97         } else {
98             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
99             dx = matrix.getScaleX();
100             dy = matrix.getSkewY();
101         }
102
103         for (; count > 0; --count) {
104             *dstC++ = cache[toggle + SkATan2_255(fy, fx)];
105             fx += dx;
106             fy += dy;
107             toggle = next_dither_toggle(toggle);
108         }
109     } else {  // perspective case
110         for (int stop = x + count; x < stop; x++) {
111             proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
112                          SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
113             *dstC++ = cache[toggle + SkATan2_255(srcPt.fY, srcPt.fX)];
114             toggle = next_dither_toggle(toggle);
115         }
116     }
117 }
118
119 void SkSweepGradient::SweepGradientContext::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
120                                                         int count) {
121     SkMatrix::MapXYProc proc = fDstToIndexProc;
122     const SkMatrix&     matrix = fDstToIndex;
123     const uint16_t* SK_RESTRICT cache = fCache->getCache16();
124     int                 toggle = init_dither_toggle16(x, y);
125     SkPoint             srcPt;
126
127     if (fDstToIndexClass != kPerspective_MatrixClass) {
128         proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
129                      SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
130         SkScalar dx, fx = srcPt.fX;
131         SkScalar dy, fy = srcPt.fY;
132
133         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
134             SkFixed storage[2];
135             (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
136                                       &storage[0], &storage[1]);
137             dx = SkFixedToScalar(storage[0]);
138             dy = SkFixedToScalar(storage[1]);
139         } else {
140             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
141             dx = matrix.getScaleX();
142             dy = matrix.getSkewY();
143         }
144
145         for (; count > 0; --count) {
146             int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits);
147             *dstC++ = cache[toggle + index];
148             toggle = next_dither_toggle16(toggle);
149             fx += dx;
150             fy += dy;
151         }
152     } else {  // perspective case
153         for (int stop = x + count; x < stop; x++) {
154             proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
155                          SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
156
157             int index = SkATan2_255(srcPt.fY, srcPt.fX);
158             index >>= (8 - kCache16Bits);
159             *dstC++ = cache[toggle + index];
160             toggle = next_dither_toggle16(toggle);
161         }
162     }
163 }
164
165 /////////////////////////////////////////////////////////////////////
166
167 #if SK_SUPPORT_GPU
168
169 #include "SkGr.h"
170 #include "gl/GrGLContext.h"
171 #include "gl/builders/GrGLProgramBuilder.h"
172
173 class GrGLSweepGradient : public GrGLGradientEffect {
174 public:
175
176     GrGLSweepGradient(const GrProcessor&) {}
177     virtual ~GrGLSweepGradient() { }
178
179     virtual void emitCode(EmitArgs&) override;
180
181     static void GenKey(const GrProcessor& processor, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
182         b->add32(GenBaseGradientKey(processor));
183     }
184
185 private:
186
187     typedef GrGLGradientEffect INHERITED;
188
189 };
190
191 /////////////////////////////////////////////////////////////////////
192
193 class GrSweepGradient : public GrGradientEffect {
194 public:
195     static GrFragmentProcessor* Create(GrContext* ctx, const SkSweepGradient& shader,
196                                        const SkMatrix& m) {
197         return new GrSweepGradient(ctx, shader, m);
198     }
199     virtual ~GrSweepGradient() { }
200
201     const char* name() const override { return "Sweep Gradient"; }
202
203 private:
204     GrSweepGradient(GrContext* ctx,
205                     const SkSweepGradient& shader,
206                     const SkMatrix& matrix)
207     : INHERITED(ctx, shader, matrix, SkShader::kClamp_TileMode) {
208         this->initClassID<GrSweepGradient>();
209     }
210
211     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
212         return new GrGLSweepGradient(*this);
213     }
214
215     virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps,
216                                        GrProcessorKeyBuilder* b) const override {
217         GrGLSweepGradient::GenKey(*this, caps, b);
218     }
219
220     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
221
222     typedef GrGradientEffect INHERITED;
223 };
224
225 /////////////////////////////////////////////////////////////////////
226
227 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSweepGradient);
228
229 const GrFragmentProcessor* GrSweepGradient::TestCreate(GrProcessorTestData* d) {
230     SkPoint center = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
231
232     SkColor colors[kMaxRandomGradientColors];
233     SkScalar stopsArray[kMaxRandomGradientColors];
234     SkScalar* stops = stopsArray;
235     SkShader::TileMode tmIgnored;
236     int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tmIgnored);
237     SkAutoTUnref<SkShader> shader(SkGradientShader::CreateSweep(center.fX, center.fY,
238                                                                 colors, stops, colorCount));
239     const GrFragmentProcessor* fp = shader->asFragmentProcessor(d->fContext,
240                                                                 GrTest::TestMatrix(d->fRandom),
241                                                                 NULL, kNone_SkFilterQuality);
242     GrAlwaysAssert(fp);
243     return fp;
244 }
245
246 /////////////////////////////////////////////////////////////////////
247
248 void GrGLSweepGradient::emitCode(EmitArgs& args) {
249     const GrSweepGradient& ge = args.fFp.cast<GrSweepGradient>();
250     this->emitUniforms(args.fBuilder, ge);
251     SkString coords2D = args.fFragBuilder->ensureFSCoords2D(args.fCoords, 0);
252     SkString t;
253     // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi]
254     // On Intel GPU there is an issue where it reads the second arguement to atan "- %s.x" as an int
255     // thus must us -1.0 * %s.x to work correctly
256     if (args.fGLSLCaps->mustForceNegatedAtanParamToFloat()){
257         t.printf("atan(- %s.y, -1.0 * %s.x) * 0.1591549430918 + 0.5",
258                  coords2D.c_str(), coords2D.c_str());
259     } else {
260         t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5",
261                  coords2D.c_str(), coords2D.c_str());
262     }
263     this->emitColor(args.fBuilder,
264                     args.fFragBuilder,
265                     args.fGLSLCaps,
266                     ge, t.c_str(),
267                     args.fOutputColor,
268                     args.fInputColor,
269                     args.fSamplers);
270 }
271
272 /////////////////////////////////////////////////////////////////////
273
274 const GrFragmentProcessor* SkSweepGradient::asFragmentProcessor(
275                                                     GrContext* context,
276                                                     const SkMatrix& viewM,
277                                                     const SkMatrix* localMatrix,
278                                                     SkFilterQuality) const {
279
280     SkMatrix matrix;
281     if (!this->getLocalMatrix().invert(&matrix)) {
282         return nullptr;
283     }
284     if (localMatrix) {
285         SkMatrix inv;
286         if (!localMatrix->invert(&inv)) {
287             return nullptr;
288         }
289         matrix.postConcat(inv);
290     }
291     matrix.postConcat(fPtsToUnit);
292
293     SkAutoTUnref<const GrFragmentProcessor> inner(
294         GrSweepGradient::Create(context, *this, matrix));
295     return GrFragmentProcessor::MulOutputByInputAlpha(inner);
296 }
297
298 #endif
299
300 #ifndef SK_IGNORE_TO_STRING
301 void SkSweepGradient::toString(SkString* str) const {
302     str->append("SkSweepGradient: (");
303
304     str->append("center: (");
305     str->appendScalar(fCenter.fX);
306     str->append(", ");
307     str->appendScalar(fCenter.fY);
308     str->append(") ");
309
310     this->INHERITED::toString(str);
311
312     str->append(")");
313 }
314 #endif