aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrLayerAtlas.h
blob: e84667b5ea02cec6b8ca4e2cb9b75c84a896da24 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

/*
 * Copyright 2010 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef GrLayerAtlas_DEFINED
#define GrLayerAtlas_DEFINED

#include "GrTexture.h"

#include "SkPoint.h"
#include "SkTDArray.h"
#include "SkTInternalLList.h"

class GrLayerAtlas;
class GrTextureProvider;
class GrRectanizer;

// The backing GrTexture for a GrLayerAtlas is broken into a spatial grid of Plots. When
// the atlas needs space on the texture (i.e., in response to an addToAtlas call), it 
// iterates through the plots in use by the requesting client looking for space and, 
// if no space is found, opens up a new Plot for that client. The Plots keep track of 
// subimage placement via their GrRectanizer. 
//
// If all Plots are full, the replacement strategy is up to the client. The Plot::reset
// call will remove a Plot's knowledge of any allocated rects - freeing its space for reuse.

class GrLayerAtlas {
public:
    class Plot {
        SK_DECLARE_INTERNAL_LLIST_INTERFACE(Plot); // In an MRU llist

    public:
        // This returns a plot ID unique to each plot in the atlas. They are
        // consecutive and start at 0.
        int id() const { return fID; }

        void reset();

    private:
        friend class GrLayerAtlas;

        Plot();
        ~Plot(); // does not try to delete the fNext field

        void init(int id, int offX, int offY, int width, int height);

        bool allocateRect(int width, int height, SkIPoint16*);

        int                     fID;
        GrRectanizer*           fRects;
        SkIPoint16              fOffset;        // the offset of the plot in the backing texture
    };

    // This class allows each client to independently track the Plots in
    // which its data is stored.
    // For example, multiple pictures may simultaneously store their layers in the 
    // layer atlas. When a picture goes away it can use the ClientPlotUsage to remove itself
    // from those plots.
    class ClientPlotUsage {
    public:
        ClientPlotUsage(int maxPlots)
            SkDEBUGCODE(: fMaxPlots(maxPlots)) {
            fPlots.setReserve(maxPlots);
        }

        bool isEmpty() const { return 0 == fPlots.count(); }

        int numPlots() const { return fPlots.count(); }
        Plot* plot(int index) { return fPlots[index]; }

        void appendPlot(Plot* plot) {
            SkASSERT(fPlots.count() <= fMaxPlots);
            SkASSERT(!fPlots.contains(plot));
            *fPlots.append() = plot;
        }

        // remove reference to 'plot'
        void removePlot(const Plot* plot) {
            int index = fPlots.find(const_cast<Plot*>(plot));
            if (index >= 0) {
                fPlots.remove(index);
            }
        }

#ifdef SK_DEBUG
        bool contains(const Plot* plot) const { 
            return fPlots.contains(const_cast<Plot*>(plot)); 
        }
#endif

    private:
        SkTDArray<Plot*> fPlots;
        SkDEBUGCODE(int fMaxPlots;)
    };

    GrLayerAtlas(GrTextureProvider*, GrPixelConfig, GrSurfaceFlags flags, 
                 const SkISize& backingTextureSize,
                 int numPlotsX, int numPlotsY);
    ~GrLayerAtlas();

    // Requests a width x height block in the atlas. Upon success it returns 
    // the containing Plot and absolute location in the backing texture. 
    // nullptr is returned if there is no more space in the atlas.
    Plot* addToAtlas(ClientPlotUsage*, int width, int height, SkIPoint16* loc);

    GrTexture* getTextureOrNull() const {
        return fTexture;
    }

    GrTexture* getTexture() const {
        SkASSERT(fTexture);
        return fTexture;
    }

    bool reattachBackingTexture();

    void detachBackingTexture() {
        fTexture.reset(nullptr);
    }

    void resetPlots();

    enum IterOrder {
        kLRUFirst_IterOrder,
        kMRUFirst_IterOrder
    };

    typedef SkTInternalLList<Plot> PlotList;
    typedef PlotList::Iter PlotIter;
    Plot* iterInit(PlotIter* iter, IterOrder order) {
        return iter->init(fPlotList, kLRUFirst_IterOrder == order
                                                       ? PlotList::Iter::kTail_IterStart
                                                       : PlotList::Iter::kHead_IterStart);
    }

private:
    void createBackingTexture();

    void makeMRU(Plot* plot);

    GrTextureProvider* fTexProvider;
    GrPixelConfig      fPixelConfig;
    GrSurfaceFlags     fFlags;
    SkAutoTUnref<GrTexture> fTexture;

    SkISize            fBackingTextureSize;

    // allocated array of Plots
    Plot*              fPlotArray;
    // LRU list of Plots (MRU at head - LRU at tail)
    PlotList           fPlotList;
};

#endif