Merge pull request #73 from skylersaleh/SurfaceCacheRing

[GPU] Add texture surface cache eviction
This commit is contained in:
wheremyfoodat 2023-07-07 12:45:08 +03:00 committed by GitHub
commit 0647fb5b85
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 43 additions and 23 deletions

View file

@ -45,7 +45,7 @@ class Renderer {
SurfaceCache<DepthBuffer, 10> depthBufferCache; SurfaceCache<DepthBuffer, 10> depthBufferCache;
SurfaceCache<ColourBuffer, 10> colourBufferCache; SurfaceCache<ColourBuffer, 10> colourBufferCache;
SurfaceCache<Texture, 256> textureCache; SurfaceCache<Texture, 256, true> textureCache;
OpenGL::uvec2 fbSize; // The size of the framebuffer (ie both the colour and depth buffer)' OpenGL::uvec2 fbSize; // The size of the framebuffer (ie both the colour and depth buffer)'

View file

@ -5,8 +5,9 @@
#include "textures.hpp" #include "textures.hpp"
// Surface cache class that can fit "capacity" instances of the "SurfaceType" class of surfaces // Surface cache class that can fit "capacity" instances of the "SurfaceType" class of surfaces
// SurfaceType *must* have all of the following // SurfaceType *must* have all of the following.
// - An "allocate" function that allocates GL resources for the surfaces // - An "allocate" function that allocates GL resources for the surfaces. On overflow it will panic
// if evictOnOverflow is false, or kick out the oldest item if it is true (like a ring buffer)
// - A "free" function that frees up all resources the surface is taking up // - A "free" function that frees up all resources the surface is taking up
// - A "matches" function that, when provided with a SurfaceType object reference // - A "matches" function that, when provided with a SurfaceType object reference
// Will tell us if the 2 surfaces match (Only as far as location in VRAM, format, dimensions, etc) // Will tell us if the 2 surfaces match (Only as far as location in VRAM, format, dimensions, etc)
@ -14,7 +15,7 @@
// Including equality of the allocated OpenGL resources, which we don't want // Including equality of the allocated OpenGL resources, which we don't want
// - A "valid" member that tells us whether the function is still valid or not // - A "valid" member that tells us whether the function is still valid or not
// - A "location" member which tells us which location in 3DS memory this surface occupies // - A "location" member which tells us which location in 3DS memory this surface occupies
template <typename SurfaceType, size_t capacity> template <typename SurfaceType, size_t capacity, bool evictOnOverflow = false>
class SurfaceCache { class SurfaceCache {
// Vanilla std::optional can't hold actual references // Vanilla std::optional can't hold actual references
using OptionalRef = std::optional<std::reference_wrapper<SurfaceType>>; using OptionalRef = std::optional<std::reference_wrapper<SurfaceType>>;
@ -22,11 +23,13 @@ class SurfaceCache {
std::is_same<SurfaceType, Texture>(), "Invalid surface type"); std::is_same<SurfaceType, Texture>(), "Invalid surface type");
size_t size; size_t size;
size_t evictionIndex;
std::array<SurfaceType, capacity> buffer; std::array<SurfaceType, capacity> buffer;
public: public:
void reset() { void reset() {
size = 0; size = 0;
evictionIndex = 0;
for (auto& e : buffer) { // Free the VRAM of all surfaces for (auto& e : buffer) { // Free the VRAM of all surfaces
e.free(); e.free();
} }
@ -51,26 +54,42 @@ public:
} }
// Adds a surface object to the cache and returns it // Adds a surface object to the cache and returns it
SurfaceType& add(const SurfaceType& surface) { SurfaceType& add(const SurfaceType& surface) {
if (size >= capacity) { if (size >= capacity) {
Helpers::panic("Surface cache full! Add emptying!"); if (evictOnOverflow) { // Do a ring buffer if evictOnOverflow is true
} auto& e = buffer[evictionIndex];
size++; evictionIndex = (evictionIndex + 1) % capacity;
// Find an invalid entry in the cache and overwrite it with the new surface e.valid = false;
for (auto& e : buffer) { e.free();
if (!e.valid) { e = surface;
e = surface; e.allocate();
e.allocate(); return e;
return e; } else {
} Helpers::panic("Surface cache full! Add emptying!");
} }
}
// This should be unreachable but helps to panic anyways size++;
Helpers::panic("Couldn't add surface to cache\n");
} // Find an invalid entry in the cache and overwrite it with the new surface
for (auto& e : buffer) {
if (!e.valid) {
e = surface;
e.allocate();
return e;
}
}
// This should be unreachable but helps to panic anyways
Helpers::panic("Couldn't add surface to cache\n");
}
SurfaceType& operator[](size_t i) { SurfaceType& operator[](size_t i) {
return buffer[i]; return buffer[i];
} }
const SurfaceType& operator[](size_t i) const {
return buffer[i];
}
}; };

View file

@ -33,10 +33,11 @@ void Texture::setNewConfig(u32 cfg) {
} }
void Texture::free() { void Texture::free() {
valid = false; valid = false;
if (texture.exists()) if (texture.exists()) {
Helpers::panic("Make this texture free itself"); texture.free();
}
} }
u64 Texture::sizeInBytes() { u64 Texture::sizeInBytes() {