Line data Source code
1 :
2 : /*
3 : * Copyright 2014 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 GrResourceKey_DEFINED
10 : #define GrResourceKey_DEFINED
11 :
12 : #include "../private/SkOnce.h"
13 : #include "../private/SkTemplates.h"
14 : #include "GrTypes.h"
15 : #include "SkData.h"
16 : #include "SkString.h"
17 :
18 : uint32_t GrResourceKeyHash(const uint32_t* data, size_t size);
19 :
20 : /**
21 : * Base class for all GrGpuResource cache keys. There are two types of cache keys. Refer to the
22 : * comments for each key type below.
23 : */
24 0 : class GrResourceKey {
25 : public:
26 0 : uint32_t hash() const {
27 0 : this->validate();
28 0 : return fKey[kHash_MetaDataIdx];
29 : }
30 :
31 0 : size_t size() const {
32 0 : this->validate();
33 0 : SkASSERT(this->isValid());
34 0 : return this->internalSize();
35 : }
36 :
37 : protected:
38 : static const uint32_t kInvalidDomain = 0;
39 :
40 0 : GrResourceKey() { this->reset(); }
41 :
42 : /** Reset to an invalid key. */
43 0 : void reset() {
44 : GR_STATIC_ASSERT((uint16_t)kInvalidDomain == kInvalidDomain);
45 0 : fKey.reset(kMetaDataCnt);
46 0 : fKey[kHash_MetaDataIdx] = 0;
47 0 : fKey[kDomainAndSize_MetaDataIdx] = kInvalidDomain;
48 0 : }
49 :
50 0 : bool operator==(const GrResourceKey& that) const {
51 0 : return this->hash() == that.hash() &&
52 0 : 0 == memcmp(&fKey[kHash_MetaDataIdx + 1],
53 0 : &that.fKey[kHash_MetaDataIdx + 1],
54 0 : this->internalSize() - sizeof(uint32_t));
55 : }
56 :
57 0 : GrResourceKey& operator=(const GrResourceKey& that) {
58 0 : SkASSERT(that.isValid());
59 0 : if (this != &that) {
60 0 : size_t bytes = that.size();
61 0 : SkASSERT(SkIsAlign4(bytes));
62 0 : fKey.reset(SkToInt(bytes / sizeof(uint32_t)));
63 0 : memcpy(fKey.get(), that.fKey.get(), bytes);
64 0 : this->validate();
65 : }
66 0 : return *this;
67 : }
68 :
69 0 : bool isValid() const { return kInvalidDomain != this->domain(); }
70 :
71 0 : uint32_t domain() const { return fKey[kDomainAndSize_MetaDataIdx] & 0xffff; }
72 :
73 : /** size of the key data, excluding meta-data (hash, domain, etc). */
74 0 : size_t dataSize() const { return this->size() - 4 * kMetaDataCnt; }
75 :
76 : /** ptr to the key data, excluding meta-data (hash, domain, etc). */
77 0 : const uint32_t* data() const {
78 0 : this->validate();
79 0 : return &fKey[kMetaDataCnt];
80 : }
81 :
82 : /** Used to initialize a key. */
83 : class Builder {
84 : public:
85 0 : Builder(GrResourceKey* key, uint32_t domain, int data32Count) : fKey(key) {
86 0 : SkASSERT(data32Count >= 0);
87 0 : SkASSERT(domain != kInvalidDomain);
88 0 : key->fKey.reset(kMetaDataCnt + data32Count);
89 0 : int size = (data32Count + kMetaDataCnt) * sizeof(uint32_t);
90 0 : SkASSERT(SkToU16(size) == size);
91 0 : SkASSERT(SkToU16(domain) == domain);
92 0 : key->fKey[kDomainAndSize_MetaDataIdx] = domain | (size << 16);
93 0 : }
94 :
95 0 : ~Builder() { this->finish(); }
96 :
97 0 : void finish() {
98 0 : if (NULL == fKey) {
99 0 : return;
100 : }
101 : GR_STATIC_ASSERT(0 == kHash_MetaDataIdx);
102 0 : uint32_t* hash = &fKey->fKey[kHash_MetaDataIdx];
103 0 : *hash = GrResourceKeyHash(hash + 1, fKey->internalSize() - sizeof(uint32_t));
104 0 : fKey->validate();
105 0 : fKey = NULL;
106 : }
107 :
108 0 : uint32_t& operator[](int dataIdx) {
109 0 : SkASSERT(fKey);
110 0 : SkDEBUGCODE(size_t dataCount = fKey->internalSize() / sizeof(uint32_t) - kMetaDataCnt;)
111 0 : SkASSERT(SkToU32(dataIdx) < dataCount);
112 0 : return fKey->fKey[kMetaDataCnt + dataIdx];
113 : }
114 :
115 : private:
116 : GrResourceKey* fKey;
117 : };
118 :
119 : private:
120 : enum MetaDataIdx {
121 : kHash_MetaDataIdx,
122 : // The key domain and size are packed into a single uint32_t.
123 : kDomainAndSize_MetaDataIdx,
124 :
125 : kLastMetaDataIdx = kDomainAndSize_MetaDataIdx
126 : };
127 : static const uint32_t kMetaDataCnt = kLastMetaDataIdx + 1;
128 :
129 0 : size_t internalSize() const {
130 0 : return fKey[kDomainAndSize_MetaDataIdx] >> 16;
131 : }
132 :
133 0 : void validate() const {
134 0 : SkASSERT(fKey[kHash_MetaDataIdx] ==
135 : GrResourceKeyHash(&fKey[kHash_MetaDataIdx] + 1,
136 : this->internalSize() - sizeof(uint32_t)));
137 0 : SkASSERT(SkIsAlign4(this->internalSize()));
138 0 : }
139 :
140 : friend class TestResource; // For unit test to access kMetaDataCnt.
141 :
142 : // bmp textures require 7 uint32_t values (5 for the base key, and two more for image
143 : // cacherator's decode format.
144 : SkAutoSTMalloc<kMetaDataCnt + 7, uint32_t> fKey;
145 : };
146 :
147 : /**
148 : * A key used for scratch resources. There are three important rules about scratch keys:
149 : * * Multiple resources can share the same scratch key. Therefore resources assigned the same
150 : * scratch key should be interchangeable with respect to the code that uses them.
151 : * * A resource can have at most one scratch key and it is set at resource creation by the
152 : * resource itself.
153 : * * When a scratch resource is ref'ed it will not be returned from the
154 : * cache for a subsequent cache request until all refs are released. This facilitates using
155 : * a scratch key for multiple render-to-texture scenarios. An example is a separable blur:
156 : *
157 : * GrTexture* texture[2];
158 : * texture[0] = get_scratch_texture(scratchKey);
159 : * texture[1] = get_scratch_texture(scratchKey); // texture[0] is already owned so we will get a
160 : * // different one for texture[1]
161 : * draw_mask(texture[0], path); // draws path mask to texture[0]
162 : * blur_x(texture[0], texture[1]); // blurs texture[0] in y and stores result in texture[1]
163 : * blur_y(texture[1], texture[0]); // blurs texture[1] in y and stores result in texture[0]
164 : * texture[1]->unref(); // texture 1 can now be recycled for the next request with scratchKey
165 : * consume_blur(texture[0]);
166 : * texture[0]->unref(); // texture 0 can now be recycled for the next request with scratchKey
167 : */
168 0 : class GrScratchKey : public GrResourceKey {
169 : private:
170 : typedef GrResourceKey INHERITED;
171 :
172 : public:
173 : /** Uniquely identifies the type of resource that is cached as scratch. */
174 : typedef uint32_t ResourceType;
175 :
176 : /** Generate a unique ResourceType. */
177 : static ResourceType GenerateResourceType();
178 :
179 : /** Creates an invalid scratch key. It must be initialized using a Builder object before use. */
180 0 : GrScratchKey() {}
181 :
182 : GrScratchKey(const GrScratchKey& that) { *this = that; }
183 :
184 : /** reset() returns the key to the invalid state. */
185 : using INHERITED::reset;
186 :
187 : using INHERITED::isValid;
188 :
189 : ResourceType resourceType() const { return this->domain(); }
190 :
191 : GrScratchKey& operator=(const GrScratchKey& that) {
192 : this->INHERITED::operator=(that);
193 : return *this;
194 : }
195 :
196 0 : bool operator==(const GrScratchKey& that) const {
197 0 : return this->INHERITED::operator==(that);
198 : }
199 : bool operator!=(const GrScratchKey& that) const { return !(*this == that); }
200 :
201 0 : class Builder : public INHERITED::Builder {
202 : public:
203 0 : Builder(GrScratchKey* key, ResourceType type, int data32Count)
204 0 : : INHERITED::Builder(key, type, data32Count) {}
205 : };
206 : };
207 :
208 : /**
209 : * A key that allows for exclusive use of a resource for a use case (AKA "domain"). There are three
210 : * rules governing the use of unique keys:
211 : * * Only one resource can have a given unique key at a time. Hence, "unique".
212 : * * A resource can have at most one unique key at a time.
213 : * * Unlike scratch keys, multiple requests for a unique key will return the same
214 : * resource even if the resource already has refs.
215 : * This key type allows a code path to create cached resources for which it is the exclusive user.
216 : * The code path creates a domain which it sets on its keys. This guarantees that there are no
217 : * cross-domain collisions.
218 : *
219 : * Unique keys preempt scratch keys. While a resource has a unique key it is inaccessible via its
220 : * scratch key. It can become scratch again if the unique key is removed.
221 : */
222 0 : class GrUniqueKey : public GrResourceKey {
223 : private:
224 : typedef GrResourceKey INHERITED;
225 :
226 : public:
227 : typedef uint32_t Domain;
228 : /** Generate a Domain for unique keys. */
229 : static Domain GenerateDomain();
230 :
231 : /** Creates an invalid unique key. It must be initialized using a Builder object before use. */
232 0 : GrUniqueKey() {}
233 :
234 0 : GrUniqueKey(const GrUniqueKey& that) { *this = that; }
235 :
236 : /** reset() returns the key to the invalid state. */
237 : using INHERITED::reset;
238 :
239 : using INHERITED::isValid;
240 :
241 0 : GrUniqueKey& operator=(const GrUniqueKey& that) {
242 0 : this->INHERITED::operator=(that);
243 0 : this->setCustomData(sk_ref_sp(that.getCustomData()));
244 0 : SkDEBUGCODE(fTag = that.fTag;)
245 0 : return *this;
246 : }
247 :
248 0 : bool operator==(const GrUniqueKey& that) const {
249 0 : return this->INHERITED::operator==(that);
250 : }
251 : bool operator!=(const GrUniqueKey& that) const { return !(*this == that); }
252 :
253 0 : void setCustomData(sk_sp<SkData> data) {
254 0 : fData = std::move(data);
255 0 : }
256 0 : SkData* getCustomData() const {
257 0 : return fData.get();
258 : }
259 :
260 : SkDEBUGCODE(const char* tag() const { return fTag.c_str(); })
261 :
262 0 : class Builder : public INHERITED::Builder {
263 : public:
264 0 : Builder(GrUniqueKey* key, Domain type, int data32Count, const char* tag = nullptr)
265 0 : : INHERITED::Builder(key, type, data32Count) {
266 0 : SkDEBUGCODE(key->fTag = tag;)
267 : (void) tag; // suppress unused named param warning.
268 0 : }
269 :
270 : /** Used to build a key that wraps another key and adds additional data. */
271 0 : Builder(GrUniqueKey* key, const GrUniqueKey& innerKey, Domain domain, int extraData32Cnt,
272 : const char* tag = nullptr)
273 0 : : INHERITED::Builder(key, domain, Data32CntForInnerKey(innerKey) + extraData32Cnt) {
274 0 : SkASSERT(&innerKey != key);
275 : // add the inner key to the end of the key so that op[] can be indexed normally.
276 0 : uint32_t* innerKeyData = &this->operator[](extraData32Cnt);
277 0 : const uint32_t* srcData = innerKey.data();
278 0 : (*innerKeyData++) = innerKey.domain();
279 0 : memcpy(innerKeyData, srcData, innerKey.dataSize());
280 0 : SkDEBUGCODE(key->fTag = tag;)
281 : (void) tag; // suppress unused named param warning.
282 0 : }
283 :
284 : private:
285 0 : static int Data32CntForInnerKey(const GrUniqueKey& innerKey) {
286 : // key data + domain
287 0 : return SkToInt((innerKey.dataSize() >> 2) + 1);
288 : }
289 : };
290 :
291 : private:
292 : sk_sp<SkData> fData;
293 : SkDEBUGCODE(SkString fTag;)
294 : };
295 :
296 : /**
297 : * It is common to need a frequently reused GrUniqueKey where the only requirement is that the key
298 : * is unique. These macros create such a key in a thread safe manner so the key can be truly global
299 : * and only constructed once.
300 : */
301 :
302 : /** Place outside of function/class definitions. */
303 : #define GR_DECLARE_STATIC_UNIQUE_KEY(name) static SkOnce name##_once
304 :
305 : /** Place inside function where the key is used. */
306 : #define GR_DEFINE_STATIC_UNIQUE_KEY(name) \
307 : static SkAlignedSTStorage<1, GrUniqueKey> name##_storage; \
308 : name##_once(gr_init_static_unique_key_once, &name##_storage); \
309 : static const GrUniqueKey& name = *reinterpret_cast<GrUniqueKey*>(name##_storage.get());
310 :
311 0 : static inline void gr_init_static_unique_key_once(SkAlignedSTStorage<1,GrUniqueKey>* keyStorage) {
312 0 : GrUniqueKey* key = new (keyStorage->get()) GrUniqueKey;
313 0 : GrUniqueKey::Builder builder(key, GrUniqueKey::GenerateDomain(), 0);
314 0 : }
315 :
316 : // The cache listens for these messages to purge junk resources proactively.
317 0 : class GrUniqueKeyInvalidatedMessage {
318 : public:
319 0 : explicit GrUniqueKeyInvalidatedMessage(const GrUniqueKey& key) : fKey(key) {}
320 :
321 0 : GrUniqueKeyInvalidatedMessage(const GrUniqueKeyInvalidatedMessage& that) : fKey(that.fKey) {}
322 :
323 : GrUniqueKeyInvalidatedMessage& operator=(const GrUniqueKeyInvalidatedMessage& that) {
324 : fKey = that.fKey;
325 : return *this;
326 : }
327 :
328 0 : const GrUniqueKey& key() const { return fKey; }
329 :
330 : private:
331 : GrUniqueKey fKey;
332 : };
333 : #endif
|