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