• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 ///////////////////////////////////////////////////////////////////////////////
Plot()15 GrLayerAtlas::Plot::Plot()
16     : fID(-1)
17     , fRects(nullptr) {
18     fOffset.set(0, 0);
19 }
20 
~Plot()21 GrLayerAtlas::Plot::~Plot() {
22     delete fRects;
23 }
24 
init(int id,int offX,int offY,int width,int height)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 
allocateRect(int width,int height,SkIPoint16 * loc)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 
reset()41 void GrLayerAtlas::Plot::reset() {
42     SkASSERT(fRects);
43     fRects->reset();
44 }
45 
46 ///////////////////////////////////////////////////////////////////////////////
47 GR_DECLARE_STATIC_UNIQUE_KEY(gLayerAtlasKey);
get_layer_atlas_key()48 static const GrUniqueKey& get_layer_atlas_key() {
49     GR_DEFINE_STATIC_UNIQUE_KEY(gLayerAtlasKey);
50     return gLayerAtlasKey;
51 }
52 
reattachBackingTexture()53 bool GrLayerAtlas::reattachBackingTexture() {
54     SkASSERT(!fTexture);
55 
56     fTexture.reset(fTexProvider->findAndRefTextureByUniqueKey(get_layer_atlas_key()));
57     return SkToBool(fTexture);
58 }
59 
createBackingTexture()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 
GrLayerAtlas(GrTextureProvider * texProvider,GrPixelConfig config,GrSurfaceFlags flags,const SkISize & backingTextureSize,int numPlotsX,int numPlotsY)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 
resetPlots()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 
~GrLayerAtlas()117 GrLayerAtlas::~GrLayerAtlas() {
118     delete[] fPlotArray;
119 }
120 
makeMRU(Plot * plot)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 
addToAtlas(ClientPlotUsage * usage,int width,int height,SkIPoint16 * loc)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