Respect max index buffer sizes in GrFillRectOp::MakeSet
This is required before we can lower the max AA quad count (again).
Bug: b/143572065 skia:9601
Change-Id: Iea5884ffff9bd62f62527fcb597dac97d33ecd76
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/254438
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
diff --git a/gn/tests.gni b/gn/tests.gni
index b893768..c823ac2 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -24,6 +24,7 @@
"$_tests/BlendTest.cpp",
"$_tests/BlitMaskClip.cpp",
"$_tests/BlurTest.cpp",
+ "$_tests/BulkFillRectTest.cpp",
"$_tests/CTest.cpp",
"$_tests/CachedDataTest.cpp",
"$_tests/CachedDecodingPixelRefTest.cpp",
diff --git a/src/gpu/GrOpsTask.h b/src/gpu/GrOpsTask.h
index 1a4c517..fd69509 100644
--- a/src/gpu/GrOpsTask.h
+++ b/src/gpu/GrOpsTask.h
@@ -106,6 +106,11 @@
SkDEBUGCODE(int numClips() const override { return fNumClips; })
SkDEBUGCODE(void visitProxies_debugOnly(const VisitSurfaceProxyFunc&) const override;)
+#if GR_TEST_UTILS
+ int numOpChains() const { return fOpChains.count(); }
+ const GrOp* getChain(int index) const { return fOpChains[index].head(); }
+#endif
+
private:
bool isNoOp() const {
// TODO: GrLoadOp::kDiscard (i.e., storing a discard) should also be grounds for skipping
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 1e0cc19..06147d9 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -733,8 +733,9 @@
const SkMatrix& viewMatrix, const QuadSetEntry quads[],
int cnt) {
GrAAType aaType = this->chooseAAType(aa);
- this->addDrawOp(clip, GrFillRectOp::MakeSet(fContext, std::move(paint), aaType, viewMatrix,
- quads, cnt));
+
+ GrFillRectOp::AddFillRectOps(this, clip, fContext, std::move(paint), aaType, viewMatrix,
+ quads, cnt);
}
int GrRenderTargetContextPriv::maxWindowRectangles() const {
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index eacff51..89fd20c 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -549,12 +549,16 @@
friend class GrTessellatingPathRenderer; // for access to add[Mesh]DrawOp
friend class GrCCPerFlushResources; // for access to addDrawOp
friend class GrCoverageCountingPathRenderer; // for access to addDrawOp
+ friend class GrFillRectOp; // for access to addDrawOp
+
+#if GR_TEST_UTILS
// for a unit test
friend void test_draw_op(GrContext*,
GrRenderTargetContext*,
std::unique_ptr<GrFragmentProcessor>,
sk_sp<GrTextureProxy>,
GrColorType);
+#endif
GrRenderTargetContext(GrRecordingContext*, sk_sp<GrRenderTargetProxy>, GrColorType,
GrSurfaceOrigin, GrSwizzle texSwizzle, GrSwizzle outSwizzle,
diff --git a/src/gpu/ops/GrDrawOp.h b/src/gpu/ops/GrDrawOp.h
index a9e9752..3385b64 100644
--- a/src/gpu/ops/GrDrawOp.h
+++ b/src/gpu/ops/GrDrawOp.h
@@ -54,6 +54,11 @@
}
#endif
+#if GR_TEST_UTILS
+ // This is really only intended for GrTextureOp and GrFillRectOp to override
+ virtual int numQuads() const { return -1; }
+#endif
+
private:
typedef GrOp INHERITED;
};
diff --git a/src/gpu/ops/GrFillRectOp.cpp b/src/gpu/ops/GrFillRectOp.cpp
index ec6fa0b..2ee183a 100644
--- a/src/gpu/ops/GrFillRectOp.cpp
+++ b/src/gpu/ops/GrFillRectOp.cpp
@@ -178,13 +178,11 @@
DEFINE_OP_CLASS_ID
private:
- // For GrFillRectOp::MakeSet's use of addQuad
- friend std::unique_ptr<GrDrawOp> GrFillRectOp::MakeSet(
- GrRecordingContext*,
- GrPaint&&,
- GrAAType, const SkMatrix& viewMatrix,
- const GrRenderTargetContext::QuadSetEntry quads[], int quadCount,
- const GrUserStencilSettings*);
+ friend class ::GrFillRectOp; // for access to addQuad
+
+#if GR_TEST_UTILS
+ int numQuads() const final { return fQuads.count(); }
+#endif
void onPrepareDraws(Target* target) override {
TRACE_EVENT0("skia.gpu", TRACE_FUNC);
@@ -297,19 +295,29 @@
// But since it's avoiding the op list management, it must update the op's bounds. This is only
// used with quad sets, which uses the same view matrix for each quad so this assumes that the
// device quad type of the new quad is the same as the op's.
- void addQuad(const GrQuad& deviceQuad, const GrQuad& localQuad,
+ bool addQuad(const GrQuad& deviceQuad, const GrQuad& localQuad,
const SkPMColor4f& color, GrQuadAAFlags edgeAA, GrAAType aaType) {
// The new quad's aa type should be the same as the first quad's or none, except when the
// first quad's aa type was already downgraded to none, in which case the stored type must
// be lifted to back to the requested type.
- if (aaType != fHelper.aaType()) {
- if (aaType != GrAAType::kNone) {
- // Original quad was downgraded to non-aa, lift back up to this quad's required type
- SkASSERT(fHelper.aaType() == GrAAType::kNone);
- fHelper.setAAType(aaType);
+ if (aaType != fHelper.aaType() && aaType != GrAAType::kNone) {
+ auto indexBufferOption = GrQuadPerEdgeAA::CalcIndexBufferOption(aaType,
+ fQuads.count()+1);
+ if (fQuads.count()+1 > GrQuadPerEdgeAA::QuadLimit(indexBufferOption)) {
+ // Promoting to the new aaType would've caused an overflow of the indexBuffer
+ // limit
+ return false;
}
- // else the new quad could have been downgraded but the other quads can't be, so don't
- // reset the op's accumulated aa type.
+
+ // Original quad was downgraded to non-aa, lift back up to this quad's required type
+ SkASSERT(fHelper.aaType() == GrAAType::kNone);
+ fHelper.setAAType(aaType);
+ } else {
+ auto indexBufferOption = GrQuadPerEdgeAA::CalcIndexBufferOption(fHelper.aaType(),
+ fQuads.count()+1);
+ if (fQuads.count()+1 > GrQuadPerEdgeAA::QuadLimit(indexBufferOption)) {
+ return false; // This op can't grow any more
+ }
}
// Update the bounds and add the quad to this op's storage
@@ -318,6 +326,7 @@
this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage),
IsHairline::kNo);
fQuads.append(deviceQuad, { color, edgeAA }, fHelper.isTrivial() ? nullptr : &localQuad);
+ return true;
}
struct ColorAndAA {
@@ -335,45 +344,46 @@
} // anonymous namespace
-namespace GrFillRectOp {
-
-std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
- GrPaint&& paint,
- GrAAType aaType,
- GrQuadAAFlags aaFlags,
- const GrQuad& deviceQuad,
- const GrQuad& localQuad,
- const GrUserStencilSettings* stencil) {
+std::unique_ptr<GrDrawOp> GrFillRectOp::Make(GrRecordingContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ GrQuadAAFlags aaFlags,
+ const GrQuad& deviceQuad,
+ const GrQuad& localQuad,
+ const GrUserStencilSettings* stencil) {
return FillRectOp::Make(context, std::move(paint), aaType, aaFlags, stencil,
deviceQuad, localQuad);
}
-std::unique_ptr<GrDrawOp> MakeNonAARect(GrRecordingContext* context,
- GrPaint&& paint,
- const SkMatrix& view,
- const SkRect& rect,
- const GrUserStencilSettings* stencil) {
+std::unique_ptr<GrDrawOp> GrFillRectOp::MakeNonAARect(GrRecordingContext* context,
+ GrPaint&& paint,
+ const SkMatrix& view,
+ const SkRect& rect,
+ const GrUserStencilSettings* stencil) {
return FillRectOp::Make(context, std::move(paint), GrAAType::kNone, GrQuadAAFlags::kNone,
stencil, GrQuad::MakeFromRect(rect, view), GrQuad(rect));
}
-std::unique_ptr<GrDrawOp> MakeSet(GrRecordingContext* context,
- GrPaint&& paint,
- GrAAType aaType,
- const SkMatrix& viewMatrix,
- const GrRenderTargetContext::QuadSetEntry quads[],
- int cnt,
- const GrUserStencilSettings* stencilSettings) {
+std::unique_ptr<GrDrawOp> GrFillRectOp::MakeOp(GrRecordingContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ const SkMatrix& viewMatrix,
+ const GrRenderTargetContext::QuadSetEntry quads[],
+ int cnt,
+ const GrUserStencilSettings* stencilSettings,
+ int* numConsumed) {
// First make a draw op for the first quad in the set
SkASSERT(cnt > 0);
paint.setColor4f(quads[0].fColor);
- std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
+ std::unique_ptr<GrDrawOp> op = FillRectOp::Make(
+ context, std::move(paint), aaType,
quads[0].fAAFlags, stencilSettings,
GrQuad::MakeFromRect(quads[0].fRect, viewMatrix),
GrQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix));
- auto* fillRects = op->cast<FillRectOp>();
+ FillRectOp* fillRects = op->cast<FillRectOp>();
+ *numConsumed = 1;
// Accumulate remaining quads similar to onCombineIfPossible() without creating an op
for (int i = 1; i < cnt; ++i) {
GrQuad deviceQuad = GrQuad::MakeFromRect(quads[i].fRect, viewMatrix);
@@ -383,18 +393,52 @@
GrQuadUtils::ResolveAAType(aaType, quads[i].fAAFlags, deviceQuad,
&resolvedAA, &resolvedEdgeFlags);
- fillRects->addQuad(deviceQuad,
- GrQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
- quads[i].fColor, resolvedEdgeFlags,resolvedAA);
+ if (!fillRects->addQuad(deviceQuad,
+ GrQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
+ quads[i].fColor, resolvedEdgeFlags, resolvedAA)) {
+ break;
+ }
+
+ (*numConsumed)++;
}
return op;
}
-} // namespace GrFillRectOp
+void GrFillRectOp::AddFillRectOps(GrRenderTargetContext* rtc,
+ const GrClip& clip,
+ GrRecordingContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ const SkMatrix& viewMatrix,
+ const GrRenderTargetContext::QuadSetEntry quads[],
+ int cnt,
+ const GrUserStencilSettings* stencilSettings) {
+
+ int offset = 0;
+ int numLeft = cnt;
+ while (numLeft) {
+ int numConsumed = 0;
+
+ std::unique_ptr<GrDrawOp> op = MakeOp(context, GrPaint::Clone(paint), aaType, viewMatrix,
+ &quads[offset], numLeft, stencilSettings,
+ &numConsumed);
+
+ offset += numConsumed;
+ numLeft -= numConsumed;
+
+ rtc->addDrawOp(clip, std::move(op));
+ }
+
+ SkASSERT(offset == cnt);
+}
#if GR_TEST_UTILS
+uint32_t GrFillRectOp::ClassID() {
+ return FillRectOp::ClassID();
+}
+
#include "src/gpu/GrDrawOpTest.h"
#include "src/gpu/SkGr.h"
@@ -417,35 +461,11 @@
if (random->nextBool()) {
if (random->nextBool()) {
- if (random->nextBool()) {
- // Local matrix with a set op
- uint32_t extraQuadCt = random->nextRangeU(1, 4);
- SkTArray<GrRenderTargetContext::QuadSetEntry> quads(extraQuadCt + 1);
- quads.push_back(
- {rect, SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
- GrTest::TestMatrixInvertible(random), aaFlags});
- for (uint32_t i = 0; i < extraQuadCt; ++i) {
- GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
- aaFlags |= random->nextBool() ? GrQuadAAFlags::kLeft : GrQuadAAFlags::kNone;
- aaFlags |= random->nextBool() ? GrQuadAAFlags::kTop : GrQuadAAFlags::kNone;
- aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
- aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
-
- quads.push_back(
- {GrTest::TestRect(random),
- SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU())),
- GrTest::TestMatrixInvertible(random), aaFlags});
- }
-
- return GrFillRectOp::MakeSet(context, std::move(paint), aaType, viewMatrix,
- quads.begin(), quads.count(), stencil);
- } else {
- // Single local matrix
- SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
- return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
- GrQuad::MakeFromRect(rect, viewMatrix),
- GrQuad::MakeFromRect(rect, localMatrix), stencil);
- }
+ // Single local matrix
+ SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
+ return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
+ GrQuad::MakeFromRect(rect, viewMatrix),
+ GrQuad::MakeFromRect(rect, localMatrix), stencil);
} else {
// Pass local rect directly
SkRect localRect = GrTest::TestRect(random);
diff --git a/src/gpu/ops/GrFillRectOp.h b/src/gpu/ops/GrFillRectOp.h
index 768ed8b..600e87b 100644
--- a/src/gpu/ops/GrFillRectOp.h
+++ b/src/gpu/ops/GrFillRectOp.h
@@ -25,34 +25,53 @@
* the GrPaint is only consumed by these methods if a valid op is returned. If null is returned then
* the paint is unmodified and may still be used.
*/
-namespace GrFillRectOp {
+class GrFillRectOp {
+public:
-std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
- GrPaint&& paint,
- GrAAType aaType,
- GrQuadAAFlags aaFlags,
- const GrQuad& deviceQuad,
- const GrQuad& localQuad,
- const GrUserStencilSettings* stencil = nullptr);
+ static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
+ GrPaint&& paint,
+ GrAAType aaType,
+ GrQuadAAFlags aaFlags,
+ const GrQuad& deviceQuad,
+ const GrQuad& localQuad,
+ const GrUserStencilSettings* stencil = nullptr);
-// Utility function to create a non-AA rect transformed by view. This is used commonly enough in
-// testing and GMs that manage ops without going through GrRTC that it's worth the convenience.
-std::unique_ptr<GrDrawOp> MakeNonAARect(GrRecordingContext* context,
- GrPaint&& paint,
- const SkMatrix& view,
- const SkRect& rect,
- const GrUserStencilSettings* stencil = nullptr);
+ // Utility function to create a non-AA rect transformed by view. This is used commonly enough
+ // in testing and GMs that manage ops without going through GrRTC that it's worth the
+ // convenience.
+ static std::unique_ptr<GrDrawOp> MakeNonAARect(GrRecordingContext* context,
+ GrPaint&& paint,
+ const SkMatrix& view,
+ const SkRect& rect,
+ const GrUserStencilSettings* stencil = nullptr);
-// Bulk API for drawing quads with a single op
-// TODO(michaelludwig) - remove if the bulk API is not useful for SkiaRenderer
-std::unique_ptr<GrDrawOp> MakeSet(GrRecordingContext* context,
- GrPaint&& paint,
- GrAAType aaType,
- const SkMatrix& viewMatrix,
- const GrRenderTargetContext::QuadSetEntry quads[],
- int quadCount,
- const GrUserStencilSettings* stencil = nullptr);
+ // Bulk API for drawing quads with a single op
+ // TODO(michaelludwig) - remove if the bulk API is not useful for SkiaRenderer
+ static void AddFillRectOps(GrRenderTargetContext*,
+ const GrClip& clip,
+ GrRecordingContext*,
+ GrPaint&&,
+ GrAAType,
+ const SkMatrix& viewMatrix,
+ const GrRenderTargetContext::QuadSetEntry quads[],
+ int quadCount,
+ const GrUserStencilSettings* = nullptr);
-} // namespace GrFillRectOp
+#if GR_TEST_UTILS
+ static uint32_t ClassID();
+#endif
+
+private:
+ // Create a GrFillRectOp that uses as many quads as possible from 'quads' w/o exceeding
+ // any index buffer size limits.
+ static std::unique_ptr<GrDrawOp> MakeOp(GrRecordingContext*,
+ GrPaint&&,
+ GrAAType,
+ const SkMatrix& viewMatrix,
+ const GrRenderTargetContext::QuadSetEntry quads[],
+ int quadCount,
+ const GrUserStencilSettings*,
+ int* numConsumed);
+};
#endif // GrFillRectOp_DEFINED
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.cpp b/src/gpu/ops/GrQuadPerEdgeAA.cpp
index 86fe00f..687d3a5 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.cpp
+++ b/src/gpu/ops/GrQuadPerEdgeAA.cpp
@@ -166,6 +166,15 @@
}
}
+int QuadLimit(IndexBufferOption option) {
+ switch (option) {
+ case IndexBufferOption::kPictureFramed: return GrResourceProvider::MaxNumAAQuads();
+ case IndexBufferOption::kIndexedRects: return GrResourceProvider::MaxNumNonAAQuads();
+ case IndexBufferOption::kTriStrips: return SK_MaxS32; // not limited by an indexBuffer
+ }
+
+ SkUNREACHABLE;
+}
void ConfigureMesh(GrMesh* mesh, const VertexSpec& spec,
int runningQuadCount, int quadsInDraw, int maxVerts,
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.h b/src/gpu/ops/GrQuadPerEdgeAA.h
index ae245ea..1e5675b 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.h
+++ b/src/gpu/ops/GrQuadPerEdgeAA.h
@@ -151,6 +151,9 @@
// It will, correctly, return nullptr if the indexBufferOption is kTriStrips.
sk_sp<const GrBuffer> GetIndexBuffer(GrMeshDrawOp::Target*, IndexBufferOption);
+ // What is the maximum number of quads allowed for the specified indexBuffer option?
+ int QuadLimit(IndexBufferOption);
+
// This method will configure the vertex and index data of the provided 'mesh' to comply
// with the indexing method specified in the vertexSpec. It is up to the calling code
// to allocate and fill in the vertex data and acquire the correct indexBuffer if it is needed.
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
index acf28b4..f184769 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
@@ -119,7 +119,7 @@
GrAAType aaType() const { return static_cast<GrAAType>(fAAType); }
void setAAType(GrAAType aaType) {
- fAAType = static_cast<unsigned>(aaType);
+ fAAType = static_cast<unsigned>(aaType);
}
void executeDrawsAndUploads(const GrOp*, GrOpFlushState*, const SkRect& chainBounds);
diff --git a/tests/BulkFillRectTest.cpp b/tests/BulkFillRectTest.cpp
new file mode 100644
index 0000000..f80a360
--- /dev/null
+++ b/tests/BulkFillRectTest.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "src/gpu/GrClip.h"
+#include "src/gpu/GrContextPriv.h"
+#include "src/gpu/GrRenderTargetContext.h"
+#include "src/gpu/ops/GrFillRectOp.h"
+#include "tests/Test.h"
+
+static std::unique_ptr<GrRenderTargetContext> new_RTC(GrContext* context) {
+ return context->priv().makeDeferredRenderTargetContext(SkBackingFit::kExact, 128, 128,
+ GrColorType::kRGBA_8888, nullptr);
+}
+
+typedef GrQuadAAFlags (*PerQuadAAFunc)(int i);
+
+static void bulk_fill_rect_create_test(skiatest::Reporter* reporter, GrContext* context,
+ PerQuadAAFunc perQuadAA, GrAAType overallAA,
+ int requestedTotNumQuads, int expectedNumOps) {
+
+ std::unique_ptr<GrRenderTargetContext> rtc = new_RTC(context);
+
+ auto quads = new GrRenderTargetContext::QuadSetEntry[requestedTotNumQuads];
+
+ for (int i = 0; i < requestedTotNumQuads; ++i) {
+ quads[i].fRect = SkRect::MakeWH(100.5f, 100.5f); // prevent the int non-AA optimization
+ quads[i].fColor = SK_PMColor4fWHITE;
+ quads[i].fLocalMatrix = SkMatrix::I();
+ quads[i].fAAFlags = perQuadAA(i);
+ }
+
+ GrPaint paint;
+
+ GrFillRectOp::AddFillRectOps(rtc.get(), GrNoClip(), context, std::move(paint), overallAA,
+ SkMatrix::I(), quads, requestedTotNumQuads);
+
+ GrOpsTask* opsTask = rtc->testingOnly_PeekLastOpsTask();
+ int actualNumOps = opsTask->numOpChains();
+
+ int actualTotNumQuads = 0;
+
+ for (int i = 0; i < actualNumOps; ++i) {
+ const GrOp* tmp = opsTask->getChain(i);
+ REPORTER_ASSERT(reporter, tmp->classID() == GrFillRectOp::ClassID());
+ REPORTER_ASSERT(reporter, tmp->isChainTail());
+ actualTotNumQuads += ((GrDrawOp*) tmp)->numQuads();
+ }
+
+ REPORTER_ASSERT(reporter, expectedNumOps == actualNumOps);
+ REPORTER_ASSERT(reporter, requestedTotNumQuads == actualTotNumQuads);
+
+ context->flush();
+
+ delete[] quads;
+}
+
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(BulkFillRectTest, reporter, ctxInfo) {
+ GrContext* context = ctxInfo.grContext();
+
+ if (!context->priv().caps()->dynamicStateArrayGeometryProcessorTextureSupport()) {
+ return;
+ }
+
+ // This is the simple case where there is no AA at all. We expect 2 non-AA clumps of quads.
+ {
+ auto noAA = [](int i) -> GrQuadAAFlags {
+ return GrQuadAAFlags::kNone;
+ };
+
+ static const int kNumExpectedOps = 2;
+
+ bulk_fill_rect_create_test(reporter, context, noAA, GrAAType::kNone,
+ 2*GrResourceProvider::MaxNumNonAAQuads(), kNumExpectedOps);
+ }
+
+ // This is the same as the above case except the overall AA is kCoverage. However, since
+ // the per-quad AA is still none, all the quads should be downgraded to non-AA.
+ {
+ auto noAA = [](int i) -> GrQuadAAFlags {
+ return GrQuadAAFlags::kNone;
+ };
+
+ static const int kNumExpectedOps = 2;
+
+ bulk_fill_rect_create_test(reporter, context, noAA, GrAAType::kCoverage,
+ 2*GrResourceProvider::MaxNumNonAAQuads(), kNumExpectedOps);
+ }
+
+ // This case has an overall AA of kCoverage but the per-quad AA alternates.
+ // We should end up with several aa-sized clumps
+ {
+ auto alternateAA = [](int i) -> GrQuadAAFlags {
+ return (i % 2) ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
+ };
+
+ int numExpectedOps = 2*GrResourceProvider::MaxNumNonAAQuads() /
+ GrResourceProvider::MaxNumAAQuads();
+
+ bulk_fill_rect_create_test(reporter, context, alternateAA, GrAAType::kCoverage,
+ 2*GrResourceProvider::MaxNumNonAAQuads(), numExpectedOps);
+ }
+
+ // In this case we have a run of MaxNumAAQuads non-AA quads and then AA quads. This
+ // exercises the case where we have a clump of quads that can't be upgraded to AA bc of
+ // its size. We expect one clump of non-AA quads followed by one clump of AA quads.
+ {
+ auto runOfNonAA = [](int i) -> GrQuadAAFlags {
+ return (i < GrResourceProvider::MaxNumAAQuads()) ? GrQuadAAFlags::kNone
+ : GrQuadAAFlags::kAll;
+ };
+
+ static const int kNumExpectedOps = 2;
+
+ bulk_fill_rect_create_test(reporter, context, runOfNonAA, GrAAType::kCoverage,
+ 2*GrResourceProvider::MaxNumAAQuads(), kNumExpectedOps);
+ }
+}