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 "SkTypes.h"
9
10 #if SK_SUPPORT_GPU
11
12 #include "GrContextPriv.h"
13 #include "Test.h"
14 #include "text/GrGlyphCache.h"
15
16 static const int kNumPlots = 2;
17 static const int kPlotSize = 32;
18 static const int kAtlasSize = kNumPlots * kPlotSize;
19
numAllocated_TestingOnly() const20 int 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
EvictionFunc(GrDrawOpAtlas::AtlasID atlasID,void *)31 void EvictionFunc(GrDrawOpAtlas::AtlasID atlasID, void*) {
32 SkASSERT(0); // The unit test shouldn't exercise this code path
33 }
34
check(skiatest::Reporter * r,GrDrawOpAtlas * atlas,uint32_t expectedActive,uint32_t expectedMax,int expectedAlloced)35 static void check(skiatest::Reporter* r, GrDrawOpAtlas* atlas,
36 uint32_t expectedActive, uint32_t expectedMax, int expectedAlloced) {
37 REPORTER_ASSERT(r, expectedActive == atlas->numActivePages());
38 REPORTER_ASSERT(r, expectedMax == atlas->maxPages());
39 REPORTER_ASSERT(r, expectedAlloced == atlas->numAllocated_TestingOnly());
40 }
41
42 class TestingUploadTarget : public GrDeferredUploadTarget {
43 public:
TestingUploadTarget()44 TestingUploadTarget() { }
45
tokenTracker()46 const GrTokenTracker* tokenTracker() final {
47 return &fTokenTracker;
48 }
49
addInlineUpload(GrDeferredTextureUploadFn &&)50 GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&&) final {
51 SkASSERT(0); // this test shouldn't invoke this code path
52 return fTokenTracker.nextDrawToken();
53 }
54
addASAPUpload(GrDeferredTextureUploadFn && upload)55 virtual GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&& upload) final {
56 return fTokenTracker.nextTokenToFlush();
57 }
58
issueDrawToken()59 void issueDrawToken() { fTokenTracker.issueDrawToken(); }
flushToken()60 void flushToken() { fTokenTracker.flushToken(); }
61
62 private:
63 GrTokenTracker fTokenTracker;
64
65 typedef GrDeferredUploadTarget INHERITED;
66 };
67
fill_plot(GrDrawOpAtlas * atlas,GrResourceProvider * resourceProvider,GrDeferredUploadTarget * target,GrDrawOpAtlas::AtlasID * atlasID,int alpha)68 static bool fill_plot(GrDrawOpAtlas* atlas,
69 GrResourceProvider* resourceProvider,
70 GrDeferredUploadTarget* target,
71 GrDrawOpAtlas::AtlasID* atlasID,
72 int alpha) {
73 SkImageInfo ii = SkImageInfo::MakeA8(kPlotSize, kPlotSize);
74
75 SkBitmap data;
76 data.allocPixels(ii);
77 data.eraseARGB(alpha, 0, 0, 0);
78
79 SkIPoint16 loc;
80 bool result = atlas->addToAtlas(resourceProvider, atlasID, target, kPlotSize, kPlotSize,
81 data.getAddr(0, 0), &loc);
82 return result;
83 }
84
85
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DrawOpAtlas,reporter,ctxInfo)86 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DrawOpAtlas, reporter, ctxInfo) {
87 auto context = ctxInfo.grContext();
88 auto proxyProvider = context->contextPriv().proxyProvider();
89 auto resourceProvider = context->contextPriv().resourceProvider();
90 auto drawingManager = context->contextPriv().drawingManager();
91
92 GrOnFlushResourceProvider onFlushResourceProvider(drawingManager);
93 TestingUploadTarget uploadTarget;
94
95 std::unique_ptr<GrDrawOpAtlas> atlas = GrDrawOpAtlas::Make(
96 proxyProvider,
97 kAlpha_8_GrPixelConfig,
98 kAtlasSize, kAtlasSize,
99 kNumPlots, kNumPlots,
100 GrDrawOpAtlas::AllowMultitexturing::kYes,
101 EvictionFunc, nullptr);
102 check(reporter, atlas.get(), 0, 4, 0);
103
104 // Fill up the first level
105 GrDrawOpAtlas::AtlasID atlasIDs[kNumPlots * kNumPlots];
106 for (int i = 0; i < kNumPlots * kNumPlots; ++i) {
107 bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasIDs[i], i*32);
108 REPORTER_ASSERT(reporter, result);
109 check(reporter, atlas.get(), 1, 4, 1);
110 }
111
112 atlas->instantiate(&onFlushResourceProvider);
113 check(reporter, atlas.get(), 1, 4, 1);
114
115 // Force allocation of a second level
116 GrDrawOpAtlas::AtlasID atlasID;
117 bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasID, 4*32);
118 REPORTER_ASSERT(reporter, result);
119 check(reporter, atlas.get(), 2, 4, 2);
120
121 // Simulate a lot of draws using only the first plot. The last texture should be compacted.
122 for (int i = 0; i < 512; ++i) {
123 atlas->setLastUseToken(atlasIDs[0], uploadTarget.tokenTracker()->nextDrawToken());
124 uploadTarget.issueDrawToken();
125 uploadTarget.flushToken();
126 atlas->compact(uploadTarget.tokenTracker()->nextTokenToFlush());
127 }
128
129 check(reporter, atlas.get(), 1, 4, 1);
130 }
131
132 #endif
133