From 255947b2fc3d676554d02e467267b0f3c789ac86 Mon Sep 17 00:00:00 2001 From: Sky Date: Thu, 6 Jul 2023 08:42:34 -0700 Subject: [PATCH 1/2] [GPU] Add texture surface cache eviction Implemented as a simple ring buffer evicting the oldest entry for now. --- include/renderer_gl/renderer_gl.hpp | 2 +- include/renderer_gl/surface_cache.hpp | 19 +++++++++++++++---- src/core/renderer_gl/textures.cpp | 5 +++-- 3 files changed, 19 insertions(+), 7 deletions(-) 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..fb0a469d 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 evict_on_overflow is false, or kick out the oldest item if it is true. // - 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 eviction_index; std::array buffer; public: void reset() { size = 0; + eviction_index=0; for (auto& e : buffer) { // Free the VRAM of all surfaces e.free(); } @@ -53,7 +56,15 @@ 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!"); + if(evict_on_overflow){ + auto & e = buffer[eviction_index % size]; + eviction_index++; + e.free(); + e.valid = false; + e = surface; + e.allocate(); + return e; + }else Helpers::panic("Surface cache full! Add emptying!"); } size++; diff --git a/src/core/renderer_gl/textures.cpp b/src/core/renderer_gl/textures.cpp index a806e1eb..e05be35a 100644 --- a/src/core/renderer_gl/textures.cpp +++ b/src/core/renderer_gl/textures.cpp @@ -35,8 +35,9 @@ void Texture::setNewConfig(u32 cfg) { void Texture::free() { valid = false; - if (texture.exists()) - Helpers::panic("Make this texture free itself"); + if (texture.exists()){ + glDeleteTextures(1, &texture.m_handle); + } } u64 Texture::sizeInBytes() { From e67b98f990f76346ea67819c3ceacb50a6985c2d Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Fri, 7 Jul 2023 12:19:04 +0300 Subject: [PATCH 2/2] doormat --- include/renderer_gl/surface_cache.hpp | 64 +++++++++++++++------------ src/core/renderer_gl/textures.cpp | 8 ++-- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/include/renderer_gl/surface_cache.hpp b/include/renderer_gl/surface_cache.hpp index fb0a469d..c5c98f79 100644 --- a/include/renderer_gl/surface_cache.hpp +++ b/include/renderer_gl/surface_cache.hpp @@ -7,7 +7,7 @@ // 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. On overflow it will panic -// if evict_on_overflow is false, or kick out the oldest item if it is true. +// 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) @@ -15,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>; @@ -23,13 +23,13 @@ class SurfaceCache { std::is_same(), "Invalid surface type"); size_t size; - size_t eviction_index; + size_t evictionIndex; std::array buffer; public: void reset() { size = 0; - eviction_index=0; + evictionIndex = 0; for (auto& e : buffer) { // Free the VRAM of all surfaces e.free(); } @@ -54,34 +54,42 @@ public: } // Adds a surface object to the cache and returns it - SurfaceType& add(const SurfaceType& surface) { - if (size >= capacity) { - if(evict_on_overflow){ - auto & e = buffer[eviction_index % size]; - eviction_index++; - e.free(); - e.valid = false; - e = surface; - e.allocate(); - return e; - }else 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 e05be35a..e4df36a0 100644 --- a/src/core/renderer_gl/textures.cpp +++ b/src/core/renderer_gl/textures.cpp @@ -33,11 +33,11 @@ void Texture::setNewConfig(u32 cfg) { } void Texture::free() { - valid = false; + valid = false; - if (texture.exists()){ - glDeleteTextures(1, &texture.m_handle); - } + if (texture.exists()) { + texture.free(); + } } u64 Texture::sizeInBytes() {