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