• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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 "include/core/SkColorFilter.h"
9 #include "include/core/SkMatrix.h"
10 #include "include/core/SkRSXform.h"
11 #include "src/core/SkBlendModePriv.h"
12 #include "src/core/SkColorSpacePriv.h"
13 #include "src/core/SkColorSpaceXformSteps.h"
14 #include "src/core/SkCoreBlitters.h"
15 #include "src/core/SkDraw.h"
16 #include "src/core/SkMatrixProvider.h"
17 #include "src/core/SkRasterClip.h"
18 #include "src/core/SkRasterPipeline.h"
19 #include "src/core/SkScan.h"
20 #include "src/core/SkScan.h"
21 #include "src/core/SkVM.h"
22 #include "src/core/SkVMBlitter.h"
23 #include "src/shaders/SkComposeShader.h"
24 #include "src/shaders/SkShaderBase.h"
25 
fill_rect(const SkMatrix & ctm,const SkRasterClip & rc,const SkRect & r,SkBlitter * blitter,SkPath * scratchPath)26 static void fill_rect(const SkMatrix& ctm, const SkRasterClip& rc,
27                       const SkRect& r, SkBlitter* blitter, SkPath* scratchPath) {
28     if (ctm.rectStaysRect()) {
29         SkRect dr;
30         ctm.mapRect(&dr, r);
31         SkScan::FillRect(dr, rc, blitter);
32     } else {
33         SkPoint pts[4];
34         r.toQuad(pts);
35         ctm.mapPoints(pts, pts, 4);
36 
37         scratchPath->rewind();
38         scratchPath->addPoly(pts, 4, true);
39         SkScan::FillPath(*scratchPath, rc, blitter);
40     }
41 }
42 
load_color(SkRasterPipeline_UniformColorCtx * ctx,const float rgba[])43 static void load_color(SkRasterPipeline_UniformColorCtx* ctx, const float rgba[]) {
44     // only need one of these. can I query the pipeline to know if its lowp or highp?
45     ctx->rgba[0] = SkScalarRoundToInt(rgba[0]*255); ctx->r = rgba[0];
46     ctx->rgba[1] = SkScalarRoundToInt(rgba[1]*255); ctx->g = rgba[1];
47     ctx->rgba[2] = SkScalarRoundToInt(rgba[2]*255); ctx->b = rgba[2];
48     ctx->rgba[3] = SkScalarRoundToInt(rgba[3]*255); ctx->a = rgba[3];
49 }
50 
51 extern bool gUseSkVMBlitter;
52 
53 class UpdatableColorShader : public SkShaderBase {
54 public:
UpdatableColorShader(SkColorSpace * cs)55     explicit UpdatableColorShader(SkColorSpace* cs)
56         : fSteps{sk_srgb_singleton(), kUnpremul_SkAlphaType, cs, kUnpremul_SkAlphaType} {}
onProgram(skvm::Builder * builder,skvm::Coord device,skvm::Coord local,skvm::Color paint,const SkMatrixProvider & provider,const SkMatrix * localM,const SkColorInfo & dst,skvm::Uniforms * uniforms,SkArenaAlloc * alloc) const57     skvm::Color onProgram(
58             skvm::Builder* builder, skvm::Coord device, skvm::Coord local, skvm::Color paint,
59             const SkMatrixProvider& provider, const SkMatrix* localM, const SkColorInfo& dst,
60             skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override {
61         skvm::Uniform color = uniforms->pushPtr(fValues);
62         skvm::F32 r = builder->arrayF(color, 0);
63         skvm::F32 g = builder->arrayF(color, 1);
64         skvm::F32 b = builder->arrayF(color, 2);
65         skvm::F32 a = builder->arrayF(color, 3);
66 
67         return {r, g, b, a};
68     }
69 
updateColor(SkColor c) const70     void updateColor(SkColor c) const {
71         SkColor4f c4 = SkColor4f::FromColor(c);
72         fSteps.apply(c4.vec());
73         auto cp4 = c4.premul();
74         fValues[0] = cp4.fR;
75         fValues[1] = cp4.fG;
76         fValues[2] = cp4.fB;
77         fValues[3] = cp4.fA;
78     }
79 
80 private:
81     // For serialization.  This will never be called.
getFactory() const82     Factory getFactory() const override { return nullptr; }
getTypeName() const83     const char* getTypeName() const override { return nullptr; }
84 
85     SkColorSpaceXformSteps fSteps;
86     mutable float fValues[4];
87 };
88 
drawAtlas(const SkRSXform xform[],const SkRect textures[],const SkColor colors[],int count,SkBlendMode bmode,const SkPaint & paint)89 void SkDraw::drawAtlas(const SkRSXform xform[],
90                        const SkRect textures[],
91                        const SkColor colors[],
92                        int count,
93                        SkBlendMode bmode,
94                        const SkPaint& paint) {
95     sk_sp<SkShader> atlasShader = paint.refShader();
96     if (!atlasShader) {
97         return;
98     }
99 
100     SkSTArenaAlloc<256> alloc;
101 
102     SkPaint p(paint);
103     p.setAntiAlias(false);  // we never respect this for drawAtlas(or drawVertices)
104     p.setStyle(SkPaint::kFill_Style);
105     p.setShader(nullptr);
106     p.setMaskFilter(nullptr);
107 
108     auto rpblit = [&]() {
109         SkRasterPipeline pipeline(&alloc);
110         SkStageRec rec = {&pipeline,
111                           &alloc,
112                           fDst.colorType(),
113                           fDst.colorSpace(),
114                           p,
115                           nullptr,
116                           *fMatrixProvider};
117 
118         SkStageUpdater* updator = as_SB(atlasShader.get())->appendUpdatableStages(rec);
119         if (!updator) {
120             SkDraw draw(*this);
121 
122             p.setShader(atlasShader);
123             for (int i = 0; i < count; ++i) {
124                 if (colors) {
125                     p.setShader(SkShaders::Blend(bmode, SkShaders::Color(colors[i]), atlasShader));
126                 }
127                 SkMatrix mx;
128                 mx.setRSXform(xform[i]);
129                 mx.preTranslate(-textures[i].fLeft, -textures[i].fTop);
130                 SkPreConcatMatrixProvider matrixProvider(*fMatrixProvider, mx);
131                 draw.fMatrixProvider = &matrixProvider;
132                 draw.drawRect(textures[i], p);
133             }
134             return true;
135         }
136 
137         SkRasterPipeline_UniformColorCtx* uniformCtx = nullptr;
138         SkColorSpaceXformSteps steps(
139                 sk_srgb_singleton(), kUnpremul_SkAlphaType, rec.fDstCS, kUnpremul_SkAlphaType);
140 
141         if (colors) {
142             // we will late-bind the values in ctx, once for each color in the loop
143             uniformCtx = alloc.make<SkRasterPipeline_UniformColorCtx>();
144             rec.fPipeline->append(SkRasterPipeline::uniform_color_dst, uniformCtx);
145             SkBlendMode_AppendStages(bmode, rec.fPipeline);
146         }
147 
148         bool isOpaque = !colors && atlasShader->isOpaque();
149         if (p.getAlphaf() != 1) {
150             rec.fPipeline->append(SkRasterPipeline::scale_1_float,
151                                   alloc.make<float>(p.getAlphaf()));
152             isOpaque = false;
153         }
154 
155         auto blitter = SkCreateRasterPipelineBlitter(
156                 fDst, p, pipeline, isOpaque, &alloc, fRC->clipShader());
157         if (!blitter) {
158             return false;
159         }
160         SkPath scratchPath;
161 
162         for (int i = 0; i < count; ++i) {
163             if (colors) {
164                 SkColor4f c4 = SkColor4f::FromColor(colors[i]);
165                 steps.apply(c4.vec());
166                 load_color(uniformCtx, c4.premul().vec());
167             }
168 
169             SkMatrix mx;
170             mx.setRSXform(xform[i]);
171             mx.preTranslate(-textures[i].fLeft, -textures[i].fTop);
172             mx.postConcat(fMatrixProvider->localToDevice());
173 
174             if (updator->update(mx)) {
175                 fill_rect(mx, *fRC, textures[i], blitter, &scratchPath);
176             }
177         }
178         return true;
179     };
180 
181     if (gUseSkVMBlitter || !rpblit()) {
182         auto updateShader = as_SB(atlasShader)->updatableShader(&alloc);
183         UpdatableColorShader* colorShader = nullptr;
184         SkShaderBase* shader = nullptr;
185         if (colors) {
186             colorShader = alloc.make<UpdatableColorShader>(fDst.colorSpace());
187             shader = alloc.make<SkShader_Blend>(
188                     bmode, sk_ref_sp(colorShader), sk_ref_sp(updateShader));
189         } else {
190             shader = as_SB(updateShader);
191         }
192         p.setShader(sk_ref_sp(shader));
193         if (auto blitter = SkVMBlitter::Make(fDst, p, *fMatrixProvider, &alloc,
194                                              fRC->clipShader())) {
195             SkPath scratchPath;
196             for (int i = 0; i < count; ++i) {
197                 if (colorShader) {
198                     colorShader->updateColor(colors[i]);
199                 }
200 
201                 SkMatrix mx;
202                 mx.setRSXform(xform[i]);
203                 mx.preTranslate(-textures[i].fLeft, -textures[i].fTop);
204                 mx.postConcat(fMatrixProvider->localToDevice());
205                 if (updateShader->update(mx)) {
206                     fill_rect(mx, *fRC, textures[i], blitter, &scratchPath);
207                 }
208             }
209         }
210     }
211 }
212