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