• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 "include/core/SkBitmap.h"
9 #include "include/core/SkColor.h"
10 #include "include/core/SkColorSpace.h"
11 #include "include/core/SkFont.h"
12 #include "include/core/SkImageInfo.h"
13 #include "include/core/SkMatrix.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkPoint.h"
16 #include "include/core/SkRefCnt.h"
17 #include "include/core/SkSize.h"
18 #include "include/core/SkTypes.h"
19 #include "include/gpu/GrBackendSurface.h"
20 #include "include/gpu/GrContext.h"
21 #include "include/private/GrTypesPriv.h"
22 #include "src/core/SkIPoint16.h"
23 #include "src/gpu/GrCaps.h"
24 #include "src/gpu/GrContextPriv.h"
25 #include "src/gpu/GrDeferredUpload.h"
26 #include "src/gpu/GrDrawOpAtlas.h"
27 #include "src/gpu/GrDrawingManager.h"
28 #include "src/gpu/GrMemoryPool.h"
29 #include "src/gpu/GrOnFlushResourceProvider.h"
30 #include "src/gpu/GrOpFlushState.h"
31 #include "src/gpu/GrRenderTargetContext.h"
32 #include "src/gpu/GrTextureProxy.h"
33 #include "src/gpu/GrXferProcessor.h"
34 #include "src/gpu/ops/GrDrawOp.h"
35 #include "src/gpu/ops/GrOp.h"
36 #include "src/gpu/text/GrAtlasManager.h"
37 #include "src/gpu/text/GrTextContext.h"
38 #include "tests/Test.h"
39 #include "tools/gpu/GrContextFactory.h"
40 
41 #include <memory>
42 #include <utility>
43 
44 class GrResourceProvider;
45 
46 static const int kNumPlots = 2;
47 static const int kPlotSize = 32;
48 static const int kAtlasSize = kNumPlots * kPlotSize;
49 
numAllocated_TestingOnly() const50 int GrDrawOpAtlas::numAllocated_TestingOnly() const {
51     int count = 0;
52     for (uint32_t i = 0; i < this->maxPages(); ++i) {
53         if (fProxies[i]->isInstantiated()) {
54             ++count;
55         }
56     }
57 
58     return count;
59 }
60 
setMaxPages_TestingOnly(uint32_t maxPages)61 void GrAtlasManager::setMaxPages_TestingOnly(uint32_t maxPages) {
62     for (int i = 0; i < kMaskFormatCount; i++) {
63         if (fAtlases[i]) {
64             fAtlases[i]->setMaxPages_TestingOnly(maxPages);
65         }
66     }
67 }
68 
setMaxPages_TestingOnly(uint32_t maxPages)69 void GrDrawOpAtlas::setMaxPages_TestingOnly(uint32_t maxPages) {
70     SkASSERT(!fNumActivePages);
71 
72     fMaxPages = maxPages;
73 }
74 
EvictionFunc(GrDrawOpAtlas::AtlasID atlasID,void *)75 void EvictionFunc(GrDrawOpAtlas::AtlasID atlasID, void*) {
76     SkASSERT(0); // The unit test shouldn't exercise this code path
77 }
78 
check(skiatest::Reporter * r,GrDrawOpAtlas * atlas,uint32_t expectedActive,uint32_t expectedMax,int expectedAlloced)79 static void check(skiatest::Reporter* r, GrDrawOpAtlas* atlas,
80                   uint32_t expectedActive, uint32_t expectedMax, int expectedAlloced) {
81     REPORTER_ASSERT(r, expectedActive == atlas->numActivePages());
82     REPORTER_ASSERT(r, expectedMax == atlas->maxPages());
83     REPORTER_ASSERT(r, expectedAlloced == atlas->numAllocated_TestingOnly());
84 }
85 
86 class TestingUploadTarget : public GrDeferredUploadTarget {
87 public:
TestingUploadTarget()88     TestingUploadTarget() { }
89 
tokenTracker()90     const GrTokenTracker* tokenTracker() final { return &fTokenTracker; }
writeableTokenTracker()91     GrTokenTracker* writeableTokenTracker() { return &fTokenTracker; }
92 
addInlineUpload(GrDeferredTextureUploadFn &&)93     GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&&) final {
94         SkASSERT(0); // this test shouldn't invoke this code path
95         return fTokenTracker.nextDrawToken();
96     }
97 
addASAPUpload(GrDeferredTextureUploadFn && upload)98     virtual GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&& upload) final {
99         return fTokenTracker.nextTokenToFlush();
100     }
101 
issueDrawToken()102     void issueDrawToken() { fTokenTracker.issueDrawToken(); }
flushToken()103     void flushToken() { fTokenTracker.flushToken(); }
104 
105 private:
106     GrTokenTracker fTokenTracker;
107 
108     typedef GrDeferredUploadTarget INHERITED;
109 };
110 
fill_plot(GrDrawOpAtlas * atlas,GrResourceProvider * resourceProvider,GrDeferredUploadTarget * target,GrDrawOpAtlas::AtlasID * atlasID,int alpha)111 static bool fill_plot(GrDrawOpAtlas* atlas,
112                       GrResourceProvider* resourceProvider,
113                       GrDeferredUploadTarget* target,
114                       GrDrawOpAtlas::AtlasID* atlasID,
115                       int alpha) {
116     SkImageInfo ii = SkImageInfo::MakeA8(kPlotSize, kPlotSize);
117 
118     SkBitmap data;
119     data.allocPixels(ii);
120     data.eraseARGB(alpha, 0, 0, 0);
121 
122     SkIPoint16 loc;
123     GrDrawOpAtlas::ErrorCode code;
124     code = atlas->addToAtlas(resourceProvider, atlasID, target, kPlotSize, kPlotSize,
125                               data.getAddr(0, 0), &loc);
126     return GrDrawOpAtlas::ErrorCode::kSucceeded == code;
127 }
128 
129 
130 // This is a basic DrawOpAtlas test. It simply verifies that multitexture atlases correctly
131 // add and remove pages. Note that this is simulating flush-time behavior.
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(BasicDrawOpAtlas,reporter,ctxInfo)132 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(BasicDrawOpAtlas, reporter, ctxInfo) {
133     auto context = ctxInfo.grContext();
134     auto proxyProvider = context->priv().proxyProvider();
135     auto resourceProvider = context->priv().resourceProvider();
136     auto drawingManager = context->priv().drawingManager();
137     const GrCaps* caps = context->priv().caps();
138 
139     GrOnFlushResourceProvider onFlushResourceProvider(drawingManager);
140     TestingUploadTarget uploadTarget;
141 
142     GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kAlpha_8,
143                                                            GrRenderable::kNo);
144 
145     std::unique_ptr<GrDrawOpAtlas> atlas = GrDrawOpAtlas::Make(
146                                                 proxyProvider,
147                                                 format,
148                                                 GrColorType::kAlpha_8,
149                                                 kAtlasSize, kAtlasSize,
150                                                 kAtlasSize/kNumPlots, kAtlasSize/kNumPlots,
151                                                 GrDrawOpAtlas::AllowMultitexturing::kYes,
152                                                 EvictionFunc, nullptr);
153     check(reporter, atlas.get(), 0, 4, 0);
154 
155     // Fill up the first level
156     GrDrawOpAtlas::AtlasID atlasIDs[kNumPlots * kNumPlots];
157     for (int i = 0; i < kNumPlots * kNumPlots; ++i) {
158         bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasIDs[i], i*32);
159         REPORTER_ASSERT(reporter, result);
160         check(reporter, atlas.get(), 1, 4, 1);
161     }
162 
163     atlas->instantiate(&onFlushResourceProvider);
164     check(reporter, atlas.get(), 1, 4, 1);
165 
166     // Force allocation of a second level
167     GrDrawOpAtlas::AtlasID atlasID;
168     bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasID, 4*32);
169     REPORTER_ASSERT(reporter, result);
170     check(reporter, atlas.get(), 2, 4, 2);
171 
172     // Simulate a lot of draws using only the first plot. The last texture should be compacted.
173     for (int i = 0; i < 512; ++i) {
174         atlas->setLastUseToken(atlasIDs[0], uploadTarget.tokenTracker()->nextDrawToken());
175         uploadTarget.issueDrawToken();
176         uploadTarget.flushToken();
177         atlas->compact(uploadTarget.tokenTracker()->nextTokenToFlush());
178     }
179 
180     check(reporter, atlas.get(), 1, 4, 1);
181 }
182 
183 // This test verifies that the GrAtlasTextOp::onPrepare method correctly handles a failure
184 // when allocating an atlas page.
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrAtlasTextOpPreparation,reporter,ctxInfo)185 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrAtlasTextOpPreparation, reporter, ctxInfo) {
186 
187     auto context = ctxInfo.grContext();
188 
189     auto gpu = context->priv().getGpu();
190     auto resourceProvider = context->priv().resourceProvider();
191     auto drawingManager = context->priv().drawingManager();
192     auto textContext = drawingManager->getTextContext();
193     auto opMemoryPool = context->priv().opMemoryPool();
194 
195     auto rtc = context->priv().makeDeferredRenderTargetContext(SkBackingFit::kApprox, 32, 32,
196                                                                GrColorType::kRGBA_8888, nullptr);
197 
198     SkPaint paint;
199     paint.setColor(SK_ColorRED);
200 
201     SkFont font;
202     font.setEdging(SkFont::Edging::kAlias);
203 
204     const char* text = "a";
205 
206     std::unique_ptr<GrDrawOp> op = textContext->createOp_TestingOnly(
207             context, textContext, rtc.get(), paint, font, SkMatrix::I(), text, 16, 16);
208     bool hasMixedSampledCoverage = false;
209     op->finalize(*context->priv().caps(), nullptr, hasMixedSampledCoverage, GrClampType::kAuto);
210 
211     TestingUploadTarget uploadTarget;
212 
213     GrOpFlushState flushState(gpu, resourceProvider, uploadTarget.writeableTokenTracker());
214     GrOpFlushState::OpArgs opArgs = {
215         op.get(),
216         rtc->asRenderTargetProxy(),
217         nullptr,
218         rtc->asRenderTargetProxy()->outputSwizzle(),
219         GrXferProcessor::DstProxy(nullptr, SkIPoint::Make(0, 0))
220     };
221 
222     // Cripple the atlas manager so it can't allocate any pages. This will force a failure
223     // in the preparation of the text op
224     auto atlasManager = context->priv().getAtlasManager();
225     unsigned int numProxies;
226     atlasManager->getProxies(kA8_GrMaskFormat, &numProxies);
227     atlasManager->setMaxPages_TestingOnly(0);
228 
229     flushState.setOpArgs(&opArgs);
230     op->prepare(&flushState);
231     flushState.setOpArgs(nullptr);
232     opMemoryPool->release(std::move(op));
233 }
234 
test_atlas_config(skiatest::Reporter * reporter,int maxTextureSize,size_t maxBytes,GrMaskFormat maskFormat,SkISize expectedDimensions,SkISize expectedPlotDimensions)235 void test_atlas_config(skiatest::Reporter* reporter, int maxTextureSize, size_t maxBytes,
236                        GrMaskFormat maskFormat, SkISize expectedDimensions,
237                        SkISize expectedPlotDimensions) {
238     GrDrawOpAtlasConfig config(maxTextureSize, maxBytes);
239     REPORTER_ASSERT(reporter, config.atlasDimensions(maskFormat) == expectedDimensions);
240     REPORTER_ASSERT(reporter, config.plotDimensions(maskFormat) == expectedPlotDimensions);
241 }
242 
DEF_GPUTEST(GrDrawOpAtlasConfig_Basic,reporter,options)243 DEF_GPUTEST(GrDrawOpAtlasConfig_Basic, reporter, options) {
244     // 1/4 MB
245     test_atlas_config(reporter, 65536, 256 * 1024, kARGB_GrMaskFormat,
246                       { 256, 256 }, { 256, 256 });
247     test_atlas_config(reporter, 65536, 256 * 1024, kA8_GrMaskFormat,
248                       { 512, 512 }, { 256, 256 });
249     // 1/2 MB
250     test_atlas_config(reporter, 65536, 512 * 1024, kARGB_GrMaskFormat,
251                       { 512, 256 }, { 256, 256 });
252     test_atlas_config(reporter, 65536, 512 * 1024, kA8_GrMaskFormat,
253                       { 1024, 512 }, { 256, 256 });
254     // 1 MB
255     test_atlas_config(reporter, 65536, 1024 * 1024, kARGB_GrMaskFormat,
256                       { 512, 512 }, { 256, 256 });
257     test_atlas_config(reporter, 65536, 1024 * 1024, kA8_GrMaskFormat,
258                       { 1024, 1024 }, { 256, 256 });
259     // 2 MB
260     test_atlas_config(reporter, 65536, 2 * 1024 * 1024, kARGB_GrMaskFormat,
261                       { 1024, 512 }, { 256, 256 });
262     test_atlas_config(reporter, 65536, 2 * 1024 * 1024, kA8_GrMaskFormat,
263                       { 2048, 1024 }, { 512, 256 });
264     // 4 MB
265     test_atlas_config(reporter, 65536, 4 * 1024 * 1024, kARGB_GrMaskFormat,
266                       { 1024, 1024 }, { 256, 256 });
267     test_atlas_config(reporter, 65536, 4 * 1024 * 1024, kA8_GrMaskFormat,
268                       { 2048, 2048 }, { 512, 512 });
269     // 8 MB
270     test_atlas_config(reporter, 65536, 8 * 1024 * 1024, kARGB_GrMaskFormat,
271                       { 2048, 1024 }, { 256, 256 });
272     test_atlas_config(reporter, 65536, 8 * 1024 * 1024, kA8_GrMaskFormat,
273                       { 2048, 2048 }, { 512, 512 });
274     // 16 MB (should be same as 8 MB)
275     test_atlas_config(reporter, 65536, 16 * 1024 * 1024, kARGB_GrMaskFormat,
276                       { 2048, 1024 }, { 256, 256 });
277     test_atlas_config(reporter, 65536, 16 * 1024 * 1024, kA8_GrMaskFormat,
278                       { 2048, 2048 }, { 512, 512 });
279 
280     // 4MB, restricted texture size
281     test_atlas_config(reporter, 1024, 8 * 1024 * 1024, kARGB_GrMaskFormat,
282                       { 1024, 1024 }, { 256, 256 });
283     test_atlas_config(reporter, 1024, 8 * 1024 * 1024, kA8_GrMaskFormat,
284                       { 1024, 1024 }, { 256, 256 });
285 
286     // 3 MB (should be same as 2 MB)
287     test_atlas_config(reporter, 65536, 3 * 1024 * 1024, kARGB_GrMaskFormat,
288                       { 1024, 512 }, { 256, 256 });
289     test_atlas_config(reporter, 65536, 3 * 1024 * 1024, kA8_GrMaskFormat,
290                       { 2048, 1024 }, { 512, 256 });
291 
292     // minimum size
293     test_atlas_config(reporter, 65536, 0, kARGB_GrMaskFormat,
294                       { 256, 256 }, { 256, 256 });
295     test_atlas_config(reporter, 65536, 0, kA8_GrMaskFormat,
296                       { 512, 512 }, { 256, 256 });
297 }
298