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