blob: f7d6900b85cb6ca41b468d15287b22d0cda03f6c [file] [log] [blame]
Robert Phillipse837e612019-11-15 11:02:50 -05001/*
2 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Robert Phillips6d344c32020-07-06 10:56:46 -04007
8#include "include/gpu/GrDirectContext.h"
Michael Ludwigfe13ca32019-11-21 10:26:41 -05009#include "src/core/SkBlendModePriv.h"
Robert Phillipse837e612019-11-15 11:02:50 -050010#include "src/gpu/GrContextPriv.h"
Robert Phillipse19babf2020-04-06 13:57:30 -040011#include "src/gpu/GrProxyProvider.h"
Robert Phillipse837e612019-11-15 11:02:50 -050012#include "src/gpu/GrRenderTargetContext.h"
13#include "src/gpu/ops/GrFillRectOp.h"
14#include "src/gpu/ops/GrTextureOp.h"
15#include "tests/Test.h"
16
17static std::unique_ptr<GrRenderTargetContext> new_RTC(GrContext* context) {
Greg Daniele20fcad2020-01-08 11:52:34 -050018 return GrRenderTargetContext::Make(
19 context, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kExact, {128, 128});
Robert Phillipse837e612019-11-15 11:02:50 -050020}
21
Robert Phillipse837e612019-11-15 11:02:50 -050022sk_sp<GrSurfaceProxy> create_proxy(GrContext* context) {
Brian Salomona56a7462020-02-07 14:17:25 -050023 static constexpr SkISize kDimensions = {128, 128};
Robert Phillipse837e612019-11-15 11:02:50 -050024
25 const GrBackendFormat format = context->priv().caps()->getDefaultBackendFormat(
26 GrColorType::kRGBA_8888,
27 GrRenderable::kYes);
Robert Phillipse837e612019-11-15 11:02:50 -050028 return context->priv().proxyProvider()->createProxy(
Brian Salomondf1bd6d2020-03-26 20:37:01 -040029 format, kDimensions, GrRenderable::kYes, 1, GrMipMapped::kNo, SkBackingFit::kExact,
30 SkBudgeted::kNo, GrProtected::kNo, GrInternalSurfaceFlags::kNone);
Robert Phillipse837e612019-11-15 11:02:50 -050031}
Robert Phillipse837e612019-11-15 11:02:50 -050032
33typedef GrQuadAAFlags (*PerQuadAAFunc)(int i);
34
35typedef void (*BulkRectTest)(skiatest::Reporter* reporter, GrContext* context,
Michael Ludwigfe13ca32019-11-21 10:26:41 -050036 PerQuadAAFunc perQuadAA, GrAAType overallAA, SkBlendMode blendMode,
Robert Phillipse837e612019-11-15 11:02:50 -050037 int requestedTotNumQuads, int expectedNumOps);
38
39//-------------------------------------------------------------------------------------------------
40static void bulk_fill_rect_create_test(skiatest::Reporter* reporter, GrContext* context,
41 PerQuadAAFunc perQuadAA, GrAAType overallAA,
Michael Ludwigfe13ca32019-11-21 10:26:41 -050042 SkBlendMode blendMode,
Robert Phillipse837e612019-11-15 11:02:50 -050043 int requestedTotNumQuads, int expectedNumOps) {
44
45 std::unique_ptr<GrRenderTargetContext> rtc = new_RTC(context);
46
47 auto quads = new GrRenderTargetContext::QuadSetEntry[requestedTotNumQuads];
48
49 for (int i = 0; i < requestedTotNumQuads; ++i) {
50 quads[i].fRect = SkRect::MakeWH(100.5f, 100.5f); // prevent the int non-AA optimization
51 quads[i].fColor = SK_PMColor4fWHITE;
52 quads[i].fLocalMatrix = SkMatrix::I();
53 quads[i].fAAFlags = perQuadAA(i);
54 }
55
56 GrPaint paint;
Michael Ludwigfe13ca32019-11-21 10:26:41 -050057 paint.setXPFactory(SkBlendMode_AsXPFactory(blendMode));
Michael Ludwig7c12e282020-05-29 09:54:07 -040058 GrFillRectOp::AddFillRectOps(rtc.get(), nullptr, context, std::move(paint), overallAA,
Robert Phillipse837e612019-11-15 11:02:50 -050059 SkMatrix::I(), quads, requestedTotNumQuads);
60
61 GrOpsTask* opsTask = rtc->testingOnly_PeekLastOpsTask();
62 int actualNumOps = opsTask->numOpChains();
63
64 int actualTotNumQuads = 0;
65
66 for (int i = 0; i < actualNumOps; ++i) {
67 const GrOp* tmp = opsTask->getChain(i);
68 REPORTER_ASSERT(reporter, tmp->classID() == GrFillRectOp::ClassID());
69 REPORTER_ASSERT(reporter, tmp->isChainTail());
70 actualTotNumQuads += ((GrDrawOp*) tmp)->numQuads();
71 }
72
73 REPORTER_ASSERT(reporter, expectedNumOps == actualNumOps);
74 REPORTER_ASSERT(reporter, requestedTotNumQuads == actualTotNumQuads);
75
Greg Daniel0a2464f2020-05-14 15:45:44 -040076 context->flushAndSubmit();
Robert Phillipse837e612019-11-15 11:02:50 -050077
78 delete[] quads;
79}
80
Robert Phillipse837e612019-11-15 11:02:50 -050081//-------------------------------------------------------------------------------------------------
82static void bulk_texture_rect_create_test(skiatest::Reporter* reporter, GrContext* context,
83 PerQuadAAFunc perQuadAA, GrAAType overallAA,
Michael Ludwigfe13ca32019-11-21 10:26:41 -050084 SkBlendMode blendMode,
Robert Phillipse837e612019-11-15 11:02:50 -050085 int requestedTotNumQuads, int expectedNumOps) {
86
87 std::unique_ptr<GrRenderTargetContext> rtc = new_RTC(context);
88
Michael Ludwigfe13ca32019-11-21 10:26:41 -050089 sk_sp<GrSurfaceProxy> proxyA = create_proxy(context);
90 sk_sp<GrSurfaceProxy> proxyB = create_proxy(context);
91 GrSurfaceProxyView proxyViewA(std::move(proxyA), kTopLeft_GrSurfaceOrigin, GrSwizzle::RGBA());
92 GrSurfaceProxyView proxyViewB(std::move(proxyB), kTopLeft_GrSurfaceOrigin, GrSwizzle::RGBA());
Robert Phillipse837e612019-11-15 11:02:50 -050093
94 auto set = new GrRenderTargetContext::TextureSetEntry[requestedTotNumQuads];
95
96 for (int i = 0; i < requestedTotNumQuads; ++i) {
Michael Ludwigfe13ca32019-11-21 10:26:41 -050097 // Alternate between two proxies to prevent op merging if the batch API was forced to submit
98 // one op at a time (to work, this does require that all fDstRects overlap).
99 set[i].fProxyView = i % 2 == 0 ? proxyViewA : proxyViewB;
Brian Salomonfc118442019-11-22 19:09:27 -0500100 set[i].fSrcAlphaType = kPremul_SkAlphaType;
Robert Phillipse837e612019-11-15 11:02:50 -0500101 set[i].fSrcRect = SkRect::MakeWH(100.0f, 100.0f);
102 set[i].fDstRect = SkRect::MakeWH(100.5f, 100.5f); // prevent the int non-AA optimization
103 set[i].fDstClipQuad = nullptr;
104 set[i].fPreViewMatrix = nullptr;
105 set[i].fAlpha = 1.0f;
106 set[i].fAAFlags = perQuadAA(i);
107 }
108
Michael Ludwig7c12e282020-05-29 09:54:07 -0400109 GrTextureOp::AddTextureSetOps(rtc.get(), nullptr, context, set, requestedTotNumQuads,
Michael Ludwig379e4962019-12-06 13:21:26 -0500110 requestedTotNumQuads, // We alternate so proxyCnt == cnt
111 GrSamplerState::Filter::kNearest,
112 GrTextureOp::Saturate::kYes,
113 blendMode,
114 overallAA,
115 SkCanvas::kStrict_SrcRectConstraint,
116 SkMatrix::I(), nullptr);
Robert Phillipse837e612019-11-15 11:02:50 -0500117
118 GrOpsTask* opsTask = rtc->testingOnly_PeekLastOpsTask();
119 int actualNumOps = opsTask->numOpChains();
120
121 int actualTotNumQuads = 0;
122
Michael Ludwigfe13ca32019-11-21 10:26:41 -0500123 if (blendMode != SkBlendMode::kSrcOver ||
124 !context->priv().caps()->dynamicStateArrayGeometryProcessorTextureSupport()) {
125 // In either of these two cases, GrTextureOp creates one op per quad instead. Since
126 // each entry alternates proxies but overlaps geometrically, this will prevent the ops
127 // from being merged back into fewer ops.
128 expectedNumOps = requestedTotNumQuads;
129 }
130 uint32_t expectedOpID = blendMode == SkBlendMode::kSrcOver ? GrTextureOp::ClassID()
131 : GrFillRectOp::ClassID();
Robert Phillipse837e612019-11-15 11:02:50 -0500132 for (int i = 0; i < actualNumOps; ++i) {
133 const GrOp* tmp = opsTask->getChain(i);
Michael Ludwigfe13ca32019-11-21 10:26:41 -0500134 REPORTER_ASSERT(reporter, tmp->classID() == expectedOpID);
Robert Phillipse837e612019-11-15 11:02:50 -0500135 REPORTER_ASSERT(reporter, tmp->isChainTail());
136 actualTotNumQuads += ((GrDrawOp*) tmp)->numQuads();
137 }
138
139 REPORTER_ASSERT(reporter, expectedNumOps == actualNumOps);
140 REPORTER_ASSERT(reporter, requestedTotNumQuads == actualTotNumQuads);
141
Greg Daniel0a2464f2020-05-14 15:45:44 -0400142 context->flushAndSubmit();
Robert Phillipse837e612019-11-15 11:02:50 -0500143
144 delete[] set;
145}
Robert Phillipse837e612019-11-15 11:02:50 -0500146
147//-------------------------------------------------------------------------------------------------
148static void run_test(GrContext* context, skiatest::Reporter* reporter, BulkRectTest test) {
Robert Phillipse837e612019-11-15 11:02:50 -0500149 // This is the simple case where there is no AA at all. We expect 2 non-AA clumps of quads.
150 {
151 auto noAA = [](int i) -> GrQuadAAFlags {
152 return GrQuadAAFlags::kNone;
153 };
154
155 static const int kNumExpectedOps = 2;
156
Michael Ludwigfe13ca32019-11-21 10:26:41 -0500157 test(reporter, context, noAA, GrAAType::kNone, SkBlendMode::kSrcOver,
Robert Phillipse837e612019-11-15 11:02:50 -0500158 2*GrResourceProvider::MaxNumNonAAQuads(), kNumExpectedOps);
159 }
160
161 // This is the same as the above case except the overall AA is kCoverage. However, since
162 // the per-quad AA is still none, all the quads should be downgraded to non-AA.
163 {
164 auto noAA = [](int i) -> GrQuadAAFlags {
165 return GrQuadAAFlags::kNone;
166 };
167
168 static const int kNumExpectedOps = 2;
169
Michael Ludwigfe13ca32019-11-21 10:26:41 -0500170 test(reporter, context, noAA, GrAAType::kCoverage, SkBlendMode::kSrcOver,
Robert Phillipse837e612019-11-15 11:02:50 -0500171 2*GrResourceProvider::MaxNumNonAAQuads(), kNumExpectedOps);
172 }
173
174 // This case has an overall AA of kCoverage but the per-quad AA alternates.
175 // We should end up with several aa-sized clumps
176 {
177 auto alternateAA = [](int i) -> GrQuadAAFlags {
178 return (i % 2) ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
179 };
180
181 int numExpectedOps = 2*GrResourceProvider::MaxNumNonAAQuads() /
182 GrResourceProvider::MaxNumAAQuads();
183
Michael Ludwigfe13ca32019-11-21 10:26:41 -0500184 test(reporter, context, alternateAA, GrAAType::kCoverage, SkBlendMode::kSrcOver,
Robert Phillipse837e612019-11-15 11:02:50 -0500185 2*GrResourceProvider::MaxNumNonAAQuads(), numExpectedOps);
186 }
187
188 // In this case we have a run of MaxNumAAQuads non-AA quads and then AA quads. This
189 // exercises the case where we have a clump of quads that can't be upgraded to AA bc of
190 // its size. We expect one clump of non-AA quads followed by one clump of AA quads.
191 {
192 auto runOfNonAA = [](int i) -> GrQuadAAFlags {
193 return (i < GrResourceProvider::MaxNumAAQuads()) ? GrQuadAAFlags::kNone
194 : GrQuadAAFlags::kAll;
195 };
196
197 static const int kNumExpectedOps = 2;
198
Michael Ludwigfe13ca32019-11-21 10:26:41 -0500199 test(reporter, context, runOfNonAA, GrAAType::kCoverage, SkBlendMode::kSrcOver,
200 2*GrResourceProvider::MaxNumAAQuads(), kNumExpectedOps);
201 }
202
203 // In this case we use a blend mode other than src-over, which hits the GrFillRectOp fallback
204 // code path for GrTextureOp. We pass in the expected results if batching was successful, to
205 // that bulk_fill_rect_create_test batches on all modes; bulk_texture_rect_create_test is
206 // responsible for revising its expectations.
207 {
208 auto fixedAA = [](int i) -> GrQuadAAFlags {
209 return GrQuadAAFlags::kAll;
210 };
211
212 static const int kNumExpectedOps = 2;
213
214 test(reporter, context, fixedAA, GrAAType::kCoverage, SkBlendMode::kSrcATop,
Robert Phillipse837e612019-11-15 11:02:50 -0500215 2*GrResourceProvider::MaxNumAAQuads(), kNumExpectedOps);
216 }
217}
218
219DEF_GPUTEST_FOR_RENDERING_CONTEXTS(BulkFillRectTest, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400220 run_test(ctxInfo.directContext(), reporter, bulk_fill_rect_create_test);
Robert Phillipse837e612019-11-15 11:02:50 -0500221}
222
Robert Phillipse837e612019-11-15 11:02:50 -0500223DEF_GPUTEST_FOR_RENDERING_CONTEXTS(BulkTextureRectTest, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400224 run_test(ctxInfo.directContext(), reporter, bulk_texture_rect_create_test);
Robert Phillipse837e612019-11-15 11:02:50 -0500225}