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 20 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 31 void EvictionFunc(GrDrawOpAtlas::AtlasID atlasID, void*) { 32 SkASSERT(0); // The unit test shouldn't exercise this code path 33 } 34 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: 44 TestingUploadTarget() { } 45 46 const GrTokenTracker* tokenTracker() final { 47 return &fTokenTracker; 48 } 49 50 GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&&) final { 51 SkASSERT(0); // this test shouldn't invoke this code path 52 return fTokenTracker.nextDrawToken(); 53 } 54 55 virtual GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&& upload) final { 56 return fTokenTracker.nextTokenToFlush(); 57 } 58 59 void issueDrawToken() { fTokenTracker.issueDrawToken(); } 60 void flushToken() { fTokenTracker.flushToken(); } 61 62 private: 63 GrTokenTracker fTokenTracker; 64 65 typedef GrDeferredUploadTarget INHERITED; 66 }; 67 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 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