Line data Source code
1 : /*
2 : * Copyright 2012 Google Inc.
3 : *
4 : * Use of this source code is governed by a BSD-style license that can be
5 : * found in the LICENSE file.
6 : */
7 :
8 : #ifndef GrTextureStripAtlas_DEFINED
9 : #define GrTextureStripAtlas_DEFINED
10 :
11 : #include "SkBitmap.h"
12 : #include "SkOpts.h"
13 : #include "SkGr.h"
14 : #include "SkTDArray.h"
15 : #include "SkTDynamicHash.h"
16 : #include "SkTypes.h"
17 :
18 : class GrSurfaceContext;
19 : class GrTextureProxy;
20 :
21 : /**
22 : * Maintains a single large texture whose rows store many textures of a small fixed height,
23 : * stored in rows across the x-axis such that we can safely wrap/repeat them horizontally.
24 : */
25 : class GrTextureStripAtlas {
26 : public:
27 : /**
28 : * Descriptor struct which we'll use as a hash table key
29 : **/
30 : struct Desc {
31 0 : Desc() { sk_bzero(this, sizeof(*this)); }
32 : GrContext* fContext;
33 : GrPixelConfig fConfig;
34 : uint16_t fWidth, fHeight, fRowHeight;
35 : uint16_t fUnusedPadding;
36 0 : bool operator==(const Desc& other) const {
37 0 : return 0 == memcmp(this, &other, sizeof(Desc));
38 : }
39 : };
40 :
41 : /**
42 : * Try to find an atlas with the required parameters, creates a new one if necessary
43 : */
44 : static GrTextureStripAtlas* GetAtlas(const Desc& desc);
45 :
46 : ~GrTextureStripAtlas();
47 :
48 : /**
49 : * Add a texture to the atlas
50 : * @param data Bitmap data to copy into the row
51 : * @return The row index we inserted into, or -1 if we failed to find an open row. The caller
52 : * is responsible for calling unlockRow() with this row index when it's done with it.
53 : */
54 : int lockRow(const SkBitmap& data);
55 : void unlockRow(int row);
56 :
57 : /**
58 : * These functions help turn an integer row index in [0, 1, 2, ... numRows] into a scalar y
59 : * texture coordinate in [0, 1] that we can use in a shader.
60 : *
61 : * If a regular texture access without using the atlas looks like:
62 : *
63 : * texture2D(sampler, vec2(x, y))
64 : *
65 : * Then when using the atlas we'd replace it with:
66 : *
67 : * texture2D(sampler, vec2(x, yOffset + y * scaleFactor))
68 : *
69 : * Where yOffset, returned by getYOffset(), is the offset to the start of the row within the
70 : * atlas and scaleFactor, returned by getNormalizedTexelHeight, is the normalized height of
71 : * one texel row.
72 : */
73 0 : SkScalar getYOffset(int row) const { return SkIntToScalar(row) / fNumRows; }
74 0 : SkScalar getNormalizedTexelHeight() const { return fNormalizedYHeight; }
75 :
76 : GrContext* getContext() const { return fDesc.fContext; }
77 :
78 : sk_sp<GrTextureProxy> asTextureProxyRef() const;
79 :
80 : private:
81 :
82 : // Key to indicate an atlas row without any meaningful data stored in it
83 : const static uint32_t kEmptyAtlasRowKey = 0xffffffff;
84 :
85 : /**
86 : * The state of a single row in our cache, next/prev pointers allow these to be chained
87 : * together to represent LRU status
88 : */
89 : struct AtlasRow : SkNoncopyable {
90 0 : AtlasRow() : fKey(kEmptyAtlasRowKey), fLocks(0), fNext(nullptr), fPrev(nullptr) { }
91 : // GenerationID of the bitmap that is represented by this row, 0xffffffff means "empty"
92 : uint32_t fKey;
93 : // How many times this has been locked (0 == unlocked)
94 : int32_t fLocks;
95 : // We maintain an LRU linked list between unlocked nodes with these pointers
96 : AtlasRow* fNext;
97 : AtlasRow* fPrev;
98 : };
99 :
100 : /**
101 : * We'll only allow construction via the static GrTextureStripAtlas::GetAtlas
102 : */
103 : GrTextureStripAtlas(Desc desc);
104 :
105 : void lockTexture();
106 : void unlockTexture();
107 :
108 : /**
109 : * Initialize our LRU list (if one already exists, clear it and start anew)
110 : */
111 : void initLRU();
112 :
113 : /**
114 : * Grabs the least recently used free row out of the LRU list, returns nullptr if no rows are free.
115 : */
116 : AtlasRow* getLRU();
117 :
118 : void appendLRU(AtlasRow* row);
119 : void removeFromLRU(AtlasRow* row);
120 :
121 : /**
122 : * Searches the key table for a key and returns the index if found; if not found, it returns
123 : * the bitwise not of the index at which we could insert the key to maintain a sorted list.
124 : **/
125 : int searchByKey(uint32_t key);
126 :
127 : /**
128 : * Compare two atlas rows by key, so we can sort/search by key
129 : */
130 0 : static bool KeyLess(const AtlasRow& lhs, const AtlasRow& rhs) {
131 0 : return lhs.fKey < rhs.fKey;
132 : }
133 :
134 : #ifdef SK_DEBUG
135 : void validate();
136 : #endif
137 :
138 : /**
139 : * Clean up callback registered with GrContext. Allows this class to
140 : * free up any allocated AtlasEntry and GrTextureStripAtlas objects
141 : */
142 : static void CleanUp(const GrContext* context, void* info);
143 :
144 : // Hash table entry for atlases
145 : class AtlasEntry : public ::SkNoncopyable {
146 : public:
147 : // for SkTDynamicHash
148 0 : static const Desc& GetKey(const AtlasEntry& entry) { return entry.fDesc; }
149 0 : static uint32_t Hash(const Desc& desc) { return SkOpts::hash(&desc, sizeof(Desc)); }
150 :
151 : // AtlasEntry proper
152 0 : AtlasEntry() : fAtlas(nullptr) {}
153 0 : ~AtlasEntry() { delete fAtlas; }
154 : Desc fDesc;
155 : GrTextureStripAtlas* fAtlas;
156 : };
157 :
158 : class Hash;
159 : static Hash* gAtlasCache;
160 :
161 : static Hash* GetCache();
162 :
163 : // We increment gCacheCount for each atlas
164 : static int32_t gCacheCount;
165 :
166 : // A unique ID for this texture (formed with: gCacheCount++), so we can be sure that if we
167 : // get a texture back from the texture cache, that it's the same one we last used.
168 : const int32_t fCacheKey;
169 :
170 : // Total locks on all rows (when this reaches zero, we can unlock our texture)
171 : int32_t fLockedRows;
172 :
173 : const Desc fDesc;
174 : const uint16_t fNumRows;
175 : sk_sp<GrSurfaceContext> fTexContext;
176 :
177 : SkScalar fNormalizedYHeight;
178 :
179 : // Array of AtlasRows which store the state of all our rows. Stored in a contiguous array, in
180 : // order that they appear in our texture, this means we can subtract this pointer from a row
181 : // pointer to get its index in the texture, and can save storing a row number in AtlasRow.
182 : AtlasRow* fRows;
183 :
184 : // Head and tail for linked list of least-recently-used rows (front = least recently used).
185 : // Note that when a texture is locked, it gets removed from this list until it is unlocked.
186 : AtlasRow* fLRUFront;
187 : AtlasRow* fLRUBack;
188 :
189 : // A list of pointers to AtlasRows that currently contain cached images, sorted by key
190 : SkTDArray<AtlasRow*> fKeyTable;
191 : };
192 :
193 : #endif
|