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,sk_sp<SkBlender> blender,const SkPaint & paint)89 void SkDraw::drawAtlas(const SkRSXform xform[],
90 const SkRect textures[],
91 const SkColor colors[],
92 int count,
93 sk_sp<SkBlender> blender,
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(
126 SkShaders::Blend(blender, SkShaders::Color(colors[i]), atlasShader));
127 }
128 SkMatrix mx;
129 mx.setRSXform(xform[i]);
130 mx.preTranslate(-textures[i].fLeft, -textures[i].fTop);
131 SkPreConcatMatrixProvider matrixProvider(*fMatrixProvider, mx);
132 draw.fMatrixProvider = &matrixProvider;
133 draw.drawRect(textures[i], p);
134 }
135 return true;
136 }
137
138 SkRasterPipeline_UniformColorCtx* uniformCtx = nullptr;
139 SkColorSpaceXformSteps steps(
140 sk_srgb_singleton(), kUnpremul_SkAlphaType, rec.fDstCS, kUnpremul_SkAlphaType);
141
142 if (colors) {
143 // we will late-bind the values in ctx, once for each color in the loop
144 uniformCtx = alloc.make<SkRasterPipeline_UniformColorCtx>();
145 rec.fPipeline->append(SkRasterPipeline::uniform_color_dst, uniformCtx);
146 if (std::optional<SkBlendMode> bm = as_BB(blender)->asBlendMode(); bm.has_value()) {
147 SkBlendMode_AppendStages(*bm, rec.fPipeline);
148 } else {
149 return false;
150 }
151 }
152
153 bool isOpaque = !colors && atlasShader->isOpaque();
154 if (p.getAlphaf() != 1) {
155 rec.fPipeline->append(SkRasterPipeline::scale_1_float,
156 alloc.make<float>(p.getAlphaf()));
157 isOpaque = false;
158 }
159
160 auto blitter = SkCreateRasterPipelineBlitter(
161 fDst, p, pipeline, isOpaque, &alloc, fRC->clipShader());
162 if (!blitter) {
163 return false;
164 }
165 SkPath scratchPath;
166
167 for (int i = 0; i < count; ++i) {
168 if (colors) {
169 SkColor4f c4 = SkColor4f::FromColor(colors[i]);
170 steps.apply(c4.vec());
171 load_color(uniformCtx, c4.premul().vec());
172 }
173
174 SkMatrix mx;
175 mx.setRSXform(xform[i]);
176 mx.preTranslate(-textures[i].fLeft, -textures[i].fTop);
177 mx.postConcat(fMatrixProvider->localToDevice());
178
179 if (updator->update(mx)) {
180 fill_rect(mx, *fRC, textures[i], blitter, &scratchPath);
181 }
182 }
183 return true;
184 };
185
186 if (gUseSkVMBlitter || !rpblit()) {
187 auto updateShader = as_SB(atlasShader)->updatableShader(&alloc);
188 UpdatableColorShader* colorShader = nullptr;
189 SkShaderBase* shader = nullptr;
190 if (colors) {
191 colorShader = alloc.make<UpdatableColorShader>(fDst.colorSpace());
192 shader = alloc.make<SkShader_Blend>(
193 std::move(blender), sk_ref_sp(colorShader), sk_ref_sp(updateShader));
194 } else {
195 shader = as_SB(updateShader);
196 }
197 p.setShader(sk_ref_sp(shader));
198 if (auto blitter = SkVMBlitter::Make(fDst, p, *fMatrixProvider, &alloc,
199 fRC->clipShader())) {
200 SkPath scratchPath;
201 for (int i = 0; i < count; ++i) {
202 if (colorShader) {
203 colorShader->updateColor(colors[i]);
204 }
205
206 SkMatrix mx;
207 mx.setRSXform(xform[i]);
208 mx.preTranslate(-textures[i].fLeft, -textures[i].fTop);
209 mx.postConcat(fMatrixProvider->localToDevice());
210 if (updateShader->update(mx)) {
211 fill_rect(mx, *fRC, textures[i], blitter, &scratchPath);
212 }
213 }
214 }
215 }
216 }
217