diff --git a/include/renderer_gl/renderer_gl.hpp b/include/renderer_gl/renderer_gl.hpp index 4fe0a37c..3ede19ff 100644 --- a/include/renderer_gl/renderer_gl.hpp +++ b/include/renderer_gl/renderer_gl.hpp @@ -45,7 +45,7 @@ class Renderer { SurfaceCache depthBufferCache; SurfaceCache colourBufferCache; - SurfaceCache textureCache; + SurfaceCache textureCache; OpenGL::uvec2 fbSize; // The size of the framebuffer (ie both the colour and depth buffer)' diff --git a/include/renderer_gl/surface_cache.hpp b/include/renderer_gl/surface_cache.hpp index e6b07763..c5c98f79 100644 --- a/include/renderer_gl/surface_cache.hpp +++ b/include/renderer_gl/surface_cache.hpp @@ -5,8 +5,9 @@ #include "textures.hpp" // Surface cache class that can fit "capacity" instances of the "SurfaceType" class of surfaces -// SurfaceType *must* have all of the following -// - An "allocate" function that allocates GL resources for the surfaces +// SurfaceType *must* have all of the following. +// - 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 "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) @@ -14,7 +15,7 @@ // 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 "location" member which tells us which location in 3DS memory this surface occupies -template +template class SurfaceCache { // Vanilla std::optional can't hold actual references using OptionalRef = std::optional>; @@ -22,11 +23,13 @@ class SurfaceCache { std::is_same(), "Invalid surface type"); size_t size; + size_t evictionIndex; std::array buffer; public: void reset() { size = 0; + evictionIndex = 0; for (auto& e : buffer) { // Free the VRAM of all surfaces e.free(); } @@ -51,26 +54,42 @@ public: } // Adds a surface object to the cache and returns it - SurfaceType& add(const SurfaceType& surface) { - if (size >= capacity) { - Helpers::panic("Surface cache full! Add emptying!"); - } - size++; + SurfaceType& add(const SurfaceType& surface) { + if (size >= capacity) { + if (evictOnOverflow) { // Do a ring buffer if evictOnOverflow is true + auto& e = buffer[evictionIndex]; + evictionIndex = (evictionIndex + 1) % capacity; - // 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; - } - } + e.valid = false; + e.free(); + e = surface; + e.allocate(); + return e; + } else { + Helpers::panic("Surface cache full! Add emptying!"); + } + } - // This should be unreachable but helps to panic anyways - Helpers::panic("Couldn't add surface to cache\n"); - } + size++; + + // 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) { return buffer[i]; } + + const SurfaceType& operator[](size_t i) const { + return buffer[i]; + } }; diff --git a/src/core/renderer_gl/textures.cpp b/src/core/renderer_gl/textures.cpp index a806e1eb..e4df36a0 100644 --- a/src/core/renderer_gl/textures.cpp +++ b/src/core/renderer_gl/textures.cpp @@ -33,10 +33,11 @@ void Texture::setNewConfig(u32 cfg) { } void Texture::free() { - valid = false; + valid = false; - if (texture.exists()) - Helpers::panic("Make this texture free itself"); + if (texture.exists()) { + texture.free(); + } } u64 Texture::sizeInBytes() {