summaryrefslogtreecommitdiffhomepage
path: root/shaders
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2023-08-27 09:57:29 +0200
committerStanislaw Halik <sthalik@misaki.pl>2023-08-27 13:13:57 +0200
commit2a527f27e22ae35d4d8fccc66451745c7c93d1f9 (patch)
tree797c5769320391c20d14a2e1eae4922b234df194 /shaders
parent24cefefa0efccaa814ffd58fec3d07fffa59c394 (diff)
shaders: add texture unit cache
Diffstat (limited to 'shaders')
-rw-r--r--shaders/texture-unit-cache.cpp105
-rw-r--r--shaders/texture-unit-cache.hpp35
2 files changed, 140 insertions, 0 deletions
diff --git a/shaders/texture-unit-cache.cpp b/shaders/texture-unit-cache.cpp
new file mode 100644
index 00000000..918ee56c
--- /dev/null
+++ b/shaders/texture-unit-cache.cpp
@@ -0,0 +1,105 @@
+#include "texture-unit-cache.hpp"
+
+#include "compat/assert.hpp"
+#include <Magnum/GL/Texture.h>
+
+namespace floormat {
+
+struct texture_unit_cache::unit_data final
+{
+ GL::AbstractTexture* ptr;
+ size_t lru_val;
+};
+
+int32_t texture_unit_cache::bind(GL::AbstractTexture* tex)
+{
+ fm_debug_assert(tex != nullptr && tex != (GL::AbstractTexture*)-1);
+
+ constexpr auto invalid = (size_t)-1;
+ auto unbound_id = invalid;
+
+ for (auto i = 0uz; i < unit_count; i++)
+ {
+ auto& unit = units[i];
+ auto* ptr = unit.ptr;
+ if (!ptr)
+ unbound_id = i;
+ else if (ptr == tex)
+ {
+ unit.lru_val = ++lru_counter;
+ ++cache_hit_count;
+ return (int32_t)i;
+ }
+ }
+
+ if (unbound_id != invalid)
+ {
+ units[unbound_id] = {tex, ++lru_counter};
+ tex->bind((Int)unbound_id);
+ ++cache_hit_count;
+ auto label = tex->label();
+ Debug{Debug::Flag::NoSpace} << "binding '" << tex->label() << "' to " << unbound_id;
+ return (int32_t)unbound_id;
+ }
+ else
+ {
+ auto min_lru = invalid, min_index = invalid;
+ for (auto i = 0uz; i < unit_count; i++)
+ {
+ auto& unit = units[i];
+ if (unit.lru_val < min_lru)
+ {
+ min_lru = unit.lru_val;
+ min_index = i;
+ }
+ }
+ fm_assert(min_index != invalid);
+ ++rebind_count;
+ units[min_index] = {tex, ++lru_counter};
+ tex->bind((Int)min_index);
+ Debug{Debug::Flag::NoSpace} << "binding '" << tex->label() << "' to " << min_index;
+ return (int32_t)min_index;
+ }
+}
+
+texture_unit_cache::texture_unit_cache() :
+ unit_count{get_unit_count()},
+ units{ValueInit, unit_count}
+{
+}
+
+void texture_unit_cache::invalidate()
+{
+ units = {};
+ lru_counter = 0;
+ rebind_count = 0;
+}
+
+void texture_unit_cache::lock(floormat::size_t i, GL::AbstractTexture* tex)
+{
+ fm_assert(i < unit_count);
+ units[i] = { .ptr = tex, .lru_val = (uint64_t)i, };
+}
+
+void texture_unit_cache::unlock(size_t i, bool immediately)
+{
+ fm_assert(i < unit_count);
+ if (units[i].ptr == (GL::AbstractTexture*)-1)
+ immediately = true;
+ units[i] = { .ptr = units[i].ptr, .lru_val = immediately ? 0 : ++lru_counter };
+}
+
+size_t texture_unit_cache::get_unit_count()
+{
+ static auto ret = [] {
+ GLint value = 0;
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &value);
+ fm_assert(value >= /*GL 3.3*/ 16);
+ return value;
+ }();
+ return (size_t)ret;
+}
+
+int32_t texture_unit_cache::bind(GL::AbstractTexture& x) { return bind(&x); }
+
+} // namespace floormat
diff --git a/shaders/texture-unit-cache.hpp b/shaders/texture-unit-cache.hpp
new file mode 100644
index 00000000..2647ea8c
--- /dev/null
+++ b/shaders/texture-unit-cache.hpp
@@ -0,0 +1,35 @@
+#pragma once
+#include "compat/defs.hpp"
+#include <Corrade/Containers/Array.h>
+
+namespace Magnum::GL { class AbstractTexture; }
+
+namespace floormat {
+
+struct texture_unit_cache final
+{
+ fm_DECLARE_DELETED_COPY_ASSIGNMENT(texture_unit_cache);
+ fm_DECLARE_DEFAULT_MOVE_ASSIGNMENT_(texture_unit_cache);
+
+ texture_unit_cache();
+
+ [[nodiscard]] int32_t bind(GL::AbstractTexture* ptr);
+ [[nodiscard]] int32_t bind(GL::AbstractTexture& x);
+ void invalidate();
+ void lock(size_t i, GL::AbstractTexture* = (GL::AbstractTexture*)-1);
+ void lock(size_t i, GL::AbstractTexture& tex) { lock(i, &tex); }
+ void unlock(size_t i, bool immediately = true);
+
+ size_t reuse_count() const { return cache_hit_count; }
+ size_t bind_count() const { return rebind_count; }
+ void reset_stats() { rebind_count = cache_hit_count = 0; }
+
+private:
+ static size_t get_unit_count();
+ struct unit_data;
+
+ size_t unit_count, lru_counter = 0, rebind_count = 0, cache_hit_count = 0;
+ Array<unit_data> units;
+};
+
+} // namespace floormat