#ifndef LIBANGLE_BLOB_CACHE_H_
#define LIBANGLE_BLOB_CACHE_H_
#include <array>
#include <cstring>
#include <anglebase/sha1.h>
#include "common/MemoryBuffer.h"
#include "common/hash_utils.h"
#include "libANGLE/Error.h"
#include "libANGLE/SizedMRUCache.h"
namespace gl
{
class Context;
}
namespace egl
{
static constexpr size_t kBlobCacheKeyLength = angle::base::kSHA1Length;
using BlobCacheKey = std::array<uint8_t, kBlobCacheKeyLength>;
}
namespace std
{
template <>
struct hash<egl::BlobCacheKey>
{
size_t operator()(const egl::BlobCacheKey &key) const
{
return angle::ComputeGenericHash(key.data(), key.size());
}
};
}
namespace egl
{
bool CompressBlobCacheData(const size_t cacheSize,
const uint8_t *cacheData,
angle::MemoryBuffer *compressedData);
bool DecompressBlobCacheData(const uint8_t *compressedData,
const size_t compressedSize,
angle::MemoryBuffer *uncompressedData);
class BlobCache final : angle::NonCopyable
{
public:
static constexpr size_t kKeyLength = kBlobCacheKeyLength;
using Key = BlobCacheKey;
class Value
{
public:
Value() : mPtr(nullptr), mSize(0) {}
Value(const uint8_t *ptr, size_t sz) : mPtr(ptr), mSize(sz) {}
const uint8_t *data() { return mPtr; }
size_t size() { return mSize; }
const uint8_t &operator[](size_t pos) const
{
ASSERT(pos < mSize);
return mPtr[pos];
}
private:
const uint8_t *mPtr;
size_t mSize;
};
enum class CacheSource
{
Memory,
Disk,
};
explicit BlobCache(size_t maxCacheSizeBytes);
~BlobCache();
void put(const BlobCache::Key &key, angle::MemoryBuffer &&value);
void putApplication(const BlobCache::Key &key, const angle::MemoryBuffer &value);
void populate(const BlobCache::Key &key,
angle::MemoryBuffer &&value,
CacheSource source = CacheSource::Disk);
ANGLE_NO_DISCARD bool get(angle::ScratchBuffer *scratchBuffer,
const BlobCache::Key &key,
BlobCache::Value *valueOut,
size_t *bufferSizeOut);
ANGLE_NO_DISCARD bool getAt(size_t index,
const BlobCache::Key **keyOut,
BlobCache::Value *valueOut);
void remove(const BlobCache::Key &key);
void clear() { mBlobCache.clear(); }
void resize(size_t maxCacheSizeBytes) { mBlobCache.resize(maxCacheSizeBytes); }
size_t entryCount() const { return mBlobCache.entryCount(); }
size_t trim(size_t limit) { return mBlobCache.shrinkToSize(limit); }
size_t size() const { return mBlobCache.size(); }
bool empty() const { return mBlobCache.empty(); }
size_t maxSize() const { return mBlobCache.maxSize(); }
void setBlobCacheFuncs(EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
bool areBlobCacheFuncsSet() const;
bool isCachingEnabled() const { return areBlobCacheFuncsSet() || maxSize() > 0; }
private:
using CacheEntry = std::pair<angle::MemoryBuffer, CacheSource>;
std::mutex mBlobCacheMutex;
angle::SizedMRUCache<BlobCache::Key, CacheEntry> mBlobCache;
EGLSetBlobFuncANDROID mSetBlobFunc;
EGLGetBlobFuncANDROID mGetBlobFunc;
};
}
#endif