blob: a3c0a85b648f47cb7ac9f7ae9420b5872ffcb02d [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 */
Michael Ludwigfe13ca32019-11-21 10:26:41 -05007#include "src/core/SkBlendModePriv.h"
Robert Phillipse837e612019-11-15 11:02:50 -05008#include "src/gpu/GrClip.h"
9#include "src/gpu/GrContextPriv.h"
10#include "src/gpu/GrRenderTargetContext.h"
11#include "src/gpu/ops/GrFillRectOp.h"
12#include "src/gpu/ops/GrTextureOp.h"
13#include "tests/Test.h"
14
15static std::unique_ptr<GrRenderTargetContext> new_RTC(GrContext* context) {
Greg Daniele20fcad2020-01-08 11:52:34 -050016 return GrRenderTargetContext::Make(
17 context, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kExact, {128, 128});
Robert Phillipse837e612019-11-15 11:02:50 -050018}
19
Robert Phillipse837e612019-11-15 11:02:50 -050020sk_sp<GrSurfaceProxy> create_proxy(GrContext* context) {
Brian Salomona56a7462020-02-07 14:17:25 -050021 static constexpr SkISize kDimensions = {128, 128};
Robert Phillipse837e612019-11-15 11:02:50 -050022
23 const GrBackendFormat format = context->priv().caps()->getDefaultBackendFormat(
24 GrColorType::kRGBA_8888,
25 GrRenderable::kYes);
Robert Phillipse837e612019-11-15 11:02:50 -050026 return context->priv().proxyProvider()->createProxy(
Brian Salomondf1bd6d2020-03-26 20:37:01 -040027 format, kDimensions, GrRenderable::kYes, 1, GrMipMapped::kNo, SkBackingFit::kExact,
28 SkBudgeted::kNo, GrProtected::kNo, GrInternalSurfaceFlags::kNone);
Robert Phillipse837e612019-11-15 11:02:50 -050029}
Robert Phillipse837e612019-11-15 11:02:50 -050030
31typedef GrQuadAAFlags (*PerQuadAAFunc)(int i);
32
33typedef void (*BulkRectTest)(skiatest::Reporter* reporter, GrContext* context,
Michael Ludwigfe13ca32019-11-21 10:26:41 -050034 PerQuadAAFunc perQuadAA, GrAAType overallAA, SkBlendMode blendMode,
Robert Phillipse837e612019-11-15 11:02:50 -050035 int requestedTotNumQuads, int expectedNumOps);
36
37//-------------------------------------------------------------------------------------------------
38static void bulk_fill_rect_create_test(skiatest::Reporter* reporter, GrContext* context,
39 PerQuadAAFunc perQuadAA, GrAAType overallAA,
Michael Ludwigfe13ca32019-11-21 10:26:41 -050040 SkBlendMode blendMode,
Robert Phillipse837e612019-11-15 11:02:50 -050041 int requestedTotNumQuads, int expectedNumOps) {
42
43 std::unique_ptr<GrRenderTargetContext> rtc = new_RTC(context);
44
45 auto quads = new GrRenderTargetContext::QuadSetEntry[requestedTotNumQuads];
46
47 for (int i = 0; i < requestedTotNumQuads; ++i) {
48 quads[i].fRect = SkRect::MakeWH(100.5f, 100.5f); // prevent the int non-AA optimization
49 quads[i].fColor = SK_PMColor4fWHITE;
50 quads[i].fLocalMatrix = SkMatrix::I();
51 quads[i].fAAFlags = perQuadAA(i);
52 }
53
54 GrPaint paint;
Michael Ludwigfe13ca32019-11-21 10:26:41 -050055 paint.setXPFactory(SkBlendMode_AsXPFactory(blendMode));
Robert Phillipse837e612019-11-15 11:02:50 -050056 GrFillRectOp::AddFillRectOps(rtc.get(), GrNoClip(), context, std::move(paint), overallAA,
57 SkMatrix::I(), quads, requestedTotNumQuads);
58
59 GrOpsTask* opsTask = rtc->testingOnly_PeekLastOpsTask();
60 int actualNumOps = opsTask->numOpChains();
61
62 int actualTotNumQuads = 0;
63
64 for (int i = 0; i < actualNumOps; ++i) {
65 const GrOp* tmp = opsTask->getChain(i);
66 REPORTER_ASSERT(reporter, tmp->classID() == GrFillRectOp::ClassID());
67 REPORTER_ASSERT(reporter, tmp->isChainTail());
68 actualTotNumQuads += ((GrDrawOp*) tmp)->numQuads();
69 }
70
71 REPORTER_ASSERT(reporter, expectedNumOps == actualNumOps);
72 REPORTER_ASSERT(reporter, requestedTotNumQuads == actualTotNumQuads);
73
74 context->flush();
75
76 delete[] quads;
77}
78
Robert Phillipse837e612019-11-15 11:02:50 -050079//-------------------------------------------------------------------------------------------------
80static void bulk_texture_rect_create_test(skiatest::Reporter* reporter, GrContext* context,
81 PerQuadAAFunc perQuadAA, GrAAType overallAA,
Michael Ludwigfe13ca32019-11-21 10:26:41 -050082 SkBlendMode blendMode,
Robert Phillipse837e612019-11-15 11:02:50 -050083 int requestedTotNumQuads, int expectedNumOps) {
84
85 std::unique_ptr<GrRenderTargetContext> rtc = new_RTC(context);
86
Michael Ludwigfe13ca32019-11-21 10:26:41 -050087 sk_sp<GrSurfaceProxy> proxyA = create_proxy(context);
88 sk_sp<GrSurfaceProxy> proxyB = create_proxy(context);
89 GrSurfaceProxyView proxyViewA(std::move(proxyA), kTopLeft_GrSurfaceOrigin, GrSwizzle::RGBA());
90 GrSurfaceProxyView proxyViewB(std::move(proxyB), kTopLeft_GrSurfaceOrigin, GrSwizzle::RGBA());
Robert Phillipse837e612019-11-15 11:02:50 -050091
92 auto set = new GrRenderTargetContext::TextureSetEntry[requestedTotNumQuads];
93
94 for (int i = 0; i < requestedTotNumQuads; ++i) {
Michael Ludwigfe13ca32019-11-21 10:26:41 -050095 // Alternate between two proxies to prevent op merging if the batch API was forced to submit
96 // one op at a time (to work, this does require that all fDstRects overlap).
97 set[i].fProxyView = i % 2 == 0 ? proxyViewA : proxyViewB;
Brian Salomonfc118442019-11-22 19:09:27 -050098 set[i].fSrcAlphaType = kPremul_SkAlphaType;
Robert Phillipse837e612019-11-15 11:02:50 -050099 set[i].fSrcRect = SkRect::MakeWH(100.0f, 100.0f);
100 set[i].fDstRect = SkRect::MakeWH(100.5f, 100.5f); // prevent the int non-AA optimization
101 set[i].fDstClipQuad = nullptr;
102 set[i].fPreViewMatrix = nullptr;
103 set[i].fAlpha = 1.0f;
104 set[i].fAAFlags = perQuadAA(i);
105 }
106
Michael Ludwigfe13ca32019-11-21 10:26:41 -0500107 GrTextureOp::AddTextureSetOps(rtc.get(), GrNoClip(), context, set, requestedTotNumQuads,
Michael Ludwig379e4962019-12-06 13:21:26 -0500108 requestedTotNumQuads, // We alternate so proxyCnt == cnt
109 GrSamplerState::Filter::kNearest,
110 GrTextureOp::Saturate::kYes,
111 blendMode,
112 overallAA,
113 SkCanvas::kStrict_SrcRectConstraint,
114 SkMatrix::I(), nullptr);
Robert Phillipse837e612019-11-15 11:02:50 -0500115
116 GrOpsTask* opsTask = rtc->testingOnly_PeekLastOpsTask();
117 int actualNumOps = opsTask->numOpChains();
118
119 int actualTotNumQuads = 0;
120
Michael Ludwigfe13ca32019-11-21 10:26:41 -0500121 if (blendMode != SkBlendMode::kSrcOver ||
122 !context->priv().caps()->dynamicStateArrayGeometryProcessorTextureSupport()) {
123 // In either of these two cases, GrTextureOp creates one op per quad instead. Since
124 // each entry alternates proxies but overlaps geometrically, this will prevent the ops
125 // from being merged back into fewer ops.
126 expectedNumOps = requestedTotNumQuads;
127 }
128 uint32_t expectedOpID = blendMode == SkBlendMode::kSrcOver ? GrTextureOp::ClassID()
129 : GrFillRectOp::ClassID();
Robert Phillipse837e612019-11-15 11:02:50 -0500130 for (int i = 0; i < actualNumOps; ++i) {
131 const GrOp* tmp = opsTask->getChain(i);
Michael Ludwigfe13ca32019-11-21 10:26:41 -0500132 REPORTER_ASSERT(reporter, tmp->classID() == expectedOpID);
Robert Phillipse837e612019-11-15 11:02:50 -0500133 REPORTER_ASSERT(reporter, tmp->isChainTail());
134 actualTotNumQuads += ((GrDrawOp*) tmp)->numQuads();
135 }
136
137 REPORTER_ASSERT(reporter, expectedNumOps == actualNumOps);
138 REPORTER_ASSERT(reporter, requestedTotNumQuads == actualTotNumQuads);
139
140 context->flush();
141
142 delete[] set;
143}
Robert Phillipse837e612019-11-15 11:02:50 -0500144
145//-------------------------------------------------------------------------------------------------
146static void run_test(GrContext* context, skiatest::Reporter* reporter, BulkRectTest test) {
Robert Phillipse837e612019-11-15 11:02:50 -0500147 // This is the simple case where there is no AA at all. We expect 2 non-AA clumps of quads.
148 {
149 auto noAA = [](int i) -> GrQuadAAFlags {
150 return GrQuadAAFlags::kNone;
151 };
152
153 static const int kNumExpectedOps = 2;
154
Michael Ludwigfe13ca32019-11-21 10:26:41 -0500155 test(reporter, context, noAA, GrAAType::kNone, SkBlendMode::kSrcOver,
Robert Phillipse837e612019-11-15 11:02:50 -0500156 2*GrResourceProvider::MaxNumNonAAQuads(), kNumExpectedOps);
157 }
158
159 // This is the same as the above case except the overall AA is kCoverage. However, since
160 // the per-quad AA is still none, all the quads should be downgraded to non-AA.
161 {
162 auto noAA = [](int i) -> GrQuadAAFlags {
163 return GrQuadAAFlags::kNone;
164 };
165
166 static const int kNumExpectedOps = 2;
167
Michael Ludwigfe13ca32019-11-21 10:26:41 -0500168 test(reporter, context, noAA, GrAAType::kCoverage, SkBlendMode::kSrcOver,
Robert Phillipse837e612019-11-15 11:02:50 -0500169 2*GrResourceProvider::MaxNumNonAAQuads(), kNumExpectedOps);
170 }
171
172 // This case has an overall AA of kCoverage but the per-quad AA alternates.
173 // We should end up with several aa-sized clumps
174 {
175 auto alternateAA = [](int i) -> GrQuadAAFlags {
176 return (i % 2) ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
177 };
178
179 int numExpectedOps = 2*GrResourceProvider::MaxNumNonAAQuads() /
180 GrResourceProvider::MaxNumAAQuads();
181
Michael Ludwigfe13ca32019-11-21 10:26:41 -0500182 test(reporter, context, alternateAA, GrAAType::kCoverage, SkBlendMode::kSrcOver,
Robert Phillipse837e612019-11-15 11:02:50 -0500183 2*GrResourceProvider::MaxNumNonAAQuads(), numExpectedOps);
184 }
185
186 // In this case we have a run of MaxNumAAQuads non-AA quads and then AA quads. This
187 // exercises the case where we have a clump of quads that can't be upgraded to AA bc of
188 // its size. We expect one clump of non-AA quads followed by one clump of AA quads.
189 {
190 auto runOfNonAA = [](int i) -> GrQuadAAFlags {
191 return (i < GrResourceProvider::MaxNumAAQuads()) ? GrQuadAAFlags::kNone
192 : GrQuadAAFlags::kAll;
193 };
194
195 static const int kNumExpectedOps = 2;
196
Michael Ludwigfe13ca32019-11-21 10:26:41 -0500197 test(reporter, context, runOfNonAA, GrAAType::kCoverage, SkBlendMode::kSrcOver,
198 2*GrResourceProvider::MaxNumAAQuads(), kNumExpectedOps);
199 }
200
201 // In this case we use a blend mode other than src-over, which hits the GrFillRectOp fallback
202 // code path for GrTextureOp. We pass in the expected results if batching was successful, to
203 // that bulk_fill_rect_create_test batches on all modes; bulk_texture_rect_create_test is
204 // responsible for revising its expectations.
205 {
206 auto fixedAA = [](int i) -> GrQuadAAFlags {
207 return GrQuadAAFlags::kAll;
208 };
209
210 static const int kNumExpectedOps = 2;
211
212 test(reporter, context, fixedAA, GrAAType::kCoverage, SkBlendMode::kSrcATop,
Robert Phillipse837e612019-11-15 11:02:50 -0500213 2*GrResourceProvider::MaxNumAAQuads(), kNumExpectedOps);
214 }
215}
216
217DEF_GPUTEST_FOR_RENDERING_CONTEXTS(BulkFillRectTest, reporter, ctxInfo) {
218 run_test(ctxInfo.grContext(), reporter, bulk_fill_rect_create_test);
219}
220
Robert Phillipse837e612019-11-15 11:02:50 -0500221DEF_GPUTEST_FOR_RENDERING_CONTEXTS(BulkTextureRectTest, reporter, ctxInfo) {
222 run_test(ctxInfo.grContext(), reporter, bulk_texture_rect_create_test);
223}