• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrColor.h"
9 #include "GrDefaultGeoProcFactory.h"
10 #include "GrMeshDrawOp.h"
11 #include "GrOpFlushState.h"
12 #include "GrRectOpFactory.h"
13 #include "GrResourceKey.h"
14 #include "GrResourceProvider.h"
15 #include "GrTypes.h"
16 #include "SkMatrix.h"
17 #include "SkRect.h"
18 #include "ops/GrSimpleMeshDrawOpHelper.h"
19 
20 GR_DECLARE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
21 
view_matrix_ok_for_aa_fill_rect(const SkMatrix & viewMatrix)22 static inline bool view_matrix_ok_for_aa_fill_rect(const SkMatrix& viewMatrix) {
23     return viewMatrix.preservesRightAngles();
24 }
25 
set_inset_fan(SkPoint * pts,size_t stride,const SkRect & r,SkScalar dx,SkScalar dy)26 static inline void set_inset_fan(SkPoint* pts, size_t stride, const SkRect& r, SkScalar dx,
27                                  SkScalar dy) {
28     pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
29 }
30 
31 static const int kNumAAFillRectsInIndexBuffer = 256;
32 static const int kVertsPerAAFillRect = 8;
33 static const int kIndicesPerAAFillRect = 30;
34 
get_index_buffer(GrResourceProvider * resourceProvider)35 const GrBuffer* get_index_buffer(GrResourceProvider* resourceProvider) {
36     GR_DEFINE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
37 
38     // clang-format off
39     static const uint16_t gFillAARectIdx[] = {
40         0, 1, 5, 5, 4, 0,
41         1, 2, 6, 6, 5, 1,
42         2, 3, 7, 7, 6, 2,
43         3, 0, 4, 4, 7, 3,
44         4, 5, 6, 6, 7, 4,
45     };
46     // clang-format on
47 
48     GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFillAARectIdx) == kIndicesPerAAFillRect);
49     return resourceProvider->findOrCreatePatternedIndexBuffer(
50             gFillAARectIdx, kIndicesPerAAFillRect, kNumAAFillRectsInIndexBuffer,
51             kVertsPerAAFillRect, gAAFillRectIndexBufferKey);
52 }
53 
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)54 static void generate_aa_fill_rect_geometry(intptr_t verts,
55                                            size_t vertexStride,
56                                            GrColor color,
57                                            const SkMatrix& viewMatrix,
58                                            const SkRect& rect,
59                                            const SkRect& devRect,
60                                            bool tweakAlphaForCoverage,
61                                            const SkMatrix* localMatrix) {
62     SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
63     SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
64 
65     SkScalar inset;
66 
67     if (viewMatrix.rectStaysRect()) {
68         inset = SkMinScalar(devRect.width(), SK_Scalar1);
69         inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
70 
71         set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
72         set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
73     } else {
74         // compute transformed (1, 0) and (0, 1) vectors
75         SkVector vec[2] = {{viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY]},
76                            {viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY]}};
77 
78         SkScalar len1 = SkPoint::Normalize(&vec[0]);
79         vec[0].scale(SK_ScalarHalf);
80         SkScalar len2 = SkPoint::Normalize(&vec[1]);
81         vec[1].scale(SK_ScalarHalf);
82 
83         inset = SkMinScalar(len1 * rect.width(), SK_Scalar1);
84         inset = SK_ScalarHalf * SkMinScalar(inset, len2 * rect.height());
85 
86         // create the rotated rect
87         fan0Pos->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride);
88         viewMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
89 
90         // Now create the inset points and then outset the original
91         // rotated points
92 
93         // TL
94         *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
95                 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
96         *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
97         // BL
98         *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
99                 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
100         *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
101         // BR
102         *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
103                 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
104         *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
105         // TR
106         *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
107                 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
108         *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
109     }
110 
111     if (localMatrix) {
112         SkMatrix invViewMatrix;
113         if (!viewMatrix.invert(&invViewMatrix)) {
114             SkDebugf("View matrix is non-invertible, local coords will be wrong.");
115             invViewMatrix = SkMatrix::I();
116         }
117         SkMatrix localCoordMatrix;
118         localCoordMatrix.setConcat(*localMatrix, invViewMatrix);
119         SkPoint* fan0Loc = reinterpret_cast<SkPoint*>(verts + sizeof(SkPoint) + sizeof(GrColor));
120         localCoordMatrix.mapPointsWithStride(fan0Loc, fan0Pos, vertexStride, 8);
121     }
122 
123     // Make verts point to vertex color and then set all the color and coverage vertex attrs
124     // values.
125     verts += sizeof(SkPoint);
126 
127     // The coverage offset is always the last vertex attribute
128     intptr_t coverageOffset = vertexStride - sizeof(GrColor) - sizeof(SkPoint);
129     for (int i = 0; i < 4; ++i) {
130         if (tweakAlphaForCoverage) {
131             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
132         } else {
133             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
134             *reinterpret_cast<float*>(verts + i * vertexStride + coverageOffset) = 0;
135         }
136     }
137 
138     int scale;
139     if (inset < SK_ScalarHalf) {
140         scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
141         SkASSERT(scale >= 0 && scale <= 255);
142     } else {
143         scale = 0xff;
144     }
145 
146     verts += 4 * vertexStride;
147 
148     float innerCoverage = GrNormalizeByteToFloat(scale);
149     GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
150 
151     for (int i = 0; i < 4; ++i) {
152         if (tweakAlphaForCoverage) {
153             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
154         } else {
155             *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
156             *reinterpret_cast<float*>(verts + i * vertexStride + coverageOffset) = innerCoverage;
157         }
158     }
159 }
160 
161 namespace {
162 
163 class AAFillRectOp final : public GrMeshDrawOp {
164 private:
165     using Helper = GrSimpleMeshDrawOpHelperWithStencil;
166 
167 public:
168     DEFINE_OP_CLASS_ID
169 
Make(GrPaint && paint,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & devRect,const SkMatrix * localMatrix,const GrUserStencilSettings * stencil)170     static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint,
171                                           const SkMatrix& viewMatrix,
172                                           const SkRect& rect,
173                                           const SkRect& devRect,
174                                           const SkMatrix* localMatrix,
175                                           const GrUserStencilSettings* stencil) {
176         SkASSERT(view_matrix_ok_for_aa_fill_rect(viewMatrix));
177         return Helper::FactoryHelper<AAFillRectOp>(std::move(paint), viewMatrix, rect, devRect,
178                                                    localMatrix, stencil);
179     }
180 
AAFillRectOp(const Helper::MakeArgs & helperArgs,GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & devRect,const SkMatrix * localMatrix,const GrUserStencilSettings * stencil)181     AAFillRectOp(const Helper::MakeArgs& helperArgs,
182                  GrColor color,
183                  const SkMatrix& viewMatrix,
184                  const SkRect& rect,
185                  const SkRect& devRect,
186                  const SkMatrix* localMatrix,
187                  const GrUserStencilSettings* stencil)
188             : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage, stencil) {
189         if (localMatrix) {
190             void* mem = fRectData.push_back_n(sizeof(RectWithLocalMatrixInfo));
191             new (mem) RectWithLocalMatrixInfo(color, viewMatrix, rect, devRect, *localMatrix);
192         } else {
193             void* mem = fRectData.push_back_n(sizeof(RectInfo));
194             new (mem) RectInfo(color, viewMatrix, rect, devRect);
195         }
196         IsZeroArea zeroArea =
197                 (!rect.width() || !rect.height()) ? IsZeroArea::kYes : IsZeroArea::kNo;
198         this->setBounds(devRect, HasAABloat::kYes, zeroArea);
199         fRectCnt = 1;
200     }
201 
name() const202     const char* name() const override { return "AAFillRectOp"; }
203 
dumpInfo() const204     SkString dumpInfo() const override {
205         SkString str;
206         str.append(INHERITED::dumpInfo());
207         str.appendf("# combined: %d\n", fRectCnt);
208         const RectInfo* info = this->first();
209         for (int i = 0; i < fRectCnt; ++i) {
210             const SkRect& rect = info->rect();
211             str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
212                         info->color(), rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
213             info = this->next(info);
214         }
215         str += fHelper.dumpInfo();
216         str += INHERITED::dumpInfo();
217         return str;
218     }
219 
fixedFunctionFlags() const220     FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
221 
finalize(const GrCaps & caps,const GrAppliedClip * clip)222     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
223         GrColor color = this->first()->color();
224         auto result = fHelper.xpRequiresDstTexture(
225                 caps, clip, GrProcessorAnalysisCoverage::kSingleChannel, &color);
226         this->first()->setColor(color);
227         return result;
228     }
229 
230 private:
onPrepareDraws(Target * target) const231     void onPrepareDraws(Target* target) const override {
232         using namespace GrDefaultGeoProcFactory;
233 
234         Color color(Color::kPremulGrColorAttribute_Type);
235         Coverage::Type coverageType = fHelper.compatibleWithAlphaAsCoverage()
236                                               ? Coverage::kSolid_Type
237                                               : Coverage::kAttribute_Type;
238         LocalCoords lc = fHelper.usesLocalCoords() ? LocalCoords::kHasExplicit_Type
239                                                    : LocalCoords::kUnused_Type;
240         sk_sp<GrGeometryProcessor> gp =
241                 GrDefaultGeoProcFactory::Make(color, coverageType, lc, SkMatrix::I());
242         if (!gp) {
243             SkDebugf("Couldn't create GrGeometryProcessor\n");
244             return;
245         }
246 
247         size_t vertexStride = gp->getVertexStride();
248 
249         sk_sp<const GrBuffer> indexBuffer(get_index_buffer(target->resourceProvider()));
250         PatternHelper helper(GrPrimitiveType::kTriangles);
251         void* vertices =
252                 helper.init(target, vertexStride, indexBuffer.get(), kVertsPerAAFillRect,
253                             kIndicesPerAAFillRect, fRectCnt);
254         if (!vertices || !indexBuffer) {
255             SkDebugf("Could not allocate vertices\n");
256             return;
257         }
258 
259         const RectInfo* info = this->first();
260         const SkMatrix* localMatrix = nullptr;
261         for (int i = 0; i < fRectCnt; i++) {
262             intptr_t verts =
263                     reinterpret_cast<intptr_t>(vertices) + i * kVertsPerAAFillRect * vertexStride;
264             if (fHelper.usesLocalCoords()) {
265                 if (info->hasLocalMatrix()) {
266                     localMatrix = &static_cast<const RectWithLocalMatrixInfo*>(info)->localMatrix();
267                 } else {
268                     localMatrix = &SkMatrix::I();
269                 }
270             }
271             generate_aa_fill_rect_geometry(verts, vertexStride, info->color(), info->viewMatrix(),
272                                            info->rect(), info->devRect(),
273                                            fHelper.compatibleWithAlphaAsCoverage(), localMatrix);
274             info = this->next(info);
275         }
276         helper.recordDraw(target, gp.get(), fHelper.makePipeline(target));
277     }
278 
onCombineIfPossible(GrOp * t,const GrCaps & caps)279     bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
280         AAFillRectOp* that = t->cast<AAFillRectOp>();
281         if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
282             return false;
283         }
284 
285         fRectData.push_back_n(that->fRectData.count(), that->fRectData.begin());
286         fRectCnt += that->fRectCnt;
287         this->joinBounds(*that);
288         return true;
289     }
290 
291     struct RectInfo {
292     public:
RectInfo__anon468432ba0111::AAFillRectOp::RectInfo293         RectInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
294                  const SkRect& devRect)
295                 : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kNo) {}
hasLocalMatrix__anon468432ba0111::AAFillRectOp::RectInfo296         bool hasLocalMatrix() const { return HasLocalMatrix::kYes == fHasLocalMatrix; }
color__anon468432ba0111::AAFillRectOp::RectInfo297         GrColor color() const { return fColor; }
viewMatrix__anon468432ba0111::AAFillRectOp::RectInfo298         const SkMatrix& viewMatrix() const { return fViewMatrix; }
rect__anon468432ba0111::AAFillRectOp::RectInfo299         const SkRect& rect() const { return fRect; }
devRect__anon468432ba0111::AAFillRectOp::RectInfo300         const SkRect& devRect() const { return fDevRect; }
301 
setColor__anon468432ba0111::AAFillRectOp::RectInfo302         void setColor(GrColor color) { fColor = color; }
303 
304     protected:
305         enum class HasLocalMatrix : uint32_t { kNo, kYes };
306 
RectInfo__anon468432ba0111::AAFillRectOp::RectInfo307         RectInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
308                  const SkRect& devRect, HasLocalMatrix hasLM)
309                 : fHasLocalMatrix(hasLM)
310                 , fColor(color)
311                 , fViewMatrix(viewMatrix)
312                 , fRect(rect)
313                 , fDevRect(devRect) {}
314 
315         HasLocalMatrix fHasLocalMatrix;
316         GrColor fColor;
317         SkMatrix fViewMatrix;
318         SkRect fRect;
319         SkRect fDevRect;
320     };
321 
322     struct RectWithLocalMatrixInfo : public RectInfo {
323     public:
RectWithLocalMatrixInfo__anon468432ba0111::AAFillRectOp::RectWithLocalMatrixInfo324         RectWithLocalMatrixInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
325                                 const SkRect& devRect, const SkMatrix& localMatrix)
326                 : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kYes)
327                 , fLocalMatrix(localMatrix) {}
localMatrix__anon468432ba0111::AAFillRectOp::RectWithLocalMatrixInfo328         const SkMatrix& localMatrix() const { return fLocalMatrix; }
329 
330     private:
331         SkMatrix fLocalMatrix;
332     };
333 
first()334     RectInfo* first() { return reinterpret_cast<RectInfo*>(fRectData.begin()); }
first() const335     const RectInfo* first() const { return reinterpret_cast<const RectInfo*>(fRectData.begin()); }
next(const RectInfo * prev) const336     const RectInfo* next(const RectInfo* prev) const {
337         intptr_t next =
338                 reinterpret_cast<intptr_t>(prev) +
339                 (prev->hasLocalMatrix() ? sizeof(RectWithLocalMatrixInfo) : sizeof(RectInfo));
340         return reinterpret_cast<const RectInfo*>(next);
341     }
342 
343     SkSTArray<4 * sizeof(RectWithLocalMatrixInfo), uint8_t, true> fRectData;
344     Helper fHelper;
345     int fRectCnt;
346 
347     typedef GrMeshDrawOp INHERITED;
348 };
349 
350 }  // anonymous namespace
351 
352 namespace GrRectOpFactory {
353 
MakeAAFill(GrPaint && paint,const SkMatrix & viewMatrix,const SkRect & rect,const GrUserStencilSettings * stencil)354 std::unique_ptr<GrDrawOp> MakeAAFill(GrPaint&& paint, const SkMatrix& viewMatrix,
355                                      const SkRect& rect, const GrUserStencilSettings* stencil) {
356     if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
357         return nullptr;
358     }
359     SkRect devRect;
360     viewMatrix.mapRect(&devRect, rect);
361     return AAFillRectOp::Make(std::move(paint), viewMatrix, rect, devRect, nullptr, stencil);
362 }
363 
MakeAAFillWithLocalMatrix(GrPaint && paint,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,const SkRect & rect)364 std::unique_ptr<GrDrawOp> MakeAAFillWithLocalMatrix(GrPaint&& paint, const SkMatrix& viewMatrix,
365                                                     const SkMatrix& localMatrix,
366                                                     const SkRect& rect) {
367     if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
368         return nullptr;
369     }
370     SkRect devRect;
371     viewMatrix.mapRect(&devRect, rect);
372     return AAFillRectOp::Make(std::move(paint), viewMatrix, rect, devRect, &localMatrix, nullptr);
373 }
374 
MakeAAFillWithLocalRect(GrPaint && paint,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & localRect)375 std::unique_ptr<GrDrawOp> MakeAAFillWithLocalRect(GrPaint&& paint, const SkMatrix& viewMatrix,
376                                                   const SkRect& rect, const SkRect& localRect) {
377     if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
378         return nullptr;
379     }
380     SkRect devRect;
381     viewMatrix.mapRect(&devRect, rect);
382     SkMatrix localMatrix;
383     if (!localMatrix.setRectToRect(rect, localRect, SkMatrix::kFill_ScaleToFit)) {
384         return nullptr;
385     }
386     return AAFillRectOp::Make(std::move(paint), viewMatrix, rect, devRect, &localMatrix, nullptr);
387 }
388 
389 }  // namespace GrRectOpFactory
390 
391 ///////////////////////////////////////////////////////////////////////////////////////////////////
392 
393 #if GR_TEST_UTILS
394 
395 #include "GrDrawOpTest.h"
396 
GR_DRAW_OP_TEST_DEFINE(AAFillRectOp)397 GR_DRAW_OP_TEST_DEFINE(AAFillRectOp) {
398     SkMatrix viewMatrix;
399     do {
400         viewMatrix = GrTest::TestMatrixInvertible(random);
401     } while (!view_matrix_ok_for_aa_fill_rect(viewMatrix));
402     SkRect rect = GrTest::TestRect(random);
403     SkRect devRect;
404     viewMatrix.mapRect(&devRect, rect);
405     const SkMatrix* localMatrix = nullptr;
406     SkMatrix m;
407     if (random->nextBool()) {
408         m = GrTest::TestMatrix(random);
409     }
410     const GrUserStencilSettings* stencil =
411             random->nextBool() ? nullptr : GrGetRandomStencil(random, context);
412     return AAFillRectOp::Make(std::move(paint), viewMatrix, rect, devRect, localMatrix, stencil);
413 }
414 
415 #endif
416