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#ifndef GrLayerAtlas_DEFINED
10#define GrLayerAtlas_DEFINED
11
12#include "GrTexture.h"
13
14#include "SkPoint.h"
15#include "SkTDArray.h"
16#include "SkTInternalLList.h"
17
18class GrLayerAtlas;
19class GrTextureProvider;
20class GrRectanizer;
21
22// The backing GrTexture for a GrLayerAtlas is broken into a spatial grid of Plots. When
23// the atlas needs space on the texture (i.e., in response to an addToAtlas call), it
24// iterates through the plots in use by the requesting client looking for space and,
25// if no space is found, opens up a new Plot for that client. The Plots keep track of
26// subimage placement via their GrRectanizer.
27//
28// If all Plots are full, the replacement strategy is up to the client. The Plot::reset
29// call will remove a Plot's knowledge of any allocated rects - freeing its space for reuse.
30
31class GrLayerAtlas {
32public:
33    class Plot {
34        SK_DECLARE_INTERNAL_LLIST_INTERFACE(Plot); // In an MRU llist
35
36    public:
37        // This returns a plot ID unique to each plot in the atlas. They are
38        // consecutive and start at 0.
39        int id() const { return fID; }
40
41        void reset();
42
43    private:
44        friend class GrLayerAtlas;
45
46        Plot();
47        ~Plot(); // does not try to delete the fNext field
48
49        void init(int id, int offX, int offY, int width, int height);
50
51        bool allocateRect(int width, int height, SkIPoint16*);
52
53        int                     fID;
54        GrRectanizer*           fRects;
55        SkIPoint16              fOffset;        // the offset of the plot in the backing texture
56    };
57
58    // This class allows each client to independently track the Plots in
59    // which its data is stored.
60    // For example, multiple pictures may simultaneously store their layers in the
61    // layer atlas. When a picture goes away it can use the ClientPlotUsage to remove itself
62    // from those plots.
63    class ClientPlotUsage {
64    public:
65        ClientPlotUsage(int maxPlots)
66            SkDEBUGCODE(: fMaxPlots(maxPlots)) {
67            fPlots.setReserve(maxPlots);
68        }
69
70        bool isEmpty() const { return 0 == fPlots.count(); }
71
72        int numPlots() const { return fPlots.count(); }
73        Plot* plot(int index) { return fPlots[index]; }
74
75        void appendPlot(Plot* plot) {
76            SkASSERT(fPlots.count() <= fMaxPlots);
77            SkASSERT(!fPlots.contains(plot));
78            *fPlots.append() = plot;
79        }
80
81        // remove reference to 'plot'
82        void removePlot(const Plot* plot) {
83            int index = fPlots.find(const_cast<Plot*>(plot));
84            if (index >= 0) {
85                fPlots.remove(index);
86            }
87        }
88
89#ifdef SK_DEBUG
90        bool contains(const Plot* plot) const {
91            return fPlots.contains(const_cast<Plot*>(plot));
92        }
93#endif
94
95    private:
96        SkTDArray<Plot*> fPlots;
97        SkDEBUGCODE(int fMaxPlots;)
98    };
99
100    GrLayerAtlas(GrTextureProvider*, GrPixelConfig, GrSurfaceFlags flags,
101                 const SkISize& backingTextureSize,
102                 int numPlotsX, int numPlotsY);
103    ~GrLayerAtlas();
104
105    // Requests a width x height block in the atlas. Upon success it returns
106    // the containing Plot and absolute location in the backing texture.
107    // nullptr is returned if there is no more space in the atlas.
108    Plot* addToAtlas(ClientPlotUsage*, int width, int height, SkIPoint16* loc);
109
110    GrTexture* getTextureOrNull() const {
111        return fTexture;
112    }
113
114    GrTexture* getTexture() const {
115        SkASSERT(fTexture);
116        return fTexture;
117    }
118
119    bool reattachBackingTexture();
120
121    void detachBackingTexture() {
122        fTexture.reset(nullptr);
123    }
124
125    void resetPlots();
126
127    enum IterOrder {
128        kLRUFirst_IterOrder,
129        kMRUFirst_IterOrder
130    };
131
132    typedef SkTInternalLList<Plot> PlotList;
133    typedef PlotList::Iter PlotIter;
134    Plot* iterInit(PlotIter* iter, IterOrder order) {
135        return iter->init(fPlotList, kLRUFirst_IterOrder == order
136                                                       ? PlotList::Iter::kTail_IterStart
137                                                       : PlotList::Iter::kHead_IterStart);
138    }
139
140private:
141    void createBackingTexture();
142
143    void makeMRU(Plot* plot);
144
145    GrTextureProvider* fTexProvider;
146    GrPixelConfig      fPixelConfig;
147    GrSurfaceFlags     fFlags;
148    SkAutoTUnref<GrTexture> fTexture;
149
150    SkISize            fBackingTextureSize;
151
152    // allocated array of Plots
153    Plot*              fPlotArray;
154    // LRU list of Plots (MRU at head - LRU at tail)
155    PlotList           fPlotList;
156};
157
158#endif
159