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