blob: e02fd0d2d953db6f268de84ec44f58475fb06f15 [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
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
#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 {
// 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
// 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);
void putCache(const Resource& resource, const void* data) override;
bool getCache(const Resource& resource, void* data) override;
// 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), id(id) {}
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