• 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/SkBlenderBase.h"
13 #include "src/core/SkColorSpacePriv.h"
14 #include "src/core/SkColorSpaceXformSteps.h"
15 #include "src/core/SkCoreBlitters.h"
16 #include "src/core/SkDraw.h"
17 #include "src/core/SkMatrixProvider.h"
18 #include "src/core/SkRasterClip.h"
19 #include "src/core/SkRasterPipeline.h"
20 #include "src/core/SkScan.h"
21 #include "src/core/SkVM.h"
22 #include "src/core/SkVMBlitter.h"
23 #include "src/shaders/SkShaderBase.h"
24 #include "src/shaders/SkTransformShader.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} {}
program(skvm::Builder * builder,skvm::Coord device,skvm::Coord local,skvm::Color paint,const MatrixRec &,const SkColorInfo & dst,skvm::Uniforms * uniforms,SkArenaAlloc * alloc) const57     skvm::Color program(skvm::Builder* builder,
58                         skvm::Coord device,
59                         skvm::Coord local,
60                         skvm::Color paint,
61                         const MatrixRec&,
62                         const SkColorInfo& dst,
63                         skvm::Uniforms* uniforms,
64                         SkArenaAlloc* alloc) const override {
65         skvm::Uniform color = uniforms->pushPtr(fValues);
66         skvm::F32 r = builder->arrayF(color, 0);
67         skvm::F32 g = builder->arrayF(color, 1);
68         skvm::F32 b = builder->arrayF(color, 2);
69         skvm::F32 a = builder->arrayF(color, 3);
70 
71         return {r, g, b, a};
72     }
73 
updateColor(SkColor c) const74     void updateColor(SkColor c) const {
75         SkColor4f c4 = SkColor4f::FromColor(c);
76         fSteps.apply(c4.vec());
77         auto cp4 = c4.premul();
78         fValues[0] = cp4.fR;
79         fValues[1] = cp4.fG;
80         fValues[2] = cp4.fB;
81         fValues[3] = cp4.fA;
82     }
83 
84 private:
85     // For serialization.  This will never be called.
getFactory() const86     Factory getFactory() const override { return nullptr; }
getTypeName() const87     const char* getTypeName() const override { return nullptr; }
88 
89     SkColorSpaceXformSteps fSteps;
90     mutable float fValues[4];
91 };
92 
drawAtlas(const SkRSXform xform[],const SkRect textures[],const SkColor colors[],int count,sk_sp<SkBlender> blender,const SkPaint & paint)93 void SkDraw::drawAtlas(const SkRSXform xform[],
94                        const SkRect textures[],
95                        const SkColor colors[],
96                        int count,
97                        sk_sp<SkBlender> blender,
98                        const SkPaint& paint) {
99     sk_sp<SkShader> atlasShader = paint.refShader();
100     if (!atlasShader) {
101         return;
102     }
103 
104     SkSTArenaAlloc<256> alloc;
105 
106     SkPaint p(paint);
107     p.setAntiAlias(false);  // we never respect this for drawAtlas(or drawVertices)
108     p.setStyle(SkPaint::kFill_Style);
109     p.setShader(nullptr);
110     p.setMaskFilter(nullptr);
111 
112     const SkMatrix& ctm = fMatrixProvider->localToDevice();
113     // The RSXForms can't contain perspective - only the CTM cab.
114     const bool perspective = ctm.hasPerspective();
115 
116     auto transformShader = alloc.make<SkTransformShader>(*as_SB(atlasShader), perspective);
117 
118     auto rpblit = [&]() {
119         SkRasterPipeline pipeline(&alloc);
120         SkSurfaceProps props = SkSurfacePropsCopyOrDefault(fProps);
121         SkStageRec rec = {&pipeline, &alloc, fDst.colorType(), fDst.colorSpace(), p, props};
122         // We pass an identity matrix here rather than the CTM. The CTM gets folded into the
123         // per-triangle matrix.
124         if (!as_SB(transformShader)->appendRootStages(rec, SkMatrix::I())) {
125             return false;
126         }
127 
128         SkRasterPipeline_UniformColorCtx* uniformCtx = nullptr;
129         SkColorSpaceXformSteps steps(
130                 sk_srgb_singleton(), kUnpremul_SkAlphaType, rec.fDstCS, kUnpremul_SkAlphaType);
131 
132         if (colors) {
133             // we will late-bind the values in ctx, once for each color in the loop
134             uniformCtx = alloc.make<SkRasterPipeline_UniformColorCtx>();
135             rec.fPipeline->append(SkRasterPipelineOp::uniform_color_dst, uniformCtx);
136             if (std::optional<SkBlendMode> bm = as_BB(blender)->asBlendMode(); bm.has_value()) {
137                 SkBlendMode_AppendStages(*bm, rec.fPipeline);
138             } else {
139                 return false;
140             }
141         }
142 
143         bool isOpaque = !colors && transformShader->isOpaque();
144         if (p.getAlphaf() != 1) {
145             rec.fPipeline->append(SkRasterPipelineOp::scale_1_float,
146                                   alloc.make<float>(p.getAlphaf()));
147             isOpaque = false;
148         }
149 
150         auto blitter = SkCreateRasterPipelineBlitter(
151                 fDst, p, pipeline, isOpaque, &alloc, fRC->clipShader());
152         if (!blitter) {
153             return false;
154         }
155         SkPath scratchPath;
156 
157         for (int i = 0; i < count; ++i) {
158             if (colors) {
159                 SkColor4f c4 = SkColor4f::FromColor(colors[i]);
160                 steps.apply(c4.vec());
161                 load_color(uniformCtx, c4.premul().vec());
162             }
163 
164             SkMatrix mx;
165             mx.setRSXform(xform[i]);
166             mx.preTranslate(-textures[i].fLeft, -textures[i].fTop);
167             mx.postConcat(ctm);
168             if (transformShader->update(mx)) {
169                 fill_rect(mx, *fRC, textures[i], blitter, &scratchPath);
170             }
171         }
172         return true;
173     };
174 
175     if (gUseSkVMBlitter || !rpblit()) {
176         UpdatableColorShader* colorShader = nullptr;
177         sk_sp<SkShader> shader;
178         if (colors) {
179             colorShader = alloc.make<UpdatableColorShader>(fDst.colorSpace());
180             shader = SkShaders::Blend(std::move(blender),
181                                       sk_ref_sp(colorShader),
182                                       sk_ref_sp(transformShader));
183         } else {
184             shader = sk_ref_sp(transformShader);
185         }
186         p.setShader(std::move(shader));
187         // We use identity here and fold the CTM into the update matrix.
188         if (auto blitter = SkVMBlitter::Make(fDst,
189                                              p,
190                                              SkMatrix::I(),
191                                              &alloc,
192                                              fRC->clipShader())) {
193             SkPath scratchPath;
194             for (int i = 0; i < count; ++i) {
195                 if (colorShader) {
196                     colorShader->updateColor(colors[i]);
197                 }
198 
199                 SkMatrix mx;
200                 mx.setRSXform(xform[i]);
201                 mx.preTranslate(-textures[i].fLeft, -textures[i].fTop);
202                 mx.postConcat(ctm);
203                 if (transformShader->update(mx)) {
204                     fill_rect(mx, *fRC, textures[i], blitter, &scratchPath);
205                 }
206             }
207         }
208     }
209 }
210