blob: eda7d0f4289297902dd330c7ae18ede445d9fc8a [file] [log] [blame]
Robert Phillips4bc70112018-03-01 10:24:02 -05001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkTypes.h"
Robert Phillips4bc70112018-03-01 10:24:02 -05009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkBitmap.h"
11#include "include/core/SkColor.h"
12#include "include/core/SkColorSpace.h"
13#include "include/core/SkImageInfo.h"
14#include "include/core/SkMatrix.h"
15#include "include/core/SkPaint.h"
16#include "include/core/SkPoint.h"
17#include "include/core/SkRefCnt.h"
18#include "include/gpu/GrContext.h"
19#include "include/private/GrTextureProxy.h"
20#include "include/private/GrTypesPriv.h"
21#include "src/core/SkIPoint16.h"
22#include "src/gpu/GrContextPriv.h"
23#include "src/gpu/GrDeferredUpload.h"
24#include "src/gpu/GrDrawOpAtlas.h"
25#include "src/gpu/GrDrawingManager.h"
26#include "src/gpu/GrMemoryPool.h"
27#include "src/gpu/GrOnFlushResourceProvider.h"
28#include "src/gpu/GrOpFlushState.h"
29#include "src/gpu/GrRenderTargetContext.h"
30#include "src/gpu/GrSurfaceProxyPriv.h"
31#include "src/gpu/GrXferProcessor.h"
32#include "src/gpu/ops/GrDrawOp.h"
33#include "src/gpu/text/GrAtlasManager.h"
34#include "src/gpu/text/GrTextContext.h"
35#include "src/gpu/text/GrTextTarget.h"
36#include "tests/Test.h"
37#include "tools/gpu/GrContextFactory.h"
Ben Wagnerd90cd3b2018-05-22 10:48:08 -040038
39#include <memory>
40
41class GrResourceProvider;
Robert Phillips4bc70112018-03-01 10:24:02 -050042
43static const int kNumPlots = 2;
44static const int kPlotSize = 32;
45static const int kAtlasSize = kNumPlots * kPlotSize;
46
47int GrDrawOpAtlas::numAllocated_TestingOnly() const {
48 int count = 0;
49 for (uint32_t i = 0; i < this->maxPages(); ++i) {
Brian Salomonfd98c2c2018-07-31 17:25:29 -040050 if (fProxies[i]->isInstantiated()) {
Robert Phillips4bc70112018-03-01 10:24:02 -050051 ++count;
52 }
53 }
54
55 return count;
56}
57
Kevin Lubickb5502b22018-03-12 10:17:06 -040058void GrAtlasManager::setMaxPages_TestingOnly(uint32_t maxPages) {
Robert Phillipsd2e9f762018-03-07 11:54:37 -050059 for (int i = 0; i < kMaskFormatCount; i++) {
60 if (fAtlases[i]) {
Kevin Lubickb5502b22018-03-12 10:17:06 -040061 fAtlases[i]->setMaxPages_TestingOnly(maxPages);
Robert Phillipsd2e9f762018-03-07 11:54:37 -050062 }
63 }
64}
65
66void GrDrawOpAtlas::setMaxPages_TestingOnly(uint32_t maxPages) {
67 SkASSERT(!fNumActivePages);
68
69 fMaxPages = maxPages;
70}
71
Robert Phillips4bc70112018-03-01 10:24:02 -050072void EvictionFunc(GrDrawOpAtlas::AtlasID atlasID, void*) {
73 SkASSERT(0); // The unit test shouldn't exercise this code path
74}
75
76static void check(skiatest::Reporter* r, GrDrawOpAtlas* atlas,
77 uint32_t expectedActive, uint32_t expectedMax, int expectedAlloced) {
78 REPORTER_ASSERT(r, expectedActive == atlas->numActivePages());
79 REPORTER_ASSERT(r, expectedMax == atlas->maxPages());
80 REPORTER_ASSERT(r, expectedAlloced == atlas->numAllocated_TestingOnly());
81}
82
83class TestingUploadTarget : public GrDeferredUploadTarget {
84public:
85 TestingUploadTarget() { }
86
Robert Phillipsd2e9f762018-03-07 11:54:37 -050087 const GrTokenTracker* tokenTracker() final { return &fTokenTracker; }
88 GrTokenTracker* writeableTokenTracker() { return &fTokenTracker; }
Robert Phillips4bc70112018-03-01 10:24:02 -050089
90 GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&&) final {
91 SkASSERT(0); // this test shouldn't invoke this code path
92 return fTokenTracker.nextDrawToken();
93 }
94
95 virtual GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&& upload) final {
96 return fTokenTracker.nextTokenToFlush();
97 }
98
99 void issueDrawToken() { fTokenTracker.issueDrawToken(); }
100 void flushToken() { fTokenTracker.flushToken(); }
101
102private:
103 GrTokenTracker fTokenTracker;
104
105 typedef GrDeferredUploadTarget INHERITED;
106};
107
108static bool fill_plot(GrDrawOpAtlas* atlas,
109 GrResourceProvider* resourceProvider,
110 GrDeferredUploadTarget* target,
111 GrDrawOpAtlas::AtlasID* atlasID,
112 int alpha) {
113 SkImageInfo ii = SkImageInfo::MakeA8(kPlotSize, kPlotSize);
114
115 SkBitmap data;
116 data.allocPixels(ii);
117 data.eraseARGB(alpha, 0, 0, 0);
118
119 SkIPoint16 loc;
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500120 GrDrawOpAtlas::ErrorCode code;
121 code = atlas->addToAtlas(resourceProvider, atlasID, target, kPlotSize, kPlotSize,
122 data.getAddr(0, 0), &loc);
123 return GrDrawOpAtlas::ErrorCode::kSucceeded == code;
Robert Phillips4bc70112018-03-01 10:24:02 -0500124}
125
126
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500127// This is a basic DrawOpAtlas test. It simply verifies that multitexture atlases correctly
128// add and remove pages. Note that this is simulating flush-time behavior.
129DEF_GPUTEST_FOR_RENDERING_CONTEXTS(BasicDrawOpAtlas, reporter, ctxInfo) {
Robert Phillips4bc70112018-03-01 10:24:02 -0500130 auto context = ctxInfo.grContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500131 auto proxyProvider = context->priv().proxyProvider();
132 auto resourceProvider = context->priv().resourceProvider();
133 auto drawingManager = context->priv().drawingManager();
Robert Phillips4bc70112018-03-01 10:24:02 -0500134
135 GrOnFlushResourceProvider onFlushResourceProvider(drawingManager);
136 TestingUploadTarget uploadTarget;
137
Greg Daniel4065d452018-11-16 15:43:41 -0500138 GrBackendFormat format =
Robert Phillips9da87e02019-02-04 13:26:26 -0500139 context->priv().caps()->getBackendFormatFromColorType(kAlpha_8_SkColorType);
Greg Daniel4065d452018-11-16 15:43:41 -0500140
Robert Phillips4bc70112018-03-01 10:24:02 -0500141 std::unique_ptr<GrDrawOpAtlas> atlas = GrDrawOpAtlas::Make(
142 proxyProvider,
Greg Daniel4065d452018-11-16 15:43:41 -0500143 format,
Robert Phillips4bc70112018-03-01 10:24:02 -0500144 kAlpha_8_GrPixelConfig,
145 kAtlasSize, kAtlasSize,
Jim Van Verthf6206f92018-12-14 08:22:24 -0500146 kAtlasSize/kNumPlots, kAtlasSize/kNumPlots,
Robert Phillips4bc70112018-03-01 10:24:02 -0500147 GrDrawOpAtlas::AllowMultitexturing::kYes,
148 EvictionFunc, nullptr);
149 check(reporter, atlas.get(), 0, 4, 0);
150
151 // Fill up the first level
152 GrDrawOpAtlas::AtlasID atlasIDs[kNumPlots * kNumPlots];
153 for (int i = 0; i < kNumPlots * kNumPlots; ++i) {
154 bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasIDs[i], i*32);
155 REPORTER_ASSERT(reporter, result);
156 check(reporter, atlas.get(), 1, 4, 1);
157 }
158
159 atlas->instantiate(&onFlushResourceProvider);
160 check(reporter, atlas.get(), 1, 4, 1);
161
162 // Force allocation of a second level
163 GrDrawOpAtlas::AtlasID atlasID;
164 bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasID, 4*32);
165 REPORTER_ASSERT(reporter, result);
166 check(reporter, atlas.get(), 2, 4, 2);
167
168 // Simulate a lot of draws using only the first plot. The last texture should be compacted.
169 for (int i = 0; i < 512; ++i) {
170 atlas->setLastUseToken(atlasIDs[0], uploadTarget.tokenTracker()->nextDrawToken());
171 uploadTarget.issueDrawToken();
172 uploadTarget.flushToken();
173 atlas->compact(uploadTarget.tokenTracker()->nextTokenToFlush());
174 }
175
176 check(reporter, atlas.get(), 1, 4, 1);
177}
178
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500179// This test verifies that the GrAtlasTextOp::onPrepare method correctly handles a failure
180// when allocating an atlas page.
181DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrAtlasTextOpPreparation, reporter, ctxInfo) {
182
183 auto context = ctxInfo.grContext();
184
Robert Phillips9da87e02019-02-04 13:26:26 -0500185 auto gpu = context->priv().getGpu();
186 auto resourceProvider = context->priv().resourceProvider();
Brian Salomon2c791fc2019-04-02 11:52:03 -0400187 auto resourceCache = context->priv().getResourceCache();
Robert Phillips9da87e02019-02-04 13:26:26 -0500188 auto drawingManager = context->priv().drawingManager();
Herb Derby26cbe512018-05-24 14:39:01 -0400189 auto textContext = drawingManager->getTextContext();
Robert Phillips9da87e02019-02-04 13:26:26 -0500190 auto opMemoryPool = context->priv().opMemoryPool();
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500191
Greg Daniel4065d452018-11-16 15:43:41 -0500192 GrBackendFormat format =
Robert Phillips9da87e02019-02-04 13:26:26 -0500193 context->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
Greg Daniel4065d452018-11-16 15:43:41 -0500194
Robert Phillips9da87e02019-02-04 13:26:26 -0500195 auto rtc = context->priv().makeDeferredRenderTargetContext(format,
196 SkBackingFit::kApprox,
197 32, 32,
198 kRGBA_8888_GrPixelConfig,
199 nullptr);
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500200
201 SkPaint paint;
202 paint.setColor(SK_ColorRED);
Mike Reed191e64b2019-01-02 15:35:29 -0500203
204 SkFont font;
205 font.setEdging(SkFont::Edging::kAlias);
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500206
207 const char* text = "a";
208
Herb Derbybc6f9c92018-08-08 13:58:45 -0400209 std::unique_ptr<GrDrawOp> op = textContext->createOp_TestingOnly(
Mike Reed191e64b2019-01-02 15:35:29 -0500210 context, textContext, rtc.get(), paint, font, SkMatrix::I(), text, 16, 16);
Brian Osman5ced0bf2019-03-15 10:15:29 -0400211 op->finalize(*context->priv().caps(), nullptr, GrFSAAType::kNone, GrClampType::kAuto);
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500212
213 TestingUploadTarget uploadTarget;
214
Brian Salomon2c791fc2019-04-02 11:52:03 -0400215 GrOpFlushState flushState(gpu, resourceProvider, resourceCache,
216 uploadTarget.writeableTokenTracker());
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500217 GrOpFlushState::OpArgs opArgs = {
218 op.get(),
219 rtc->asRenderTargetProxy(),
220 nullptr,
221 GrXferProcessor::DstProxy(nullptr, SkIPoint::Make(0, 0))
222 };
223
224 // Cripple the atlas manager so it can't allocate any pages. This will force a failure
225 // in the preparation of the text op
Robert Phillips9da87e02019-02-04 13:26:26 -0500226 auto atlasManager = context->priv().getAtlasManager();
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500227 unsigned int numProxies;
228 atlasManager->getProxies(kA8_GrMaskFormat, &numProxies);
229 atlasManager->setMaxPages_TestingOnly(0);
230
231 flushState.setOpArgs(&opArgs);
232 op->prepare(&flushState);
233 flushState.setOpArgs(nullptr);
Robert Phillipsc994a932018-06-19 13:09:54 -0400234 opMemoryPool->release(std::move(op));
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500235}
Herb Derby15d9ef22018-10-18 13:41:32 -0400236
Jim Van Verthf6206f92018-12-14 08:22:24 -0500237void test_atlas_config(skiatest::Reporter* reporter, int maxTextureSize, size_t maxBytes,
238 GrMaskFormat maskFormat, SkISize expectedDimensions,
239 SkISize expectedPlotDimensions) {
240 GrDrawOpAtlasConfig config(maxTextureSize, maxBytes);
241 REPORTER_ASSERT(reporter, config.atlasDimensions(maskFormat) == expectedDimensions);
242 REPORTER_ASSERT(reporter, config.plotDimensions(maskFormat) == expectedPlotDimensions);
243}
244
Herb Derby15d9ef22018-10-18 13:41:32 -0400245DEF_GPUTEST(GrDrawOpAtlasConfig_Basic, reporter, options) {
Jim Van Verthf6206f92018-12-14 08:22:24 -0500246 // 1/4 MB
247 test_atlas_config(reporter, 65536, 256 * 1024, kARGB_GrMaskFormat,
248 { 256, 256 }, { 256, 256 });
249 test_atlas_config(reporter, 65536, 256 * 1024, kA8_GrMaskFormat,
250 { 512, 512 }, { 256, 256 });
251 // 1/2 MB
252 test_atlas_config(reporter, 65536, 512 * 1024, kARGB_GrMaskFormat,
253 { 512, 256 }, { 256, 256 });
254 test_atlas_config(reporter, 65536, 512 * 1024, kA8_GrMaskFormat,
255 { 1024, 512 }, { 256, 256 });
256 // 1 MB
257 test_atlas_config(reporter, 65536, 1024 * 1024, kARGB_GrMaskFormat,
258 { 512, 512 }, { 256, 256 });
259 test_atlas_config(reporter, 65536, 1024 * 1024, kA8_GrMaskFormat,
260 { 1024, 1024 }, { 256, 256 });
261 // 2 MB
262 test_atlas_config(reporter, 65536, 2 * 1024 * 1024, kARGB_GrMaskFormat,
263 { 1024, 512 }, { 256, 256 });
264 test_atlas_config(reporter, 65536, 2 * 1024 * 1024, kA8_GrMaskFormat,
265 { 2048, 1024 }, { 512, 256 });
266 // 4 MB
267 test_atlas_config(reporter, 65536, 4 * 1024 * 1024, kARGB_GrMaskFormat,
268 { 1024, 1024 }, { 256, 256 });
269 test_atlas_config(reporter, 65536, 4 * 1024 * 1024, kA8_GrMaskFormat,
Jim Van Verth578b0892018-12-20 20:48:55 +0000270 { 2048, 2048 }, { 512, 512 });
Jim Van Verthf6206f92018-12-14 08:22:24 -0500271 // 8 MB
272 test_atlas_config(reporter, 65536, 8 * 1024 * 1024, kARGB_GrMaskFormat,
273 { 2048, 1024 }, { 256, 256 });
274 test_atlas_config(reporter, 65536, 8 * 1024 * 1024, kA8_GrMaskFormat,
Jim Van Verth578b0892018-12-20 20:48:55 +0000275 { 2048, 2048 }, { 512, 512 });
Jim Van Verthf6206f92018-12-14 08:22:24 -0500276 // 16 MB (should be same as 8 MB)
277 test_atlas_config(reporter, 65536, 16 * 1024 * 1024, kARGB_GrMaskFormat,
278 { 2048, 1024 }, { 256, 256 });
279 test_atlas_config(reporter, 65536, 16 * 1024 * 1024, kA8_GrMaskFormat,
Jim Van Verth578b0892018-12-20 20:48:55 +0000280 { 2048, 2048 }, { 512, 512 });
Jim Van Verthf6206f92018-12-14 08:22:24 -0500281
282 // 4MB, restricted texture size
283 test_atlas_config(reporter, 1024, 8 * 1024 * 1024, kARGB_GrMaskFormat,
284 { 1024, 1024 }, { 256, 256 });
285 test_atlas_config(reporter, 1024, 8 * 1024 * 1024, kA8_GrMaskFormat,
286 { 1024, 1024 }, { 256, 256 });
287
288 // 3 MB (should be same as 2 MB)
289 test_atlas_config(reporter, 65536, 3 * 1024 * 1024, kARGB_GrMaskFormat,
290 { 1024, 512 }, { 256, 256 });
291 test_atlas_config(reporter, 65536, 3 * 1024 * 1024, kA8_GrMaskFormat,
292 { 2048, 1024 }, { 512, 256 });
293
294 // minimum size
295 test_atlas_config(reporter, 65536, 0, kARGB_GrMaskFormat,
296 { 256, 256 }, { 256, 256 });
297 test_atlas_config(reporter, 65536, 0, kA8_GrMaskFormat,
298 { 512, 512 }, { 256, 256 });
Brian Salomon58f153c2018-10-18 21:51:15 -0400299}