Flutter Engine
The Flutter Engine
ResourceKey.h
Go to the documentation of this file.
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"
19
20#include <cstdint>
21#include <cstring>
22#include <new>
23#include <utility>
24
25class TestResource;
26
27namespace skgpu {
28
29uint32_t ResourceKeyHash(const uint32_t* data, size_t size);
30
31/**
32 * Base class for all gpu Resource cache keys. There are two types of cache keys. Refer to the
33 * comments for each key type below.
34 */
36public:
37 uint32_t hash() const {
38 this->validate();
39 return fKey[kHash_MetaDataIdx];
40 }
41
42 size_t size() const {
43 this->validate();
44 SkASSERT(this->isValid());
45 return this->internalSize();
46 }
47
48 /** Reset to an invalid key. */
49 void reset() {
50 fKey.reset(kMetaDataCnt);
51 fKey[kHash_MetaDataIdx] = 0;
52 fKey[kDomainAndSize_MetaDataIdx] = kInvalidDomain;
53 }
54
55 bool isValid() const { return kInvalidDomain != this->domain(); }
56
57 /** Used to initialize a key. */
58 class Builder {
59 public:
60 ~Builder() { this->finish(); }
61
62 void finish() {
63 if (nullptr == fKey) {
64 return;
65 }
66 uint32_t* hash = &fKey->fKey[kHash_MetaDataIdx];
67 *hash = ResourceKeyHash(hash + 1, fKey->internalSize() - sizeof(uint32_t));
68 fKey->validate();
69 fKey = nullptr;
70 }
71
72 uint32_t& operator[](int dataIdx) {
73 SkASSERT(fKey);
74 SkDEBUGCODE(size_t dataCount = fKey->internalSize() / sizeof(uint32_t) - kMetaDataCnt;)
75 SkASSERT(SkToU32(dataIdx) < dataCount);
76 return fKey->fKey[(int)kMetaDataCnt + dataIdx];
77 }
78
79 protected:
80 Builder(ResourceKey* key, uint32_t domain, int data32Count) : fKey(key) {
81 size_t count = SkToSizeT(data32Count);
83 key->fKey.reset(kMetaDataCnt + count);
84 size_t size = (count + kMetaDataCnt) * sizeof(uint32_t);
87 key->fKey[kDomainAndSize_MetaDataIdx] = SkToU32(domain | (size << 16));
88 }
89
90 private:
91 ResourceKey* fKey;
92 };
93
94protected:
95 static const uint32_t kInvalidDomain = 0;
96
97 ResourceKey() { this->reset(); }
98
99 bool operator==(const ResourceKey& that) const {
100 // Both keys should be sized to at least contain the meta data. The metadata contains each
101 // key's length. So the second memcmp should only run if the keys have the same length.
102 return 0 == memcmp(fKey.get(), that.fKey.get(), kMetaDataCnt*sizeof(uint32_t)) &&
103 0 == memcmp(&fKey[kMetaDataCnt], &that.fKey[kMetaDataCnt], this->dataSize());
104 }
105
107 if (this != &that) {
108 if (!that.isValid()) {
109 this->reset();
110 } else {
111 size_t bytes = that.size();
112 SkASSERT(SkIsAlign4(bytes));
113 fKey.reset(bytes / sizeof(uint32_t));
114 memcpy(fKey.get(), that.fKey.get(), bytes);
115 this->validate();
116 }
117 }
118 return *this;
119 }
120
121 uint32_t domain() const { return fKey[kDomainAndSize_MetaDataIdx] & 0xffff; }
122
123 /** size of the key data, excluding meta-data (hash, domain, etc). */
124 size_t dataSize() const { return this->size() - 4 * kMetaDataCnt; }
125
126 /** ptr to the key data, excluding meta-data (hash, domain, etc). */
127 const uint32_t* data() const {
128 this->validate();
129 return &fKey[kMetaDataCnt];
130 }
131
132#ifdef SK_DEBUG
133 void dump() const {
134 if (!this->isValid()) {
135 SkDebugf("Invalid Key\n");
136 } else {
137 SkDebugf("hash: %u ", this->hash());
138 SkDebugf("domain: %u ", this->domain());
139 SkDebugf("size: %zuB ", this->internalSize());
140 size_t dataCount = this->internalSize() / sizeof(uint32_t) - kMetaDataCnt;
141 for (size_t i = 0; i < dataCount; ++i) {
142 SkDebugf("%u ", fKey[SkTo<int>(kMetaDataCnt+i)]);
143 }
144 SkDebugf("\n");
145 }
146 }
147#endif
148
149private:
150 enum MetaDataIdx {
151 kHash_MetaDataIdx,
152 // The key domain and size are packed into a single uint32_t.
153 kDomainAndSize_MetaDataIdx,
154
155 kLastMetaDataIdx = kDomainAndSize_MetaDataIdx
156 };
157 static const uint32_t kMetaDataCnt = kLastMetaDataIdx + 1;
158
159 size_t internalSize() const { return fKey[kDomainAndSize_MetaDataIdx] >> 16; }
160
161 void validate() const {
162 SkASSERT(this->isValid());
163 SkASSERT(fKey[kHash_MetaDataIdx] ==
164 ResourceKeyHash(&fKey[kHash_MetaDataIdx] + 1,
165 this->internalSize() - sizeof(uint32_t)));
166 SkASSERT(SkIsAlign4(this->internalSize()));
167 }
168
169 friend class ::TestResource; // For unit test to access kMetaDataCnt.
170
171 // For Ganesh, bmp textures require 5 uint32_t values. Graphite requires 6 (due to
172 // storing mipmap status as part of the key).
174};
175
176/**
177 * A key used for scratch resources. There are three important rules about scratch keys:
178 * * Multiple resources can share the same scratch key. Therefore resources assigned the same
179 * scratch key should be interchangeable with respect to the code that uses them.
180 * * A resource can have at most one scratch key and it is set at resource creation by the
181 * resource itself.
182 * * When a scratch resource is ref'ed it will not be returned from the
183 * cache for a subsequent cache request until all refs are released. This facilitates using
184 * a scratch key for multiple render-to-texture scenarios. An example is a separable blur:
185 *
186 * GrTexture* texture[2];
187 * texture[0] = get_scratch_texture(scratchKey);
188 * texture[1] = get_scratch_texture(scratchKey); // texture[0] is already owned so we will get a
189 * // different one for texture[1]
190 * draw_mask(texture[0], path); // draws path mask to texture[0]
191 * blur_x(texture[0], texture[1]); // blurs texture[0] in y and stores result in texture[1]
192 * blur_y(texture[1], texture[0]); // blurs texture[1] in y and stores result in texture[0]
193 * texture[1]->unref(); // texture 1 can now be recycled for the next request with scratchKey
194 * consume_blur(texture[0]);
195 * texture[0]->unref(); // texture 0 can now be recycled for the next request with scratchKey
196 */
197class ScratchKey : public ResourceKey {
198public:
199 /** Uniquely identifies the type of resource that is cached as scratch. */
200 typedef uint32_t ResourceType;
201
202 /** Generate a unique ResourceType. */
204
205 /** Creates an invalid scratch key. It must be initialized using a Builder object before use. */
207
208 ScratchKey(const ScratchKey& that) { *this = that; }
209
210 ResourceType resourceType() const { return this->domain(); }
211
213 this->ResourceKey::operator=(that);
214 return *this;
215 }
216
217 bool operator==(const ScratchKey& that) const { return this->ResourceKey::operator==(that); }
218 bool operator!=(const ScratchKey& that) const { return !(*this == that); }
219
221 public:
223 : ResourceKey::Builder(key, type, data32Count) {}
224 };
225};
226
227/**
228 * A key that allows for exclusive use of a resource for a use case (AKA "domain"). There are three
229 * rules governing the use of unique keys:
230 * * Only one resource can have a given unique key at a time. Hence, "unique".
231 * * A resource can have at most one unique key at a time.
232 * * Unlike scratch keys, multiple requests for a unique key will return the same
233 * resource even if the resource already has refs.
234 * This key type allows a code path to create cached resources for which it is the exclusive user.
235 * The code path creates a domain which it sets on its keys. This guarantees that there are no
236 * cross-domain collisions.
237 *
238 * Unique keys preempt scratch keys. While a resource has a unique key it is inaccessible via its
239 * scratch key. It can become scratch again if the unique key is removed.
240 */
241class UniqueKey : public ResourceKey {
242public:
243 typedef uint32_t Domain;
244 /** Generate a Domain for unique keys. */
245 static Domain GenerateDomain();
246
247 /** Creates an invalid unique key. It must be initialized using a Builder object before use. */
248 UniqueKey() : fTag(nullptr) {}
249
250 UniqueKey(const UniqueKey& that) { *this = that; }
251
253 this->ResourceKey::operator=(that);
255 fTag = that.fTag;
256 return *this;
257 }
258
259 bool operator==(const UniqueKey& that) const { return this->ResourceKey::operator==(that); }
260 bool operator!=(const UniqueKey& that) const { return !(*this == that); }
261
262 void setCustomData(sk_sp<SkData> data) { fData = std::move(data); }
263 SkData* getCustomData() const { return fData.get(); }
264 sk_sp<SkData> refCustomData() const { return fData; }
265
266 const char* tag() const { return fTag; }
267
268 const uint32_t* data() const { return this->ResourceKey::data(); }
269
270#ifdef SK_DEBUG
271 uint32_t domain() const { return this->ResourceKey::domain(); }
272 size_t dataSize() const { return this->ResourceKey::dataSize(); }
273
274 void dump(const char* label) const {
275 SkDebugf("%s tag: %s\n", label, fTag ? fTag : "None");
276 this->ResourceKey::dump();
277 }
278#endif
279
281 public:
282 Builder(UniqueKey* key, Domain type, int data32Count, const char* tag = nullptr)
283 : ResourceKey::Builder(key, type, data32Count) {
284 key->fTag = tag;
285 }
286
287 /** Used to build a key that wraps another key and adds additional data. */
288 Builder(UniqueKey* key, const UniqueKey& innerKey, Domain domain, int extraData32Cnt,
289 const char* tag = nullptr)
291 domain,
292 Data32CntForInnerKey(innerKey) + extraData32Cnt) {
293 SkASSERT(&innerKey != key);
294 // add the inner key to the end of the key so that op[] can be indexed normally.
295 uint32_t* innerKeyData = &this->operator[](extraData32Cnt);
296 const uint32_t* srcData = innerKey.data();
297 (*innerKeyData++) = innerKey.domain();
298 memcpy(innerKeyData, srcData, innerKey.dataSize());
299 key->fTag = tag;
300 }
301
302 private:
303 static int Data32CntForInnerKey(const UniqueKey& innerKey) {
304 // key data + domain
305 return SkToInt((innerKey.dataSize() >> 2) + 1);
306 }
307 };
308
309private:
310 sk_sp<SkData> fData;
311 const char* fTag;
312};
313
314/**
315 * It is common to need a frequently reused UniqueKey where the only requirement is that the key
316 * is unique. These macros create such a key in a thread safe manner so the key can be truly global
317 * and only constructed once.
318 */
319
320/** Place outside of function/class definitions. */
321#define SKGPU_DECLARE_STATIC_UNIQUE_KEY(name) static SkOnce name##_once
322
323/** Place inside function where the key is used. */
324#define SKGPU_DEFINE_STATIC_UNIQUE_KEY(name) \
325 static SkAlignedSTStorage<1, skgpu::UniqueKey> name##_storage; \
326 name##_once(skgpu::skgpu_init_static_unique_key_once, &name##_storage); \
327 static const skgpu::UniqueKey& name = \
328 *reinterpret_cast<skgpu::UniqueKey*>(name##_storage.get())
329
331 UniqueKey* key = new (keyStorage->get()) UniqueKey;
333}
334
335// The cache listens for these messages to purge junk resources proactively.
337public:
340 uint32_t contextUniqueID,
341 bool inThreadSafeCache = false)
342 : fKey(key), fContextID(contextUniqueID), fInThreadSafeCache(inThreadSafeCache) {
343 SkASSERT(SK_InvalidUniqueID != contextUniqueID);
344 }
345
347
349
350 const UniqueKey& key() const { return fKey; }
351 uint32_t contextID() const { return fContextID; }
352 bool inThreadSafeCache() const { return fInThreadSafeCache; }
353
354private:
355 UniqueKey fKey;
356 uint32_t fContextID = SK_InvalidUniqueID;
357 bool fInThreadSafeCache = false;
358};
359
361 uint32_t msgBusUniqueID) {
362 return msg.contextID() == msgBusUniqueID;
363}
364
366public:
369 : fKey(key), fRecorderID(recorderID) {
370 SkASSERT(SK_InvalidUniqueID != fRecorderID);
371 }
372
374
376
377 const UniqueKey& key() const { return fKey; }
378 uint32_t recorderID() const { return fRecorderID; }
379
380private:
381 UniqueKey fKey;
382 uint32_t fRecorderID = SK_InvalidUniqueID;
383};
384
386 uint32_t msgBusUniqueID) {
387 return msg.recorderID() == msgBusUniqueID;
388}
389
390} // namespace skgpu
391
392#endif // skgpu_ResourceKey_DEFINED
int count
Definition: FontMgrTest.cpp:50
static constexpr bool SkIsAlign4(T x)
Definition: SkAlign.h:20
#define SkASSERT(cond)
Definition: SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
constexpr size_t SkToSizeT(S x)
Definition: SkTo.h:31
constexpr uint16_t SkToU16(S x)
Definition: SkTo.h:24
constexpr int SkToInt(S x)
Definition: SkTo.h:29
constexpr uint32_t SkToU32(S x)
Definition: SkTo.h:26
static constexpr uint32_t SK_InvalidUniqueID
Definition: SkTypes.h:196
static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv)
Definition: SkYUVMath.cpp:629
GLenum type
Definition: SkData.h:25
T * get() const
Definition: SkRefCnt.h:303
uint32_t & operator[](int dataIdx)
Definition: ResourceKey.h:72
Builder(ResourceKey *key, uint32_t domain, int data32Count)
Definition: ResourceKey.h:80
size_t size() const
Definition: ResourceKey.h:42
bool isValid() const
Definition: ResourceKey.h:55
static const uint32_t kInvalidDomain
Definition: ResourceKey.h:95
const uint32_t * data() const
Definition: ResourceKey.h:127
ResourceKey & operator=(const ResourceKey &that)
Definition: ResourceKey.h:106
uint32_t domain() const
Definition: ResourceKey.h:121
bool operator==(const ResourceKey &that) const
Definition: ResourceKey.h:99
uint32_t hash() const
Definition: ResourceKey.h:37
size_t dataSize() const
Definition: ResourceKey.h:124
Builder(ScratchKey *key, ResourceType type, int data32Count)
Definition: ResourceKey.h:222
static ResourceType GenerateResourceType()
Definition: ResourceKey.cpp:16
uint32_t ResourceType
Definition: ResourceKey.h:200
ResourceType resourceType() const
Definition: ResourceKey.h:210
bool operator==(const ScratchKey &that) const
Definition: ResourceKey.h:217
ScratchKey(const ScratchKey &that)
Definition: ResourceKey.h:208
bool operator!=(const ScratchKey &that) const
Definition: ResourceKey.h:218
ScratchKey & operator=(const ScratchKey &that)
Definition: ResourceKey.h:212
const UniqueKey & key() const
Definition: ResourceKey.h:350
UniqueKeyInvalidatedMessage & operator=(const UniqueKeyInvalidatedMessage &)=default
UniqueKeyInvalidatedMessage(const UniqueKeyInvalidatedMessage &)=default
UniqueKeyInvalidatedMessage(const UniqueKey &key, uint32_t contextUniqueID, bool inThreadSafeCache=false)
Definition: ResourceKey.h:339
UniqueKeyInvalidatedMsg_Graphite(const UniqueKey &key, uint32_t recorderID)
Definition: ResourceKey.h:368
const UniqueKey & key() const
Definition: ResourceKey.h:377
UniqueKeyInvalidatedMsg_Graphite & operator=(const UniqueKeyInvalidatedMsg_Graphite &)=default
UniqueKeyInvalidatedMsg_Graphite(const UniqueKeyInvalidatedMsg_Graphite &)=default
Builder(UniqueKey *key, Domain type, int data32Count, const char *tag=nullptr)
Definition: ResourceKey.h:282
Builder(UniqueKey *key, const UniqueKey &innerKey, Domain domain, int extraData32Cnt, const char *tag=nullptr)
Definition: ResourceKey.h:288
static Domain GenerateDomain()
Definition: ResourceKey.cpp:27
UniqueKey & operator=(const UniqueKey &that)
Definition: ResourceKey.h:252
sk_sp< SkData > refCustomData() const
Definition: ResourceKey.h:264
const uint32_t * data() const
Definition: ResourceKey.h:268
SkData * getCustomData() const
Definition: ResourceKey.h:263
const char * tag() const
Definition: ResourceKey.h:266
void setCustomData(sk_sp< SkData > data)
Definition: ResourceKey.h:262
UniqueKey(const UniqueKey &that)
Definition: ResourceKey.h:250
bool operator!=(const UniqueKey &that) const
Definition: ResourceKey.h:260
bool operator==(const UniqueKey &that) const
Definition: ResourceKey.h:259
T * reset(size_t count)
Definition: SkTemplates.h:356
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: GpuTools.h:21
static bool SkShouldPostMessageToBus(const UniqueKeyInvalidatedMessage &msg, uint32_t msgBusUniqueID)
Definition: ResourceKey.h:360
static void skgpu_init_static_unique_key_once(SkAlignedSTStorage< 1, UniqueKey > *keyStorage)
Definition: ResourceKey.h:330
uint32_t ResourceKeyHash(const uint32_t *data, size_t size)
Definition: ResourceKey.cpp:38
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63