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