blob: 38f66893a2cf1cad649abf2f7ad9158860fe9ccf [file] [log] [blame]
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// BlobCache: Stores compiled and linked programs in memory so they don't
// always have to be re-compiled. Can be used in conjunction with the platform
// layer to warm up the cache from disk.
#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 gl
namespace egl
{
// 160-bit SHA-1 hash key used for hasing a program. BlobCache opts in using fixed keys for
// simplicity and efficiency.
static constexpr size_t kBlobCacheKeyLength = angle::base::kSHA1Length;
using BlobCacheKey = std::array<uint8_t, kBlobCacheKeyLength>;
} // namespace egl
namespace std
{
template <>
struct hash<egl::BlobCacheKey>
{
// Simple routine to hash four ints.
size_t operator()(const egl::BlobCacheKey &key) const
{
return angle::ComputeGenericHash(key.data(), key.size());
}
};
} // namespace std
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:
// 160-bit SHA-1 hash key used for hasing a program. BlobCache opts in using fixed keys for
// simplicity and efficiency.
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) {}
// A very basic struct to hold the pointer and size together. The objects of this class
// don't own the memory.
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();
// Store a key-blob pair in the cache. If application callbacks are set, the application cache
// will be used. Otherwise the value is cached in this object.
void put(const BlobCache::Key &key, angle::MemoryBuffer &&value);
// Store a key-blob pair in the application cache, only if application callbacks are set.
void putApplication(const BlobCache::Key &key, const angle::MemoryBuffer &value);
// Store a key-blob pair in the cache without making callbacks to the application. This is used
// to repopulate this object's cache on startup without generating callback calls.
void populate(const BlobCache::Key &key,
angle::MemoryBuffer &&value,
CacheSource source = CacheSource::Disk);
// Check if the cache contains the blob corresponding to this key. If application callbacks are
// set, those will be used. Otherwise they key is looked up in this object's cache.
ANGLE_NO_DISCARD bool get(angle::ScratchBuffer *scratchBuffer,
const BlobCache::Key &key,
BlobCache::Value *valueOut,
size_t *bufferSizeOut);
// For querying the contents of the cache.
ANGLE_NO_DISCARD bool getAt(size_t index,
const BlobCache::Key **keyOut,
BlobCache::Value *valueOut);
// Evict a blob from the binary cache.
void remove(const BlobCache::Key &key);
// Empty the cache.
void clear() { mBlobCache.clear(); }
// Resize the cache. Discards current contents.
void resize(size_t maxCacheSizeBytes) { mBlobCache.resize(maxCacheSizeBytes); }
// Returns the number of entries in the cache.
size_t entryCount() const { return mBlobCache.entryCount(); }
// Reduces the current cache size and returns the number of bytes freed.
size_t trim(size_t limit) { return mBlobCache.shrinkToSize(limit); }
// Returns the current cache size in bytes.
size_t size() const { return mBlobCache.size(); }
// Returns whether the cache is empty
bool empty() const { return mBlobCache.empty(); }
// Returns the maximum cache size in bytes.
size_t maxSize() const { return mBlobCache.maxSize(); }
void setBlobCacheFuncs(EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
bool areBlobCacheFuncsSet() const;
bool isCachingEnabled() const { return areBlobCacheFuncsSet() || maxSize() > 0; }
private:
// This internal cache is used only if the application is not providing caching callbacks
using CacheEntry = std::pair<angle::MemoryBuffer, CacheSource>;
std::mutex mBlobCacheMutex;
angle::SizedMRUCache<BlobCache::Key, CacheEntry> mBlobCache;
EGLSetBlobFuncANDROID mSetBlobFunc;
EGLGetBlobFuncANDROID mGetBlobFunc;
};
} // namespace egl
#endif // LIBANGLE_MEMORY_PROGRAM_CACHE_H_