aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrAtlas.h
blob: 1e91d1e90ee111833cf0c3a83fe0c71e4960dce3 (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

/*
 * 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 GrAtlas_DEFINED
#define GrAtlas_DEFINED


#include "GrTexture.h"
#include "GrDrawTarget.h"
#include "SkPoint.h"
#include "SkTInternalLList.h"

class GrGpu;
class GrRectanizer;
class GrAtlas;

// The backing GrTexture for a set of GrAtlases is broken into a spatial grid of GrPlots. When
// a GrAtlas needs space on the texture, it requests a GrPlot. Each GrAtlas can claim one
// or more GrPlots. The GrPlots keep track of subimage placement via their GrRectanizer. Once a
// GrPlot is "full" (i.e. there is no room for the new subimage according to the GrRectanizer), the
// GrAtlas can request a new GrPlot via GrAtlas::addToAtlas().
//
// If all GrPlots are allocated, the replacement strategy is up to the client. The drawToken is
// available to ensure that all draw calls are finished for that particular GrPlot.
// GrAtlas::removeUnusedPlots() will free up any finished plots for a given GrAtlas.

class GrPlot {
public:
    SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrPlot);

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

    GrTexture* texture() const { return fTexture; }

    bool addSubImage(int width, int height, const void*, SkIPoint16*);

    GrDrawTarget::DrawToken drawToken() const { return fDrawToken; }
    void setDrawToken(GrDrawTarget::DrawToken draw) { fDrawToken = draw; }

    void uploadToTexture();

    void resetRects();

private:
    GrPlot();
    ~GrPlot(); // does not try to delete the fNext field
    void init(GrAtlas* atlas, int id, int offX, int offY, int width, int height, size_t bpp,
              bool batchUploads);

    // for recycling
    GrDrawTarget::DrawToken fDrawToken;

    int                     fID;
    unsigned char*          fPlotData;
    GrTexture*              fTexture;
    GrRectanizer*           fRects;
    GrAtlas*                fAtlas;
    SkIPoint16              fOffset;        // the offset of the plot in the backing texture
    size_t                  fBytesPerPixel;
    SkIRect                 fDirtyRect;
    bool                    fDirty;
    bool                    fBatchUploads;

    friend class GrAtlas;
};

typedef SkTInternalLList<GrPlot> GrPlotList;

class GrAtlas {
public:
    // This class allows each client to independently track the GrPlots in
    // which its data is stored.
    class ClientPlotUsage {
    public:
        bool isEmpty() const { return 0 == fPlots.count(); }

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

    private:
        SkTDArray<GrPlot*> fPlots;

        friend class GrAtlas;
    };

    GrAtlas(GrGpu*, GrPixelConfig, GrTextureFlags flags, 
            const SkISize& backingTextureSize,
            int numPlotsX, int numPlotsY, bool batchUploads);
    ~GrAtlas();

    // Adds a width x height subimage to the atlas. Upon success it returns 
    // the containing GrPlot and absolute location in the backing texture. 
    // NULL is returned if the subimage cannot fit in the atlas.
    // If provided, the image data will either be immediately uploaded or
    // written to the CPU-side backing bitmap.
    GrPlot* addToAtlas(ClientPlotUsage*, int width, int height, const void* image, SkIPoint16* loc);

    // remove reference to this plot
    static void RemovePlot(ClientPlotUsage* usage, const GrPlot* plot);

    // get a plot that's not being used by the current draw
    // this allows us to overwrite this plot without flushing
    GrPlot* getUnusedPlot();

    GrTexture* getTexture() const {
        return fTexture;
    }

    void uploadPlotsToTexture();

    enum IterOrder {
        kLRUFirst_IterOrder,
        kMRUFirst_IterOrder
    };

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

private:
    void makeMRU(GrPlot* plot);

    GrGpu*         fGpu;
    GrPixelConfig  fPixelConfig;
    GrTextureFlags fFlags;
    GrTexture*     fTexture;
    SkISize        fBackingTextureSize;
    int            fNumPlotsX;
    int            fNumPlotsY;
    bool           fBatchUploads;

    // allocated array of GrPlots
    GrPlot*       fPlotArray;
    // LRU list of GrPlots (MRU at head - LRU at tail)
    GrPlotList    fPlotList;
};

#endif