blob: b35db8c7c641e6b454eb6dc9b96efda7c6942efc [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GAPIR_RESOURCE_IN_MEMORY_CACHE_H
#define GAPIR_RESOURCE_IN_MEMORY_CACHE_H
#include "resource_cache.h"
#include <gapic/assert.h>
#include <memory>
#include <unordered_map>
namespace gapir {
// Fixed size in-memory resource cache. It uses a ring buffer to store the cache and
// starts invalidating cache entries from the oldest to the newest when more space
// is required.
class ResourceInMemoryCache : public ResourceCache {
public:
// Creates a new in-memory cache with the given fallback provider and base address. The initial
// cache size is 0 byte.
static std::unique_ptr<ResourceInMemoryCache> create(
std::unique_ptr<ResourceProvider> fallbackProvider, void* buffer);
// destructor
~ResourceInMemoryCache();
// Prefetches the specified resources, caching as many that fit in memory as possible.
void prefetch(const Resource* resources, size_t count, const ServerConnection& server,
void* temp, size_t tempSize) override;
// clears the cache.
void clear();
// resets the size of the buffer used for caching.
void resize(size_t newSize);
protected:
void putCache(const Resource& resource, const void* data) override;
bool getCache(const Resource& resource, void* data) override;
private:
// constructor
ResourceInMemoryCache(std::unique_ptr<ResourceProvider> fallbackProvider, void* buffer);
// A doubly-linked list data structure representing a chunk of memory in the cache.
struct Block {
inline Block();
inline Block(size_t offset, size_t size);
inline Block(size_t offset, size_t size, const ResourceId& id);
inline ~Block();
inline void linkAfter(Block* other);
inline void linkBefore(Block* other);
inline void unlink();
size_t offset; // offset in bytes from mBuffer.
size_t size; // size in bytes. May wrap-around the cache buffer.
ResourceId id;
Block* next;
Block* prev;
};
// put adds the the resource to the cache.
// size must be less or equal to mBufferSize.
void put(const ResourceId& id, size_t size, const uint8_t* data);
// A pointer to the next block to be used for a resource allocation.
// While filling the cache, mHead will point to the first free block. Once
// the cache is full it will point to an existing cache entry that will be
// next to be evicted.
Block* mHead;
// A map of cached resource identifiers to offsets on mBuffer.
std::unordered_map<ResourceId, size_t> mCache;
// The base address and the size of the memory used for caching.
// This memory region is owned by the memory manager class, not by the cache itself.
uint8_t* mBuffer;
size_t mBufferSize;
};
inline ResourceInMemoryCache::Block::Block()
: offset(0), size(0), next(nullptr), prev(nullptr) {}
inline ResourceInMemoryCache::Block::Block(size_t offset_, size_t size_)
: offset(offset_), size(size_), next(nullptr), prev(nullptr) {}
inline ResourceInMemoryCache::Block::Block(size_t offset_, size_t size_, const ResourceId& id)
: offset(offset_), size(size_), next(nullptr), prev(nullptr) {}
inline ResourceInMemoryCache::Block::~Block() {
GAPID_ASSERT((next == nullptr && prev == nullptr) || next == prev);
}
inline void ResourceInMemoryCache::Block::linkAfter(Block* other) {
GAPID_ASSERT(next == nullptr && prev == nullptr);
next = other->next;
prev = other;
next->prev = this;
prev->next = this;
}
inline void ResourceInMemoryCache::Block::linkBefore(Block* other) {
GAPID_ASSERT(next == nullptr && prev == nullptr);
next = other;
prev = other->prev;
next->prev = this;
prev->next = this;
}
inline void ResourceInMemoryCache::Block::unlink() {
GAPID_ASSERT(next != nullptr && prev != nullptr);
next->prev = prev;
prev->next = next;
next = nullptr;
prev = nullptr;
}
} // namespace gapir
#endif // GAPIR_RESOURCE_IN_MEMORY_CACHE_H