Home | History | Annotate | Download | only in tests
      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