• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 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 "GrFillRectOp.h"
9 
10 #include "GrGeometryProcessor.h"
11 #include "GrMeshDrawOp.h"
12 #include "GrPaint.h"
13 #include "GrQuad.h"
14 #include "GrQuadPerEdgeAA.h"
15 #include "GrSimpleMeshDrawOpHelper.h"
16 #include "SkMatrix.h"
17 #include "SkRect.h"
18 #include "glsl/GrGLSLColorSpaceXformHelper.h"
19 #include "glsl/GrGLSLGeometryProcessor.h"
20 #include "glsl/GrGLSLVarying.h"
21 
22 namespace {
23 
24 using VertexSpec = GrQuadPerEdgeAA::VertexSpec;
25 using ColorType = GrQuadPerEdgeAA::ColorType;
26 
27 #ifdef SK_DEBUG
dump_quad_info(int index,const GrPerspQuad & deviceQuad,const GrPerspQuad & localQuad,const SkPMColor4f & color,GrQuadAAFlags aaFlags)28 static SkString dump_quad_info(int index, const GrPerspQuad& deviceQuad,
29                                const GrPerspQuad& localQuad, const SkPMColor4f& color,
30                                GrQuadAAFlags aaFlags) {
31     SkString str;
32     str.appendf("%d: Color: [%.2f, %.2f, %.2f, %.2f], Edge AA: l%u_t%u_r%u_b%u, \n"
33                 "  device quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
34                 "(%.2f, %.2f, %.2f)],\n"
35                 "  local quad: [(%.2f, %2.f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), "
36                 "(%.2f, %.2f, %.2f)]\n",
37                 index, color.fR, color.fG, color.fB, color.fA,
38                 (uint32_t) (aaFlags & GrQuadAAFlags::kLeft),
39                 (uint32_t) (aaFlags & GrQuadAAFlags::kTop),
40                 (uint32_t) (aaFlags & GrQuadAAFlags::kRight),
41                 (uint32_t) (aaFlags & GrQuadAAFlags::kBottom),
42                 deviceQuad.x(0), deviceQuad.y(0), deviceQuad.w(0),
43                 deviceQuad.x(1), deviceQuad.y(1), deviceQuad.w(1),
44                 deviceQuad.x(2), deviceQuad.y(2), deviceQuad.w(2),
45                 deviceQuad.x(3), deviceQuad.y(3), deviceQuad.w(3),
46                 localQuad.x(0), localQuad.y(0), localQuad.w(0),
47                 localQuad.x(1), localQuad.y(1), localQuad.w(1),
48                 localQuad.x(2), localQuad.y(2), localQuad.w(2),
49                 localQuad.x(3), localQuad.y(3), localQuad.w(3));
50     return str;
51 }
52 #endif
53 
54 class FillRectOp final : public GrMeshDrawOp {
55 private:
56     using Helper = GrSimpleMeshDrawOpHelperWithStencil;
57 
58 public:
Make(GrContext * context,GrPaint && paint,GrAAType aaType,GrQuadAAFlags edgeAA,const GrUserStencilSettings * stencilSettings,const GrPerspQuad & deviceQuad,GrQuadType deviceQuadType,const GrPerspQuad & localQuad,GrQuadType localQuadType)59     static std::unique_ptr<GrDrawOp> Make(GrContext* context,
60                                           GrPaint&& paint,
61                                           GrAAType aaType,
62                                           GrQuadAAFlags edgeAA,
63                                           const GrUserStencilSettings* stencilSettings,
64                                           const GrPerspQuad& deviceQuad,
65                                           GrQuadType deviceQuadType,
66                                           const GrPerspQuad& localQuad,
67                                           GrQuadType localQuadType) {
68         // Clean up deviations between aaType and edgeAA
69         GrResolveAATypeForQuad(aaType, edgeAA, deviceQuad, deviceQuadType, &aaType, &edgeAA);
70         return Helper::FactoryHelper<FillRectOp>(context, std::move(paint), aaType, edgeAA,
71                 stencilSettings, deviceQuad, deviceQuadType, localQuad, localQuadType);
72     }
73 
74     // aaType is passed to Helper in the initializer list, so incongruities between aaType and
75     // edgeFlags must be resolved prior to calling this constructor.
FillRectOp(Helper::MakeArgs args,SkPMColor4f paintColor,GrAAType aaType,GrQuadAAFlags edgeFlags,const GrUserStencilSettings * stencil,const GrPerspQuad & deviceQuad,GrQuadType deviceQuadType,const GrPerspQuad & localQuad,GrQuadType localQuadType)76     FillRectOp(Helper::MakeArgs args, SkPMColor4f paintColor, GrAAType aaType,
77                GrQuadAAFlags edgeFlags, const GrUserStencilSettings* stencil,
78                const GrPerspQuad& deviceQuad, GrQuadType deviceQuadType,
79                const GrPerspQuad& localQuad, GrQuadType localQuadType)
80             : INHERITED(ClassID())
81             , fHelper(args, aaType, stencil)
82             , fWideColor(!SkPMColor4fFitsInBytes(paintColor)) {
83         // The color stored with the quad is the clear color if a scissor-clear is decided upon
84         // when executing the op.
85         fDeviceQuads.push_back(deviceQuad, deviceQuadType, { paintColor, edgeFlags });
86 
87         if (!fHelper.isTrivial()) {
88             // Conservatively keep track of the local coordinates; it may be that the paint doesn't
89             // need them after analysis is finished. If the paint is known to be solid up front they
90             // can be skipped entirely.
91             fLocalQuads.push_back(localQuad, localQuadType);
92         }
93         this->setBounds(deviceQuad.bounds(deviceQuadType),
94                         HasAABloat(aaType == GrAAType::kCoverage), IsZeroArea::kNo);
95     }
96 
name() const97     const char* name() const override { return "FillRectOp"; }
98 
visitProxies(const VisitProxyFunc & func,VisitorType) const99     void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
100         return fHelper.visitProxies(func);
101     }
102 
103 #ifdef SK_DEBUG
dumpInfo() const104     SkString dumpInfo() const override {
105         SkString str;
106         str.appendf("# draws: %u\n", this->quadCount());
107         str.appendf("Device quad type: %u, local quad type: %u\n",
108                     (uint32_t) fDeviceQuads.quadType(), (uint32_t) fLocalQuads.quadType());
109         str += fHelper.dumpInfo();
110         GrPerspQuad device, local;
111         for (int i = 0; i < this->quadCount(); i++) {
112             device = fDeviceQuads[i];
113             const ColorAndAA& info = fDeviceQuads.metadata(i);
114             if (!fHelper.isTrivial()) {
115                 local = fLocalQuads[i];
116             }
117             str += dump_quad_info(i, device, local, info.fColor, info.fAAFlags);
118         }
119         str += INHERITED::dumpInfo();
120         return str;
121     }
122 #endif
123 
finalize(const GrCaps & caps,const GrAppliedClip * clip)124     GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
125         // Initialize aggregate color analysis with the first quad's color (which always exists)
126         SkASSERT(this->quadCount() > 0);
127         GrProcessorAnalysisColor quadColors(fDeviceQuads.metadata(0).fColor);
128         // Then combine the colors of any additional quads (e.g. from MakeSet)
129         for (int i = 1; i < this->quadCount(); ++i) {
130             quadColors = GrProcessorAnalysisColor::Combine(quadColors,
131                                                            fDeviceQuads.metadata(i).fColor);
132             if (quadColors.isUnknown()) {
133                 // No point in accumulating additional starting colors, combining cannot make it
134                 // less unknown.
135                 break;
136             }
137         }
138 
139         // If the AA type is coverage, it will be a single value per pixel; if it's not coverage AA
140         // then the coverage is always 1.0, so specify kNone for more optimal blending.
141         GrProcessorAnalysisCoverage coverage = fHelper.aaType() == GrAAType::kCoverage ?
142                 GrProcessorAnalysisCoverage::kSingleChannel :
143                 GrProcessorAnalysisCoverage::kNone;
144         auto result = fHelper.finalizeProcessors(caps, clip, coverage, &quadColors);
145         // If there is a constant color after analysis, that means all of the quads should be set
146         // to the same color (even if they started out with different colors).
147         SkPMColor4f colorOverride;
148         if (quadColors.isConstant(&colorOverride)) {
149             for (int i = 0; i < this->quadCount(); ++i) {
150                 fDeviceQuads.metadata(i).fColor = colorOverride;
151             }
152         }
153 
154         return result;
155     }
156 
fixedFunctionFlags() const157     FixedFunctionFlags fixedFunctionFlags() const override {
158         // Since the AA type of the whole primitive is kept consistent with the per edge AA flags
159         // the helper's fixed function flags are appropriate.
160         return fHelper.fixedFunctionFlags();
161     }
162 
163     DEFINE_OP_CLASS_ID
164 
165 private:
166     // For GrFillRectOp::MakeSet's use of addQuad
167     friend std::unique_ptr<GrDrawOp> GrFillRectOp::MakeSet(GrContext* context, GrPaint&& paint,
168             GrAAType aaType, const SkMatrix& viewMatrix,
169             const GrRenderTargetContext::QuadSetEntry quads[], int quadCount,
170             const GrUserStencilSettings* stencilSettings);
171 
onPrepareDraws(Target * target)172     void onPrepareDraws(Target* target) override {
173         TRACE_EVENT0("skia", TRACE_FUNC);
174 
175         using Domain = GrQuadPerEdgeAA::Domain;
176         static constexpr SkRect kEmptyDomain = SkRect::MakeEmpty();
177 
178         VertexSpec vertexSpec(fDeviceQuads.quadType(),
179                               fWideColor ? ColorType::kHalf : ColorType::kByte,
180                               fLocalQuads.quadType(), fHelper.usesLocalCoords(), Domain::kNo,
181                               fHelper.aaType(), fHelper.compatibleWithAlphaAsCoverage());
182         // Make sure that if the op thought it was a solid color, the vertex spec does not use
183         // local coords.
184         SkASSERT(!fHelper.isTrivial() || !fHelper.usesLocalCoords());
185 
186         sk_sp<GrGeometryProcessor> gp = GrQuadPerEdgeAA::MakeProcessor(vertexSpec);
187         size_t vertexSize = gp->vertexStride();
188 
189         sk_sp<const GrBuffer> vbuffer;
190         int vertexOffsetInBuffer = 0;
191 
192         // Fill the allocated vertex data
193         void* vdata = target->makeVertexSpace(
194                 vertexSize, this->quadCount() * vertexSpec.verticesPerQuad(),
195                 &vbuffer, &vertexOffsetInBuffer);
196         if (!vdata) {
197             SkDebugf("Could not allocate vertices\n");
198             return;
199         }
200 
201         // vertices pointer advances through vdata based on Tessellate's return value
202         void* vertices = vdata;
203         if (fHelper.isTrivial()) {
204             SkASSERT(fLocalQuads.count() == 0); // No local coords, so send an ignored dummy quad
205             static const GrPerspQuad kIgnoredLocal(SkRect::MakeEmpty(), SkMatrix::I());
206             for (int i = 0; i < this->quadCount(); ++i) {
207                 const ColorAndAA& info = fDeviceQuads.metadata(i);
208                 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, fDeviceQuads[i],
209                         info.fColor, kIgnoredLocal, kEmptyDomain, info.fAAFlags);
210             }
211         } else {
212             SkASSERT(fLocalQuads.count() == fDeviceQuads.count());
213             for (int i = 0; i < this->quadCount(); ++i) {
214                 const ColorAndAA& info = fDeviceQuads.metadata(i);
215                 vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, fDeviceQuads[i],
216                         info.fColor, fLocalQuads[i], kEmptyDomain, info.fAAFlags);
217             }
218         }
219 
220         // Configure the mesh for the vertex data
221         GrMesh* mesh = target->allocMeshes(1);
222         if (!GrQuadPerEdgeAA::ConfigureMeshIndices(target, mesh, vertexSpec, this->quadCount())) {
223             SkDebugf("Could not allocate indices\n");
224             return;
225         }
226         mesh->setVertexData(std::move(vbuffer), vertexOffsetInBuffer);
227 
228         auto pipe = fHelper.makePipeline(target);
229         target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
230    }
231 
onCombineIfPossible(GrOp * t,const GrCaps & caps)232     CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
233         TRACE_EVENT0("skia", TRACE_FUNC);
234         const auto* that = t->cast<FillRectOp>();
235 
236         if ((fHelper.aaType() == GrAAType::kCoverage ||
237              that->fHelper.aaType() == GrAAType::kCoverage) &&
238             this->quadCount() + that->quadCount() > GrQuadPerEdgeAA::kNumAAQuadsInIndexBuffer) {
239             // This limit on batch size seems to help on Adreno devices
240             return CombineResult::kCannotCombine;
241         }
242 
243         // Unlike most users of the draw op helper, this op can merge none-aa and coverage-aa draw
244         // ops together, so pass true as the last argument.
245         if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds(), true)) {
246             return CombineResult::kCannotCombine;
247         }
248 
249         // If the paints were compatible, the trivial/solid-color state should be the same
250         SkASSERT(fHelper.isTrivial() == that->fHelper.isTrivial());
251 
252         // If the processor sets are compatible, the two ops are always compatible; it just needs to
253         // adjust the state of the op to be the more general quad and aa types of the two ops and
254         // then concatenate the per-quad data.
255         fWideColor |= that->fWideColor;
256 
257         // The helper stores the aa type, but isCompatible(with true arg) allows the two ops' aa
258         // types to be none and coverage, in which case this op's aa type must be lifted to coverage
259         // so that quads with no aa edges can be batched with quads that have some/all edges aa'ed.
260         if (fHelper.aaType() == GrAAType::kNone && that->fHelper.aaType() == GrAAType::kCoverage) {
261             fHelper.setAAType(GrAAType::kCoverage);
262         }
263 
264         fDeviceQuads.concat(that->fDeviceQuads);
265         if (!fHelper.isTrivial()) {
266             fLocalQuads.concat(that->fLocalQuads);
267         }
268         return CombineResult::kMerged;
269     }
270 
271     // Similar to onCombineIfPossible, but adds a quad assuming its op would have been compatible.
272     // But since it's avoiding the op list management, it must update the op's bounds. This is only
273     // used with quad sets, which uses the same view matrix for each quad so this assumes that the
274     // device quad type of the new quad is the same as the op's.
addQuad(const GrPerspQuad & deviceQuad,const GrPerspQuad & localQuad,GrQuadType localQuadType,const SkPMColor4f & color,GrQuadAAFlags edgeAA,GrAAType aaType)275     void addQuad(const GrPerspQuad& deviceQuad, const GrPerspQuad& localQuad,
276                  GrQuadType localQuadType, const SkPMColor4f& color, GrQuadAAFlags edgeAA,
277                  GrAAType aaType) {
278         SkASSERT(deviceQuad.quadType() <= fDeviceQuads.quadType());
279 
280         // The new quad's aa type should be the same as the first quad's or none, except when the
281         // first quad's aa type was already downgraded to none, in which case the stored type must
282         // be lifted to back to the requested type.
283         if (aaType != fHelper.aaType()) {
284             if (aaType != GrAAType::kNone) {
285                 // Original quad was downgraded to non-aa, lift back up to this quad's required type
286                 SkASSERT(fHelper.aaType() == GrAAType::kNone);
287                 fHelper.setAAType(aaType);
288             }
289             // else the new quad could have been downgraded but the other quads can't be, so don't
290             // reset the op's accumulated aa type.
291         }
292 
293         // clear compatible won't need to be updated, since device quad type and paint is the same,
294         // but this quad has a new color, so maybe update wide color
295         fWideColor |= !SkPMColor4fFitsInBytes(color);
296 
297         // Update the bounds and add the quad to this op's storage
298         SkRect newBounds = this->bounds();
299         newBounds.joinPossiblyEmptyRect(deviceQuad.bounds(fDeviceQuads.quadType()));
300         this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage),
301                         IsZeroArea::kNo);
302         fDeviceQuads.push_back(deviceQuad, fDeviceQuads.quadType(), { color, edgeAA });
303         if (!fHelper.isTrivial()) {
304             fLocalQuads.push_back(localQuad, localQuadType);
305         }
306     }
307 
quadCount() const308     int quadCount() const {
309         // Sanity check that the parallel arrays for quad properties all have the same size
310         SkASSERT(fDeviceQuads.count() == fLocalQuads.count() ||
311                  (fLocalQuads.count() == 0 && fHelper.isTrivial()));
312         return fDeviceQuads.count();
313     }
314 
315     struct ColorAndAA {
316         SkPMColor4f fColor;
317         GrQuadAAFlags fAAFlags;
318     };
319 
320     Helper fHelper;
321     GrTQuadList<ColorAndAA> fDeviceQuads;
322     // No metadata attached to the local quads; this list is empty when local coords are not needed.
323     GrQuadList fLocalQuads;
324 
325     unsigned fWideColor: 1;
326 
327     typedef GrMeshDrawOp INHERITED;
328 };
329 
330 } // anonymous namespace
331 
332 namespace GrFillRectOp {
333 
MakePerEdge(GrContext * context,GrPaint && paint,GrAAType aaType,GrQuadAAFlags edgeAA,const SkMatrix & viewMatrix,const SkRect & rect,const GrUserStencilSettings * stencilSettings)334 std::unique_ptr<GrDrawOp> MakePerEdge(GrContext* context,
335                                       GrPaint&& paint,
336                                       GrAAType aaType,
337                                       GrQuadAAFlags edgeAA,
338                                       const SkMatrix& viewMatrix,
339                                       const SkRect& rect,
340                                       const GrUserStencilSettings* stencilSettings) {
341     return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
342                             GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
343                             GrPerspQuad(rect, SkMatrix::I()), GrQuadType::kRect);
344 }
345 
MakePerEdgeWithLocalMatrix(GrContext * context,GrPaint && paint,GrAAType aaType,GrQuadAAFlags edgeAA,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,const SkRect & rect,const GrUserStencilSettings * stencilSettings)346 std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalMatrix(GrContext* context,
347                                                      GrPaint&& paint,
348                                                      GrAAType aaType,
349                                                      GrQuadAAFlags edgeAA,
350                                                      const SkMatrix& viewMatrix,
351                                                      const SkMatrix& localMatrix,
352                                                      const SkRect& rect,
353                                                      const GrUserStencilSettings* stencilSettings) {
354     GrQuadType localQuadType = GrQuadTypeForTransformedRect(localMatrix);
355     return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
356                             GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
357                             GrPerspQuad(rect, localMatrix), localQuadType);
358 }
359 
MakePerEdgeWithLocalRect(GrContext * context,GrPaint && paint,GrAAType aaType,GrQuadAAFlags edgeAA,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & localRect,const GrUserStencilSettings * stencilSettings)360 std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalRect(GrContext* context,
361                                                    GrPaint&& paint,
362                                                    GrAAType aaType,
363                                                    GrQuadAAFlags edgeAA,
364                                                    const SkMatrix& viewMatrix,
365                                                    const SkRect& rect,
366                                                    const SkRect& localRect,
367                                                    const GrUserStencilSettings* stencilSettings) {
368     return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
369                             GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
370                             GrPerspQuad(localRect, SkMatrix::I()), GrQuadType::kRect);
371 }
372 
MakeSet(GrContext * context,GrPaint && paint,GrAAType aaType,const SkMatrix & viewMatrix,const GrRenderTargetContext::QuadSetEntry quads[],int cnt,const GrUserStencilSettings * stencilSettings)373 std::unique_ptr<GrDrawOp> MakeSet(GrContext* context,
374                                   GrPaint&& paint,
375                                   GrAAType aaType,
376                                   const SkMatrix& viewMatrix,
377                                   const GrRenderTargetContext::QuadSetEntry quads[],
378                                   int cnt,
379                                   const GrUserStencilSettings* stencilSettings) {
380     // First make a draw op for the first quad in the set
381     SkASSERT(cnt > 0);
382     GrQuadType deviceQuadType = GrQuadTypeForTransformedRect(viewMatrix);
383 
384     paint.setColor4f(quads[0].fColor);
385     std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
386             quads[0].fAAFlags, stencilSettings, GrPerspQuad(quads[0].fRect, viewMatrix),
387             deviceQuadType, GrPerspQuad(quads[0].fRect, quads[0].fLocalMatrix),
388             GrQuadTypeForTransformedRect(quads[0].fLocalMatrix));
389     auto* fillRects = op->cast<FillRectOp>();
390 
391     // Accumulate remaining quads similar to onCombineIfPossible() without creating an op
392     for (int i = 1; i < cnt; ++i) {
393         GrPerspQuad deviceQuad(quads[i].fRect, viewMatrix);
394 
395         GrAAType resolvedAA;
396         GrQuadAAFlags resolvedEdgeFlags;
397         GrResolveAATypeForQuad(aaType, quads[i].fAAFlags, deviceQuad, deviceQuadType,
398                                &resolvedAA, &resolvedEdgeFlags);
399 
400         fillRects->addQuad(deviceQuad, GrPerspQuad(quads[i].fRect, quads[i].fLocalMatrix),
401                            GrQuadTypeForTransformedRect(quads[i].fLocalMatrix), quads[i].fColor,
402                            resolvedEdgeFlags,resolvedAA);
403     }
404 
405     return op;
406 }
407 
Make(GrContext * context,GrPaint && paint,GrAAType aaType,const SkMatrix & viewMatrix,const SkRect & rect,const GrUserStencilSettings * stencil)408 std::unique_ptr<GrDrawOp> Make(GrContext* context,
409                                GrPaint&& paint,
410                                GrAAType aaType,
411                                const SkMatrix& viewMatrix,
412                                const SkRect& rect,
413                                const GrUserStencilSettings* stencil) {
414     return MakePerEdge(context, std::move(paint), aaType,
415             aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
416             viewMatrix, rect, stencil);
417 }
418 
MakeWithLocalMatrix(GrContext * context,GrPaint && paint,GrAAType aaType,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,const SkRect & rect,const GrUserStencilSettings * stencil)419 std::unique_ptr<GrDrawOp> MakeWithLocalMatrix(GrContext* context,
420                                               GrPaint&& paint,
421                                               GrAAType aaType,
422                                               const SkMatrix& viewMatrix,
423                                               const SkMatrix& localMatrix,
424                                               const SkRect& rect,
425                                               const GrUserStencilSettings* stencil) {
426     return MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
427             aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
428             viewMatrix, localMatrix, rect, stencil);
429 }
430 
MakeWithLocalRect(GrContext * context,GrPaint && paint,GrAAType aaType,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect & localRect,const GrUserStencilSettings * stencil)431 std::unique_ptr<GrDrawOp> MakeWithLocalRect(GrContext* context,
432                                             GrPaint&& paint,
433                                             GrAAType aaType,
434                                             const SkMatrix& viewMatrix,
435                                             const SkRect& rect,
436                                             const SkRect& localRect,
437                                             const GrUserStencilSettings* stencil) {
438     return MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
439             aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
440             viewMatrix, rect, localRect, stencil);
441 }
442 
443 } // namespace GrFillRectOp
444 
445 #if GR_TEST_UTILS
446 
447 #include "GrDrawOpTest.h"
448 #include "SkGr.h"
449 
GR_DRAW_OP_TEST_DEFINE(FillRectOp)450 GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
451     SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
452     SkRect rect = GrTest::TestRect(random);
453 
454     GrAAType aaType = GrAAType::kNone;
455     if (random->nextBool()) {
456         aaType = (fsaaType == GrFSAAType::kUnifiedMSAA) ? GrAAType::kMSAA : GrAAType::kCoverage;
457     }
458     const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
459                                                               : GrGetRandomStencil(random, context);
460 
461     GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
462     aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
463     aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
464     aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
465     aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
466 
467     if (random->nextBool()) {
468         if (random->nextBool()) {
469             if (random->nextBool()) {
470                 // Local matrix with a set op
471                 uint32_t extraQuadCt = random->nextRangeU(1, 4);
472                 SkTArray<GrRenderTargetContext::QuadSetEntry> quads(extraQuadCt + 1);
473                 quads.push_back(
474                         {rect, SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
475                          GrTest::TestMatrixInvertible(random), aaFlags});
476                 for (uint32_t i = 0; i < extraQuadCt; ++i) {
477                     GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
478                     aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
479                     aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
480                     aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
481                     aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
482 
483                     quads.push_back(
484                         {GrTest::TestRect(random),
485                          SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
486                          GrTest::TestMatrixInvertible(random), aaFlags});
487                 }
488 
489                 return GrFillRectOp::MakeSet(context, std::move(paint), aaType, viewMatrix,
490                                              quads.begin(), quads.count(), stencil);
491             } else {
492                 // Single local matrix
493                 SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
494                 return GrFillRectOp::MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
495                                                                 aaFlags, viewMatrix, localMatrix,
496                                                                 rect, stencil);
497             }
498         } else {
499             // Pass local rect directly
500             SkRect localRect = GrTest::TestRect(random);
501             return GrFillRectOp::MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
502                                                           aaFlags, viewMatrix, rect, localRect,
503                                                           stencil);
504         }
505     } else {
506         // The simplest constructor
507         return GrFillRectOp::MakePerEdge(context, std::move(paint), aaType, aaFlags, viewMatrix,
508                                          rect, stencil);
509     }
510 }
511 
512 #endif
513