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