blob: aecdc70c0bdcc1b113a1454c018d39fef194aa57 [file] [log] [blame]
bsalomon744998e2014-08-28 09:54:34 -07001
2/*
3 * Copyright 2014 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#ifndef GrResourceKey_DEFINED
10#define GrResourceKey_DEFINED
11
12#include "GrTypes.h"
bsalomon7775c852014-12-30 12:50:52 -080013#include "SkTemplates.h"
bsalomon744998e2014-08-28 09:54:34 -070014
bsalomon24db3b12015-01-23 04:24:04 -080015uint32_t GrResourceKeyHash(const uint32_t* data, size_t size);
bsalomon7775c852014-12-30 12:50:52 -080016
bsalomon8718aaf2015-02-19 07:24:21 -080017/**
18 * Base class for all GrGpuResource cache keys. There are two types of cache keys. Refer to the
19 * comments for each key type below.
20 */
bsalomon24db3b12015-01-23 04:24:04 -080021class GrResourceKey {
22public:
23 uint32_t hash() const {
24 this->validate();
25 return fKey[kHash_MetaDataIdx];
26 }
27
28 size_t size() const {
29 this->validate();
bsalomon3bd12ef2015-01-28 11:39:48 -080030 SkASSERT(this->isValid());
bsalomon24db3b12015-01-23 04:24:04 -080031 return this->internalSize();
32 }
33
bsalomon24db3b12015-01-23 04:24:04 -080034protected:
35 static const uint32_t kInvalidDomain = 0;
36
37 GrResourceKey() { this->reset(); }
bsalomon7775c852014-12-30 12:50:52 -080038
39 /** Reset to an invalid key. */
40 void reset() {
bsalomon24db3b12015-01-23 04:24:04 -080041 GR_STATIC_ASSERT((uint16_t)kInvalidDomain == kInvalidDomain);
bsalomon7775c852014-12-30 12:50:52 -080042 fKey.reset(kMetaDataCnt);
43 fKey[kHash_MetaDataIdx] = 0;
bsalomon24db3b12015-01-23 04:24:04 -080044 fKey[kDomainAndSize_MetaDataIdx] = kInvalidDomain;
bsalomon7775c852014-12-30 12:50:52 -080045 }
46
bsalomon24db3b12015-01-23 04:24:04 -080047 bool operator==(const GrResourceKey& that) const {
48 return 0 == memcmp(fKey.get(), that.fKey.get(), this->size());
49 }
bsalomon7775c852014-12-30 12:50:52 -080050
bsalomon24db3b12015-01-23 04:24:04 -080051 GrResourceKey& operator=(const GrResourceKey& that) {
bsalomon23e619c2015-02-06 11:54:28 -080052 SkASSERT(that.isValid());
bsalomon4dffede2015-01-23 07:17:55 -080053 if (this != &that) {
54 size_t bytes = that.size();
55 SkASSERT(SkIsAlign4(bytes));
56 fKey.reset(SkToInt(bytes / sizeof(uint32_t)));
57 memcpy(fKey.get(), that.fKey.get(), bytes);
bsalomon23e619c2015-02-06 11:54:28 -080058 this->validate();
bsalomon4dffede2015-01-23 07:17:55 -080059 }
bsalomon7775c852014-12-30 12:50:52 -080060 return *this;
61 }
62
bsalomon24db3b12015-01-23 04:24:04 -080063 bool isValid() const { return kInvalidDomain != this->domain(); }
bsalomon7775c852014-12-30 12:50:52 -080064
bsalomon24db3b12015-01-23 04:24:04 -080065 uint32_t domain() const { return fKey[kDomainAndSize_MetaDataIdx] & 0xffff; }
66
bsalomon3bd12ef2015-01-28 11:39:48 -080067 /** size of the key data, excluding meta-data (hash, domain, etc). */
68 size_t dataSize() const { return this->size() - 4 * kMetaDataCnt; }
69
70 /** ptr to the key data, excluding meta-data (hash, domain, etc). */
71 const uint32_t* data() const {
72 this->validate();
73 return &fKey[kMetaDataCnt];
74 }
75
bsalomon24db3b12015-01-23 04:24:04 -080076 /** Used to initialize a key. */
bsalomon7775c852014-12-30 12:50:52 -080077 class Builder {
78 public:
bsalomon24db3b12015-01-23 04:24:04 -080079 Builder(GrResourceKey* key, uint32_t domain, int data32Count) : fKey(key) {
bsalomon7775c852014-12-30 12:50:52 -080080 SkASSERT(data32Count >= 0);
bsalomon24db3b12015-01-23 04:24:04 -080081 SkASSERT(domain != kInvalidDomain);
bsalomon7775c852014-12-30 12:50:52 -080082 key->fKey.reset(kMetaDataCnt + data32Count);
bsalomon7775c852014-12-30 12:50:52 -080083 int size = (data32Count + kMetaDataCnt) * sizeof(uint32_t);
bsalomon24db3b12015-01-23 04:24:04 -080084 SkASSERT(SkToU16(size) == size);
85 SkASSERT(SkToU16(domain) == domain);
86 key->fKey[kDomainAndSize_MetaDataIdx] = domain | (size << 16);
bsalomon7775c852014-12-30 12:50:52 -080087 }
88
89 ~Builder() { this->finish(); }
90
bsalomon24db3b12015-01-23 04:24:04 -080091 void finish() {
92 if (NULL == fKey) {
93 return;
94 }
95 GR_STATIC_ASSERT(0 == kHash_MetaDataIdx);
96 uint32_t* hash = &fKey->fKey[kHash_MetaDataIdx];
97 *hash = GrResourceKeyHash(hash + 1, fKey->internalSize() - sizeof(uint32_t));
98 fKey->validate();
99 fKey = NULL;
100 }
bsalomon7775c852014-12-30 12:50:52 -0800101
102 uint32_t& operator[](int dataIdx) {
103 SkASSERT(fKey);
bsalomon24db3b12015-01-23 04:24:04 -0800104 SkDEBUGCODE(size_t dataCount = fKey->internalSize() / sizeof(uint32_t) - kMetaDataCnt;)
bsalomon7775c852014-12-30 12:50:52 -0800105 SkASSERT(SkToU32(dataIdx) < dataCount);
106 return fKey->fKey[kMetaDataCnt + dataIdx];
107 }
108
109 private:
bsalomon24db3b12015-01-23 04:24:04 -0800110 GrResourceKey* fKey;
bsalomon7775c852014-12-30 12:50:52 -0800111 };
112
113private:
114 enum MetaDataIdx {
115 kHash_MetaDataIdx,
bsalomon24db3b12015-01-23 04:24:04 -0800116 // The key domain and size are packed into a single uint32_t.
117 kDomainAndSize_MetaDataIdx,
bsalomon7775c852014-12-30 12:50:52 -0800118
bsalomon24db3b12015-01-23 04:24:04 -0800119 kLastMetaDataIdx = kDomainAndSize_MetaDataIdx
bsalomon7775c852014-12-30 12:50:52 -0800120 };
bsalomon7775c852014-12-30 12:50:52 -0800121 static const uint32_t kMetaDataCnt = kLastMetaDataIdx + 1;
122
bsalomon3bd12ef2015-01-28 11:39:48 -0800123 size_t internalSize() const {
124 return fKey[kDomainAndSize_MetaDataIdx] >> 16;
125 }
126
127 void validate() const {
128 SkASSERT(fKey[kHash_MetaDataIdx] ==
129 GrResourceKeyHash(&fKey[kHash_MetaDataIdx] + 1,
130 this->internalSize() - sizeof(uint32_t)));
131 SkASSERT(SkIsAlign4(this->internalSize()));
132 }
133
bsalomon1c60dfe2015-01-21 09:32:40 -0800134 friend class TestResource; // For unit test to access kMetaDataCnt.
135
bsalomon24db3b12015-01-23 04:24:04 -0800136 // bmp textures require 4 uint32_t values.
bsalomon0aa94792015-02-18 11:33:04 -0800137 SkAutoSTMalloc<kMetaDataCnt + 4, uint32_t> fKey;
bsalomon7775c852014-12-30 12:50:52 -0800138};
139
bsalomon24db3b12015-01-23 04:24:04 -0800140/**
bsalomon8718aaf2015-02-19 07:24:21 -0800141 * A key used for scratch resources. There are three important rules about scratch keys:
142 * * Multiple resources can share the same scratch key. Therefore resources assigned the same
143 * scratch key should be interchangeable with respect to the code that uses them.
144 * * A resource can have at most one scratch key and it is set at resource creation by the
145 * resource itself.
146 * * When a scratch resource is ref'ed it will not be returned from the
147 * cache for a subsequent cache request until all refs are released. This facilitates using
148 * a scratch key for multiple render-to-texture scenarios. An example is a separable blur:
149 *
150 * GrTexture* texture[2];
151 * texture[0] = get_scratch_texture(scratchKey);
152 * texture[1] = get_scratch_texture(scratchKey); // texture[0] is already owned so we will get a
153 * // different one for texture[1]
154 * draw_mask(texture[0], path); // draws path mask to texture[0]
155 * blur_x(texture[0], texture[1]); // blurs texture[0] in y and stores result in texture[1]
156 * blur_y(texture[1], texture[0]); // blurs texture[1] in y and stores result in texture[0]
157 * texture[1]->unref(); // texture 1 can now be recycled for the next request with scratchKey
158 * consume_blur(texture[0]);
159 * texture[0]->unref(); // texture 0 can now be recycled for the next request with scratchKey
bsalomon24db3b12015-01-23 04:24:04 -0800160 */
161class GrScratchKey : public GrResourceKey {
bsalomon744998e2014-08-28 09:54:34 -0700162private:
bsalomon24db3b12015-01-23 04:24:04 -0800163 typedef GrResourceKey INHERITED;
bsalomon744998e2014-08-28 09:54:34 -0700164
bsalomon24db3b12015-01-23 04:24:04 -0800165public:
166 /** Uniquely identifies the type of resource that is cached as scratch. */
167 typedef uint32_t ResourceType;
bsalomon744998e2014-08-28 09:54:34 -0700168
bsalomon24db3b12015-01-23 04:24:04 -0800169 /** Generate a unique ResourceType. */
170 static ResourceType GenerateResourceType();
171
172 /** Creates an invalid scratch key. It must be initialized using a Builder object before use. */
173 GrScratchKey() {}
174
175 GrScratchKey(const GrScratchKey& that) { *this = that; }
176
177 /** reset() returns the key to the invalid state. */
178 using INHERITED::reset;
179
180 using INHERITED::isValid;
181
182 ResourceType resourceType() const { return this->domain(); }
183
184 GrScratchKey& operator=(const GrScratchKey& that) {
185 this->INHERITED::operator=(that);
186 return *this;
bsalomon744998e2014-08-28 09:54:34 -0700187 }
bsalomon24db3b12015-01-23 04:24:04 -0800188
189 bool operator==(const GrScratchKey& that) const {
190 return this->INHERITED::operator==(that);
191 }
192 bool operator!=(const GrScratchKey& that) const { return !(*this == that); }
193
194 class Builder : public INHERITED::Builder {
195 public:
196 Builder(GrScratchKey* key, ResourceType type, int data32Count)
197 : INHERITED::Builder(key, type, data32Count) {}
198 };
199};
200
201/**
bsalomon8718aaf2015-02-19 07:24:21 -0800202 * A key that allows for exclusive use of a resource for a use case (AKA "domain"). There are three
203 * rules governing the use of unique keys:
204 * * Only one resource can have a given unique key at a time. Hence, "unique".
205 * * A resource can have at most one unique key at a time.
206 * * Unlike scratch keys, multiple requests for a unique key will return the same
207 * resource even if the resource already has refs.
208 * This key type allows a code path to create cached resources for which it is the exclusive user.
209 * The code path creates a domain which it sets on its keys. This guarantees that there are no
210 * cross-domain collisions.
211 *
212 * Unique keys preempt scratch keys. While a resource has a unique key it is inaccessible via its
213 * scratch key. It can become scratch again if the unique key is removed.
bsalomon24db3b12015-01-23 04:24:04 -0800214 */
bsalomon8718aaf2015-02-19 07:24:21 -0800215class GrUniqueKey : public GrResourceKey {
bsalomon24db3b12015-01-23 04:24:04 -0800216private:
217 typedef GrResourceKey INHERITED;
218
219public:
220 typedef uint32_t Domain;
bsalomon8718aaf2015-02-19 07:24:21 -0800221 /** Generate a Domain for unique keys. */
bsalomon24db3b12015-01-23 04:24:04 -0800222 static Domain GenerateDomain();
223
bsalomon8718aaf2015-02-19 07:24:21 -0800224 /** Creates an invalid unique key. It must be initialized using a Builder object before use. */
225 GrUniqueKey() {}
bsalomon24db3b12015-01-23 04:24:04 -0800226
bsalomon8718aaf2015-02-19 07:24:21 -0800227 GrUniqueKey(const GrUniqueKey& that) { *this = that; }
bsalomon24db3b12015-01-23 04:24:04 -0800228
229 /** reset() returns the key to the invalid state. */
230 using INHERITED::reset;
231
232 using INHERITED::isValid;
233
bsalomon8718aaf2015-02-19 07:24:21 -0800234 GrUniqueKey& operator=(const GrUniqueKey& that) {
bsalomon24db3b12015-01-23 04:24:04 -0800235 this->INHERITED::operator=(that);
236 return *this;
237 }
238
bsalomon8718aaf2015-02-19 07:24:21 -0800239 bool operator==(const GrUniqueKey& that) const {
bsalomon24db3b12015-01-23 04:24:04 -0800240 return this->INHERITED::operator==(that);
241 }
bsalomon8718aaf2015-02-19 07:24:21 -0800242 bool operator!=(const GrUniqueKey& that) const { return !(*this == that); }
bsalomon24db3b12015-01-23 04:24:04 -0800243
244 class Builder : public INHERITED::Builder {
245 public:
bsalomon8718aaf2015-02-19 07:24:21 -0800246 Builder(GrUniqueKey* key, Domain domain, int data32Count)
bsalomon24db3b12015-01-23 04:24:04 -0800247 : INHERITED::Builder(key, domain, data32Count) {}
248
249 /** Used to build a key that wraps another key and adds additional data. */
bsalomon8718aaf2015-02-19 07:24:21 -0800250 Builder(GrUniqueKey* key, const GrUniqueKey& innerKey, Domain domain,
bsalomon24db3b12015-01-23 04:24:04 -0800251 int extraData32Cnt)
bsalomon3bd12ef2015-01-28 11:39:48 -0800252 : INHERITED::Builder(key, domain, Data32CntForInnerKey(innerKey) + extraData32Cnt) {
bsalomon37f9a262015-02-02 13:00:10 -0800253 SkASSERT(&innerKey != key);
bsalomon24db3b12015-01-23 04:24:04 -0800254 // add the inner key to the end of the key so that op[] can be indexed normally.
bsalomon3bd12ef2015-01-28 11:39:48 -0800255 uint32_t* innerKeyData = &this->operator[](extraData32Cnt);
256 const uint32_t* srcData = innerKey.data();
257 (*innerKeyData++) = innerKey.domain();
258 memcpy(innerKeyData, srcData, innerKey.dataSize());
259 }
260
261 private:
bsalomon8718aaf2015-02-19 07:24:21 -0800262 static int Data32CntForInnerKey(const GrUniqueKey& innerKey) {
bsalomon3bd12ef2015-01-28 11:39:48 -0800263 // key data + domain
264 return SkToInt((innerKey.dataSize() >> 2) + 1);
bsalomon24db3b12015-01-23 04:24:04 -0800265 }
266 };
bsalomon744998e2014-08-28 09:54:34 -0700267};
268
bsalomon23e619c2015-02-06 11:54:28 -0800269// The cache listens for these messages to purge junk resources proactively.
bsalomon8718aaf2015-02-19 07:24:21 -0800270class GrUniqueKeyInvalidatedMessage {
bsalomon23e619c2015-02-06 11:54:28 -0800271public:
bsalomon8718aaf2015-02-19 07:24:21 -0800272 explicit GrUniqueKeyInvalidatedMessage(const GrUniqueKey& key) : fKey(key) {}
273
274 GrUniqueKeyInvalidatedMessage(const GrUniqueKeyInvalidatedMessage& that) : fKey(that.fKey) {}
275
276 GrUniqueKeyInvalidatedMessage& operator=(const GrUniqueKeyInvalidatedMessage& that) {
bsalomon23e619c2015-02-06 11:54:28 -0800277 fKey = that.fKey;
278 return *this;
279 }
bsalomon8718aaf2015-02-19 07:24:21 -0800280
281 const GrUniqueKey& key() const { return fKey; }
282
bsalomon23e619c2015-02-06 11:54:28 -0800283private:
bsalomon8718aaf2015-02-19 07:24:21 -0800284 GrUniqueKey fKey;
bsalomon23e619c2015-02-06 11:54:28 -0800285};
bsalomon744998e2014-08-28 09:54:34 -0700286#endif