LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu - GrDrawOpAtlas.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 79 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 31 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2015 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             : #ifndef GrDrawOpAtlas_DEFINED
       9             : #define GrDrawOpAtlas_DEFINED
      10             : 
      11             : #include "SkPoint.h"
      12             : #include "SkTDArray.h"
      13             : #include "SkTInternalLList.h"
      14             : 
      15             : #include "ops/GrDrawOp.h"
      16             : 
      17             : class GrRectanizer;
      18             : 
      19             : struct GrDrawOpAtlasConfig {
      20           0 :     int numPlotsX() const { return fWidth / fPlotWidth; }
      21           0 :     int numPlotsY() const { return fHeight / fPlotWidth; }
      22             :     int fWidth;
      23             :     int fHeight;
      24             :     int fLog2Width;
      25             :     int fLog2Height;
      26             :     int fPlotWidth;
      27             :     int fPlotHeight;
      28             : };
      29             : 
      30             : /**
      31             :  * This class manages an atlas texture on behalf of GrDrawOps. The draw ops that use the atlas
      32             :  * perform texture uploads when preparing their draws during flush. The class provides facilities
      33             :  * for using GrDrawOpUploadToken to detect data hazards. Op's uploads are performed in "asap" mode
      34             :  * until it is impossible to add data without overwriting texels read by draws that have not yet
      35             :  * executed on the gpu. At that point the uploads are performed "inline" between draws. If a single
      36             :  * draw would use enough subimage space to overflow the atlas texture then the atlas will fail to
      37             :  * add a subimage. This gives the op the chance to end the draw and begin a new one. Additional
      38             :  * uploads will then succeed in inline mode.
      39             :  */
      40           0 : class GrDrawOpAtlas {
      41             : public:
      42             :     /**
      43             :      * An AtlasID is an opaque handle which callers can use to determine if the atlas contains
      44             :      * a specific piece of data.
      45             :      */
      46             :     typedef uint64_t AtlasID;
      47             :     static const uint32_t kInvalidAtlasID = 0;
      48             :     static const uint64_t kInvalidAtlasGeneration = 0;
      49             : 
      50             :     /**
      51             :      * A function pointer for use as a callback during eviction. Whenever GrDrawOpAtlas evicts a
      52             :      * specific AtlasID, it will call all of the registered listeners so they can process the
      53             :      * eviction.
      54             :      */
      55             :     typedef void (*EvictionFunc)(GrDrawOpAtlas::AtlasID, void*);
      56             : 
      57             :     /**
      58             :      * Returns a GrDrawOpAtlas. This function can be called anywhere, but the returned atlas
      59             :      * should only be used inside of GrMeshDrawOp::onPrepareDraws.
      60             :      *  @param GrPixelConfig    The pixel config which this atlas will store
      61             :      *  @param width            width in pixels of the atlas
      62             :      *  @param height           height in pixels of the atlas
      63             :      *  @param numPlotsX        The number of plots the atlas should be broken up into in the X
      64             :      *                          direction
      65             :      *  @param numPlotsY        The number of plots the atlas should be broken up into in the Y
      66             :      *                          direction
      67             :      *  @param func             An eviction function which will be called whenever the atlas has to
      68             :      *                          evict data
      69             :      *  @param data             User supplied data which will be passed into func whenver an
      70             :      *                          eviction occurs
      71             :      *  @return                 An initialized GrDrawOpAtlas, or nullptr if creation fails
      72             :      */
      73             :     static std::unique_ptr<GrDrawOpAtlas> Make(GrContext*, GrPixelConfig,
      74             :                                                int width, int height,
      75             :                                                int numPlotsX, int numPlotsY,
      76             :                                                GrDrawOpAtlas::EvictionFunc func, void* data);
      77             : 
      78             :     /**
      79             :      * Adds a width x height subimage to the atlas. Upon success it returns an ID and the subimage's
      80             :      * coordinates in the backing texture. False is returned if the subimage cannot fit in the
      81             :      * atlas without overwriting texels that will be read in the current draw. This indicates that
      82             :      * the op should end its current draw and begin another before adding more data. Upon success,
      83             :      * an upload of the provided image data will have been added to the GrDrawOp::Target, in "asap"
      84             :      * mode if possible, otherwise in "inline" mode. Successive uploads in either mode may be
      85             :      * consolidated.
      86             :      * NOTE: When the GrDrawOp prepares a draw that reads from the atlas, it must immediately call
      87             :      * 'setUseToken' with the currentToken from the GrDrawOp::Target, otherwise the next call to
      88             :      * addToAtlas might cause the previous data to be overwritten before it has been read.
      89             :      */
      90             :     bool addToAtlas(AtlasID*, GrDrawOp::Target*, int width, int height, const void* image,
      91             :                     SkIPoint16* loc);
      92             : 
      93           0 :     GrContext* context() const { return fContext; }
      94           0 :     sk_sp<GrTextureProxy> getProxy() const { return fProxy; }
      95             : 
      96           0 :     uint64_t atlasGeneration() const { return fAtlasGeneration; }
      97             : 
      98           0 :     inline bool hasID(AtlasID id) {
      99           0 :         uint32_t index = GetIndexFromID(id);
     100           0 :         SkASSERT(index < fNumPlots);
     101           0 :         return fPlotArray[index]->genID() == GetGenerationFromID(id);
     102             :     }
     103             : 
     104             :     /** To ensure the atlas does not evict a given entry, the client must set the last use token. */
     105           0 :     inline void setLastUseToken(AtlasID id, GrDrawOpUploadToken token) {
     106           0 :         SkASSERT(this->hasID(id));
     107           0 :         uint32_t index = GetIndexFromID(id);
     108           0 :         SkASSERT(index < fNumPlots);
     109           0 :         this->makeMRU(fPlotArray[index].get());
     110           0 :         fPlotArray[index]->setLastUseToken(token);
     111           0 :     }
     112             : 
     113           0 :     inline void registerEvictionCallback(EvictionFunc func, void* userData) {
     114           0 :         EvictionData* data = fEvictionCallbacks.append();
     115           0 :         data->fFunc = func;
     116           0 :         data->fData = userData;
     117           0 :     }
     118             : 
     119             :     /**
     120             :      * A class which can be handed back to GrDrawOpAtlas for updating last use tokens in bulk.  The
     121             :      * current max number of plots the GrDrawOpAtlas can handle is 32. If in the future this is
     122             :      * insufficient then we can move to a 64 bit int.
     123             :      */
     124           0 :     class BulkUseTokenUpdater {
     125             :     public:
     126           0 :         BulkUseTokenUpdater() : fPlotAlreadyUpdated(0) {}
     127           0 :         BulkUseTokenUpdater(const BulkUseTokenUpdater& that)
     128           0 :             : fPlotsToUpdate(that.fPlotsToUpdate)
     129           0 :             , fPlotAlreadyUpdated(that.fPlotAlreadyUpdated) {
     130           0 :         }
     131             : 
     132           0 :         void add(AtlasID id) {
     133           0 :             int index = GrDrawOpAtlas::GetIndexFromID(id);
     134           0 :             if (!this->find(index)) {
     135           0 :                 this->set(index);
     136             :             }
     137           0 :         }
     138             : 
     139           0 :         void reset() {
     140           0 :             fPlotsToUpdate.reset();
     141           0 :             fPlotAlreadyUpdated = 0;
     142           0 :         }
     143             : 
     144             :     private:
     145           0 :         bool find(int index) const {
     146           0 :             SkASSERT(index < kMaxPlots);
     147           0 :             return (fPlotAlreadyUpdated >> index) & 1;
     148             :         }
     149             : 
     150           0 :         void set(int index) {
     151           0 :             SkASSERT(!this->find(index));
     152           0 :             fPlotAlreadyUpdated = fPlotAlreadyUpdated | (1 << index);
     153           0 :             fPlotsToUpdate.push_back(index);
     154           0 :         }
     155             : 
     156             :         static const int kMinItems = 4;
     157             :         static const int kMaxPlots = 32;
     158             :         SkSTArray<kMinItems, int, true> fPlotsToUpdate;
     159             :         uint32_t fPlotAlreadyUpdated;
     160             : 
     161             :         friend class GrDrawOpAtlas;
     162             :     };
     163             : 
     164           0 :     void setLastUseTokenBulk(const BulkUseTokenUpdater& updater, GrDrawOpUploadToken token) {
     165           0 :         int count = updater.fPlotsToUpdate.count();
     166           0 :         for (int i = 0; i < count; i++) {
     167           0 :             Plot* plot = fPlotArray[updater.fPlotsToUpdate[i]].get();
     168           0 :             this->makeMRU(plot);
     169           0 :             plot->setLastUseToken(token);
     170             :         }
     171           0 :     }
     172             : 
     173             :     static const int kGlyphMaxDim = 256;
     174           0 :     static bool GlyphTooLargeForAtlas(int width, int height) {
     175           0 :         return width > kGlyphMaxDim || height > kGlyphMaxDim;
     176             :     }
     177             : 
     178             : private:
     179             :     GrDrawOpAtlas(GrContext*, sk_sp<GrTextureProxy>, int numPlotsX, int numPlotsY);
     180             : 
     181             :     /**
     182             :      * The backing GrTexture for a GrDrawOpAtlas is broken into a spatial grid of Plots. The Plots
     183             :      * keep track of subimage placement via their GrRectanizer. A Plot manages the lifetime of its
     184             :      * data using two tokens, a last use token and a last upload token. Once a Plot is "full" (i.e.
     185             :      * there is no room for the new subimage according to the GrRectanizer), it can no longer be
     186             :      * used unless the last use of the Plot has already been flushed through to the gpu.
     187             :      */
     188             :     class Plot : public SkRefCnt {
     189             :         SK_DECLARE_INTERNAL_LLIST_INTERFACE(Plot);
     190             : 
     191             :     public:
     192             :         /** index() is a unique id for the plot relative to the owning GrAtlas. */
     193           0 :         uint32_t index() const { return fIndex; }
     194             :         /**
     195             :          * genID() is incremented when the plot is evicted due to a atlas spill. It is used to know
     196             :          * if a particular subimage is still present in the atlas.
     197             :          */
     198           0 :         uint64_t genID() const { return fGenID; }
     199           0 :         GrDrawOpAtlas::AtlasID id() const {
     200           0 :             SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != fID);
     201           0 :             return fID;
     202             :         }
     203           0 :         SkDEBUGCODE(size_t bpp() const { return fBytesPerPixel; })
     204             : 
     205             :         bool addSubImage(int width, int height, const void* image, SkIPoint16* loc);
     206             : 
     207             :         /**
     208             :          * To manage the lifetime of a plot, we use two tokens. We use the last upload token to
     209             :          * know when we can 'piggy back' uploads, i.e. if the last upload hasn't been flushed to
     210             :          * the gpu, we don't need to issue a new upload even if we update the cpu backing store. We
     211             :          * use lastUse to determine when we can evict a plot from the cache, i.e. if the last use
     212             :          * has already flushed through the gpu then we can reuse the plot.
     213             :          */
     214           0 :         GrDrawOpUploadToken lastUploadToken() const { return fLastUpload; }
     215           0 :         GrDrawOpUploadToken lastUseToken() const { return fLastUse; }
     216           0 :         void setLastUploadToken(GrDrawOpUploadToken token) { fLastUpload = token; }
     217           0 :         void setLastUseToken(GrDrawOpUploadToken token) { fLastUse = token; }
     218             : 
     219             :         void uploadToTexture(GrDrawOp::WritePixelsFn&, GrTexture* texture);
     220             :         void resetRects();
     221             : 
     222             :     private:
     223             :         Plot(int index, uint64_t genID, int offX, int offY, int width, int height,
     224             :              GrPixelConfig config);
     225             : 
     226             :         ~Plot() override;
     227             : 
     228             :         /**
     229             :          * Create a clone of this plot. The cloned plot will take the place of the current plot in
     230             :          * the atlas
     231             :          */
     232           0 :         Plot* clone() const {
     233           0 :             return new Plot(fIndex, fGenID + 1, fX, fY, fWidth, fHeight, fConfig);
     234             :         }
     235             : 
     236           0 :         static GrDrawOpAtlas::AtlasID CreateId(uint32_t index, uint64_t generation) {
     237           0 :             SkASSERT(index < (1 << 16));
     238           0 :             SkASSERT(generation < ((uint64_t)1 << 48));
     239           0 :             return generation << 16 | index;
     240             :         }
     241             : 
     242             :         GrDrawOpUploadToken   fLastUpload;
     243             :         GrDrawOpUploadToken   fLastUse;
     244             : 
     245             :         const uint32_t fIndex;
     246             :         uint64_t fGenID;
     247             :         GrDrawOpAtlas::AtlasID fID;
     248             :         unsigned char* fData;
     249             :         const int fWidth;
     250             :         const int fHeight;
     251             :         const int fX;
     252             :         const int fY;
     253             :         GrRectanizer* fRects;
     254             :         const SkIPoint16 fOffset;  // the offset of the plot in the backing texture
     255             :         const GrPixelConfig fConfig;
     256             :         const size_t fBytesPerPixel;
     257             :         SkIRect fDirtyRect;
     258             :         SkDEBUGCODE(bool fDirty);
     259             : 
     260             :         friend class GrDrawOpAtlas;
     261             : 
     262             :         typedef SkRefCnt INHERITED;
     263             :     };
     264             : 
     265             :     typedef SkTInternalLList<Plot> PlotList;
     266             : 
     267           0 :     static uint32_t GetIndexFromID(AtlasID id) {
     268           0 :         return id & 0xffff;
     269             :     }
     270             : 
     271             :     // top 48 bits are reserved for the generation ID
     272           0 :     static uint64_t GetGenerationFromID(AtlasID id) {
     273           0 :         return (id >> 16) & 0xffffffffffff;
     274             :     }
     275             : 
     276             :     inline bool updatePlot(GrDrawOp::Target*, AtlasID*, Plot*);
     277             : 
     278           0 :     inline void makeMRU(Plot* plot) {
     279           0 :         if (fPlotList.head() == plot) {
     280           0 :             return;
     281             :         }
     282             : 
     283           0 :         fPlotList.remove(plot);
     284           0 :         fPlotList.addToHead(plot);
     285             :     }
     286             : 
     287             :     inline void processEviction(AtlasID);
     288             : 
     289             :     GrContext*            fContext;
     290             :     sk_sp<GrTextureProxy> fProxy;
     291             :     int                   fPlotWidth;
     292             :     int                   fPlotHeight;
     293             :     SkDEBUGCODE(uint32_t  fNumPlots;)
     294             : 
     295             :     uint64_t              fAtlasGeneration;
     296             : 
     297             :     struct EvictionData {
     298             :         EvictionFunc fFunc;
     299             :         void* fData;
     300             :     };
     301             : 
     302             :     SkTDArray<EvictionData> fEvictionCallbacks;
     303             :     // allocated array of Plots
     304             :     std::unique_ptr<sk_sp<Plot>[]> fPlotArray;
     305             :     // LRU list of Plots (MRU at head - LRU at tail)
     306             :     PlotList fPlotList;
     307             : };
     308             : 
     309             : #endif

Generated by: LCOV version 1.13