Home | History | Annotate | Download | only in gpu
      1 
      2 /*
      3  * Copyright 2010 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #include "GrGpuResourcePriv.h"
     10 #include "GrLayerAtlas.h"
     11 #include "GrRectanizer.h"
     12 #include "GrTextureProvider.h"
     13 
     14 ///////////////////////////////////////////////////////////////////////////////
     15 GrLayerAtlas::Plot::Plot()
     16     : fID(-1)
     17     , fRects(nullptr) {
     18     fOffset.set(0, 0);
     19 }
     20 
     21 GrLayerAtlas::Plot::~Plot() {
     22     delete fRects;
     23 }
     24 
     25 void GrLayerAtlas::Plot::init(int id, int offX, int offY, int width, int height) {
     26     fID = id;
     27     fRects = GrRectanizer::Factory(width, height);
     28     fOffset.set(offX * width, offY * height);
     29 }
     30 
     31 bool GrLayerAtlas::Plot::allocateRect(int width, int height, SkIPoint16* loc) {
     32     if (!fRects->addRect(width, height, loc)) {
     33         return false;
     34     }
     35 
     36     loc->fX += fOffset.fX;
     37     loc->fY += fOffset.fY;
     38     return true;
     39 }
     40 
     41 void GrLayerAtlas::Plot::reset() {
     42     SkASSERT(fRects);
     43     fRects->reset();
     44 }
     45 
     46 ///////////////////////////////////////////////////////////////////////////////
     47 GR_DECLARE_STATIC_UNIQUE_KEY(gLayerAtlasKey);
     48 static const GrUniqueKey& get_layer_atlas_key() {
     49     GR_DEFINE_STATIC_UNIQUE_KEY(gLayerAtlasKey);
     50     return gLayerAtlasKey;
     51 }
     52 
     53 bool GrLayerAtlas::reattachBackingTexture() {
     54     SkASSERT(!fTexture);
     55 
     56     fTexture.reset(fTexProvider->findAndRefTextureByUniqueKey(get_layer_atlas_key()));
     57     return SkToBool(fTexture);
     58 }
     59 
     60 void GrLayerAtlas::createBackingTexture() {
     61     SkASSERT(!fTexture);
     62 
     63     GrSurfaceDesc desc;
     64     desc.fFlags = fFlags;
     65     desc.fWidth = fBackingTextureSize.width();
     66     desc.fHeight = fBackingTextureSize.height();
     67     desc.fConfig = fPixelConfig;
     68 
     69     fTexture.reset(fTexProvider->createTexture(desc, SkBudgeted::kYes, nullptr, 0));
     70 
     71     fTexture->resourcePriv().setUniqueKey(get_layer_atlas_key());
     72 }
     73 
     74 GrLayerAtlas::GrLayerAtlas(GrTextureProvider* texProvider, GrPixelConfig config,
     75                            GrSurfaceFlags flags,
     76                            const SkISize& backingTextureSize,
     77                            int numPlotsX, int numPlotsY) {
     78     fTexProvider = texProvider;
     79     fPixelConfig = config;
     80     fFlags = flags;
     81     fBackingTextureSize = backingTextureSize;
     82 
     83     int textureWidth = fBackingTextureSize.width();
     84     int textureHeight = fBackingTextureSize.height();
     85 
     86     int plotWidth = textureWidth / numPlotsX;
     87     int plotHeight = textureHeight / numPlotsY;
     88 
     89     SkASSERT(plotWidth * numPlotsX == textureWidth);
     90     SkASSERT(plotHeight * numPlotsY == textureHeight);
     91 
     92     // We currently do not support compressed atlases...
     93     SkASSERT(!GrPixelConfigIsCompressed(config));
     94 
     95     // set up allocated plots
     96     fPlotArray = new Plot[numPlotsX * numPlotsY];
     97 
     98     Plot* currPlot = fPlotArray;
     99     for (int y = numPlotsY-1; y >= 0; --y) {
    100         for (int x = numPlotsX-1; x >= 0; --x) {
    101             currPlot->init(y*numPlotsX+x, x, y, plotWidth, plotHeight);
    102 
    103             // build LRU list
    104             fPlotList.addToHead(currPlot);
    105             ++currPlot;
    106         }
    107     }
    108 }
    109 
    110 void GrLayerAtlas::resetPlots() {
    111     PlotIter iter;
    112     for (Plot* plot = iter.init(fPlotList, PlotIter::kHead_IterStart); plot; plot = iter.next()) {
    113         plot->reset();
    114     }
    115 }
    116 
    117 GrLayerAtlas::~GrLayerAtlas() {
    118     delete[] fPlotArray;
    119 }
    120 
    121 void GrLayerAtlas::makeMRU(Plot* plot) {
    122     if (fPlotList.head() == plot) {
    123         return;
    124     }
    125 
    126     fPlotList.remove(plot);
    127     fPlotList.addToHead(plot);
    128 };
    129 
    130 GrLayerAtlas::Plot* GrLayerAtlas::addToAtlas(ClientPlotUsage* usage,
    131                                              int width, int height, SkIPoint16* loc) {
    132     // Iterate through the plots currently being used by this client and see if we can find a hole.
    133     // The last one was most recently added and probably most empty.
    134     // We want to consolidate the uses from individual clients to the same plot(s) so that
    135     // when a specific client goes away they are more likely to completely empty a plot.
    136     for (int i = usage->numPlots()-1; i >= 0; --i) {
    137         Plot* plot = usage->plot(i);
    138         if (plot->allocateRect(width, height, loc)) {
    139             this->makeMRU(plot);
    140             return plot;
    141         }
    142     }
    143 
    144     // before we get a new plot, make sure we have a backing texture
    145     if (nullptr == fTexture) {
    146         this->createBackingTexture();
    147         if (nullptr == fTexture) {
    148             return nullptr;
    149         }
    150     }
    151 
    152     // Now look through all allocated plots for one we can share, in MRU order
    153     // TODO: its seems like traversing from emptiest to fullest would make more sense
    154     PlotList::Iter plotIter;
    155     plotIter.init(fPlotList, PlotList::Iter::kHead_IterStart);
    156     Plot* plot;
    157     while ((plot = plotIter.get())) {
    158         if (plot->allocateRect(width, height, loc)) {
    159             this->makeMRU(plot);
    160             // new plot for atlas, put at end of array
    161             usage->appendPlot(plot);
    162             return plot;
    163         }
    164         plotIter.next();
    165     }
    166 
    167     // If the above fails, then the current plot list has no room
    168     return nullptr;
    169 }
    170 
    171