1 /*
2  * Copyright 2017 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/SkString.h"
9 #include "include/private/SkNx.h"
10 #include "src/core/SkArenaAlloc.h"
11 #include "src/core/SkAutoBlitterChoose.h"
12 #include "src/core/SkConvertPixels.h"
13 #include "src/core/SkCoreBlitters.h"
14 #include "src/core/SkDraw.h"
15 #include "src/core/SkRasterClip.h"
16 #include "src/core/SkRasterPipeline.h"
17 #include "src/core/SkScan.h"
18 #include "src/core/SkVertState.h"
19 #include "src/shaders/SkComposeShader.h"
20 #include "src/shaders/SkShaderBase.h"
21 
22 struct Matrix43 {
23     float fMat[12];    // column major
24 
mapMatrix4325     Sk4f map(float x, float y) const {
26         return Sk4f::Load(&fMat[0]) * x + Sk4f::Load(&fMat[4]) * y + Sk4f::Load(&fMat[8]);
27     }
28 
setConcatMatrix4329     void setConcat(const Matrix43& a, const SkMatrix& b) {
30         fMat[ 0] = a.dot(0, b.getScaleX(), b.getSkewY());
31         fMat[ 1] = a.dot(1, b.getScaleX(), b.getSkewY());
32         fMat[ 2] = a.dot(2, b.getScaleX(), b.getSkewY());
33         fMat[ 3] = a.dot(3, b.getScaleX(), b.getSkewY());
34 
35         fMat[ 4] = a.dot(0, b.getSkewX(), b.getScaleY());
36         fMat[ 5] = a.dot(1, b.getSkewX(), b.getScaleY());
37         fMat[ 6] = a.dot(2, b.getSkewX(), b.getScaleY());
38         fMat[ 7] = a.dot(3, b.getSkewX(), b.getScaleY());
39 
40         fMat[ 8] = a.dot(0, b.getTranslateX(), b.getTranslateY()) + a.fMat[ 8];
41         fMat[ 9] = a.dot(1, b.getTranslateX(), b.getTranslateY()) + a.fMat[ 9];
42         fMat[10] = a.dot(2, b.getTranslateX(), b.getTranslateY()) + a.fMat[10];
43         fMat[11] = a.dot(3, b.getTranslateX(), b.getTranslateY()) + a.fMat[11];
44     }
45 
46 private:
dotMatrix4347     float dot(int index, float x, float y) const {
48         return fMat[index + 0] * x + fMat[index + 4] * y;
49     }
50 };
51 
ChooseHairProc(bool doAntiAlias)52 static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) {
53     return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine;
54 }
55 
56 static bool SK_WARN_UNUSED_RESULT
texture_to_matrix(const VertState & state,const SkPoint verts[],const SkPoint texs[],SkMatrix * matrix)57 texture_to_matrix(const VertState& state, const SkPoint verts[], const SkPoint texs[],
58                   SkMatrix* matrix) {
59     SkPoint src[3], dst[3];
60 
61     src[0] = texs[state.f0];
62     src[1] = texs[state.f1];
63     src[2] = texs[state.f2];
64     dst[0] = verts[state.f0];
65     dst[1] = verts[state.f1];
66     dst[2] = verts[state.f2];
67     return matrix->setPolyToPoly(src, dst, 3);
68 }
69 
70 class SkTriColorShader : public SkShaderBase {
71 public:
SkTriColorShader(bool isOpaque)72     SkTriColorShader(bool isOpaque) : fIsOpaque(isOpaque) {}
73 
74     bool update(const SkMatrix& ctmInv, const SkPoint pts[], const SkPMColor4f colors[],
75                 int index0, int index1, int index2);
76 
77 protected:
78 #ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
onMakeContext(const ContextRec & rec,SkArenaAlloc * alloc) const79     Context* onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const override {
80         return nullptr;
81     }
82 #endif
onAppendStages(const SkStageRec & rec) const83     bool onAppendStages(const SkStageRec& rec) const override {
84         rec.fPipeline->append(SkRasterPipeline::seed_shader);
85         rec.fPipeline->append(SkRasterPipeline::matrix_4x3, &fM43);
86         return true;
87     }
88 
89 private:
isOpaque() const90     bool isOpaque() const override { return fIsOpaque; }
91     // For serialization.  This will never be called.
getFactory() const92     Factory getFactory() const override { return nullptr; }
getTypeName() const93     const char* getTypeName() const override { return nullptr; }
94 
95     Matrix43 fM43;  // we overwrite this for each triangle
96     const bool fIsOpaque;
97 
98     typedef SkShaderBase INHERITED;
99 };
100 
update(const SkMatrix & ctmInv,const SkPoint pts[],const SkPMColor4f colors[],int index0,int index1,int index2)101 bool SkTriColorShader::update(const SkMatrix& ctmInv, const SkPoint pts[],
102                               const SkPMColor4f colors[], int index0, int index1, int index2) {
103     SkMatrix m, im;
104     m.reset();
105     m.set(0, pts[index1].fX - pts[index0].fX);
106     m.set(1, pts[index2].fX - pts[index0].fX);
107     m.set(2, pts[index0].fX);
108     m.set(3, pts[index1].fY - pts[index0].fY);
109     m.set(4, pts[index2].fY - pts[index0].fY);
110     m.set(5, pts[index0].fY);
111     if (!m.invert(&im)) {
112         return false;
113     }
114 
115     SkMatrix dstToUnit;
116     dstToUnit.setConcat(im, ctmInv);
117 
118     Sk4f c0 = Sk4f::Load(colors[index0].vec()),
119          c1 = Sk4f::Load(colors[index1].vec()),
120          c2 = Sk4f::Load(colors[index2].vec());
121 
122     Matrix43 colorm;
123     (c1 - c0).store(&colorm.fMat[0]);
124     (c2 - c0).store(&colorm.fMat[4]);
125     c0.store(&colorm.fMat[8]);
126     fM43.setConcat(colorm, dstToUnit);
127     return true;
128 }
129 
130 // Convert the SkColors into float colors. The conversion depends on some conditions:
131 // - If the pixmap has a dst colorspace, we have to be "color-correct".
132 //   Do we map into dst-colorspace before or after we interpolate?
133 // - We have to decide when to apply per-color alpha (before or after we interpolate)
134 //
135 // For now, we will take a simple approach, but recognize this is just a start:
136 // - convert colors into dst colorspace before interpolation (matches gradients)
137 // - apply per-color alpha before interpolation (matches old version of vertices)
138 //
convert_colors(const SkColor src[],int count,SkColorSpace * deviceCS,SkArenaAlloc * alloc)139 static SkPMColor4f* convert_colors(const SkColor src[], int count, SkColorSpace* deviceCS,
140                                    SkArenaAlloc* alloc) {
141     SkPMColor4f* dst = alloc->makeArray<SkPMColor4f>(count);
142     SkImageInfo srcInfo = SkImageInfo::Make(count, 1, kBGRA_8888_SkColorType,
143                                             kUnpremul_SkAlphaType, SkColorSpace::MakeSRGB());
144     SkImageInfo dstInfo = SkImageInfo::Make(count, 1, kRGBA_F32_SkColorType,
145                                             kPremul_SkAlphaType, sk_ref_sp(deviceCS));
146     SkConvertPixels(dstInfo, dst, 0, srcInfo, src, 0);
147     return dst;
148 }
149 
compute_is_opaque(const SkColor colors[],int count)150 static bool compute_is_opaque(const SkColor colors[], int count) {
151     uint32_t c = ~0;
152     for (int i = 0; i < count; ++i) {
153         c &= colors[i];
154     }
155     return SkColorGetA(c) == 0xFF;
156 }
157 
drawVertices(SkVertices::VertexMode vmode,int vertexCount,const SkPoint vertices[],const SkPoint textures[],const SkColor colors[],const SkVertices::BoneIndices boneIndices[],const SkVertices::BoneWeights boneWeights[],SkBlendMode bmode,const uint16_t indices[],int indexCount,const SkPaint & paint,const SkVertices::Bone bones[],int boneCount) const158 void SkDraw::drawVertices(SkVertices::VertexMode vmode, int vertexCount,
159                           const SkPoint vertices[], const SkPoint textures[],
160                           const SkColor colors[], const SkVertices::BoneIndices boneIndices[],
161                           const SkVertices::BoneWeights boneWeights[], SkBlendMode bmode,
162                           const uint16_t indices[], int indexCount,
163                           const SkPaint& paint, const SkVertices::Bone bones[],
164                           int boneCount) const {
165     SkASSERT(0 == vertexCount || vertices);
166 
167     // abort early if there is nothing to draw
168     if (vertexCount < 3 || (indices && indexCount < 3) || fRC->isEmpty()) {
169         return;
170     }
171     SkMatrix ctmInv;
172     if (!fMatrix->invert(&ctmInv)) {
173         return;
174     }
175 
176     // make textures and shader mutually consistent
177     SkShader* shader = paint.getShader();
178     if (!(shader && textures)) {
179         shader = nullptr;
180         textures = nullptr;
181     }
182 
183     // We can simplify things for certain blendmodes. This is for speed, and SkComposeShader
184     // itself insists we don't pass kSrc or kDst to it.
185     //
186     if (colors && textures) {
187         switch (bmode) {
188             case SkBlendMode::kSrc:
189                 colors = nullptr;
190                 break;
191             case SkBlendMode::kDst:
192                 textures = nullptr;
193                 break;
194             default: break;
195         }
196     }
197 
198     // we don't use the shader if there are no textures
199     if (!textures) {
200         shader = nullptr;
201     }
202 
203     constexpr size_t kDefVertexCount = 16;
204     constexpr size_t kOuterSize = sizeof(SkTriColorShader) +
205                                  sizeof(SkShader_Blend) +
206                                  (2 * sizeof(SkPoint) + sizeof(SkColor4f)) * kDefVertexCount;
207     SkSTArenaAlloc<kOuterSize> outerAlloc;
208 
209     // deform vertices using the skeleton if it is passed in
210     if (bones && boneCount) {
211         // allocate space for the deformed vertices
212         SkPoint* deformed = outerAlloc.makeArray<SkPoint>(vertexCount);
213 
214         // deform the vertices
215         if (boneIndices && boneWeights) {
216             for (int i = 0; i < vertexCount; i ++) {
217                 const SkVertices::BoneIndices& indices = boneIndices[i];
218                 const SkVertices::BoneWeights& weights = boneWeights[i];
219 
220                 // apply the world transform
221                 SkPoint worldPoint = bones[0].mapPoint(vertices[i]);
222 
223                 // apply bone deformations
224                 deformed[i] = SkPoint::Make(0.0f, 0.0f);
225                 for (uint32_t j = 0; j < 4; j ++) {
226                     // get the attachment data
227                     uint32_t index = indices[j];
228                     float weight = weights[j];
229 
230                     // skip the bone if there is no weight
231                     if (weight == 0.0f) {
232                         continue;
233                     }
234                     SkASSERT(index != 0);
235 
236                     // deformed += M * v * w
237                     deformed[i] += bones[index].mapPoint(worldPoint) * weight;
238                 }
239             }
240         } else {
241             // no bones, so only apply world transform
242             SkMatrix worldTransform = SkMatrix::I();
243             worldTransform.setAffine(bones[0].values);
244             worldTransform.mapPoints(deformed, vertices, vertexCount);
245         }
246 
247         // change the vertices to point to deformed
248         vertices = deformed;
249     }
250 
251     SkPoint* devVerts = outerAlloc.makeArray<SkPoint>(vertexCount);
252     fMatrix->mapPoints(devVerts, vertices, vertexCount);
253 
254     {
255         SkRect bounds;
256         // this also sets bounds to empty if we see a non-finite value
257         bounds.setBounds(devVerts, vertexCount);
258         if (bounds.isEmpty()) {
259             return;
260         }
261     }
262 
263     VertState       state(vertexCount, indices, indexCount);
264     VertState::Proc vertProc = state.chooseProc(vmode);
265 
266     if (!(colors || textures)) {
267         // no colors[] and no texture, stroke hairlines with paint's color.
268         SkPaint p;
269         p.setStyle(SkPaint::kStroke_Style);
270         SkAutoBlitterChoose blitter(*this, nullptr, p);
271         // Abort early if we failed to create a shader context.
272         if (blitter->isNullBlitter()) {
273             return;
274         }
275         SkScan::HairRCProc hairProc = ChooseHairProc(paint.isAntiAlias());
276         const SkRasterClip& clip = *fRC;
277         while (vertProc(&state)) {
278             SkPoint array[] = {
279                 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2], devVerts[state.f0]
280             };
281             hairProc(array, 4, clip, blitter.get());
282         }
283         return;
284     }
285 
286     SkTriColorShader* triShader = nullptr;
287     SkPMColor4f*  dstColors = nullptr;
288 
289     if (colors) {
290         dstColors = convert_colors(colors, vertexCount, fDst.colorSpace(), &outerAlloc);
291         triShader = outerAlloc.make<SkTriColorShader>(compute_is_opaque(colors, vertexCount));
292         if (shader) {
293             shader = outerAlloc.make<SkShader_Blend>(bmode,
294                                                      sk_ref_sp(triShader), sk_ref_sp(shader),
295                                                      nullptr);
296         } else {
297             shader = triShader;
298         }
299     }
300 
301     SkPaint p(paint);
302     p.setShader(sk_ref_sp(shader));
303 
304     if (!textures) {    // only tricolor shader
305         auto blitter = SkCreateRasterPipelineBlitter(fDst, p, *fMatrix, &outerAlloc);
306         while (vertProc(&state)) {
307             if (!triShader->update(ctmInv, vertices, dstColors, state.f0, state.f1, state.f2)) {
308                 continue;
309             }
310 
311             SkPoint tmp[] = {
312                 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
313             };
314             SkScan::FillTriangle(tmp, *fRC, blitter);
315         }
316         return;
317     }
318 
319     SkRasterPipeline pipeline(&outerAlloc);
320     SkStageRec rec = {
321         &pipeline, &outerAlloc, fDst.colorType(), fDst.colorSpace(), p, nullptr, *fMatrix
322     };
323     if (auto updater = as_SB(shader)->appendUpdatableStages(rec)) {
324         bool isOpaque = shader->isOpaque();
325         if (triShader) {
326             isOpaque = false;   // unless we want to walk all the colors, and see if they are
327                                 // all opaque (and the blendmode will keep them that way
328         }
329 
330         auto blitter = SkCreateRasterPipelineBlitter(fDst, p, pipeline, isOpaque, &outerAlloc);
331         while (vertProc(&state)) {
332             if (triShader && !triShader->update(ctmInv, vertices, dstColors,
333                                                 state.f0, state.f1, state.f2)) {
334                 continue;
335             }
336 
337             SkMatrix localM;
338             if (!texture_to_matrix(state, vertices, textures, &localM) ||
339                 !updater->update(*fMatrix, &localM)) {
340                 continue;
341             }
342 
343             SkPoint tmp[] = {
344                 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
345             };
346             SkScan::FillTriangle(tmp, *fRC, blitter);
347         }
348     } else {
349         // must rebuild pipeline for each triangle, to pass in the computed ctm
350         while (vertProc(&state)) {
351             if (triShader && !triShader->update(ctmInv, vertices, dstColors,
352                                                 state.f0, state.f1, state.f2)) {
353                 continue;
354             }
355 
356             SkSTArenaAlloc<2048> innerAlloc;
357 
358             const SkMatrix* ctm = fMatrix;
359             SkMatrix tmpCtm;
360             if (textures) {
361                 SkMatrix localM;
362                 if (!texture_to_matrix(state, vertices, textures, &localM)) {
363                     continue;
364                 }
365                 tmpCtm = SkMatrix::Concat(*fMatrix, localM);
366                 ctm = &tmpCtm;
367             }
368 
369             SkPoint tmp[] = {
370                 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
371             };
372             auto blitter = SkCreateRasterPipelineBlitter(fDst, p, *ctm, &innerAlloc);
373             SkScan::FillTriangle(tmp, *fRC, blitter);
374         }
375     }
376 }
377