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