Clening up GrBinHashKey. Removing unnecessary streaming capability
BUG=http://code.google.com/p/skia/issues/detail?id=278 REVIEW=http://codereview.appspot.com/4910045/ git-svn-id: http://skia.googlecode.com/svn/trunk@2136 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
37ad8fb72f
commit
f7c00f6be1
@ -13,213 +13,77 @@
|
||||
#include "GrTypes.h"
|
||||
|
||||
/**
|
||||
* Abstract base class that presents the building interface of GrBinHashKey.
|
||||
* This base class allows builder methods to not know the exact template
|
||||
* parameters of GrBinHashKey
|
||||
*/
|
||||
class GrBinHashKeyBuilder {
|
||||
public:
|
||||
GrBinHashKeyBuilder() {}
|
||||
virtual ~GrBinHashKeyBuilder() {}
|
||||
virtual void keyData(const uint32_t *dataToAdd, size_t len) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hash function class than can take a data stream of indeterminate length.
|
||||
* It also has the ability to recieve data in several chunks (steamed). The
|
||||
* hash function used is the One-at-a-Time Hash
|
||||
* Hash function class that can take a data chunk of any predetermined
|
||||
* length. The hash function used is the One-at-a-Time Hash
|
||||
* (http://burtleburtle.net/bob/hash/doobs.html).
|
||||
*
|
||||
* Keys are built in two passes the first pass builds the key until the
|
||||
* allocated storage for the key runs out, raw data accumulation stops, but
|
||||
* the calculation of the 32-bit hash value and total key length continue.
|
||||
* The second pass is only necessary if storage ran-out during the first pass.
|
||||
* If that is the case, the heap storage portion of the key will be
|
||||
* re-allocated so that the entire key can be stored in the second pass.
|
||||
*
|
||||
* Code for building a key:
|
||||
*
|
||||
* GrBinHashKey<MyEntryStruct, MyStackSize> MyKey;
|
||||
* while( MyKey->doPass() )
|
||||
* {
|
||||
* MyObject->buildKey(&MyKey); //invoke a builder method
|
||||
* }
|
||||
*
|
||||
* All the builder method needs to do is make calls to the keyData method to
|
||||
* append binary data to the key.
|
||||
*/
|
||||
template<typename Entry, size_t StackSize>
|
||||
class GrBinHashKey : public GrBinHashKeyBuilder {
|
||||
template<typename Entry, size_t KeySize>
|
||||
class GrBinHashKey {
|
||||
public:
|
||||
GrBinHashKey()
|
||||
: fA(0)
|
||||
, fLength(0)
|
||||
, fHeapData(NULL)
|
||||
, fPhysicalSize(StackSize)
|
||||
, fUseHeap(false)
|
||||
, fPass(0)
|
||||
: fHash(0)
|
||||
#if GR_DEBUG
|
||||
, fIsValid(true)
|
||||
, fIsValid(false)
|
||||
#endif
|
||||
{}
|
||||
|
||||
private:
|
||||
// Illegal: must choose explicitly between copyAndTakeOwnership
|
||||
// and deepCopyFrom.
|
||||
// Not inheriting GrNoncopyable, because it causes very obscure compiler
|
||||
// errors with template classes, which are hard to trace back to the use
|
||||
// of assignment.
|
||||
GrBinHashKey(const GrBinHashKey<Entry, StackSize>&) {}
|
||||
GrBinHashKey<Entry, StackSize>& operator=(const GrBinHashKey<Entry,
|
||||
StackSize>&) {
|
||||
return this;
|
||||
GrBinHashKey(const GrBinHashKey<Entry, KeySize>& other) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
public:
|
||||
void copyAndTakeOwnership(GrBinHashKey<Entry, StackSize>& key) {
|
||||
GrAssert(key.fIsValid);
|
||||
copyFields(key);
|
||||
if (fUseHeap) {
|
||||
key.fHeapData = NULL; // ownership transfer
|
||||
}
|
||||
// Consistency Checking
|
||||
// To avoid the overhead of copying or ref-counting the dynamically
|
||||
// allocated portion of the key, we use ownership transfer
|
||||
// Key usability is only tracked in debug builds.
|
||||
GR_DEBUGCODE(key.fIsValid = false;)
|
||||
}
|
||||
|
||||
void deepCopyFrom(const GrBinHashKey<Entry, StackSize>& key) {
|
||||
GrAssert(key.fIsValid);
|
||||
copyFields(key);
|
||||
if (fUseHeap) {
|
||||
fHeapData = reinterpret_cast<uint8_t*>(
|
||||
GrMalloc(sizeof(uint8_t) * fPhysicalSize));
|
||||
memcpy(fHeapData, key.fHeapData, fLength);
|
||||
}
|
||||
GrBinHashKey<Entry, KeySize>& operator=(const GrBinHashKey<Entry,
|
||||
KeySize>& other) {
|
||||
memcpy(this, &other, sizeof(*this));
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~GrBinHashKey() {
|
||||
if (fUseHeap) {
|
||||
GrFree(fHeapData);
|
||||
}
|
||||
}
|
||||
|
||||
bool doPass() {
|
||||
GrAssert(fIsValid);
|
||||
if (0 == fPass) {
|
||||
fPass++;
|
||||
return true;
|
||||
void setKeyData(const uint32_t *data) {
|
||||
GrAssert(GrIsALIGN4(KeySize));
|
||||
memcpy(&fData, data, KeySize);
|
||||
|
||||
fHash = 0;
|
||||
size_t len = KeySize;
|
||||
while (len >= 4) {
|
||||
fHash += *data++;
|
||||
fHash += (fHash << 10);
|
||||
fHash ^= (fHash >> 6);
|
||||
len -= 4;
|
||||
}
|
||||
if (1 == fPass) {
|
||||
bool passNeeded = false;
|
||||
if (fLength > fPhysicalSize) {
|
||||
// If the first pass ran out of space the we need to
|
||||
// re-allocate and perform a second pass
|
||||
GrFree(fHeapData);
|
||||
fHeapData = reinterpret_cast<uint8_t*>(
|
||||
GrMalloc(sizeof(uint8_t) * fLength));
|
||||
fPhysicalSize = fLength;
|
||||
fUseHeap = true;
|
||||
passNeeded = true;
|
||||
fLength = 0;
|
||||
}
|
||||
fPass++;
|
||||
return passNeeded;
|
||||
}
|
||||
return false;
|
||||
fHash += (fHash << 3);
|
||||
fHash ^= (fHash >> 11);
|
||||
fHash += (fHash << 15);
|
||||
#if GR_DEBUG
|
||||
fIsValid = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void keyData(const uint32_t *dataToAdd, size_t len) {
|
||||
GrAssert(fIsValid);
|
||||
GrAssert(fPass);
|
||||
GrAssert(GrIsALIGN4(len));
|
||||
if (fUseHeap) {
|
||||
GrAssert(fHeapData);
|
||||
GrAssert(fLength + len <= fPhysicalSize);
|
||||
memcpy(&fHeapData[fLength], dataToAdd, len );
|
||||
} else {
|
||||
if (fLength + len <= StackSize) {
|
||||
memcpy(&fStackData[fLength], dataToAdd, len);
|
||||
} else {
|
||||
GrAssert(1 == fPass);
|
||||
}
|
||||
}
|
||||
|
||||
fLength += len;
|
||||
|
||||
if (1 == fPass) {
|
||||
uint32_t a = fA;
|
||||
while (len >= 4) {
|
||||
a += *dataToAdd++;
|
||||
a += (a << 10);
|
||||
a ^= (a >> 6);
|
||||
len -= 4;
|
||||
}
|
||||
a += (a << 3);
|
||||
a ^= (a >> 11);
|
||||
a += (a << 15);
|
||||
|
||||
fA = a;
|
||||
}
|
||||
}
|
||||
|
||||
int compare(const GrBinHashKey<Entry, StackSize>& key) const {
|
||||
GrAssert(fIsValid);
|
||||
if (fLength == key.fLength) {
|
||||
GrAssert(fUseHeap == key.fUseHeap);
|
||||
if(fUseHeap) {
|
||||
return memcmp(fHeapData, key.fHeapData, fLength);
|
||||
} else {
|
||||
return memcmp(fStackData, key.fStackData, fLength);
|
||||
}
|
||||
}
|
||||
|
||||
return (fLength - key.fLength);
|
||||
int compare(const GrBinHashKey<Entry, KeySize>& key) const {
|
||||
GrAssert(fIsValid && key.fIsValid);
|
||||
return memcmp(fData, key.fData, KeySize);
|
||||
}
|
||||
|
||||
static bool
|
||||
EQ(const Entry& entry, const GrBinHashKey<Entry, StackSize>& key) {
|
||||
EQ(const Entry& entry, const GrBinHashKey<Entry, KeySize>& key) {
|
||||
GrAssert(key.fIsValid);
|
||||
return 0 == entry.compare(key);
|
||||
}
|
||||
|
||||
static bool
|
||||
LT(const Entry& entry, const GrBinHashKey<Entry, StackSize>& key) {
|
||||
LT(const Entry& entry, const GrBinHashKey<Entry, KeySize>& key) {
|
||||
GrAssert(key.fIsValid);
|
||||
return entry.compare(key) < 0;
|
||||
}
|
||||
|
||||
uint32_t getHash() const {
|
||||
GrAssert(fIsValid);
|
||||
return fA;
|
||||
return fHash;
|
||||
}
|
||||
|
||||
private:
|
||||
void copyFields(const GrBinHashKey<Entry, StackSize>& src) {
|
||||
if (fUseHeap) {
|
||||
GrFree(fHeapData);
|
||||
}
|
||||
// We do a field-by-field copy because this is a non-POD
|
||||
// class, and therefore memcpy would be bad
|
||||
fA = src.fA;
|
||||
fLength = src.fLength;
|
||||
memcpy(fStackData, src.fStackData, StackSize);
|
||||
fHeapData = src.fHeapData;
|
||||
fPhysicalSize = src.fPhysicalSize;
|
||||
fUseHeap = src.fUseHeap;
|
||||
fPass = src.fPass;
|
||||
}
|
||||
|
||||
uint32_t fA;
|
||||
|
||||
// For accumulating the variable length binary key
|
||||
size_t fLength; // length of data accumulated so far
|
||||
uint8_t fStackData[StackSize]; //Buffer for key storage
|
||||
uint8_t* fHeapData; //Dynamically allocated extended key storage
|
||||
size_t fPhysicalSize; //Total size available for key storage
|
||||
bool fUseHeap; //Using a dynamically allocated key storage
|
||||
int fPass; //Key generation pass counter
|
||||
uint32_t fHash;
|
||||
uint8_t fData[KeySize]; //Buffer for key storage
|
||||
|
||||
#if GR_DEBUG
|
||||
public:
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "GrGLProgram.h"
|
||||
|
||||
#include "GrBinHashKey.h"
|
||||
#include "GrGLConfig.h"
|
||||
|
||||
#include "SkTrace.h"
|
||||
@ -165,11 +164,6 @@ void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
|
||||
// Add stage configuration to the key
|
||||
key.keyData(reinterpret_cast<const uint32_t*>(&fProgramDesc), sizeof(ProgramDesc));
|
||||
}
|
||||
|
||||
// assigns modulation of two vars to an output var
|
||||
// vars can be vec4s or floats (or one of each)
|
||||
// result is always vec4
|
||||
|
@ -46,14 +46,6 @@ public:
|
||||
GrGLProgram();
|
||||
~GrGLProgram();
|
||||
|
||||
/**
|
||||
* Streams data that can uniquely identifies the generated
|
||||
* gpu program into a key, for cache indexing purposes.
|
||||
*
|
||||
* @param key The key object to receive the key data
|
||||
*/
|
||||
void buildKey(GrBinHashKeyBuilder& key) const;
|
||||
|
||||
/**
|
||||
* This is the heavy initilization routine for building a GLProgram.
|
||||
* The result of heavy init is not stored in datamembers of GrGLProgam,
|
||||
@ -265,6 +257,15 @@ public:
|
||||
|
||||
}; // CachedData
|
||||
|
||||
enum Constants {
|
||||
kProgramKeySize = sizeof(ProgramDesc)
|
||||
};
|
||||
|
||||
// Provide an opaque ProgramDesc
|
||||
const uint32_t* keyData() const{
|
||||
return reinterpret_cast<const uint32_t*>(&fProgramDesc);
|
||||
}
|
||||
|
||||
private:
|
||||
enum {
|
||||
kUseUniform = 2000
|
||||
|
@ -24,18 +24,14 @@ class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable {
|
||||
private:
|
||||
class Entry;
|
||||
|
||||
#if GR_DEBUG
|
||||
typedef GrBinHashKey<Entry, 4> ProgramHashKey; // Flex the dynamic allocation muscle in debug
|
||||
#else
|
||||
typedef GrBinHashKey<Entry, 64> ProgramHashKey;
|
||||
#endif
|
||||
typedef GrBinHashKey<Entry, GrGLProgram::kProgramKeySize> ProgramHashKey;
|
||||
|
||||
class Entry : public ::GrNoncopyable {
|
||||
public:
|
||||
Entry() {}
|
||||
void copyAndTakeOwnership(Entry& entry) {
|
||||
fProgramData.copyAndTakeOwnership(entry.fProgramData);
|
||||
fKey.copyAndTakeOwnership(entry.fKey); // ownership transfer
|
||||
fKey = entry.fKey; // ownership transfer
|
||||
fLRUStamp = entry.fLRUStamp;
|
||||
}
|
||||
|
||||
@ -84,9 +80,8 @@ public:
|
||||
|
||||
GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) {
|
||||
Entry newEntry;
|
||||
while (newEntry.fKey.doPass()) {
|
||||
desc.buildKey(newEntry.fKey);
|
||||
}
|
||||
newEntry.fKey.setKeyData(desc.keyData());
|
||||
|
||||
Entry* entry = fHashCache.find(newEntry.fKey);
|
||||
if (NULL == entry) {
|
||||
if (!desc.genProgram(&newEntry.fProgramData)) {
|
||||
|
@ -77,72 +77,31 @@ class BogusEntry {};
|
||||
|
||||
static void test_binHashKey()
|
||||
{
|
||||
const char* testStringA = "abcdABCD";
|
||||
const char* testStringB = "abcdBBCD";
|
||||
const char* testStringA_ = "abcdABCD";
|
||||
const char* testStringB_ = "abcdBBCD";
|
||||
const uint32_t* testStringA = reinterpret_cast<const uint32_t*>(testStringA_);
|
||||
const uint32_t* testStringB = reinterpret_cast<const uint32_t*>(testStringB_);
|
||||
enum {
|
||||
kDataLenUsedForKey = 8
|
||||
};
|
||||
|
||||
typedef GrBinHashKey<BogusEntry, kDataLenUsedForKey> KeyType;
|
||||
class Entry {};
|
||||
|
||||
KeyType keyA;
|
||||
int passCnt = 0;
|
||||
while (keyA.doPass()) {
|
||||
++passCnt;
|
||||
keyA.keyData(reinterpret_cast<const uint32_t*>(testStringA), kDataLenUsedForKey);
|
||||
}
|
||||
GrAssert(passCnt == 1); //We expect the static allocation to suffice
|
||||
GrBinHashKey<BogusEntry, kDataLenUsedForKey-1> keyBust;
|
||||
passCnt = 0;
|
||||
while (keyBust.doPass()) {
|
||||
++passCnt;
|
||||
// Exceed static storage by 1
|
||||
keyBust.keyData(reinterpret_cast<const uint32_t*>(testStringA), kDataLenUsedForKey);
|
||||
}
|
||||
GrAssert(passCnt == 2); //We expect dynamic allocation to be necessary
|
||||
GrAssert(keyA.getHash() == keyBust.getHash());
|
||||
|
||||
// Test that adding keyData in chunks gives
|
||||
// the same hash as with one chunk
|
||||
KeyType keyA2;
|
||||
while (keyA2.doPass()) {
|
||||
keyA2.keyData(reinterpret_cast<const uint32_t*>(testStringA), 4);
|
||||
keyA2.keyData(&reinterpret_cast<const uint32_t*>(testStringA)[4], kDataLenUsedForKey-4);
|
||||
}
|
||||
GrBinHashKey<Entry, kDataLenUsedForKey> keyA;
|
||||
keyA.setKeyData(testStringA);
|
||||
// test copy constructor and comparison
|
||||
GrBinHashKey<Entry, kDataLenUsedForKey> keyA2(keyA);
|
||||
GrAssert(keyA.compare(keyA2) == 0);
|
||||
GrAssert(keyA.getHash() == keyA2.getHash());
|
||||
|
||||
KeyType keyB;
|
||||
while (keyB.doPass()){
|
||||
keyB.keyData(reinterpret_cast<const uint32_t*>(testStringB), kDataLenUsedForKey);
|
||||
}
|
||||
// test re-init
|
||||
keyA2.setKeyData(testStringA);
|
||||
GrAssert(keyA.compare(keyA2) == 0);
|
||||
GrAssert(keyA.getHash() == keyA2.getHash());
|
||||
// test sorting
|
||||
GrBinHashKey<Entry, kDataLenUsedForKey> keyB;
|
||||
keyB.setKeyData(testStringB);
|
||||
GrAssert(keyA.compare(keyB) < 0);
|
||||
GrAssert(keyA.compare(keyA2) == 0);
|
||||
|
||||
//Test ownership tranfer and copying
|
||||
keyB.copyAndTakeOwnership(keyA);
|
||||
GrAssert(keyA.fIsValid == false);
|
||||
GrAssert(keyB.fIsValid);
|
||||
GrAssert(keyB.getHash() == keyA2.getHash());
|
||||
GrAssert(keyB.compare(keyA2) == 0);
|
||||
keyA.deepCopyFrom(keyB);
|
||||
GrAssert(keyA.fIsValid);
|
||||
GrAssert(keyB.fIsValid);
|
||||
GrAssert(keyA.getHash() == keyA2.getHash());
|
||||
GrAssert(keyA.compare(keyA2) == 0);
|
||||
|
||||
//Test ownership tranfer and copying with key on heap
|
||||
GrBinHashKey<BogusEntry, kDataLenUsedForKey-1> keyBust2;
|
||||
keyBust2.deepCopyFrom(keyBust);
|
||||
GrAssert(keyBust.fIsValid);
|
||||
GrAssert(keyBust2.fIsValid);
|
||||
GrAssert(keyBust.getHash() == keyBust2.getHash());
|
||||
GrAssert(keyBust.compare(keyBust2) == 0);
|
||||
GrBinHashKey<BogusEntry, kDataLenUsedForKey-1> keyBust3;
|
||||
keyBust3.deepCopyFrom(keyBust);
|
||||
GrAssert(keyBust.fIsValid == false);
|
||||
GrAssert(keyBust3.fIsValid);
|
||||
GrAssert(keyBust3.getHash() == keyBust2.getHash());
|
||||
GrAssert(keyBust3.compare(keyBust2) == 0);
|
||||
GrAssert(keyA.getHash() != keyB.getHash());
|
||||
}
|
||||
|
||||
static void test_convex() {
|
||||
|
Loading…
Reference in New Issue
Block a user