skia2/include/gpu/GrResourceKey.h
kkinnunen 711ef48313 Make GrScratchKey memory buffer correct size on copy
Scratch key memory buffer of a copy of a key was too big. The (new) copy
was N times uint32_t bytes instead of N bytes.

Adds few tests to resource cache. These tests would not catch the too
big buffer. This is just a precaution for too small buffers. The main
idea of the test change is that the scratch key should contain some
information, so that lookup with a scratch key can also return no
match. Otherwise testing of scratch lookup result is not indicative of
correct code (eg. no-information scratch key will always match).

Review URL: https://codereview.chromium.org/860333002
2015-01-21 06:39:14 -08:00

160 lines
5.1 KiB
C++

/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrResourceKey_DEFINED
#define GrResourceKey_DEFINED
#include "GrTypes.h"
#include "SkTemplates.h"
#include "GrBinHashKey.h"
/**
* A key used for scratch resources. The key consists of a resource type (subclass) identifier, a
* hash, a data length, and type-specific data. A Builder object is used to initialize the
* key contents. The contents must be initialized before the key can be used.
*/
class GrScratchKey {
public:
/** Uniquely identifies the type of resource that is cached as scratch. */
typedef uint32_t ResourceType;
/** Generate a unique ResourceType. */
static ResourceType GenerateResourceType();
GrScratchKey() { this->reset(); }
GrScratchKey(const GrScratchKey& that) { *this = that; }
/** Reset to an invalid key. */
void reset() {
fKey.reset(kMetaDataCnt);
fKey[kHash_MetaDataIdx] = 0;
fKey[kTypeAndSize_MetaDataIdx] = kInvalidResourceType;
}
bool isValid() const { return kInvalidResourceType != this->resourceType(); }
ResourceType resourceType() const { return fKey[kTypeAndSize_MetaDataIdx] & 0xffff; }
uint32_t hash() const { return fKey[kHash_MetaDataIdx]; }
size_t size() const { return SkToInt(fKey[kTypeAndSize_MetaDataIdx] >> 16); }
const uint32_t* data() const { return &fKey[kMetaDataCnt]; }
GrScratchKey& operator=(const GrScratchKey& that) {
size_t bytes = that.size();
fKey.reset(SkToInt(bytes / sizeof(uint32_t)));
memcpy(fKey.get(), that.fKey.get(), bytes);
return *this;
}
bool operator==(const GrScratchKey& that) const {
return 0 == memcmp(fKey.get(), that.fKey.get(), this->size());
}
bool operator!=(const GrScratchKey& that) const { return !(*this == that); }
/** Used to initialize scratch key. */
class Builder {
public:
Builder(GrScratchKey* key, ResourceType type, int data32Count) : fKey(key) {
SkASSERT(data32Count >= 0);
SkASSERT(type != kInvalidResourceType);
key->fKey.reset(kMetaDataCnt + data32Count);
SkASSERT(type <= SK_MaxU16);
int size = (data32Count + kMetaDataCnt) * sizeof(uint32_t);
SkASSERT(size <= SK_MaxU16);
key->fKey[kTypeAndSize_MetaDataIdx] = type | (size << 16);
}
~Builder() { this->finish(); }
void finish();
uint32_t& operator[](int dataIdx) {
SkASSERT(fKey);
SkDEBUGCODE(size_t dataCount = fKey->size() / sizeof(uint32_t) - kMetaDataCnt;)
SkASSERT(SkToU32(dataIdx) < dataCount);
return fKey->fKey[kMetaDataCnt + dataIdx];
}
private:
GrScratchKey* fKey;
};
private:
enum MetaDataIdx {
kHash_MetaDataIdx,
// The resource type and size are packed into a single uint32_t.
kTypeAndSize_MetaDataIdx,
kLastMetaDataIdx = kTypeAndSize_MetaDataIdx
};
static const uint32_t kInvalidResourceType = 0;
static const uint32_t kMetaDataCnt = kLastMetaDataIdx + 1;
// Stencil and textures each require 2 uint32_t values.
SkAutoSTArray<kMetaDataCnt + 2, uint32_t> fKey;
};
class GrResourceKey {
public:
/** Flags set by the GrGpuResource subclass. */
typedef uint8_t ResourceFlags;
/** Creates a key for resource */
GrResourceKey(const GrCacheID& id, ResourceFlags flags) {
this->init(id.getDomain(), id.getKey(), flags);
};
GrResourceKey(const GrResourceKey& src) { fKey = src.fKey; }
GrResourceKey() { fKey.reset(); }
void reset(const GrCacheID& id, ResourceFlags flags) {
this->init(id.getDomain(), id.getKey(), flags);
}
uint32_t getHash() const { return fKey.getHash(); }
ResourceFlags getResourceFlags() const {
return *reinterpret_cast<const ResourceFlags*>(fKey.getData() +
kResourceFlagsOffset);
}
bool operator==(const GrResourceKey& other) const { return fKey == other.fKey; }
// A key indicating that the resource is not usable as a scratch resource.
static GrResourceKey& NullScratchKey();
private:
enum {
kCacheIDKeyOffset = 0,
kCacheIDDomainOffset = kCacheIDKeyOffset + sizeof(GrCacheID::Key),
kResourceFlagsOffset = kCacheIDDomainOffset + sizeof(GrCacheID::Domain),
kPadOffset = kResourceFlagsOffset + sizeof(ResourceFlags),
kKeySize = SkAlign4(kPadOffset),
kPadSize = kKeySize - kPadOffset
};
void init(const GrCacheID::Domain domain, const GrCacheID::Key& key, ResourceFlags flags) {
union {
uint8_t fKey8[kKeySize];
uint32_t fKey32[kKeySize / 4];
} keyData;
uint8_t* k = keyData.fKey8;
memcpy(k + kCacheIDKeyOffset, key.fData8, sizeof(GrCacheID::Key));
memcpy(k + kCacheIDDomainOffset, &domain, sizeof(GrCacheID::Domain));
memcpy(k + kResourceFlagsOffset, &flags, sizeof(ResourceFlags));
memset(k + kPadOffset, 0, kPadSize);
fKey.setKeyData(keyData.fKey32);
}
GrBinHashKey<kKeySize> fKey;
};
#endif