• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrAppliedClip.h"
9 #include "GrColor.h"
10 #include "GrDefaultGeoProcFactory.h"
11 #include "GrDrawOpTest.h"
12 #include "GrMeshDrawOp.h"
13 #include "GrOpFlushState.h"
14 #include "GrPrimitiveProcessor.h"
15 #include "GrQuad.h"
16 #include "GrRectOpFactory.h"
17 #include "GrResourceProvider.h"
18 #include "GrSimpleMeshDrawOpHelper.h"
19 #include "SkMatrixPriv.h"
20 
21 static const int kVertsPerRect = 4;
22 static const int kIndicesPerRect = 6;
23 
24 /** We always use per-vertex colors so that rects can be combined across color changes. Sometimes
25     we  have explicit local coords and sometimes not. We *could* always provide explicit local
26     coords and just duplicate the positions when the caller hasn't provided a local coord rect,
27     but we haven't seen a use case which frequently switches between local rect and no local
28     rect draws.
29 
30     The vertex attrib order is always pos, color, [local coords].
31  */
make_gp()32 static sk_sp<GrGeometryProcessor> make_gp() {
33     using namespace GrDefaultGeoProcFactory;
34     return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, Coverage::kSolid_Type,
35                                          LocalCoords::kHasExplicit_Type, SkMatrix::I());
36 }
37 
make_perspective_gp(const SkMatrix & viewMatrix,bool hasExplicitLocalCoords,const SkMatrix * localMatrix)38 static sk_sp<GrGeometryProcessor> make_perspective_gp(const SkMatrix& viewMatrix,
39                                                       bool hasExplicitLocalCoords,
40                                                       const SkMatrix* localMatrix) {
41     SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective()));
42 
43     using namespace GrDefaultGeoProcFactory;
44 
45     // If we have perspective on the viewMatrix then we won't map on the CPU, nor will we map
46     // the local rect on the cpu (in case the localMatrix also has perspective).
47     // Otherwise, if we have a local rect, then we apply the localMatrix directly to the localRect
48     // to generate vertex local coords
49     if (viewMatrix.hasPerspective()) {
50         LocalCoords localCoords(hasExplicitLocalCoords ? LocalCoords::kHasExplicit_Type
51                                                        : LocalCoords::kUsePosition_Type,
52                                 localMatrix);
53         return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
54                                              Coverage::kSolid_Type, localCoords, viewMatrix);
55     } else if (hasExplicitLocalCoords) {
56         LocalCoords localCoords(LocalCoords::kHasExplicit_Type, localMatrix);
57         return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
58                                              Coverage::kSolid_Type, localCoords, SkMatrix::I());
59     } else {
60         LocalCoords localCoords(LocalCoords::kUsePosition_Type, localMatrix);
61         return GrDefaultGeoProcFactory::MakeForDeviceSpace(Color::kPremulGrColorAttribute_Type,
62                                                            Coverage::kSolid_Type, localCoords,
63                                                            viewMatrix);
64     }
65 }
66 
tesselate(intptr_t vertices,size_t vertexStride,GrColor color,const SkMatrix * viewMatrix,const SkRect & rect,const GrQuad * localQuad)67 static void tesselate(intptr_t vertices,
68                       size_t vertexStride,
69                       GrColor color,
70                       const SkMatrix* viewMatrix,
71                       const SkRect& rect,
72                       const GrQuad* localQuad) {
73     SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
74 
75     positions->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride);
76 
77     if (viewMatrix) {
78         SkMatrixPriv::MapPointsWithStride(*viewMatrix, positions, vertexStride, kVertsPerRect);
79     }
80 
81     // Setup local coords
82     // TODO we should only do this if local coords are being read
83     if (localQuad) {
84         static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
85         for (int i = 0; i < kVertsPerRect; i++) {
86             SkPoint* coords =
87                     reinterpret_cast<SkPoint*>(vertices + kLocalOffset + i * vertexStride);
88             *coords = localQuad->point(i);
89         }
90     }
91 
92     static const int kColorOffset = sizeof(SkPoint);
93     GrColor* vertColor = reinterpret_cast<GrColor*>(vertices + kColorOffset);
94     for (int j = 0; j < 4; ++j) {
95         *vertColor = color;
96         vertColor = (GrColor*)((intptr_t)vertColor + vertexStride);
97     }
98 }
99 
100 namespace {
101 
102 class NonAAFillRectOp final : public GrMeshDrawOp {
103 private:
104     using Helper = GrSimpleMeshDrawOpHelperWithStencil;
105 
106 public:
Make(GrPaint && paint,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect * localRect,const SkMatrix * localMatrix,GrAAType aaType,const GrUserStencilSettings * stencilSettings)107     static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
108                                           const SkRect& rect, const SkRect* localRect,
109                                           const SkMatrix* localMatrix, GrAAType aaType,
110                                           const GrUserStencilSettings* stencilSettings) {
111         SkASSERT(GrAAType::kCoverage != aaType);
112         return Helper::FactoryHelper<NonAAFillRectOp>(std::move(paint), viewMatrix, rect, localRect,
113                                                       localMatrix, aaType, stencilSettings);
114     }
115 
116     NonAAFillRectOp() = delete;
117 
NonAAFillRectOp(const Helper::MakeArgs & args,GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect * localRect,const SkMatrix * localMatrix,GrAAType aaType,const GrUserStencilSettings * stencilSettings)118     NonAAFillRectOp(const Helper::MakeArgs& args, GrColor color, const SkMatrix& viewMatrix,
119                     const SkRect& rect, const SkRect* localRect, const SkMatrix* localMatrix,
120                     GrAAType aaType, const GrUserStencilSettings* stencilSettings)
121             : INHERITED(ClassID()), fHelper(args, aaType, stencilSettings) {
122 
123         SkASSERT(!viewMatrix.hasPerspective() && (!localMatrix || !localMatrix->hasPerspective()));
124         RectInfo& info = fRects.push_back();
125         info.fColor = color;
126         info.fViewMatrix = viewMatrix;
127         info.fRect = rect;
128         if (localRect && localMatrix) {
129             info.fLocalQuad.setFromMappedRect(*localRect, *localMatrix);
130         } else if (localRect) {
131             info.fLocalQuad.set(*localRect);
132         } else if (localMatrix) {
133             info.fLocalQuad.setFromMappedRect(rect, *localMatrix);
134         } else {
135             info.fLocalQuad.set(rect);
136         }
137         this->setTransformedBounds(fRects[0].fRect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
138     }
139 
name() const140     const char* name() const override { return "NonAAFillRectOp"; }
141 
dumpInfo() const142     SkString dumpInfo() const override {
143         SkString str;
144         str.append(GrMeshDrawOp::dumpInfo());
145         str.appendf("# combined: %d\n", fRects.count());
146         for (int i = 0; i < fRects.count(); ++i) {
147             const RectInfo& info = fRects[i];
148             str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
149                         info.fColor, info.fRect.fLeft, info.fRect.fTop, info.fRect.fRight,
150                         info.fRect.fBottom);
151         }
152         str += fHelper.dumpInfo();
153         str += INHERITED::dumpInfo();
154         return str;
155     }
156 
finalize(const GrCaps & caps,const GrAppliedClip * clip)157     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
158         GrColor* color = &fRects.front().fColor;
159         return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color);
160     }
161 
fixedFunctionFlags() const162     FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
163 
164     DEFINE_OP_CLASS_ID
165 
166 private:
onPrepareDraws(Target * target) const167     void onPrepareDraws(Target* target) const override {
168         sk_sp<GrGeometryProcessor> gp = make_gp();
169         if (!gp) {
170             SkDebugf("Couldn't create GrGeometryProcessor\n");
171             return;
172         }
173         SkASSERT(gp->getVertexStride() ==
174                  sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr));
175 
176         size_t vertexStride = gp->getVertexStride();
177         int rectCount = fRects.count();
178 
179         sk_sp<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer());
180         PatternHelper helper(GrPrimitiveType::kTriangles);
181         void* vertices = helper.init(target, vertexStride, indexBuffer.get(), kVertsPerRect,
182                                      kIndicesPerRect, rectCount);
183         if (!vertices || !indexBuffer) {
184             SkDebugf("Could not allocate vertices\n");
185             return;
186         }
187 
188         for (int i = 0; i < rectCount; i++) {
189             intptr_t verts =
190                     reinterpret_cast<intptr_t>(vertices) + i * kVertsPerRect * vertexStride;
191             tesselate(verts, vertexStride, fRects[i].fColor, &fRects[i].fViewMatrix,
192                       fRects[i].fRect, &fRects[i].fLocalQuad);
193         }
194         helper.recordDraw(target, gp.get(), fHelper.makePipeline(target));
195     }
196 
onCombineIfPossible(GrOp * t,const GrCaps & caps)197     bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
198         NonAAFillRectOp* that = t->cast<NonAAFillRectOp>();
199         if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
200             return false;
201         }
202         fRects.push_back_n(that->fRects.count(), that->fRects.begin());
203         this->joinBounds(*that);
204         return true;
205     }
206 
207     struct RectInfo {
208         GrColor fColor;
209         SkMatrix fViewMatrix;
210         SkRect fRect;
211         GrQuad fLocalQuad;
212     };
213 
214     Helper fHelper;
215     SkSTArray<1, RectInfo, true> fRects;
216     typedef GrMeshDrawOp INHERITED;
217 };
218 
219 // We handle perspective in the local matrix or viewmatrix with special ops.
220 class NonAAFillRectPerspectiveOp final : public GrMeshDrawOp {
221 private:
222     using Helper = GrSimpleMeshDrawOpHelperWithStencil;
223 
224 public:
Make(GrPaint && paint,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect * localRect,const SkMatrix * localMatrix,GrAAType aaType,const GrUserStencilSettings * stencilSettings)225     static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
226                                           const SkRect& rect, const SkRect* localRect,
227                                           const SkMatrix* localMatrix, GrAAType aaType,
228                                           const GrUserStencilSettings* stencilSettings) {
229         SkASSERT(GrAAType::kCoverage != aaType);
230         return Helper::FactoryHelper<NonAAFillRectPerspectiveOp>(std::move(paint), viewMatrix, rect,
231                                                                  localRect, localMatrix, aaType,
232                                                                  stencilSettings);
233     }
234 
235     NonAAFillRectPerspectiveOp() = delete;
236 
NonAAFillRectPerspectiveOp(const Helper::MakeArgs & args,GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect * localRect,const SkMatrix * localMatrix,GrAAType aaType,const GrUserStencilSettings * stencilSettings)237     NonAAFillRectPerspectiveOp(const Helper::MakeArgs& args, GrColor color,
238                                const SkMatrix& viewMatrix, const SkRect& rect,
239                                const SkRect* localRect, const SkMatrix* localMatrix,
240                                GrAAType aaType, const GrUserStencilSettings* stencilSettings)
241             : INHERITED(ClassID())
242             , fHelper(args, aaType, stencilSettings)
243             , fViewMatrix(viewMatrix) {
244         SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective()));
245         RectInfo& info = fRects.push_back();
246         info.fColor = color;
247         info.fRect = rect;
248         fHasLocalRect = SkToBool(localRect);
249         fHasLocalMatrix = SkToBool(localMatrix);
250         if (fHasLocalMatrix) {
251             fLocalMatrix = *localMatrix;
252         }
253         if (fHasLocalRect) {
254             info.fLocalRect = *localRect;
255         }
256         this->setTransformedBounds(rect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
257     }
258 
name() const259     const char* name() const override { return "NonAAFillRectPerspectiveOp"; }
260 
dumpInfo() const261     SkString dumpInfo() const override {
262         SkString str;
263         str.appendf("# combined: %d\n", fRects.count());
264         for (int i = 0; i < fRects.count(); ++i) {
265             const RectInfo& geo = fRects[0];
266             str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
267                         geo.fColor, geo.fRect.fLeft, geo.fRect.fTop, geo.fRect.fRight,
268                         geo.fRect.fBottom);
269         }
270         str += fHelper.dumpInfo();
271         str += INHERITED::dumpInfo();
272         return str;
273     }
274 
finalize(const GrCaps & caps,const GrAppliedClip * clip)275     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
276         GrColor* color = &fRects.front().fColor;
277         return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color);
278     }
279 
fixedFunctionFlags() const280     FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
281 
282     DEFINE_OP_CLASS_ID
283 
284 private:
onPrepareDraws(Target * target) const285     void onPrepareDraws(Target* target) const override {
286         sk_sp<GrGeometryProcessor> gp = make_perspective_gp(
287                 fViewMatrix, fHasLocalRect, fHasLocalMatrix ? &fLocalMatrix : nullptr);
288         if (!gp) {
289             SkDebugf("Couldn't create GrGeometryProcessor\n");
290             return;
291         }
292         SkASSERT(fHasLocalRect
293                          ? gp->getVertexStride() ==
294                                    sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)
295                          : gp->getVertexStride() ==
296                                    sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
297 
298         size_t vertexStride = gp->getVertexStride();
299         int rectCount = fRects.count();
300 
301         sk_sp<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer());
302         PatternHelper helper(GrPrimitiveType::kTriangles);
303         void* vertices = helper.init(target, vertexStride, indexBuffer.get(), kVertsPerRect,
304                                      kIndicesPerRect, rectCount);
305         if (!vertices || !indexBuffer) {
306             SkDebugf("Could not allocate vertices\n");
307             return;
308         }
309 
310         for (int i = 0; i < rectCount; i++) {
311             const RectInfo& info = fRects[i];
312             intptr_t verts =
313                     reinterpret_cast<intptr_t>(vertices) + i * kVertsPerRect * vertexStride;
314             if (fHasLocalRect) {
315                 GrQuad quad(info.fLocalRect);
316                 tesselate(verts, vertexStride, info.fColor, nullptr, info.fRect, &quad);
317             } else {
318                 tesselate(verts, vertexStride, info.fColor, nullptr, info.fRect, nullptr);
319             }
320         }
321         helper.recordDraw(target, gp.get(), fHelper.makePipeline(target));
322     }
323 
onCombineIfPossible(GrOp * t,const GrCaps & caps)324     bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
325         NonAAFillRectPerspectiveOp* that = t->cast<NonAAFillRectPerspectiveOp>();
326         if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
327             return false;
328         }
329 
330         // We could combine across perspective vm changes if we really wanted to.
331         if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
332             return false;
333         }
334         if (fHasLocalRect != that->fHasLocalRect) {
335             return false;
336         }
337         if (fHasLocalMatrix && !fLocalMatrix.cheapEqualTo(that->fLocalMatrix)) {
338             return false;
339         }
340 
341         fRects.push_back_n(that->fRects.count(), that->fRects.begin());
342         this->joinBounds(*that);
343         return true;
344     }
345 
346     struct RectInfo {
347         SkRect fRect;
348         GrColor fColor;
349         SkRect fLocalRect;
350     };
351 
352     SkSTArray<1, RectInfo, true> fRects;
353     Helper fHelper;
354     bool fHasLocalMatrix;
355     bool fHasLocalRect;
356     SkMatrix fLocalMatrix;
357     SkMatrix fViewMatrix;
358 
359     typedef GrMeshDrawOp INHERITED;
360 };
361 
362 }  // anonymous namespace
363 
364 namespace GrRectOpFactory {
365 
MakeNonAAFill(GrPaint && paint,const SkMatrix & viewMatrix,const SkRect & rect,GrAAType aaType,const GrUserStencilSettings * stencilSettings)366 std::unique_ptr<GrDrawOp> MakeNonAAFill(GrPaint&& paint, const SkMatrix& viewMatrix,
367                                         const SkRect& rect, GrAAType aaType,
368                                         const GrUserStencilSettings* stencilSettings) {
369     if (viewMatrix.hasPerspective()) {
370         return NonAAFillRectPerspectiveOp::Make(std::move(paint), viewMatrix, rect, nullptr,
371                                                 nullptr, aaType, stencilSettings);
372     } else {
373         return NonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, nullptr, nullptr, aaType,
374                                      stencilSettings);
375     }
376 }
377 
MakeNonAAFillWithLocalMatrix(GrPaint && paint,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,const SkRect & rect,GrAAType aaType,const GrUserStencilSettings * stencilSettings)378 std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalMatrix(
379         GrPaint&& paint, const SkMatrix& viewMatrix, const SkMatrix& localMatrix,
380         const SkRect& rect, GrAAType aaType, const GrUserStencilSettings* stencilSettings) {
381     if (viewMatrix.hasPerspective() || localMatrix.hasPerspective()) {
382         return NonAAFillRectPerspectiveOp::Make(std::move(paint), viewMatrix, rect, nullptr,
383                                                 &localMatrix, aaType, stencilSettings);
384     } else {
385         return NonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, nullptr, &localMatrix,
386                                      aaType, stencilSettings);
387     }
388 }
389 
MakeNonAAFillWithLocalRect(GrPaint && paint,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & localRect,GrAAType aaType)390 std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalRect(GrPaint&& paint, const SkMatrix& viewMatrix,
391                                                      const SkRect& rect, const SkRect& localRect,
392                                                      GrAAType aaType) {
393     if (viewMatrix.hasPerspective()) {
394         return NonAAFillRectPerspectiveOp::Make(std::move(paint), viewMatrix, rect, &localRect,
395                                                 nullptr, aaType, nullptr);
396     } else {
397         return NonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, &localRect, nullptr,
398                                      aaType, nullptr);
399     }
400 }
401 
402 }  // namespace GrRectOpFactory
403 
404 ///////////////////////////////////////////////////////////////////////////////////////////////////
405 
406 #if GR_TEST_UTILS
407 
GR_DRAW_OP_TEST_DEFINE(NonAAFillRectOp)408 GR_DRAW_OP_TEST_DEFINE(NonAAFillRectOp) {
409     SkRect rect = GrTest::TestRect(random);
410     SkRect localRect = GrTest::TestRect(random);
411     SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
412     SkMatrix localMatrix = GrTest::TestMatrix(random);
413     const GrUserStencilSettings* stencil = GrGetRandomStencil(random, context);
414     GrAAType aaType = GrAAType::kNone;
415     if (fsaaType == GrFSAAType::kUnifiedMSAA) {
416         aaType = random->nextBool() ? GrAAType::kMSAA : GrAAType::kNone;
417     }
418     const SkRect* lr = random->nextBool() ? &localRect : nullptr;
419     const SkMatrix* lm = random->nextBool() ? &localMatrix : nullptr;
420     if (viewMatrix.hasPerspective() || (lm && lm->hasPerspective())) {
421         return NonAAFillRectPerspectiveOp::Make(std::move(paint), viewMatrix, rect, lr, lm, aaType,
422                                                 stencil);
423     } else {
424         return NonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, lr, lm, aaType, stencil);
425     }
426 }
427 
428 #endif
429