• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/shaders/gradients/SkSweepGradient.h"
9 
10 #include "include/private/SkFloatingPoint.h"
11 #include "src/core/SkKeyHelpers.h"
12 #include "src/core/SkRasterPipeline.h"
13 #include "src/core/SkReadBuffer.h"
14 #include "src/core/SkWriteBuffer.h"
15 
SkSweepGradient(const SkPoint & center,SkScalar t0,SkScalar t1,const Descriptor & desc)16 SkSweepGradient::SkSweepGradient(const SkPoint& center, SkScalar t0, SkScalar t1,
17                                  const Descriptor& desc)
18     : SkGradientShaderBase(desc, SkMatrix::Translate(-center.x(), -center.y()))
19     , fCenter(center)
20     , fTBias(-t0)
21     , fTScale(1 / (t1 - t0))
22 {
23     SkASSERT(t0 < t1);
24 }
25 
asAGradient(GradientInfo * info) const26 SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const {
27     if (info) {
28         commonAsAGradient(info);
29         info->fPoint[0] = fCenter;
30     }
31     return kSweep_GradientType;
32 }
33 
angles_from_t_coeff(SkScalar tBias,SkScalar tScale)34 static std::tuple<SkScalar, SkScalar> angles_from_t_coeff(SkScalar tBias, SkScalar tScale) {
35     return std::make_tuple(-tBias * 360, (sk_ieee_float_divide(1, tScale) - tBias) * 360);
36 }
37 
CreateProc(SkReadBuffer & buffer)38 sk_sp<SkFlattenable> SkSweepGradient::CreateProc(SkReadBuffer& buffer) {
39     DescriptorScope desc;
40     if (!desc.unflatten(buffer)) {
41         return nullptr;
42     }
43     const SkPoint center = buffer.readPoint();
44 
45     const auto tBias  = buffer.readScalar(),
46                tScale = buffer.readScalar();
47     auto [startAngle, endAngle] = angles_from_t_coeff(tBias, tScale);
48 
49     return SkGradientShader::MakeSweep(center.x(), center.y(), desc.fColors,
50                                        std::move(desc.fColorSpace), desc.fPos, desc.fCount,
51                                        desc.fTileMode, startAngle, endAngle,
52                                        desc.fGradFlags, desc.fLocalMatrix);
53 }
54 
flatten(SkWriteBuffer & buffer) const55 void SkSweepGradient::flatten(SkWriteBuffer& buffer) const {
56     this->INHERITED::flatten(buffer);
57     buffer.writePoint(fCenter);
58     buffer.writeScalar(fTBias);
59     buffer.writeScalar(fTScale);
60 }
61 
appendGradientStages(SkArenaAlloc * alloc,SkRasterPipeline * p,SkRasterPipeline *) const62 void SkSweepGradient::appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* p,
63                                            SkRasterPipeline*) const {
64     p->append(SkRasterPipeline::xy_to_unit_angle);
65     p->append_matrix(alloc, SkMatrix::Scale(fTScale, 1) * SkMatrix::Translate(fTBias, 0));
66 }
67 
transformT(skvm::Builder * p,skvm::Uniforms * uniforms,skvm::Coord coord,skvm::I32 * mask) const68 skvm::F32 SkSweepGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms,
69                                       skvm::Coord coord, skvm::I32* mask) const {
70     skvm::F32 xabs = abs(coord.x),
71               yabs = abs(coord.y),
72              slope = min(xabs, yabs) / max(xabs, yabs);
73     skvm::F32 s = slope * slope;
74 
75     // Use a 7th degree polynomial to approximate atan.
76     // This was generated using sollya.gforge.inria.fr.
77     // A float optimized polynomial was generated using the following command.
78     // P1 = fpminimax((1/(2*Pi))*atan(x),[|1,3,5,7|],[|24...|],[2^(-40),1],relative);
79     skvm::F32 phi = slope * poly(s, -7.0547382347285747528076171875e-3f,
80                                     +2.476101927459239959716796875e-2f,
81                                     -5.185396969318389892578125e-2f,
82                                     +0.15912117063999176025390625f);
83     phi = select(   xabs < yabs, (1/4.0f) - phi, phi);
84     phi = select(coord.x < 0.0f, (1/2.0f) - phi, phi);
85     phi = select(coord.y < 0.0f, (1/1.0f) - phi, phi);
86 
87     skvm::F32 t = select(is_NaN(phi), p->splat(0.0f)
88                                     , phi);
89 
90     if (fTScale != 1.0f || fTBias != 0.0f) {
91         t = t * p->uniformF(uniforms->pushF(fTScale))
92               + p->uniformF(uniforms->pushF(fTScale*fTBias));
93     }
94     return t;
95 }
96 
97 /////////////////////////////////////////////////////////////////////
98 
99 #if SK_SUPPORT_GPU
100 
101 #include "src/gpu/gradients/GrGradientShader.h"
102 
asFragmentProcessor(const GrFPArgs & args) const103 std::unique_ptr<GrFragmentProcessor> SkSweepGradient::asFragmentProcessor(
104         const GrFPArgs& args) const {
105     return GrGradientShader::MakeSweep(*this, args);
106 }
107 
108 #endif
109 
addToKey(SkShaderCodeDictionary * dict,SkBackend backend,SkPaintParamsKeyBuilder * builder,SkUniformBlock * uniformBlock) const110 void SkSweepGradient::addToKey(SkShaderCodeDictionary* dict,
111                                SkBackend backend,
112                                SkPaintParamsKeyBuilder* builder,
113                                SkUniformBlock* uniformBlock) const {
114     GradientShaderBlocks::GradientData data(kSweep_GradientType,
115                                             fCenter, { 0.0f, 0.0f },
116                                             0.0, 0.0f,
117                                             fTileMode,
118                                             fColorCount,
119                                             fOrigColors4f,
120                                             fOrigPos);
121 
122     GradientShaderBlocks::AddToKey(dict, backend, builder, uniformBlock, data);
123 }
124