aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsnowstormxd <214507868+snowstormxd@users.noreply.github.com>2026-11-01 22:04:01 +0000
committersnowstormxd <214507868+snowstormxd@users.noreply.github.com>2026-11-02 19:00:26 +0000
commit24da16703dd2a9f883d80f3c5c0280d12767b5ea (patch)
tree773f7f0c1711e6337b9dca2e26902dc82e08f4e8
parent1e37847a805e87a0cac9e78755fe103571329eaa (diff)
texture_cache: clear only exposed descriptor bitmap words
Avoid zeroing unused preallocation during invalidation and pool refresh. Clear newly exposed words whenever limits grow, bound clearing to allocated storage, and test word/allocation boundaries, shrink/regrowth and malformed large limits. Assisted-by: Codex (implementation, review, commit text and automated validation) (cherry picked from commit 4bc1ae01f79cef43be016504c850ca8a6998457a)
-rw-r--r--src/tests/video_core/descriptor_table.cpp36
-rw-r--r--src/video_core/texture_cache/descriptor_table.h13
2 files changed, 45 insertions, 4 deletions
diff --git a/src/tests/video_core/descriptor_table.cpp b/src/tests/video_core/descriptor_table.cpp
index b4c226241d..8b20564949 100644
--- a/src/tests/video_core/descriptor_table.cpp
+++ b/src/tests/video_core/descriptor_table.cpp
@@ -4,6 +4,7 @@
#include <chrono>
#include <cstring>
#include <iostream>
+#include <limits>
#include <random>
#include <catch2/catch_test_macros.hpp>
#include "video_core/texture_cache/descriptor_table.h"
@@ -97,6 +98,41 @@ TEST_CASE("Repeated image deletion cannot reuse stale descriptor view IDs", "[de
}
}
+TEST_CASE("Descriptor limits clear exposed slots after shrink and growth", "[descriptor_table]") {
+ struct AddressMemory {
+ void ReadBlockUnsafe(GPUVAddr address, void* output, size_t size) const {
+ std::memcpy(output, &address, size);
+ }
+ } memory;
+ constexpr std::array<u32, 9> limits{0, 63, 64, 127, 128, 0x7ffff, 0x80000, 0x80001, 0x100000};
+ for (const u32 limit : limits) {
+ VideoCommon::DescriptorTable<u64> table;
+ REQUIRE(table.Synchronize(0x1000, limit));
+ CHECK(table.Read(memory, limit).second);
+ CHECK_FALSE(table.Read(memory, limit).second);
+ table.Refresh(0x1000, 0);
+ table.Invalidate();
+ CHECK(table.Read(memory, 0).second);
+ CHECK_FALSE(table.Read(memory, 0).second);
+ table.Refresh(0x1000, limit);
+ CHECK(table.Read(memory, limit).second);
+ CHECK_FALSE(table.Read(memory, limit).second);
+ table.Invalidate();
+ table.Invalidate();
+ CHECK(table.Read(memory, limit).second);
+ CHECK_FALSE(table.Read(memory, limit).second);
+ }
+ for (const u32 limit :
+ {std::numeric_limits<u32>::max(), std::numeric_limits<u32>::max() - 0x1000}) {
+ VideoCommon::DescriptorTable<u64> table;
+ table.Refresh(0x1000, limit);
+ CHECK(table.Read(memory, 0).second);
+ table.Invalidate();
+ CHECK(table.Read(memory, 0).second);
+ CHECK_FALSE(table.Read(memory, 0).second);
+ }
+}
+
TEST_CASE("Descriptor invalidation CPU benchmark", "[.][cache_bench]") {
DescriptorMemory memory;
const auto measure = [&](bool deferred) {
diff --git a/src/video_core/texture_cache/descriptor_table.h b/src/video_core/texture_cache/descriptor_table.h
index 32ce01eeed..a441e572de 100644
--- a/src/video_core/texture_cache/descriptor_table.h
+++ b/src/video_core/texture_cache/descriptor_table.h
@@ -39,7 +39,7 @@ public:
[[nodiscard]] std::pair<T, bool> Read(const MemoryManager& gpu_memory, u32 index) noexcept {
DEBUG_ASSERT(index <= current_limit);
if (invalidated) {
- std::ranges::fill(read_descriptors, 0);
+ ClearReadDescriptors();
invalidated = false;
}
const GPUVAddr gpu_addr = current_gpu_addr + index * sizeof(T);
@@ -63,10 +63,8 @@ public:
// Mario Brothership reallocates a lot of times, so use aggressive pre-alloc sizes
// std::vector<T> by default uses quadratic growth, but that isn't even enough to satisfy brothership
const size_t num_descriptors = ((limit + 0x80000) & (~0x7ffff)) + 1;
- size_t old_size = read_descriptors.size();
read_descriptors.resize(Common::DivCeil(num_descriptors, 64U));
- old_size = (std::min)(old_size, read_descriptors.size());
- std::fill(read_descriptors.begin(), read_descriptors.begin() + old_size, 0);
+ ClearReadDescriptors();
invalidated = false;
//
descriptors.resize(num_descriptors);
@@ -77,6 +75,13 @@ public:
GPUVAddr current_gpu_addr{};
u32 current_limit{};
bool invalidated{}; ///< read_descriptors is to be cleared before the next read
+
+private:
+ void ClearReadDescriptors() noexcept {
+ // Reserved capacity is not addressable. A later limit increase clears its new range.
+ const size_t words = (std::min)(read_descriptors.size(), size_t{current_limit} / 64 + 1);
+ std::fill_n(read_descriptors.begin(), words, u64{0});
+ }
};
} // namespace VideoCommon