1 /*
2  * Copyright 2015 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 "GrAAFillRectOp.h"
9 
10 #include "GrColor.h"
11 #include "GrDefaultGeoProcFactory.h"
12 #include "GrMeshDrawOp.h"
13 #include "GrOpFlushState.h"
14 #include "GrResourceKey.h"
15 #include "GrResourceProvider.h"
16 #include "GrTypes.h"
17 #include "SkMatrix.h"
18 #include "SkRect.h"
19 
20 GR_DECLARE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
21 
set_inset_fan(SkPoint * pts,size_t stride,const SkRect & r,SkScalar dx,SkScalar dy)22 static void set_inset_fan(SkPoint* pts, size_t stride, const SkRect& r, SkScalar dx, SkScalar dy) {
23     pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
24 }
25 
26 static const int kNumAAFillRectsInIndexBuffer = 256;
27 static const int kVertsPerAAFillRect = 8;
28 static const int kIndicesPerAAFillRect = 30;
29 
get_index_buffer(GrResourceProvider * resourceProvider)30 const GrBuffer* get_index_buffer(GrResourceProvider* resourceProvider) {
31     GR_DEFINE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
32 
33     // clang-format off
34     static const uint16_t gFillAARectIdx[] = {
35         0, 1, 5, 5, 4, 0,
36         1, 2, 6, 6, 5, 1,
37         2, 3, 7, 7, 6, 2,
38         3, 0, 4, 4, 7, 3,
39         4, 5, 6, 6, 7, 4,
40     };
41     // clang-format on
42 
43     GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFillAARectIdx) == kIndicesPerAAFillRect);
44     return resourceProvider->findOrCreateInstancedIndexBuffer(
45             gFillAARectIdx, kIndicesPerAAFillRect, kNumAAFillRectsInIndexBuffer,
46             kVertsPerAAFillRect, gAAFillRectIndexBufferKey);
47 }
48 
generate_aa_fill_rect_geometry(intptr_t verts,size_t vertexStride,GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & devRect,bool tweakAlphaForCoverage,const SkMatrix * localMatrix)49 static void generate_aa_fill_rect_geometry(intptr_t verts,
50                                            size_t vertexStride,
51                                            GrColor color,
52                                            const SkMatrix& viewMatrix,
53                                            const SkRect& rect,
54                                            const SkRect& devRect,
55                                            bool tweakAlphaForCoverage,
56                                            const SkMatrix* localMatrix) {
57     SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
58     SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
59 
60     SkScalar inset;
61 
62     if (viewMatrix.rectStaysRect()) {
63         inset = SkMinScalar(devRect.width(), SK_Scalar1);
64         inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
65 
66         set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
67         set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
68     } else {
69         // compute transformed (1, 0) and (0, 1) vectors
70         SkVector vec[2] = {{viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY]},
71                            {viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY]}};
72 
73         SkScalar len1 = SkPoint::Normalize(&vec[0]);
74         vec[0].scale(SK_ScalarHalf);
75         SkScalar len2 = SkPoint::Normalize(&vec[1]);
76         vec[1].scale(SK_ScalarHalf);
77 
78         inset = SkMinScalar(len1 * rect.width(), SK_Scalar1);
79         inset = SK_ScalarHalf * SkMinScalar(inset, len2 * rect.height());
80 
81         // create the rotated rect
82         fan0Pos->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride);
83         viewMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
84 
85         // Now create the inset points and then outset the original
86         // rotated points
87 
88         // TL
89         *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
90                 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
91         *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
92         // BL
93         *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
94                 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
95         *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
96         // BR
97         *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
98                 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
99         *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
100         // TR
101         *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
102                 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
103         *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
104     }
105 
106     if (localMatrix) {
107         SkMatrix invViewMatrix;
108         if (!viewMatrix.invert(&invViewMatrix)) {
109             SkDebugf("View matrix is non-invertible, local coords will be wrong.");
110             invViewMatrix = SkMatrix::I();
111         }
112         SkMatrix localCoordMatrix;
113         localCoordMatrix.setConcat(*localMatrix, invViewMatrix);
114         SkPoint* fan0Loc = reinterpret_cast<SkPoint*>(verts + sizeof(SkPoint) + sizeof(GrColor));
115         localCoordMatrix.mapPointsWithStride(fan0Loc, fan0Pos, vertexStride, 8);
116     }
117 
118     // Make verts point to vertex color and then set all the color and coverage vertex attrs
119     // values.
120     verts += sizeof(SkPoint);
121 
122     // The coverage offset is always the last vertex attribute
123     intptr_t coverageOffset = vertexStride - sizeof(GrColor) - sizeof(SkPoint);
124     for (int i = 0; i < 4; ++i) {
125         if (tweakAlphaForCoverage) {
126             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
127         } else {
128             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
129             *reinterpret_cast<float*>(verts + i * vertexStride + coverageOffset) = 0;
130         }
131     }
132 
133     int scale;
134     if (inset < SK_ScalarHalf) {
135         scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
136         SkASSERT(scale >= 0 && scale <= 255);
137     } else {
138         scale = 0xff;
139     }
140 
141     verts += 4 * vertexStride;
142 
143     float innerCoverage = GrNormalizeByteToFloat(scale);
144     GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
145 
146     for (int i = 0; i < 4; ++i) {
147         if (tweakAlphaForCoverage) {
148             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
149         } else {
150             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
151             *reinterpret_cast<float*>(verts + i * vertexStride + coverageOffset) = innerCoverage;
152         }
153     }
154 }
155 
156 class AAFillRectOp final: public GrMeshDrawOp {
157 public:
158     DEFINE_OP_CLASS_ID
159 
AAFillRectOp(GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & devRect,const SkMatrix * localMatrix)160     AAFillRectOp(GrColor color,
161                  const SkMatrix& viewMatrix,
162                  const SkRect& rect,
163                  const SkRect& devRect,
164                  const SkMatrix* localMatrix)
165             : INHERITED(ClassID()) {
166         if (localMatrix) {
167             void* mem = fRectData.push_back_n(sizeof(RectWithLocalMatrixInfo));
168             new (mem) RectWithLocalMatrixInfo(color, viewMatrix, rect, devRect, *localMatrix);
169         } else {
170             void* mem = fRectData.push_back_n(sizeof(RectInfo));
171             new (mem) RectInfo(color, viewMatrix, rect, devRect);
172         }
173         IsZeroArea zeroArea =
174                 (!rect.width() || !rect.height()) ? IsZeroArea::kYes : IsZeroArea::kNo;
175         this->setBounds(devRect, HasAABloat::kYes, zeroArea);
176         fRectCnt = 1;
177     }
178 
name() const179     const char* name() const override { return "AAFillRectOp"; }
180 
dumpInfo() const181     SkString dumpInfo() const override {
182         SkString str;
183         str.appendf("# combined: %d\n", fRectCnt);
184         const RectInfo* info = this->first();
185         for (int i = 0; i < fRectCnt; ++i) {
186             const SkRect& rect = info->rect();
187             str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
188                         info->color(), rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
189             info = this->next(info);
190         }
191         str.append(DumpPipelineInfo(*this->pipeline()));
192         str.append(INHERITED::dumpInfo());
193         return str;
194     }
195 
applyPipelineOptimizations(const GrPipelineOptimizations & optimizations)196     void applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) override {
197         GrColor color;
198         if (optimizations.getOverrideColorIfSet(&color)) {
199             this->first()->setColor(color);
200         }
201         fCanTweakAlphaForCoverage = optimizations.canTweakAlphaForCoverage();
202         fNeedsLocalCoords = optimizations.readsLocalCoords();
203     }
204 
205 private:
getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor * color,GrPipelineAnalysisCoverage * coverage) const206     void getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor* color,
207                                             GrPipelineAnalysisCoverage* coverage) const override {
208         color->setToConstant(this->first()->color());
209         *coverage = GrPipelineAnalysisCoverage::kSingleChannel;
210     }
211 
onPrepareDraws(Target * target) const212     void onPrepareDraws(Target* target) const override {
213         using namespace GrDefaultGeoProcFactory;
214 
215         Color color(Color::kPremulGrColorAttribute_Type);
216         Coverage::Type coverageType;
217         if (fCanTweakAlphaForCoverage) {
218             coverageType = Coverage::kSolid_Type;
219         } else {
220             coverageType = Coverage::kAttribute_Type;
221         }
222         LocalCoords lc =
223                 fNeedsLocalCoords ? LocalCoords::kHasExplicit_Type : LocalCoords::kUnused_Type;
224         sk_sp<GrGeometryProcessor> gp =
225                 GrDefaultGeoProcFactory::Make(color, coverageType, lc, SkMatrix::I());
226         if (!gp) {
227             SkDebugf("Couldn't create GrGeometryProcessor\n");
228             return;
229         }
230 
231         size_t vertexStride = gp->getVertexStride();
232 
233         sk_sp<const GrBuffer> indexBuffer(get_index_buffer(target->resourceProvider()));
234         InstancedHelper helper;
235         void* vertices =
236                 helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer.get(),
237                             kVertsPerAAFillRect, kIndicesPerAAFillRect, fRectCnt);
238         if (!vertices || !indexBuffer) {
239             SkDebugf("Could not allocate vertices\n");
240             return;
241         }
242 
243         const RectInfo* info = this->first();
244         const SkMatrix* localMatrix = nullptr;
245         for (int i = 0; i < fRectCnt; i++) {
246             intptr_t verts =
247                     reinterpret_cast<intptr_t>(vertices) + i * kVertsPerAAFillRect * vertexStride;
248             if (fNeedsLocalCoords) {
249                 if (info->hasLocalMatrix()) {
250                     localMatrix = &static_cast<const RectWithLocalMatrixInfo*>(info)->localMatrix();
251                 } else {
252                     localMatrix = &SkMatrix::I();
253                 }
254             }
255             generate_aa_fill_rect_geometry(verts, vertexStride, info->color(), info->viewMatrix(),
256                                            info->rect(), info->devRect(), fCanTweakAlphaForCoverage,
257                                            localMatrix);
258             info = this->next(info);
259         }
260         helper.recordDraw(target, gp.get());
261     }
262 
onCombineIfPossible(GrOp * t,const GrCaps & caps)263     bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
264         AAFillRectOp* that = t->cast<AAFillRectOp>();
265         if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
266                                     that->bounds(), caps)) {
267             return false;
268         }
269 
270         SkASSERT(fNeedsLocalCoords == that->fNeedsLocalCoords);
271 
272         // In the event of two ops, one who can tweak, one who cannot, we just fall back to not
273         // tweaking.
274         if (fCanTweakAlphaForCoverage && !that->fCanTweakAlphaForCoverage) {
275             fCanTweakAlphaForCoverage = false;
276         }
277 
278         fRectData.push_back_n(that->fRectData.count(), that->fRectData.begin());
279         fRectCnt += that->fRectCnt;
280         this->joinBounds(*that);
281         return true;
282     }
283 
284     struct RectInfo {
285     public:
RectInfoAAFillRectOp::RectInfo286         RectInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
287                  const SkRect& devRect)
288                 : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kNo) {}
hasLocalMatrixAAFillRectOp::RectInfo289         bool hasLocalMatrix() const { return HasLocalMatrix::kYes == fHasLocalMatrix; }
colorAAFillRectOp::RectInfo290         GrColor color() const { return fColor; }
viewMatrixAAFillRectOp::RectInfo291         const SkMatrix& viewMatrix() const { return fViewMatrix; }
rectAAFillRectOp::RectInfo292         const SkRect& rect() const { return fRect; }
devRectAAFillRectOp::RectInfo293         const SkRect& devRect() const { return fDevRect; }
294 
setColorAAFillRectOp::RectInfo295         void setColor(GrColor color) { fColor = color; }
296 
297     protected:
298         enum class HasLocalMatrix : uint32_t { kNo, kYes };
299 
RectInfoAAFillRectOp::RectInfo300         RectInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
301                  const SkRect& devRect, HasLocalMatrix hasLM)
302                 : fHasLocalMatrix(hasLM)
303                 , fColor(color)
304                 , fViewMatrix(viewMatrix)
305                 , fRect(rect)
306                 , fDevRect(devRect) {}
307 
308         HasLocalMatrix fHasLocalMatrix;
309         GrColor fColor;
310         SkMatrix fViewMatrix;
311         SkRect fRect;
312         SkRect fDevRect;
313     };
314 
315     struct RectWithLocalMatrixInfo : public RectInfo {
316     public:
RectWithLocalMatrixInfoAAFillRectOp::RectWithLocalMatrixInfo317         RectWithLocalMatrixInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
318                                 const SkRect& devRect, const SkMatrix& localMatrix)
319                 : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kYes)
320                 , fLocalMatrix(localMatrix) {}
localMatrixAAFillRectOp::RectWithLocalMatrixInfo321         const SkMatrix& localMatrix() const { return fLocalMatrix; }
322 
323     private:
324         SkMatrix fLocalMatrix;
325     };
326 
first()327     RectInfo* first() { return reinterpret_cast<RectInfo*>(fRectData.begin()); }
first() const328     const RectInfo* first() const { return reinterpret_cast<const RectInfo*>(fRectData.begin()); }
next(const RectInfo * prev) const329     const RectInfo* next(const RectInfo* prev) const {
330         intptr_t next =
331                 reinterpret_cast<intptr_t>(prev) +
332                 (prev->hasLocalMatrix() ? sizeof(RectWithLocalMatrixInfo) : sizeof(RectInfo));
333         return reinterpret_cast<const RectInfo*>(next);
334     }
335 
336     bool fNeedsLocalCoords;
337     bool fCanTweakAlphaForCoverage;
338     SkSTArray<4 * sizeof(RectWithLocalMatrixInfo), uint8_t, true> fRectData;
339     int fRectCnt;
340 
341     typedef GrMeshDrawOp INHERITED;
342 };
343 
344 namespace GrAAFillRectOp {
345 
Make(GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & devRect)346 std::unique_ptr<GrMeshDrawOp> Make(GrColor color,
347                                    const SkMatrix& viewMatrix,
348                                    const SkRect& rect,
349                                    const SkRect& devRect) {
350     return std::unique_ptr<GrMeshDrawOp>(
351             new AAFillRectOp(color, viewMatrix, rect, devRect, nullptr));
352 }
353 
Make(GrColor color,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,const SkRect & rect,const SkRect & devRect)354 std::unique_ptr<GrMeshDrawOp> Make(GrColor color,
355                                    const SkMatrix& viewMatrix,
356                                    const SkMatrix& localMatrix,
357                                    const SkRect& rect,
358                                    const SkRect& devRect) {
359     return std::unique_ptr<GrMeshDrawOp>(
360             new AAFillRectOp(color, viewMatrix, rect, devRect, &localMatrix));
361 }
362 
Make(GrColor color,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,const SkRect & rect)363 std::unique_ptr<GrMeshDrawOp> Make(GrColor color,
364                                    const SkMatrix& viewMatrix,
365                                    const SkMatrix& localMatrix,
366                                    const SkRect& rect) {
367     SkRect devRect;
368     viewMatrix.mapRect(&devRect, rect);
369     return Make(color, viewMatrix, localMatrix, rect, devRect);
370 }
371 
MakeWithLocalRect(GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & localRect)372 std::unique_ptr<GrMeshDrawOp> MakeWithLocalRect(GrColor color,
373                                                 const SkMatrix& viewMatrix,
374                                                 const SkRect& rect,
375                                                 const SkRect& localRect) {
376     SkRect devRect;
377     viewMatrix.mapRect(&devRect, rect);
378     SkMatrix localMatrix;
379     if (!localMatrix.setRectToRect(rect, localRect, SkMatrix::kFill_ScaleToFit)) {
380         return nullptr;
381     }
382     return Make(color, viewMatrix, localMatrix, rect, devRect);
383 }
384 };
385 
386 ///////////////////////////////////////////////////////////////////////////////////////////////////
387 
388 #if GR_TEST_UTILS
389 
390 #include "GrDrawOpTest.h"
391 
DRAW_OP_TEST_DEFINE(AAFillRectOp)392 DRAW_OP_TEST_DEFINE(AAFillRectOp) {
393     GrColor color = GrRandomColor(random);
394     SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
395     SkRect rect = GrTest::TestRect(random);
396     SkRect devRect = GrTest::TestRect(random);
397     return GrAAFillRectOp::Make(color, viewMatrix, rect, devRect);
398 }
399 
DRAW_OP_TEST_DEFINE(AAFillRectOpLocalMatrix)400 DRAW_OP_TEST_DEFINE(AAFillRectOpLocalMatrix) {
401     GrColor color = GrRandomColor(random);
402     SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
403     SkMatrix localMatrix = GrTest::TestMatrix(random);
404     SkRect rect = GrTest::TestRect(random);
405     SkRect devRect = GrTest::TestRect(random);
406     return GrAAFillRectOp::Make(color, viewMatrix, localMatrix, rect, devRect);
407 }
408 
409 #endif
410