blob: ef219d94122f533247f4443c748aa97f4492f1f5 [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
8#include "SkTypes.h"
9
10#if SK_SUPPORT_GPU
11
12#include "GrContextPriv.h"
13#include "Test.h"
Robert Phillipsc4039ea2018-03-01 11:36:45 -050014#include "text/GrGlyphCache.h"
Robert Phillips4bc70112018-03-01 10:24:02 -050015
16static const int kNumPlots = 2;
17static const int kPlotSize = 32;
18static const int kAtlasSize = kNumPlots * kPlotSize;
19
20int GrDrawOpAtlas::numAllocated_TestingOnly() const {
21 int count = 0;
22 for (uint32_t i = 0; i < this->maxPages(); ++i) {
23 if (fProxies[i]->priv().isInstantiated()) {
24 ++count;
25 }
26 }
27
28 return count;
29}
30
Kevin Lubickb5502b22018-03-12 10:17:06 -040031void GrAtlasManager::setMaxPages_TestingOnly(uint32_t maxPages) {
Robert Phillipsd2e9f762018-03-07 11:54:37 -050032 for (int i = 0; i < kMaskFormatCount; i++) {
33 if (fAtlases[i]) {
Kevin Lubickb5502b22018-03-12 10:17:06 -040034 fAtlases[i]->setMaxPages_TestingOnly(maxPages);
Robert Phillipsd2e9f762018-03-07 11:54:37 -050035 }
36 }
37}
38
39void GrDrawOpAtlas::setMaxPages_TestingOnly(uint32_t maxPages) {
40 SkASSERT(!fNumActivePages);
41
42 fMaxPages = maxPages;
43}
44
Robert Phillips4bc70112018-03-01 10:24:02 -050045void EvictionFunc(GrDrawOpAtlas::AtlasID atlasID, void*) {
46 SkASSERT(0); // The unit test shouldn't exercise this code path
47}
48
49static void check(skiatest::Reporter* r, GrDrawOpAtlas* atlas,
50 uint32_t expectedActive, uint32_t expectedMax, int expectedAlloced) {
51 REPORTER_ASSERT(r, expectedActive == atlas->numActivePages());
52 REPORTER_ASSERT(r, expectedMax == atlas->maxPages());
53 REPORTER_ASSERT(r, expectedAlloced == atlas->numAllocated_TestingOnly());
54}
55
56class TestingUploadTarget : public GrDeferredUploadTarget {
57public:
58 TestingUploadTarget() { }
59
Robert Phillipsd2e9f762018-03-07 11:54:37 -050060 const GrTokenTracker* tokenTracker() final { return &fTokenTracker; }
61 GrTokenTracker* writeableTokenTracker() { return &fTokenTracker; }
Robert Phillips4bc70112018-03-01 10:24:02 -050062
63 GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&&) final {
64 SkASSERT(0); // this test shouldn't invoke this code path
65 return fTokenTracker.nextDrawToken();
66 }
67
68 virtual GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&& upload) final {
69 return fTokenTracker.nextTokenToFlush();
70 }
71
72 void issueDrawToken() { fTokenTracker.issueDrawToken(); }
73 void flushToken() { fTokenTracker.flushToken(); }
74
75private:
76 GrTokenTracker fTokenTracker;
77
78 typedef GrDeferredUploadTarget INHERITED;
79};
80
81static bool fill_plot(GrDrawOpAtlas* atlas,
82 GrResourceProvider* resourceProvider,
83 GrDeferredUploadTarget* target,
84 GrDrawOpAtlas::AtlasID* atlasID,
85 int alpha) {
86 SkImageInfo ii = SkImageInfo::MakeA8(kPlotSize, kPlotSize);
87
88 SkBitmap data;
89 data.allocPixels(ii);
90 data.eraseARGB(alpha, 0, 0, 0);
91
92 SkIPoint16 loc;
Robert Phillipsd2e9f762018-03-07 11:54:37 -050093 GrDrawOpAtlas::ErrorCode code;
94 code = atlas->addToAtlas(resourceProvider, atlasID, target, kPlotSize, kPlotSize,
95 data.getAddr(0, 0), &loc);
96 return GrDrawOpAtlas::ErrorCode::kSucceeded == code;
Robert Phillips4bc70112018-03-01 10:24:02 -050097}
98
99
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500100// This is a basic DrawOpAtlas test. It simply verifies that multitexture atlases correctly
101// add and remove pages. Note that this is simulating flush-time behavior.
102DEF_GPUTEST_FOR_RENDERING_CONTEXTS(BasicDrawOpAtlas, reporter, ctxInfo) {
Robert Phillips4bc70112018-03-01 10:24:02 -0500103 auto context = ctxInfo.grContext();
104 auto proxyProvider = context->contextPriv().proxyProvider();
105 auto resourceProvider = context->contextPriv().resourceProvider();
106 auto drawingManager = context->contextPriv().drawingManager();
107
108 GrOnFlushResourceProvider onFlushResourceProvider(drawingManager);
109 TestingUploadTarget uploadTarget;
110
111 std::unique_ptr<GrDrawOpAtlas> atlas = GrDrawOpAtlas::Make(
112 proxyProvider,
113 kAlpha_8_GrPixelConfig,
114 kAtlasSize, kAtlasSize,
115 kNumPlots, kNumPlots,
116 GrDrawOpAtlas::AllowMultitexturing::kYes,
117 EvictionFunc, nullptr);
118 check(reporter, atlas.get(), 0, 4, 0);
119
120 // Fill up the first level
121 GrDrawOpAtlas::AtlasID atlasIDs[kNumPlots * kNumPlots];
122 for (int i = 0; i < kNumPlots * kNumPlots; ++i) {
123 bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasIDs[i], i*32);
124 REPORTER_ASSERT(reporter, result);
125 check(reporter, atlas.get(), 1, 4, 1);
126 }
127
128 atlas->instantiate(&onFlushResourceProvider);
129 check(reporter, atlas.get(), 1, 4, 1);
130
131 // Force allocation of a second level
132 GrDrawOpAtlas::AtlasID atlasID;
133 bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasID, 4*32);
134 REPORTER_ASSERT(reporter, result);
135 check(reporter, atlas.get(), 2, 4, 2);
136
137 // Simulate a lot of draws using only the first plot. The last texture should be compacted.
138 for (int i = 0; i < 512; ++i) {
139 atlas->setLastUseToken(atlasIDs[0], uploadTarget.tokenTracker()->nextDrawToken());
140 uploadTarget.issueDrawToken();
141 uploadTarget.flushToken();
142 atlas->compact(uploadTarget.tokenTracker()->nextTokenToFlush());
143 }
144
145 check(reporter, atlas.get(), 1, 4, 1);
146}
147
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500148#include "GrTest.h"
149
150#include "GrDrawingManager.h"
151#include "GrOpFlushState.h"
152#include "GrProxyProvider.h"
153
154#include "effects/GrConstColorProcessor.h"
155#include "ops/GrAtlasTextOp.h"
156#include "text/GrAtlasTextContext.h"
157
158// This test verifies that the GrAtlasTextOp::onPrepare method correctly handles a failure
159// when allocating an atlas page.
160DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrAtlasTextOpPreparation, reporter, ctxInfo) {
161
162 auto context = ctxInfo.grContext();
163
164 auto gpu = context->contextPriv().getGpu();
165 auto resourceProvider = context->contextPriv().resourceProvider();
166 auto drawingManager = context->contextPriv().drawingManager();
167 auto textContext = drawingManager->getAtlasTextContext();
168
169 auto rtc = context->contextPriv().makeDeferredRenderTargetContext(SkBackingFit::kApprox,
170 32, 32,
171 kRGBA_8888_GrPixelConfig,
172 nullptr);
173
174 SkPaint paint;
175 paint.setColor(SK_ColorRED);
176 paint.setLCDRenderText(false);
177 paint.setAntiAlias(false);
178 paint.setSubpixelText(false);
179 GrTextUtils::Paint utilsPaint(&paint, &rtc->colorSpaceInfo());
180
181 const char* text = "a";
182
183 std::unique_ptr<GrDrawOp> op = textContext->createOp_TestingOnly(context, textContext,
184 rtc.get(), paint,
185 SkMatrix::I(), text,
186 16, 16);
187 op->finalize(*context->caps(), nullptr, GrPixelConfigIsClamped::kNo);
188
189 TestingUploadTarget uploadTarget;
190
191 GrOpFlushState flushState(gpu, resourceProvider, uploadTarget.writeableTokenTracker());
192 GrOpFlushState::OpArgs opArgs = {
193 op.get(),
194 rtc->asRenderTargetProxy(),
195 nullptr,
196 GrXferProcessor::DstProxy(nullptr, SkIPoint::Make(0, 0))
197 };
198
199 // Cripple the atlas manager so it can't allocate any pages. This will force a failure
200 // in the preparation of the text op
Robert Phillips5a66efb2018-03-07 15:13:18 -0500201 auto atlasManager = context->contextPriv().getAtlasManager();
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500202 unsigned int numProxies;
203 atlasManager->getProxies(kA8_GrMaskFormat, &numProxies);
204 atlasManager->setMaxPages_TestingOnly(0);
205
206 flushState.setOpArgs(&opArgs);
207 op->prepare(&flushState);
208 flushState.setOpArgs(nullptr);
209}
210
211
Robert Phillips4bc70112018-03-01 10:24:02 -0500212#endif