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