Home | History | Annotate | Download | only in gpu
      1 
      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"
     13 #include "SkOnce.h"
     14 #include "SkTemplates.h"
     15 
     16 uint32_t GrResourceKeyHash(const uint32_t* data, size_t size);
     17 
     18 /**
     19  * Base class for all GrGpuResource cache keys. There are two types of cache keys. Refer to the
     20  * comments for each key type below.
     21  */
     22 class GrResourceKey {
     23 public:
     24     uint32_t hash() const {
     25         this->validate();
     26         return fKey[kHash_MetaDataIdx];
     27     }
     28 
     29     size_t size() const {
     30         this->validate();
     31         SkASSERT(this->isValid());
     32         return this->internalSize();
     33     }
     34 
     35 protected:
     36     static const uint32_t kInvalidDomain = 0;
     37 
     38     GrResourceKey() { this->reset(); }
     39 
     40     /** Reset to an invalid key. */
     41     void reset() {
     42         GR_STATIC_ASSERT((uint16_t)kInvalidDomain == kInvalidDomain);
     43         fKey.reset(kMetaDataCnt);
     44         fKey[kHash_MetaDataIdx] = 0;
     45         fKey[kDomainAndSize_MetaDataIdx] = kInvalidDomain;
     46     }
     47 
     48     bool operator==(const GrResourceKey& that) const {
     49         return 0 == memcmp(fKey.get(), that.fKey.get(), this->size());
     50     }
     51 
     52     GrResourceKey& operator=(const GrResourceKey& that) {
     53         SkASSERT(that.isValid());
     54         if (this != &that) {
     55             size_t bytes = that.size();
     56             SkASSERT(SkIsAlign4(bytes));
     57             fKey.reset(SkToInt(bytes / sizeof(uint32_t)));
     58             memcpy(fKey.get(), that.fKey.get(), bytes);
     59             this->validate();
     60         }
     61         return *this;
     62     }
     63 
     64     bool isValid() const { return kInvalidDomain != this->domain(); }
     65 
     66     uint32_t domain() const { return fKey[kDomainAndSize_MetaDataIdx] & 0xffff; }
     67 
     68     /** size of the key data, excluding meta-data (hash, domain, etc).  */
     69     size_t dataSize() const { return this->size() - 4 * kMetaDataCnt; }
     70 
     71     /** ptr to the key data, excluding meta-data (hash, domain, etc).  */
     72     const uint32_t* data() const {
     73         this->validate();
     74         return &fKey[kMetaDataCnt];
     75     }
     76 
     77     /** Used to initialize a key. */
     78     class Builder {
     79     public:
     80         Builder(GrResourceKey* key, uint32_t domain, int data32Count) : fKey(key) {
     81             SkASSERT(data32Count >= 0);
     82             SkASSERT(domain != kInvalidDomain);
     83             key->fKey.reset(kMetaDataCnt + data32Count);
     84             int size = (data32Count + kMetaDataCnt) * sizeof(uint32_t);
     85             SkASSERT(SkToU16(size) == size);
     86             SkASSERT(SkToU16(domain) == domain);
     87             key->fKey[kDomainAndSize_MetaDataIdx] = domain | (size << 16);
     88         }
     89 
     90         ~Builder() { this->finish(); }
     91 
     92         void finish() {
     93             if (NULL == fKey) {
     94                 return;
     95             }
     96             GR_STATIC_ASSERT(0 == kHash_MetaDataIdx);
     97             uint32_t* hash = &fKey->fKey[kHash_MetaDataIdx];
     98             *hash = GrResourceKeyHash(hash + 1, fKey->internalSize() - sizeof(uint32_t));
     99             fKey->validate();
    100             fKey = NULL;
    101         }
    102 
    103         uint32_t& operator[](int dataIdx) {
    104             SkASSERT(fKey);
    105             SkDEBUGCODE(size_t dataCount = fKey->internalSize() / sizeof(uint32_t) - kMetaDataCnt;)
    106             SkASSERT(SkToU32(dataIdx) < dataCount);
    107             return fKey->fKey[kMetaDataCnt + dataIdx];
    108         }
    109 
    110     private:
    111         GrResourceKey* fKey;
    112     };
    113 
    114 private:
    115     enum MetaDataIdx {
    116         kHash_MetaDataIdx,
    117         // The key domain and size are packed into a single uint32_t.
    118         kDomainAndSize_MetaDataIdx,
    119 
    120         kLastMetaDataIdx = kDomainAndSize_MetaDataIdx
    121     };
    122     static const uint32_t kMetaDataCnt = kLastMetaDataIdx + 1;
    123 
    124     size_t internalSize() const {
    125         return fKey[kDomainAndSize_MetaDataIdx] >> 16;
    126     }
    127 
    128     void validate() const {
    129         SkASSERT(fKey[kHash_MetaDataIdx] ==
    130                  GrResourceKeyHash(&fKey[kHash_MetaDataIdx] + 1,
    131                                    this->internalSize() - sizeof(uint32_t)));
    132         SkASSERT(SkIsAlign4(this->internalSize()));
    133     }
    134 
    135     friend class TestResource; // For unit test to access kMetaDataCnt.
    136 
    137     // bmp textures require 4 uint32_t values.
    138     SkAutoSTMalloc<kMetaDataCnt + 4, uint32_t> fKey;
    139 };
    140 
    141 /**
    142  * A key used for scratch resources. There are three important rules about scratch keys:
    143  *        * Multiple resources can share the same scratch key. Therefore resources assigned the same
    144  *          scratch key should be interchangeable with respect to the code that uses them.
    145  *        * A resource can have at most one scratch key and it is set at resource creation by the
    146  *          resource itself.
    147  *        * When a scratch resource is ref'ed it will not be returned from the
    148  *          cache for a subsequent cache request until all refs are released. This facilitates using
    149  *          a scratch key for multiple render-to-texture scenarios. An example is a separable blur:
    150  *
    151  *  GrTexture* texture[2];
    152  *  texture[0] = get_scratch_texture(scratchKey);
    153  *  texture[1] = get_scratch_texture(scratchKey); // texture[0] is already owned so we will get a
    154  *                                                // different one for texture[1]
    155  *  draw_mask(texture[0], path);        // draws path mask to texture[0]
    156  *  blur_x(texture[0], texture[1]);     // blurs texture[0] in y and stores result in texture[1]
    157  *  blur_y(texture[1], texture[0]);     // blurs texture[1] in y and stores result in texture[0]
    158  *  texture[1]->unref();  // texture 1 can now be recycled for the next request with scratchKey
    159  *  consume_blur(texture[0]);
    160  *  texture[0]->unref();  // texture 0 can now be recycled for the next request with scratchKey
    161  */
    162 class GrScratchKey : public GrResourceKey {
    163 private:
    164     typedef GrResourceKey INHERITED;
    165 
    166 public:
    167     /** Uniquely identifies the type of resource that is cached as scratch. */
    168     typedef uint32_t ResourceType;
    169 
    170     /** Generate a unique ResourceType. */
    171     static ResourceType GenerateResourceType();
    172 
    173     /** Creates an invalid scratch key. It must be initialized using a Builder object before use. */
    174     GrScratchKey() {}
    175 
    176     GrScratchKey(const GrScratchKey& that) { *this = that; }
    177 
    178     /** reset() returns the key to the invalid state. */
    179     using INHERITED::reset;
    180 
    181     using INHERITED::isValid;
    182 
    183     ResourceType resourceType() const { return this->domain(); }
    184 
    185     GrScratchKey& operator=(const GrScratchKey& that) {
    186         this->INHERITED::operator=(that);
    187         return *this;
    188     }
    189 
    190     bool operator==(const GrScratchKey& that) const {
    191         return this->INHERITED::operator==(that);
    192     }
    193     bool operator!=(const GrScratchKey& that) const { return !(*this == that); }
    194 
    195     class Builder : public INHERITED::Builder {
    196     public:
    197         Builder(GrScratchKey* key, ResourceType type, int data32Count)
    198             : INHERITED::Builder(key, type, data32Count) {}
    199     };
    200 };
    201 
    202 /**
    203  * A key that allows for exclusive use of a resource for a use case (AKA "domain"). There are three
    204  * rules governing the use of unique keys:
    205  *        * Only one resource can have a given unique key at a time. Hence, "unique".
    206  *        * A resource can have at most one unique key at a time.
    207  *        * Unlike scratch keys, multiple requests for a unique key will return the same
    208  *          resource even if the resource already has refs.
    209  * This key type allows a code path to create cached resources for which it is the exclusive user.
    210  * The code path creates a domain which it sets on its keys. This guarantees that there are no
    211  * cross-domain collisions.
    212  *
    213  * Unique keys preempt scratch keys. While a resource has a unique key it is inaccessible via its
    214  * scratch key. It can become scratch again if the unique key is removed.
    215  */
    216 class GrUniqueKey : public GrResourceKey {
    217 private:
    218     typedef GrResourceKey INHERITED;
    219 
    220 public:
    221     typedef uint32_t Domain;
    222     /** Generate a Domain for unique keys. */
    223     static Domain GenerateDomain();
    224 
    225     /** Creates an invalid unique key. It must be initialized using a Builder object before use. */
    226     GrUniqueKey() {}
    227 
    228     GrUniqueKey(const GrUniqueKey& that) { *this = that; }
    229 
    230     /** reset() returns the key to the invalid state. */
    231     using INHERITED::reset;
    232 
    233     using INHERITED::isValid;
    234 
    235     GrUniqueKey& operator=(const GrUniqueKey& that) {
    236         this->INHERITED::operator=(that);
    237         return *this;
    238     }
    239 
    240     bool operator==(const GrUniqueKey& that) const {
    241         return this->INHERITED::operator==(that);
    242     }
    243     bool operator!=(const GrUniqueKey& that) const { return !(*this == that); }
    244 
    245     class Builder : public INHERITED::Builder {
    246     public:
    247         Builder(GrUniqueKey* key, Domain domain, int data32Count)
    248             : INHERITED::Builder(key, domain, data32Count) {}
    249 
    250         /** Used to build a key that wraps another key and adds additional data. */
    251         Builder(GrUniqueKey* key, const GrUniqueKey& innerKey, Domain domain,
    252                 int extraData32Cnt)
    253             : INHERITED::Builder(key, domain, Data32CntForInnerKey(innerKey) + extraData32Cnt) {
    254             SkASSERT(&innerKey != key);
    255             // add the inner key to the end of the key so that op[] can be indexed normally.
    256             uint32_t* innerKeyData = &this->operator[](extraData32Cnt);
    257             const uint32_t* srcData = innerKey.data();
    258             (*innerKeyData++) = innerKey.domain();
    259             memcpy(innerKeyData, srcData, innerKey.dataSize());
    260         }
    261 
    262     private:
    263         static int Data32CntForInnerKey(const GrUniqueKey& innerKey) {
    264             // key data + domain
    265             return SkToInt((innerKey.dataSize() >> 2) + 1);
    266         }
    267     };
    268 };
    269 
    270 /**
    271  * It is common to need a frequently reused GrUniqueKey where the only requirement is that the key
    272  * is unique. These macros create such a key in a thread safe manner so the key can be truly global
    273  * and only constructed once.
    274  */
    275 
    276 /** Place outside of function/class definitions. */
    277 #define GR_DECLARE_STATIC_UNIQUE_KEY(name) SK_DECLARE_STATIC_ONCE(name##_once)
    278 
    279 /** Place inside function where the key is used. */
    280 #define GR_DEFINE_STATIC_UNIQUE_KEY(name)                           \
    281     static GrUniqueKey name;                                        \
    282     SkOnce(&name##_once, gr_init_static_unique_key_once, &name)
    283 
    284 static inline void gr_init_static_unique_key_once(GrUniqueKey* key) {
    285     GrUniqueKey::Builder builder(key, GrUniqueKey::GenerateDomain(), 0);
    286 }
    287 
    288 // The cache listens for these messages to purge junk resources proactively.
    289 class GrUniqueKeyInvalidatedMessage {
    290 public:
    291     explicit GrUniqueKeyInvalidatedMessage(const GrUniqueKey& key) : fKey(key) {}
    292 
    293     GrUniqueKeyInvalidatedMessage(const GrUniqueKeyInvalidatedMessage& that) : fKey(that.fKey) {}
    294 
    295     GrUniqueKeyInvalidatedMessage& operator=(const GrUniqueKeyInvalidatedMessage& that) {
    296         fKey = that.fKey;
    297         return *this;
    298     }
    299 
    300     const GrUniqueKey& key() const { return fKey; }
    301 
    302 private:
    303     GrUniqueKey fKey;
    304 };
    305 #endif
    306