diff options
| author | 2023-04-23 11:58:43 +0200 | |
|---|---|---|
| committer | 2023-04-29 00:46:31 +0200 | |
| commit | fff6155bc3a24016496d1290944b8f111a367c9a (patch) | |
| tree | 1e6c0a53e1d9c4a54e8ec28d247f6b9b70151d9a | |
| parent | Clang: format and ficx compile errors. (diff) | |
| download | yuzu-fff6155bc3a24016496d1290944b8f111a367c9a.tar.gz yuzu-fff6155bc3a24016496d1290944b8f111a367c9a.tar.xz yuzu-fff6155bc3a24016496d1290944b8f111a367c9a.zip | |
Tests: Add memory tracker tests.
| -rw-r--r-- | src/tests/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/tests/video_core/buffer_base.cpp | 549 | ||||
| -rw-r--r-- | src/tests/video_core/memory_tracker.cpp | 547 |
3 files changed, 548 insertions, 550 deletions
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 39b774c98..1e158f375 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt | |||
| @@ -15,7 +15,7 @@ add_executable(tests | |||
| 15 | core/core_timing.cpp | 15 | core/core_timing.cpp |
| 16 | core/internal_network/network.cpp | 16 | core/internal_network/network.cpp |
| 17 | precompiled_headers.h | 17 | precompiled_headers.h |
| 18 | video_core/buffer_base.cpp | 18 | video_core/memory_tracker.cpp |
| 19 | input_common/calibration_configuration_job.cpp | 19 | input_common/calibration_configuration_job.cpp |
| 20 | ) | 20 | ) |
| 21 | 21 | ||
diff --git a/src/tests/video_core/buffer_base.cpp b/src/tests/video_core/buffer_base.cpp deleted file mode 100644 index 734dbf4b6..000000000 --- a/src/tests/video_core/buffer_base.cpp +++ /dev/null | |||
| @@ -1,549 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <stdexcept> | ||
| 5 | #include <unordered_map> | ||
| 6 | |||
| 7 | #include <catch2/catch_test_macros.hpp> | ||
| 8 | |||
| 9 | #include "common/alignment.h" | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "video_core/buffer_cache/buffer_base.h" | ||
| 12 | |||
| 13 | namespace { | ||
| 14 | using VideoCommon::BufferBase; | ||
| 15 | using Range = std::pair<u64, u64>; | ||
| 16 | |||
| 17 | constexpr u64 PAGE = 4096; | ||
| 18 | constexpr u64 WORD = 4096 * 64; | ||
| 19 | |||
| 20 | constexpr VAddr c = 0x1328914000; | ||
| 21 | |||
| 22 | class RasterizerInterface { | ||
| 23 | public: | ||
| 24 | void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { | ||
| 25 | const u64 page_start{addr >> Core::Memory::YUZU_PAGEBITS}; | ||
| 26 | const u64 page_end{(addr + size + Core::Memory::YUZU_PAGESIZE - 1) >> | ||
| 27 | Core::Memory::YUZU_PAGEBITS}; | ||
| 28 | for (u64 page = page_start; page < page_end; ++page) { | ||
| 29 | int& value = page_table[page]; | ||
| 30 | value += delta; | ||
| 31 | if (value < 0) { | ||
| 32 | throw std::logic_error{"negative page"}; | ||
| 33 | } | ||
| 34 | if (value == 0) { | ||
| 35 | page_table.erase(page); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | [[nodiscard]] int Count(VAddr addr) const noexcept { | ||
| 41 | const auto it = page_table.find(addr >> Core::Memory::YUZU_PAGEBITS); | ||
| 42 | return it == page_table.end() ? 0 : it->second; | ||
| 43 | } | ||
| 44 | |||
| 45 | [[nodiscard]] unsigned Count() const noexcept { | ||
| 46 | unsigned count = 0; | ||
| 47 | for (const auto& [index, value] : page_table) { | ||
| 48 | count += value; | ||
| 49 | } | ||
| 50 | return count; | ||
| 51 | } | ||
| 52 | |||
| 53 | private: | ||
| 54 | std::unordered_map<u64, int> page_table; | ||
| 55 | }; | ||
| 56 | } // Anonymous namespace | ||
| 57 | |||
| 58 | TEST_CASE("BufferBase: Small buffer", "[video_core]") { | ||
| 59 | RasterizerInterface rasterizer; | ||
| 60 | BufferBase buffer(rasterizer, c, WORD); | ||
| 61 | REQUIRE(rasterizer.Count() == 0); | ||
| 62 | buffer.UnmarkRegionAsCpuModified(c, WORD); | ||
| 63 | REQUIRE(rasterizer.Count() == WORD / PAGE); | ||
| 64 | REQUIRE(buffer.ModifiedCpuRegion(c, WORD) == Range{0, 0}); | ||
| 65 | |||
| 66 | buffer.MarkRegionAsCpuModified(c + PAGE, 1); | ||
| 67 | REQUIRE(buffer.ModifiedCpuRegion(c, WORD) == Range{PAGE * 1, PAGE * 2}); | ||
| 68 | } | ||
| 69 | |||
| 70 | TEST_CASE("BufferBase: Large buffer", "[video_core]") { | ||
| 71 | RasterizerInterface rasterizer; | ||
| 72 | BufferBase buffer(rasterizer, c, WORD * 32); | ||
| 73 | buffer.UnmarkRegionAsCpuModified(c, WORD * 32); | ||
| 74 | buffer.MarkRegionAsCpuModified(c + 4096, WORD * 4); | ||
| 75 | REQUIRE(buffer.ModifiedCpuRegion(c, WORD + PAGE * 2) == Range{PAGE, WORD + PAGE * 2}); | ||
| 76 | REQUIRE(buffer.ModifiedCpuRegion(c + PAGE * 2, PAGE * 6) == Range{PAGE * 2, PAGE * 8}); | ||
| 77 | REQUIRE(buffer.ModifiedCpuRegion(c, WORD * 32) == Range{PAGE, WORD * 4 + PAGE}); | ||
| 78 | REQUIRE(buffer.ModifiedCpuRegion(c + WORD * 4, PAGE) == Range{WORD * 4, WORD * 4 + PAGE}); | ||
| 79 | REQUIRE(buffer.ModifiedCpuRegion(c + WORD * 3 + PAGE * 63, PAGE) == | ||
| 80 | Range{WORD * 3 + PAGE * 63, WORD * 4}); | ||
| 81 | |||
| 82 | buffer.MarkRegionAsCpuModified(c + WORD * 5 + PAGE * 6, PAGE); | ||
| 83 | buffer.MarkRegionAsCpuModified(c + WORD * 5 + PAGE * 8, PAGE); | ||
| 84 | REQUIRE(buffer.ModifiedCpuRegion(c + WORD * 5, WORD) == | ||
| 85 | Range{WORD * 5 + PAGE * 6, WORD * 5 + PAGE * 9}); | ||
| 86 | |||
| 87 | buffer.UnmarkRegionAsCpuModified(c + WORD * 5 + PAGE * 8, PAGE); | ||
| 88 | REQUIRE(buffer.ModifiedCpuRegion(c + WORD * 5, WORD) == | ||
| 89 | Range{WORD * 5 + PAGE * 6, WORD * 5 + PAGE * 7}); | ||
| 90 | |||
| 91 | buffer.MarkRegionAsCpuModified(c + PAGE, WORD * 31 + PAGE * 63); | ||
| 92 | REQUIRE(buffer.ModifiedCpuRegion(c, WORD * 32) == Range{PAGE, WORD * 32}); | ||
| 93 | |||
| 94 | buffer.UnmarkRegionAsCpuModified(c + PAGE * 4, PAGE); | ||
| 95 | buffer.UnmarkRegionAsCpuModified(c + PAGE * 6, PAGE); | ||
| 96 | |||
| 97 | buffer.UnmarkRegionAsCpuModified(c, WORD * 32); | ||
| 98 | REQUIRE(buffer.ModifiedCpuRegion(c, WORD * 32) == Range{0, 0}); | ||
| 99 | } | ||
| 100 | |||
| 101 | TEST_CASE("BufferBase: Rasterizer counting", "[video_core]") { | ||
| 102 | RasterizerInterface rasterizer; | ||
| 103 | BufferBase buffer(rasterizer, c, PAGE * 2); | ||
| 104 | REQUIRE(rasterizer.Count() == 0); | ||
| 105 | buffer.UnmarkRegionAsCpuModified(c, PAGE); | ||
| 106 | REQUIRE(rasterizer.Count() == 1); | ||
| 107 | buffer.MarkRegionAsCpuModified(c, PAGE * 2); | ||
| 108 | REQUIRE(rasterizer.Count() == 0); | ||
| 109 | buffer.UnmarkRegionAsCpuModified(c, PAGE); | ||
| 110 | buffer.UnmarkRegionAsCpuModified(c + PAGE, PAGE); | ||
| 111 | REQUIRE(rasterizer.Count() == 2); | ||
| 112 | buffer.MarkRegionAsCpuModified(c, PAGE * 2); | ||
| 113 | REQUIRE(rasterizer.Count() == 0); | ||
| 114 | } | ||
| 115 | |||
| 116 | TEST_CASE("BufferBase: Basic range", "[video_core]") { | ||
| 117 | RasterizerInterface rasterizer; | ||
| 118 | BufferBase buffer(rasterizer, c, WORD); | ||
| 119 | buffer.UnmarkRegionAsCpuModified(c, WORD); | ||
| 120 | buffer.MarkRegionAsCpuModified(c, PAGE); | ||
| 121 | int num = 0; | ||
| 122 | buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { | ||
| 123 | REQUIRE(offset == 0U); | ||
| 124 | REQUIRE(size == PAGE); | ||
| 125 | ++num; | ||
| 126 | }); | ||
| 127 | REQUIRE(num == 1U); | ||
| 128 | } | ||
| 129 | |||
| 130 | TEST_CASE("BufferBase: Border upload", "[video_core]") { | ||
| 131 | RasterizerInterface rasterizer; | ||
| 132 | BufferBase buffer(rasterizer, c, WORD * 2); | ||
| 133 | buffer.UnmarkRegionAsCpuModified(c, WORD * 2); | ||
| 134 | buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2); | ||
| 135 | buffer.ForEachUploadRange(c, WORD * 2, [](u64 offset, u64 size) { | ||
| 136 | REQUIRE(offset == WORD - PAGE); | ||
| 137 | REQUIRE(size == PAGE * 2); | ||
| 138 | }); | ||
| 139 | } | ||
| 140 | |||
| 141 | TEST_CASE("BufferBase: Border upload range", "[video_core]") { | ||
| 142 | RasterizerInterface rasterizer; | ||
| 143 | BufferBase buffer(rasterizer, c, WORD * 2); | ||
| 144 | buffer.UnmarkRegionAsCpuModified(c, WORD * 2); | ||
| 145 | buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2); | ||
| 146 | buffer.ForEachUploadRange(c + WORD - PAGE, PAGE * 2, [](u64 offset, u64 size) { | ||
| 147 | REQUIRE(offset == WORD - PAGE); | ||
| 148 | REQUIRE(size == PAGE * 2); | ||
| 149 | }); | ||
| 150 | buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2); | ||
| 151 | buffer.ForEachUploadRange(c + WORD - PAGE, PAGE, [](u64 offset, u64 size) { | ||
| 152 | REQUIRE(offset == WORD - PAGE); | ||
| 153 | REQUIRE(size == PAGE); | ||
| 154 | }); | ||
| 155 | buffer.ForEachUploadRange(c + WORD, PAGE, [](u64 offset, u64 size) { | ||
| 156 | REQUIRE(offset == WORD); | ||
| 157 | REQUIRE(size == PAGE); | ||
| 158 | }); | ||
| 159 | } | ||
| 160 | |||
| 161 | TEST_CASE("BufferBase: Border upload partial range", "[video_core]") { | ||
| 162 | RasterizerInterface rasterizer; | ||
| 163 | BufferBase buffer(rasterizer, c, WORD * 2); | ||
| 164 | buffer.UnmarkRegionAsCpuModified(c, WORD * 2); | ||
| 165 | buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2); | ||
| 166 | buffer.ForEachUploadRange(c + WORD - 1, 2, [](u64 offset, u64 size) { | ||
| 167 | REQUIRE(offset == WORD - PAGE); | ||
| 168 | REQUIRE(size == PAGE * 2); | ||
| 169 | }); | ||
| 170 | buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2); | ||
| 171 | buffer.ForEachUploadRange(c + WORD - 1, 1, [](u64 offset, u64 size) { | ||
| 172 | REQUIRE(offset == WORD - PAGE); | ||
| 173 | REQUIRE(size == PAGE); | ||
| 174 | }); | ||
| 175 | buffer.ForEachUploadRange(c + WORD + 50, 1, [](u64 offset, u64 size) { | ||
| 176 | REQUIRE(offset == WORD); | ||
| 177 | REQUIRE(size == PAGE); | ||
| 178 | }); | ||
| 179 | } | ||
| 180 | |||
| 181 | TEST_CASE("BufferBase: Partial word uploads", "[video_core]") { | ||
| 182 | RasterizerInterface rasterizer; | ||
| 183 | BufferBase buffer(rasterizer, c, 0x9d000); | ||
| 184 | int num = 0; | ||
| 185 | buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { | ||
| 186 | REQUIRE(offset == 0U); | ||
| 187 | REQUIRE(size == WORD); | ||
| 188 | ++num; | ||
| 189 | }); | ||
| 190 | REQUIRE(num == 1); | ||
| 191 | buffer.ForEachUploadRange(c + WORD, WORD, [&](u64 offset, u64 size) { | ||
| 192 | REQUIRE(offset == WORD); | ||
| 193 | REQUIRE(size == WORD); | ||
| 194 | ++num; | ||
| 195 | }); | ||
| 196 | REQUIRE(num == 2); | ||
| 197 | buffer.ForEachUploadRange(c + 0x79000, 0x24000, [&](u64 offset, u64 size) { | ||
| 198 | REQUIRE(offset == WORD * 2); | ||
| 199 | REQUIRE(size == PAGE * 0x1d); | ||
| 200 | ++num; | ||
| 201 | }); | ||
| 202 | REQUIRE(num == 3); | ||
| 203 | } | ||
| 204 | |||
| 205 | TEST_CASE("BufferBase: Partial page upload", "[video_core]") { | ||
| 206 | RasterizerInterface rasterizer; | ||
| 207 | BufferBase buffer(rasterizer, c, WORD); | ||
| 208 | buffer.UnmarkRegionAsCpuModified(c, WORD); | ||
| 209 | int num = 0; | ||
| 210 | buffer.MarkRegionAsCpuModified(c + PAGE * 2, PAGE); | ||
| 211 | buffer.MarkRegionAsCpuModified(c + PAGE * 9, PAGE); | ||
| 212 | buffer.ForEachUploadRange(c, PAGE * 3, [&](u64 offset, u64 size) { | ||
| 213 | REQUIRE(offset == PAGE * 2); | ||
| 214 | REQUIRE(size == PAGE); | ||
| 215 | ++num; | ||
| 216 | }); | ||
| 217 | REQUIRE(num == 1); | ||
| 218 | buffer.ForEachUploadRange(c + PAGE * 7, PAGE * 3, [&](u64 offset, u64 size) { | ||
| 219 | REQUIRE(offset == PAGE * 9); | ||
| 220 | REQUIRE(size == PAGE); | ||
| 221 | ++num; | ||
| 222 | }); | ||
| 223 | REQUIRE(num == 2); | ||
| 224 | } | ||
| 225 | |||
| 226 | TEST_CASE("BufferBase: Partial page upload with multiple words on the right") { | ||
| 227 | RasterizerInterface rasterizer; | ||
| 228 | BufferBase buffer(rasterizer, c, WORD * 8); | ||
| 229 | buffer.UnmarkRegionAsCpuModified(c, WORD * 8); | ||
| 230 | buffer.MarkRegionAsCpuModified(c + PAGE * 13, WORD * 7); | ||
| 231 | int num = 0; | ||
| 232 | buffer.ForEachUploadRange(c + PAGE * 10, WORD * 7, [&](u64 offset, u64 size) { | ||
| 233 | REQUIRE(offset == PAGE * 13); | ||
| 234 | REQUIRE(size == WORD * 7 - PAGE * 3); | ||
| 235 | ++num; | ||
| 236 | }); | ||
| 237 | REQUIRE(num == 1); | ||
| 238 | buffer.ForEachUploadRange(c + PAGE, WORD * 8, [&](u64 offset, u64 size) { | ||
| 239 | REQUIRE(offset == WORD * 7 + PAGE * 10); | ||
| 240 | REQUIRE(size == PAGE * 3); | ||
| 241 | ++num; | ||
| 242 | }); | ||
| 243 | REQUIRE(num == 2); | ||
| 244 | } | ||
| 245 | |||
| 246 | TEST_CASE("BufferBase: Partial page upload with multiple words on the left", "[video_core]") { | ||
| 247 | RasterizerInterface rasterizer; | ||
| 248 | BufferBase buffer(rasterizer, c, WORD * 8); | ||
| 249 | buffer.UnmarkRegionAsCpuModified(c, WORD * 8); | ||
| 250 | buffer.MarkRegionAsCpuModified(c + PAGE * 13, WORD * 7); | ||
| 251 | int num = 0; | ||
| 252 | buffer.ForEachUploadRange(c + PAGE * 16, WORD * 7, [&](u64 offset, u64 size) { | ||
| 253 | REQUIRE(offset == PAGE * 16); | ||
| 254 | REQUIRE(size == WORD * 7 - PAGE * 3); | ||
| 255 | ++num; | ||
| 256 | }); | ||
| 257 | REQUIRE(num == 1); | ||
| 258 | buffer.ForEachUploadRange(c + PAGE, WORD, [&](u64 offset, u64 size) { | ||
| 259 | REQUIRE(offset == PAGE * 13); | ||
| 260 | REQUIRE(size == PAGE * 3); | ||
| 261 | ++num; | ||
| 262 | }); | ||
| 263 | REQUIRE(num == 2); | ||
| 264 | } | ||
| 265 | |||
| 266 | TEST_CASE("BufferBase: Partial page upload with multiple words in the middle", "[video_core]") { | ||
| 267 | RasterizerInterface rasterizer; | ||
| 268 | BufferBase buffer(rasterizer, c, WORD * 8); | ||
| 269 | buffer.UnmarkRegionAsCpuModified(c, WORD * 8); | ||
| 270 | buffer.MarkRegionAsCpuModified(c + PAGE * 13, PAGE * 140); | ||
| 271 | int num = 0; | ||
| 272 | buffer.ForEachUploadRange(c + PAGE * 16, WORD, [&](u64 offset, u64 size) { | ||
| 273 | REQUIRE(offset == PAGE * 16); | ||
| 274 | REQUIRE(size == WORD); | ||
| 275 | ++num; | ||
| 276 | }); | ||
| 277 | REQUIRE(num == 1); | ||
| 278 | buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { | ||
| 279 | REQUIRE(offset == PAGE * 13); | ||
| 280 | REQUIRE(size == PAGE * 3); | ||
| 281 | ++num; | ||
| 282 | }); | ||
| 283 | REQUIRE(num == 2); | ||
| 284 | buffer.ForEachUploadRange(c, WORD * 8, [&](u64 offset, u64 size) { | ||
| 285 | REQUIRE(offset == WORD + PAGE * 16); | ||
| 286 | REQUIRE(size == PAGE * 73); | ||
| 287 | ++num; | ||
| 288 | }); | ||
| 289 | REQUIRE(num == 3); | ||
| 290 | } | ||
| 291 | |||
| 292 | TEST_CASE("BufferBase: Empty right bits", "[video_core]") { | ||
| 293 | RasterizerInterface rasterizer; | ||
| 294 | BufferBase buffer(rasterizer, c, WORD * 2048); | ||
| 295 | buffer.UnmarkRegionAsCpuModified(c, WORD * 2048); | ||
| 296 | buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2); | ||
| 297 | buffer.ForEachUploadRange(c, WORD * 2048, [](u64 offset, u64 size) { | ||
| 298 | REQUIRE(offset == WORD - PAGE); | ||
| 299 | REQUIRE(size == PAGE * 2); | ||
| 300 | }); | ||
| 301 | } | ||
| 302 | |||
| 303 | TEST_CASE("BufferBase: Out of bound ranges 1", "[video_core]") { | ||
| 304 | RasterizerInterface rasterizer; | ||
| 305 | BufferBase buffer(rasterizer, c, WORD); | ||
| 306 | buffer.UnmarkRegionAsCpuModified(c, WORD); | ||
| 307 | buffer.MarkRegionAsCpuModified(c, PAGE); | ||
| 308 | int num = 0; | ||
| 309 | buffer.ForEachUploadRange(c - WORD, WORD, [&](u64 offset, u64 size) { ++num; }); | ||
| 310 | buffer.ForEachUploadRange(c + WORD, WORD, [&](u64 offset, u64 size) { ++num; }); | ||
| 311 | buffer.ForEachUploadRange(c - PAGE, PAGE, [&](u64 offset, u64 size) { ++num; }); | ||
| 312 | REQUIRE(num == 0); | ||
| 313 | buffer.ForEachUploadRange(c - PAGE, PAGE * 2, [&](u64 offset, u64 size) { ++num; }); | ||
| 314 | REQUIRE(num == 1); | ||
| 315 | buffer.MarkRegionAsCpuModified(c, WORD); | ||
| 316 | REQUIRE(rasterizer.Count() == 0); | ||
| 317 | } | ||
| 318 | |||
| 319 | TEST_CASE("BufferBase: Out of bound ranges 2", "[video_core]") { | ||
| 320 | RasterizerInterface rasterizer; | ||
| 321 | BufferBase buffer(rasterizer, c, 0x22000); | ||
| 322 | REQUIRE_NOTHROW(buffer.UnmarkRegionAsCpuModified(c + 0x22000, PAGE)); | ||
| 323 | REQUIRE_NOTHROW(buffer.UnmarkRegionAsCpuModified(c + 0x28000, PAGE)); | ||
| 324 | REQUIRE(rasterizer.Count() == 0); | ||
| 325 | REQUIRE_NOTHROW(buffer.UnmarkRegionAsCpuModified(c + 0x21100, PAGE - 0x100)); | ||
| 326 | REQUIRE(rasterizer.Count() == 1); | ||
| 327 | REQUIRE_NOTHROW(buffer.UnmarkRegionAsCpuModified(c - 0x1000, PAGE * 2)); | ||
| 328 | buffer.UnmarkRegionAsCpuModified(c - 0x3000, PAGE * 2); | ||
| 329 | buffer.UnmarkRegionAsCpuModified(c - 0x2000, PAGE * 2); | ||
| 330 | REQUIRE(rasterizer.Count() == 2); | ||
| 331 | } | ||
| 332 | |||
| 333 | TEST_CASE("BufferBase: Out of bound ranges 3", "[video_core]") { | ||
| 334 | RasterizerInterface rasterizer; | ||
| 335 | BufferBase buffer(rasterizer, c, 0x310720); | ||
| 336 | buffer.UnmarkRegionAsCpuModified(c, 0x310720); | ||
| 337 | REQUIRE(rasterizer.Count(c) == 1); | ||
| 338 | REQUIRE(rasterizer.Count(c + PAGE) == 1); | ||
| 339 | REQUIRE(rasterizer.Count(c + WORD) == 1); | ||
| 340 | REQUIRE(rasterizer.Count(c + WORD + PAGE) == 1); | ||
| 341 | } | ||
| 342 | |||
| 343 | TEST_CASE("BufferBase: Sparse regions 1", "[video_core]") { | ||
| 344 | RasterizerInterface rasterizer; | ||
| 345 | BufferBase buffer(rasterizer, c, WORD); | ||
| 346 | buffer.UnmarkRegionAsCpuModified(c, WORD); | ||
| 347 | buffer.MarkRegionAsCpuModified(c + PAGE * 1, PAGE); | ||
| 348 | buffer.MarkRegionAsCpuModified(c + PAGE * 3, PAGE * 4); | ||
| 349 | buffer.ForEachUploadRange(c, WORD, [i = 0](u64 offset, u64 size) mutable { | ||
| 350 | static constexpr std::array<u64, 2> offsets{PAGE, PAGE * 3}; | ||
| 351 | static constexpr std::array<u64, 2> sizes{PAGE, PAGE * 4}; | ||
| 352 | REQUIRE(offset == offsets.at(i)); | ||
| 353 | REQUIRE(size == sizes.at(i)); | ||
| 354 | ++i; | ||
| 355 | }); | ||
| 356 | } | ||
| 357 | |||
| 358 | TEST_CASE("BufferBase: Sparse regions 2", "[video_core]") { | ||
| 359 | RasterizerInterface rasterizer; | ||
| 360 | BufferBase buffer(rasterizer, c, 0x22000); | ||
| 361 | buffer.UnmarkRegionAsCpuModified(c, 0x22000); | ||
| 362 | REQUIRE(rasterizer.Count() == 0x22); | ||
| 363 | buffer.MarkRegionAsCpuModified(c + PAGE * 0x1B, PAGE); | ||
| 364 | buffer.MarkRegionAsCpuModified(c + PAGE * 0x21, PAGE); | ||
| 365 | buffer.ForEachUploadRange(c, WORD, [i = 0](u64 offset, u64 size) mutable { | ||
| 366 | static constexpr std::array<u64, 2> offsets{PAGE * 0x1B, PAGE * 0x21}; | ||
| 367 | static constexpr std::array<u64, 2> sizes{PAGE, PAGE}; | ||
| 368 | REQUIRE(offset == offsets.at(i)); | ||
| 369 | REQUIRE(size == sizes.at(i)); | ||
| 370 | ++i; | ||
| 371 | }); | ||
| 372 | } | ||
| 373 | |||
| 374 | TEST_CASE("BufferBase: Single page modified range", "[video_core]") { | ||
| 375 | RasterizerInterface rasterizer; | ||
| 376 | BufferBase buffer(rasterizer, c, PAGE); | ||
| 377 | REQUIRE(buffer.IsRegionCpuModified(c, PAGE)); | ||
| 378 | buffer.UnmarkRegionAsCpuModified(c, PAGE); | ||
| 379 | REQUIRE(!buffer.IsRegionCpuModified(c, PAGE)); | ||
| 380 | } | ||
| 381 | |||
| 382 | TEST_CASE("BufferBase: Two page modified range", "[video_core]") { | ||
| 383 | RasterizerInterface rasterizer; | ||
| 384 | BufferBase buffer(rasterizer, c, PAGE * 2); | ||
| 385 | REQUIRE(buffer.IsRegionCpuModified(c, PAGE)); | ||
| 386 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 387 | REQUIRE(buffer.IsRegionCpuModified(c, PAGE * 2)); | ||
| 388 | buffer.UnmarkRegionAsCpuModified(c, PAGE); | ||
| 389 | REQUIRE(!buffer.IsRegionCpuModified(c, PAGE)); | ||
| 390 | } | ||
| 391 | |||
| 392 | TEST_CASE("BufferBase: Multi word modified ranges", "[video_core]") { | ||
| 393 | for (int offset = 0; offset < 4; ++offset) { | ||
| 394 | const VAddr address = c + WORD * offset; | ||
| 395 | RasterizerInterface rasterizer; | ||
| 396 | BufferBase buffer(rasterizer, address, WORD * 4); | ||
| 397 | REQUIRE(buffer.IsRegionCpuModified(address, PAGE)); | ||
| 398 | REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 48, PAGE)); | ||
| 399 | REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 56, PAGE)); | ||
| 400 | |||
| 401 | buffer.UnmarkRegionAsCpuModified(address + PAGE * 32, PAGE); | ||
| 402 | REQUIRE(buffer.IsRegionCpuModified(address + PAGE, WORD)); | ||
| 403 | REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 31, PAGE)); | ||
| 404 | REQUIRE(!buffer.IsRegionCpuModified(address + PAGE * 32, PAGE)); | ||
| 405 | REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 33, PAGE)); | ||
| 406 | REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 31, PAGE * 2)); | ||
| 407 | REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 32, PAGE * 2)); | ||
| 408 | |||
| 409 | buffer.UnmarkRegionAsCpuModified(address + PAGE * 33, PAGE); | ||
| 410 | REQUIRE(!buffer.IsRegionCpuModified(address + PAGE * 32, PAGE * 2)); | ||
| 411 | } | ||
| 412 | } | ||
| 413 | |||
| 414 | TEST_CASE("BufferBase: Single page in large buffer", "[video_core]") { | ||
| 415 | RasterizerInterface rasterizer; | ||
| 416 | BufferBase buffer(rasterizer, c, WORD * 16); | ||
| 417 | buffer.UnmarkRegionAsCpuModified(c, WORD * 16); | ||
| 418 | REQUIRE(!buffer.IsRegionCpuModified(c, WORD * 16)); | ||
| 419 | |||
| 420 | buffer.MarkRegionAsCpuModified(c + WORD * 12 + PAGE * 8, PAGE); | ||
| 421 | REQUIRE(buffer.IsRegionCpuModified(c, WORD * 16)); | ||
| 422 | REQUIRE(buffer.IsRegionCpuModified(c + WORD * 10, WORD * 2)); | ||
| 423 | REQUIRE(buffer.IsRegionCpuModified(c + WORD * 11, WORD * 2)); | ||
| 424 | REQUIRE(buffer.IsRegionCpuModified(c + WORD * 12, WORD * 2)); | ||
| 425 | REQUIRE(buffer.IsRegionCpuModified(c + WORD * 12 + PAGE * 4, PAGE * 8)); | ||
| 426 | REQUIRE(buffer.IsRegionCpuModified(c + WORD * 12 + PAGE * 6, PAGE * 8)); | ||
| 427 | REQUIRE(!buffer.IsRegionCpuModified(c + WORD * 12 + PAGE * 6, PAGE)); | ||
| 428 | REQUIRE(buffer.IsRegionCpuModified(c + WORD * 12 + PAGE * 7, PAGE * 2)); | ||
| 429 | REQUIRE(buffer.IsRegionCpuModified(c + WORD * 12 + PAGE * 8, PAGE * 2)); | ||
| 430 | } | ||
| 431 | |||
| 432 | TEST_CASE("BufferBase: Out of bounds region query") { | ||
| 433 | RasterizerInterface rasterizer; | ||
| 434 | BufferBase buffer(rasterizer, c, WORD * 16); | ||
| 435 | REQUIRE(!buffer.IsRegionCpuModified(c - PAGE, PAGE)); | ||
| 436 | REQUIRE(!buffer.IsRegionCpuModified(c - PAGE * 2, PAGE)); | ||
| 437 | REQUIRE(!buffer.IsRegionCpuModified(c + WORD * 16, PAGE)); | ||
| 438 | REQUIRE(buffer.IsRegionCpuModified(c + WORD * 16 - PAGE, WORD * 64)); | ||
| 439 | REQUIRE(!buffer.IsRegionCpuModified(c + WORD * 16, WORD * 64)); | ||
| 440 | } | ||
| 441 | |||
| 442 | TEST_CASE("BufferBase: Wrap word regions") { | ||
| 443 | RasterizerInterface rasterizer; | ||
| 444 | BufferBase buffer(rasterizer, c, WORD * 2); | ||
| 445 | buffer.UnmarkRegionAsCpuModified(c, WORD * 2); | ||
| 446 | buffer.MarkRegionAsCpuModified(c + PAGE * 63, PAGE * 2); | ||
| 447 | REQUIRE(buffer.IsRegionCpuModified(c, WORD * 2)); | ||
| 448 | REQUIRE(!buffer.IsRegionCpuModified(c + PAGE * 62, PAGE)); | ||
| 449 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 63, PAGE)); | ||
| 450 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 64, PAGE)); | ||
| 451 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 63, PAGE * 2)); | ||
| 452 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 63, PAGE * 8)); | ||
| 453 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 60, PAGE * 8)); | ||
| 454 | |||
| 455 | REQUIRE(!buffer.IsRegionCpuModified(c + PAGE * 127, WORD * 16)); | ||
| 456 | buffer.MarkRegionAsCpuModified(c + PAGE * 127, PAGE); | ||
| 457 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 127, WORD * 16)); | ||
| 458 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 127, PAGE)); | ||
| 459 | REQUIRE(!buffer.IsRegionCpuModified(c + PAGE * 126, PAGE)); | ||
| 460 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 126, PAGE * 2)); | ||
| 461 | REQUIRE(!buffer.IsRegionCpuModified(c + PAGE * 128, WORD * 16)); | ||
| 462 | } | ||
| 463 | |||
| 464 | TEST_CASE("BufferBase: Unaligned page region query") { | ||
| 465 | RasterizerInterface rasterizer; | ||
| 466 | BufferBase buffer(rasterizer, c, WORD); | ||
| 467 | buffer.UnmarkRegionAsCpuModified(c, WORD); | ||
| 468 | buffer.MarkRegionAsCpuModified(c + 4000, 1000); | ||
| 469 | REQUIRE(buffer.IsRegionCpuModified(c, PAGE)); | ||
| 470 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 471 | REQUIRE(buffer.IsRegionCpuModified(c + 4000, 1000)); | ||
| 472 | REQUIRE(buffer.IsRegionCpuModified(c + 4000, 1)); | ||
| 473 | } | ||
| 474 | |||
| 475 | TEST_CASE("BufferBase: Cached write") { | ||
| 476 | RasterizerInterface rasterizer; | ||
| 477 | BufferBase buffer(rasterizer, c, WORD); | ||
| 478 | buffer.UnmarkRegionAsCpuModified(c, WORD); | ||
| 479 | buffer.CachedCpuWrite(c + PAGE, PAGE); | ||
| 480 | REQUIRE(!buffer.IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 481 | buffer.FlushCachedWrites(); | ||
| 482 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 483 | buffer.MarkRegionAsCpuModified(c, WORD); | ||
| 484 | REQUIRE(rasterizer.Count() == 0); | ||
| 485 | } | ||
| 486 | |||
| 487 | TEST_CASE("BufferBase: Multiple cached write") { | ||
| 488 | RasterizerInterface rasterizer; | ||
| 489 | BufferBase buffer(rasterizer, c, WORD); | ||
| 490 | buffer.UnmarkRegionAsCpuModified(c, WORD); | ||
| 491 | buffer.CachedCpuWrite(c + PAGE, PAGE); | ||
| 492 | buffer.CachedCpuWrite(c + PAGE * 3, PAGE); | ||
| 493 | REQUIRE(!buffer.IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 494 | REQUIRE(!buffer.IsRegionCpuModified(c + PAGE * 3, PAGE)); | ||
| 495 | buffer.FlushCachedWrites(); | ||
| 496 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 497 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 3, PAGE)); | ||
| 498 | buffer.MarkRegionAsCpuModified(c, WORD); | ||
| 499 | REQUIRE(rasterizer.Count() == 0); | ||
| 500 | } | ||
| 501 | |||
| 502 | TEST_CASE("BufferBase: Cached write unmarked") { | ||
| 503 | RasterizerInterface rasterizer; | ||
| 504 | BufferBase buffer(rasterizer, c, WORD); | ||
| 505 | buffer.UnmarkRegionAsCpuModified(c, WORD); | ||
| 506 | buffer.CachedCpuWrite(c + PAGE, PAGE); | ||
| 507 | buffer.UnmarkRegionAsCpuModified(c + PAGE, PAGE); | ||
| 508 | REQUIRE(!buffer.IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 509 | buffer.FlushCachedWrites(); | ||
| 510 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 511 | buffer.MarkRegionAsCpuModified(c, WORD); | ||
| 512 | REQUIRE(rasterizer.Count() == 0); | ||
| 513 | } | ||
| 514 | |||
| 515 | TEST_CASE("BufferBase: Cached write iterated") { | ||
| 516 | RasterizerInterface rasterizer; | ||
| 517 | BufferBase buffer(rasterizer, c, WORD); | ||
| 518 | buffer.UnmarkRegionAsCpuModified(c, WORD); | ||
| 519 | buffer.CachedCpuWrite(c + PAGE, PAGE); | ||
| 520 | int num = 0; | ||
| 521 | buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { ++num; }); | ||
| 522 | REQUIRE(num == 0); | ||
| 523 | REQUIRE(!buffer.IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 524 | buffer.FlushCachedWrites(); | ||
| 525 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 526 | buffer.MarkRegionAsCpuModified(c, WORD); | ||
| 527 | REQUIRE(rasterizer.Count() == 0); | ||
| 528 | } | ||
| 529 | |||
| 530 | TEST_CASE("BufferBase: Cached write downloads") { | ||
| 531 | RasterizerInterface rasterizer; | ||
| 532 | BufferBase buffer(rasterizer, c, WORD); | ||
| 533 | buffer.UnmarkRegionAsCpuModified(c, WORD); | ||
| 534 | REQUIRE(rasterizer.Count() == 64); | ||
| 535 | buffer.CachedCpuWrite(c + PAGE, PAGE); | ||
| 536 | REQUIRE(rasterizer.Count() == 63); | ||
| 537 | buffer.MarkRegionAsGpuModified(c + PAGE, PAGE); | ||
| 538 | int num = 0; | ||
| 539 | buffer.ForEachDownloadRangeAndClear(c, WORD, [&](u64 offset, u64 size) { ++num; }); | ||
| 540 | buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { ++num; }); | ||
| 541 | REQUIRE(num == 0); | ||
| 542 | REQUIRE(!buffer.IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 543 | REQUIRE(!buffer.IsRegionGpuModified(c + PAGE, PAGE)); | ||
| 544 | buffer.FlushCachedWrites(); | ||
| 545 | REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 546 | REQUIRE(!buffer.IsRegionGpuModified(c + PAGE, PAGE)); | ||
| 547 | buffer.MarkRegionAsCpuModified(c, WORD); | ||
| 548 | REQUIRE(rasterizer.Count() == 0); | ||
| 549 | } | ||
diff --git a/src/tests/video_core/memory_tracker.cpp b/src/tests/video_core/memory_tracker.cpp new file mode 100644 index 000000000..77d391f15 --- /dev/null +++ b/src/tests/video_core/memory_tracker.cpp | |||
| @@ -0,0 +1,547 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include <memory> | ||
| 5 | #include <stdexcept> | ||
| 6 | #include <unordered_map> | ||
| 7 | |||
| 8 | #include <catch2/catch_test_macros.hpp> | ||
| 9 | |||
| 10 | #include "common/alignment.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "video_core/buffer_cache/memory_tracker_base.h" | ||
| 13 | |||
| 14 | namespace { | ||
| 15 | using Range = std::pair<u64, u64>; | ||
| 16 | |||
| 17 | constexpr u64 PAGE = 4096; | ||
| 18 | constexpr u64 WORD = 4096 * 64; | ||
| 19 | constexpr u64 HIGH_PAGE_BITS = 22; | ||
| 20 | constexpr u64 HIGH_PAGE_SIZE = 1ULL << HIGH_PAGE_BITS; | ||
| 21 | |||
| 22 | constexpr VAddr c = 16 * HIGH_PAGE_SIZE; | ||
| 23 | |||
| 24 | class RasterizerInterface { | ||
| 25 | public: | ||
| 26 | void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { | ||
| 27 | const u64 page_start{addr >> Core::Memory::YUZU_PAGEBITS}; | ||
| 28 | const u64 page_end{(addr + size + Core::Memory::YUZU_PAGESIZE - 1) >> | ||
| 29 | Core::Memory::YUZU_PAGEBITS}; | ||
| 30 | for (u64 page = page_start; page < page_end; ++page) { | ||
| 31 | int& value = page_table[page]; | ||
| 32 | value += delta; | ||
| 33 | if (value < 0) { | ||
| 34 | throw std::logic_error{"negative page"}; | ||
| 35 | } | ||
| 36 | if (value == 0) { | ||
| 37 | page_table.erase(page); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | [[nodiscard]] int Count(VAddr addr) const noexcept { | ||
| 43 | const auto it = page_table.find(addr >> Core::Memory::YUZU_PAGEBITS); | ||
| 44 | return it == page_table.end() ? 0 : it->second; | ||
| 45 | } | ||
| 46 | |||
| 47 | [[nodiscard]] unsigned Count() const noexcept { | ||
| 48 | unsigned count = 0; | ||
| 49 | for (const auto& [index, value] : page_table) { | ||
| 50 | count += value; | ||
| 51 | } | ||
| 52 | return count; | ||
| 53 | } | ||
| 54 | |||
| 55 | private: | ||
| 56 | std::unordered_map<u64, int> page_table; | ||
| 57 | }; | ||
| 58 | } // Anonymous namespace | ||
| 59 | |||
| 60 | using MemoryTracker = VideoCommon::MemoryTrackerBase<RasterizerInterface>; | ||
| 61 | |||
| 62 | TEST_CASE("MemoryTracker: Small region", "[video_core]") { | ||
| 63 | RasterizerInterface rasterizer; | ||
| 64 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 65 | REQUIRE(rasterizer.Count() == 0); | ||
| 66 | memory_track->UnmarkRegionAsCpuModified(c, WORD); | ||
| 67 | REQUIRE(rasterizer.Count() == WORD / PAGE); | ||
| 68 | REQUIRE(memory_track->ModifiedCpuRegion(c, WORD) == Range{0, 0}); | ||
| 69 | |||
| 70 | memory_track->MarkRegionAsCpuModified(c + PAGE, 1); | ||
| 71 | REQUIRE(memory_track->ModifiedCpuRegion(c, WORD) == Range{c + PAGE * 1, c + PAGE * 2}); | ||
| 72 | } | ||
| 73 | |||
| 74 | TEST_CASE("MemoryTracker: Large region", "[video_core]") { | ||
| 75 | RasterizerInterface rasterizer; | ||
| 76 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 77 | memory_track->UnmarkRegionAsCpuModified(c, WORD * 32); | ||
| 78 | memory_track->MarkRegionAsCpuModified(c + 4096, WORD * 4); | ||
| 79 | REQUIRE(memory_track->ModifiedCpuRegion(c, WORD + PAGE * 2) == | ||
| 80 | Range{c + PAGE, c + WORD + PAGE * 2}); | ||
| 81 | REQUIRE(memory_track->ModifiedCpuRegion(c + PAGE * 2, PAGE * 6) == | ||
| 82 | Range{c + PAGE * 2, c + PAGE * 8}); | ||
| 83 | REQUIRE(memory_track->ModifiedCpuRegion(c, WORD * 32) == Range{c + PAGE, c + WORD * 4 + PAGE}); | ||
| 84 | REQUIRE(memory_track->ModifiedCpuRegion(c + WORD * 4, PAGE) == | ||
| 85 | Range{c + WORD * 4, c + WORD * 4 + PAGE}); | ||
| 86 | REQUIRE(memory_track->ModifiedCpuRegion(c + WORD * 3 + PAGE * 63, PAGE) == | ||
| 87 | Range{c + WORD * 3 + PAGE * 63, c + WORD * 4}); | ||
| 88 | |||
| 89 | memory_track->MarkRegionAsCpuModified(c + WORD * 5 + PAGE * 6, PAGE); | ||
| 90 | memory_track->MarkRegionAsCpuModified(c + WORD * 5 + PAGE * 8, PAGE); | ||
| 91 | REQUIRE(memory_track->ModifiedCpuRegion(c + WORD * 5, WORD) == | ||
| 92 | Range{c + WORD * 5 + PAGE * 6, c + WORD * 5 + PAGE * 9}); | ||
| 93 | |||
| 94 | memory_track->UnmarkRegionAsCpuModified(c + WORD * 5 + PAGE * 8, PAGE); | ||
| 95 | REQUIRE(memory_track->ModifiedCpuRegion(c + WORD * 5, WORD) == | ||
| 96 | Range{c + WORD * 5 + PAGE * 6, c + WORD * 5 + PAGE * 7}); | ||
| 97 | |||
| 98 | memory_track->MarkRegionAsCpuModified(c + PAGE, WORD * 31 + PAGE * 63); | ||
| 99 | REQUIRE(memory_track->ModifiedCpuRegion(c, WORD * 32) == Range{c + PAGE, c + WORD * 32}); | ||
| 100 | |||
| 101 | memory_track->UnmarkRegionAsCpuModified(c + PAGE * 4, PAGE); | ||
| 102 | memory_track->UnmarkRegionAsCpuModified(c + PAGE * 6, PAGE); | ||
| 103 | |||
| 104 | memory_track->UnmarkRegionAsCpuModified(c, WORD * 32); | ||
| 105 | REQUIRE(memory_track->ModifiedCpuRegion(c, WORD * 32) == Range{0, 0}); | ||
| 106 | } | ||
| 107 | |||
| 108 | TEST_CASE("MemoryTracker: Rasterizer counting", "[video_core]") { | ||
| 109 | RasterizerInterface rasterizer; | ||
| 110 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 111 | REQUIRE(rasterizer.Count() == 0); | ||
| 112 | memory_track->UnmarkRegionAsCpuModified(c, PAGE); | ||
| 113 | REQUIRE(rasterizer.Count() == 1); | ||
| 114 | memory_track->MarkRegionAsCpuModified(c, PAGE * 2); | ||
| 115 | REQUIRE(rasterizer.Count() == 0); | ||
| 116 | memory_track->UnmarkRegionAsCpuModified(c, PAGE); | ||
| 117 | memory_track->UnmarkRegionAsCpuModified(c + PAGE, PAGE); | ||
| 118 | REQUIRE(rasterizer.Count() == 2); | ||
| 119 | memory_track->MarkRegionAsCpuModified(c, PAGE * 2); | ||
| 120 | REQUIRE(rasterizer.Count() == 0); | ||
| 121 | } | ||
| 122 | |||
| 123 | TEST_CASE("MemoryTracker: Basic range", "[video_core]") { | ||
| 124 | RasterizerInterface rasterizer; | ||
| 125 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 126 | memory_track->UnmarkRegionAsCpuModified(c, WORD); | ||
| 127 | memory_track->MarkRegionAsCpuModified(c, PAGE); | ||
| 128 | int num = 0; | ||
| 129 | memory_track->ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { | ||
| 130 | REQUIRE(offset == c); | ||
| 131 | REQUIRE(size == PAGE); | ||
| 132 | ++num; | ||
| 133 | }); | ||
| 134 | REQUIRE(num == 1U); | ||
| 135 | } | ||
| 136 | |||
| 137 | TEST_CASE("MemoryTracker: Border upload", "[video_core]") { | ||
| 138 | RasterizerInterface rasterizer; | ||
| 139 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 140 | memory_track->UnmarkRegionAsCpuModified(c, WORD * 2); | ||
| 141 | memory_track->MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2); | ||
| 142 | memory_track->ForEachUploadRange(c, WORD * 2, [](u64 offset, u64 size) { | ||
| 143 | REQUIRE(offset == c + WORD - PAGE); | ||
| 144 | REQUIRE(size == PAGE * 2); | ||
| 145 | }); | ||
| 146 | } | ||
| 147 | |||
| 148 | TEST_CASE("MemoryTracker: Border upload range", "[video_core]") { | ||
| 149 | RasterizerInterface rasterizer; | ||
| 150 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 151 | memory_track->UnmarkRegionAsCpuModified(c, WORD * 2); | ||
| 152 | memory_track->MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2); | ||
| 153 | memory_track->ForEachUploadRange(c + WORD - PAGE, PAGE * 2, [](u64 offset, u64 size) { | ||
| 154 | REQUIRE(offset == c + WORD - PAGE); | ||
| 155 | REQUIRE(size == PAGE * 2); | ||
| 156 | }); | ||
| 157 | memory_track->MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2); | ||
| 158 | memory_track->ForEachUploadRange(c + WORD - PAGE, PAGE, [](u64 offset, u64 size) { | ||
| 159 | REQUIRE(offset == c + WORD - PAGE); | ||
| 160 | REQUIRE(size == PAGE); | ||
| 161 | }); | ||
| 162 | memory_track->ForEachUploadRange(c + WORD, PAGE, [](u64 offset, u64 size) { | ||
| 163 | REQUIRE(offset == c + WORD); | ||
| 164 | REQUIRE(size == PAGE); | ||
| 165 | }); | ||
| 166 | } | ||
| 167 | |||
| 168 | TEST_CASE("MemoryTracker: Border upload partial range", "[video_core]") { | ||
| 169 | RasterizerInterface rasterizer; | ||
| 170 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 171 | memory_track->UnmarkRegionAsCpuModified(c, WORD * 2); | ||
| 172 | memory_track->MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2); | ||
| 173 | memory_track->ForEachUploadRange(c + WORD - 1, 2, [](u64 offset, u64 size) { | ||
| 174 | REQUIRE(offset == c + WORD - PAGE); | ||
| 175 | REQUIRE(size == PAGE * 2); | ||
| 176 | }); | ||
| 177 | memory_track->MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2); | ||
| 178 | memory_track->ForEachUploadRange(c + WORD - 1, 1, [](u64 offset, u64 size) { | ||
| 179 | REQUIRE(offset == c + WORD - PAGE); | ||
| 180 | REQUIRE(size == PAGE); | ||
| 181 | }); | ||
| 182 | memory_track->ForEachUploadRange(c + WORD + 50, 1, [](u64 offset, u64 size) { | ||
| 183 | REQUIRE(offset == c + WORD); | ||
| 184 | REQUIRE(size == PAGE); | ||
| 185 | }); | ||
| 186 | } | ||
| 187 | |||
| 188 | TEST_CASE("MemoryTracker: Partial word uploads", "[video_core]") { | ||
| 189 | RasterizerInterface rasterizer; | ||
| 190 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 191 | int num = 0; | ||
| 192 | memory_track->ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { | ||
| 193 | REQUIRE(offset == c); | ||
| 194 | REQUIRE(size == WORD); | ||
| 195 | ++num; | ||
| 196 | }); | ||
| 197 | REQUIRE(num == 1); | ||
| 198 | memory_track->ForEachUploadRange(c + WORD, WORD, [&](u64 offset, u64 size) { | ||
| 199 | REQUIRE(offset == c + WORD); | ||
| 200 | REQUIRE(size == WORD); | ||
| 201 | ++num; | ||
| 202 | }); | ||
| 203 | REQUIRE(num == 2); | ||
| 204 | memory_track->ForEachUploadRange(c + 0x79000, 0x24000, [&](u64 offset, u64 size) { | ||
| 205 | REQUIRE(offset == c + WORD * 2); | ||
| 206 | REQUIRE(size == PAGE * 0x1d); | ||
| 207 | ++num; | ||
| 208 | }); | ||
| 209 | REQUIRE(num == 3); | ||
| 210 | } | ||
| 211 | |||
| 212 | TEST_CASE("MemoryTracker: Partial page upload", "[video_core]") { | ||
| 213 | RasterizerInterface rasterizer; | ||
| 214 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 215 | memory_track->UnmarkRegionAsCpuModified(c, WORD); | ||
| 216 | int num = 0; | ||
| 217 | memory_track->MarkRegionAsCpuModified(c + PAGE * 2, PAGE); | ||
| 218 | memory_track->MarkRegionAsCpuModified(c + PAGE * 9, PAGE); | ||
| 219 | memory_track->ForEachUploadRange(c, PAGE * 3, [&](u64 offset, u64 size) { | ||
| 220 | REQUIRE(offset == c + PAGE * 2); | ||
| 221 | REQUIRE(size == PAGE); | ||
| 222 | ++num; | ||
| 223 | }); | ||
| 224 | REQUIRE(num == 1); | ||
| 225 | memory_track->ForEachUploadRange(c + PAGE * 7, PAGE * 3, [&](u64 offset, u64 size) { | ||
| 226 | REQUIRE(offset == c + PAGE * 9); | ||
| 227 | REQUIRE(size == PAGE); | ||
| 228 | ++num; | ||
| 229 | }); | ||
| 230 | REQUIRE(num == 2); | ||
| 231 | } | ||
| 232 | |||
| 233 | TEST_CASE("MemoryTracker: Partial page upload with multiple words on the right") { | ||
| 234 | RasterizerInterface rasterizer; | ||
| 235 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 236 | memory_track->UnmarkRegionAsCpuModified(c, WORD * 9); | ||
| 237 | memory_track->MarkRegionAsCpuModified(c + PAGE * 13, WORD * 7); | ||
| 238 | int num = 0; | ||
| 239 | memory_track->ForEachUploadRange(c + PAGE * 10, WORD * 7, [&](u64 offset, u64 size) { | ||
| 240 | REQUIRE(offset == c + PAGE * 13); | ||
| 241 | REQUIRE(size == WORD * 7 - PAGE * 3); | ||
| 242 | ++num; | ||
| 243 | }); | ||
| 244 | REQUIRE(num == 1); | ||
| 245 | memory_track->ForEachUploadRange(c + PAGE, WORD * 8, [&](u64 offset, u64 size) { | ||
| 246 | REQUIRE(offset == c + WORD * 7 + PAGE * 10); | ||
| 247 | REQUIRE(size == PAGE * 3); | ||
| 248 | ++num; | ||
| 249 | }); | ||
| 250 | REQUIRE(num == 2); | ||
| 251 | } | ||
| 252 | |||
| 253 | TEST_CASE("MemoryTracker: Partial page upload with multiple words on the left", "[video_core]") { | ||
| 254 | RasterizerInterface rasterizer; | ||
| 255 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 256 | memory_track->UnmarkRegionAsCpuModified(c, WORD * 8); | ||
| 257 | memory_track->MarkRegionAsCpuModified(c + PAGE * 13, WORD * 7); | ||
| 258 | int num = 0; | ||
| 259 | memory_track->ForEachUploadRange(c + PAGE * 16, WORD * 7, [&](u64 offset, u64 size) { | ||
| 260 | REQUIRE(offset == c + PAGE * 16); | ||
| 261 | REQUIRE(size == WORD * 7 - PAGE * 3); | ||
| 262 | ++num; | ||
| 263 | }); | ||
| 264 | REQUIRE(num == 1); | ||
| 265 | memory_track->ForEachUploadRange(c + PAGE, WORD, [&](u64 offset, u64 size) { | ||
| 266 | REQUIRE(offset == c + PAGE * 13); | ||
| 267 | REQUIRE(size == PAGE * 3); | ||
| 268 | ++num; | ||
| 269 | }); | ||
| 270 | REQUIRE(num == 2); | ||
| 271 | } | ||
| 272 | |||
| 273 | TEST_CASE("MemoryTracker: Partial page upload with multiple words in the middle", "[video_core]") { | ||
| 274 | RasterizerInterface rasterizer; | ||
| 275 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 276 | memory_track->UnmarkRegionAsCpuModified(c, WORD * 8); | ||
| 277 | memory_track->MarkRegionAsCpuModified(c + PAGE * 13, PAGE * 140); | ||
| 278 | int num = 0; | ||
| 279 | memory_track->ForEachUploadRange(c + PAGE * 16, WORD, [&](u64 offset, u64 size) { | ||
| 280 | REQUIRE(offset == c + PAGE * 16); | ||
| 281 | REQUIRE(size == WORD); | ||
| 282 | ++num; | ||
| 283 | }); | ||
| 284 | REQUIRE(num == 1); | ||
| 285 | memory_track->ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { | ||
| 286 | REQUIRE(offset == c + PAGE * 13); | ||
| 287 | REQUIRE(size == PAGE * 3); | ||
| 288 | ++num; | ||
| 289 | }); | ||
| 290 | REQUIRE(num == 2); | ||
| 291 | memory_track->ForEachUploadRange(c, WORD * 8, [&](u64 offset, u64 size) { | ||
| 292 | REQUIRE(offset == c + WORD + PAGE * 16); | ||
| 293 | REQUIRE(size == PAGE * 73); | ||
| 294 | ++num; | ||
| 295 | }); | ||
| 296 | REQUIRE(num == 3); | ||
| 297 | } | ||
| 298 | |||
| 299 | TEST_CASE("MemoryTracker: Empty right bits", "[video_core]") { | ||
| 300 | RasterizerInterface rasterizer; | ||
| 301 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 302 | memory_track->UnmarkRegionAsCpuModified(c, WORD * 2048); | ||
| 303 | memory_track->MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2); | ||
| 304 | memory_track->ForEachUploadRange(c, WORD * 2048, [](u64 offset, u64 size) { | ||
| 305 | REQUIRE(offset == c + WORD - PAGE); | ||
| 306 | REQUIRE(size == PAGE * 2); | ||
| 307 | }); | ||
| 308 | } | ||
| 309 | |||
| 310 | TEST_CASE("MemoryTracker: Out of bound ranges 1", "[video_core]") { | ||
| 311 | RasterizerInterface rasterizer; | ||
| 312 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 313 | memory_track->UnmarkRegionAsCpuModified(c - WORD, 3 * WORD); | ||
| 314 | memory_track->MarkRegionAsCpuModified(c, PAGE); | ||
| 315 | REQUIRE(rasterizer.Count() == (3 * WORD - PAGE) / PAGE); | ||
| 316 | int num = 0; | ||
| 317 | memory_track->ForEachUploadRange(c - WORD, WORD, [&](u64 offset, u64 size) { ++num; }); | ||
| 318 | memory_track->ForEachUploadRange(c + WORD, WORD, [&](u64 offset, u64 size) { ++num; }); | ||
| 319 | memory_track->ForEachUploadRange(c - PAGE, PAGE, [&](u64 offset, u64 size) { ++num; }); | ||
| 320 | REQUIRE(num == 0); | ||
| 321 | memory_track->ForEachUploadRange(c - PAGE, PAGE * 2, [&](u64 offset, u64 size) { ++num; }); | ||
| 322 | REQUIRE(num == 1); | ||
| 323 | memory_track->MarkRegionAsCpuModified(c, WORD); | ||
| 324 | REQUIRE(rasterizer.Count() == 2 * WORD / PAGE); | ||
| 325 | } | ||
| 326 | |||
| 327 | TEST_CASE("MemoryTracker: Out of bound ranges 2", "[video_core]") { | ||
| 328 | RasterizerInterface rasterizer; | ||
| 329 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 330 | REQUIRE_NOTHROW(memory_track->UnmarkRegionAsCpuModified(c + 0x22000, PAGE)); | ||
| 331 | REQUIRE_NOTHROW(memory_track->UnmarkRegionAsCpuModified(c + 0x28000, PAGE)); | ||
| 332 | REQUIRE(rasterizer.Count() == 2); | ||
| 333 | REQUIRE_NOTHROW(memory_track->UnmarkRegionAsCpuModified(c + 0x21100, PAGE - 0x100)); | ||
| 334 | REQUIRE(rasterizer.Count() == 3); | ||
| 335 | REQUIRE_NOTHROW(memory_track->UnmarkRegionAsCpuModified(c - PAGE, PAGE * 2)); | ||
| 336 | memory_track->UnmarkRegionAsCpuModified(c - PAGE * 3, PAGE * 2); | ||
| 337 | memory_track->UnmarkRegionAsCpuModified(c - PAGE * 2, PAGE * 2); | ||
| 338 | REQUIRE(rasterizer.Count() == 7); | ||
| 339 | } | ||
| 340 | |||
| 341 | TEST_CASE("MemoryTracker: Out of bound ranges 3", "[video_core]") { | ||
| 342 | RasterizerInterface rasterizer; | ||
| 343 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 344 | memory_track->UnmarkRegionAsCpuModified(c, 0x310720); | ||
| 345 | REQUIRE(rasterizer.Count(c) == 1); | ||
| 346 | REQUIRE(rasterizer.Count(c + PAGE) == 1); | ||
| 347 | REQUIRE(rasterizer.Count(c + WORD) == 1); | ||
| 348 | REQUIRE(rasterizer.Count(c + WORD + PAGE) == 1); | ||
| 349 | } | ||
| 350 | |||
| 351 | TEST_CASE("MemoryTracker: Sparse regions 1", "[video_core]") { | ||
| 352 | RasterizerInterface rasterizer; | ||
| 353 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 354 | memory_track->UnmarkRegionAsCpuModified(c, WORD); | ||
| 355 | memory_track->MarkRegionAsCpuModified(c + PAGE * 1, PAGE); | ||
| 356 | memory_track->MarkRegionAsCpuModified(c + PAGE * 3, PAGE * 4); | ||
| 357 | memory_track->ForEachUploadRange(c, WORD, [i = 0](u64 offset, u64 size) mutable { | ||
| 358 | static constexpr std::array<u64, 2> offsets{c + PAGE, c + PAGE * 3}; | ||
| 359 | static constexpr std::array<u64, 2> sizes{PAGE, PAGE * 4}; | ||
| 360 | REQUIRE(offset == offsets.at(i)); | ||
| 361 | REQUIRE(size == sizes.at(i)); | ||
| 362 | ++i; | ||
| 363 | }); | ||
| 364 | } | ||
| 365 | |||
| 366 | TEST_CASE("MemoryTracker: Sparse regions 2", "[video_core]") { | ||
| 367 | RasterizerInterface rasterizer; | ||
| 368 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 369 | memory_track->UnmarkRegionAsCpuModified(c, PAGE * 0x23); | ||
| 370 | REQUIRE(rasterizer.Count() == 0x23); | ||
| 371 | memory_track->MarkRegionAsCpuModified(c + PAGE * 0x1B, PAGE); | ||
| 372 | memory_track->MarkRegionAsCpuModified(c + PAGE * 0x21, PAGE); | ||
| 373 | memory_track->ForEachUploadRange(c, PAGE * 0x23, [i = 0](u64 offset, u64 size) mutable { | ||
| 374 | static constexpr std::array<u64, 3> offsets{c + PAGE * 0x1B, c + PAGE * 0x21}; | ||
| 375 | static constexpr std::array<u64, 3> sizes{PAGE, PAGE}; | ||
| 376 | REQUIRE(offset == offsets.at(i)); | ||
| 377 | REQUIRE(size == sizes.at(i)); | ||
| 378 | ++i; | ||
| 379 | }); | ||
| 380 | } | ||
| 381 | |||
| 382 | TEST_CASE("MemoryTracker: Single page modified range", "[video_core]") { | ||
| 383 | RasterizerInterface rasterizer; | ||
| 384 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 385 | REQUIRE(memory_track->IsRegionCpuModified(c, PAGE)); | ||
| 386 | memory_track->UnmarkRegionAsCpuModified(c, PAGE); | ||
| 387 | REQUIRE(!memory_track->IsRegionCpuModified(c, PAGE)); | ||
| 388 | } | ||
| 389 | |||
| 390 | TEST_CASE("MemoryTracker: Two page modified range", "[video_core]") { | ||
| 391 | RasterizerInterface rasterizer; | ||
| 392 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 393 | REQUIRE(memory_track->IsRegionCpuModified(c, PAGE)); | ||
| 394 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 395 | REQUIRE(memory_track->IsRegionCpuModified(c, PAGE * 2)); | ||
| 396 | memory_track->UnmarkRegionAsCpuModified(c, PAGE); | ||
| 397 | REQUIRE(!memory_track->IsRegionCpuModified(c, PAGE)); | ||
| 398 | } | ||
| 399 | |||
| 400 | TEST_CASE("MemoryTracker: Multi word modified ranges", "[video_core]") { | ||
| 401 | for (int offset = 0; offset < 4; ++offset) { | ||
| 402 | const VAddr address = c + WORD * offset; | ||
| 403 | RasterizerInterface rasterizer; | ||
| 404 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 405 | REQUIRE(memory_track->IsRegionCpuModified(address, PAGE)); | ||
| 406 | REQUIRE(memory_track->IsRegionCpuModified(address + PAGE * 48, PAGE)); | ||
| 407 | REQUIRE(memory_track->IsRegionCpuModified(address + PAGE * 56, PAGE)); | ||
| 408 | |||
| 409 | memory_track->UnmarkRegionAsCpuModified(address + PAGE * 32, PAGE); | ||
| 410 | REQUIRE(memory_track->IsRegionCpuModified(address + PAGE, WORD)); | ||
| 411 | REQUIRE(memory_track->IsRegionCpuModified(address + PAGE * 31, PAGE)); | ||
| 412 | REQUIRE(!memory_track->IsRegionCpuModified(address + PAGE * 32, PAGE)); | ||
| 413 | REQUIRE(memory_track->IsRegionCpuModified(address + PAGE * 33, PAGE)); | ||
| 414 | REQUIRE(memory_track->IsRegionCpuModified(address + PAGE * 31, PAGE * 2)); | ||
| 415 | REQUIRE(memory_track->IsRegionCpuModified(address + PAGE * 32, PAGE * 2)); | ||
| 416 | |||
| 417 | memory_track->UnmarkRegionAsCpuModified(address + PAGE * 33, PAGE); | ||
| 418 | REQUIRE(!memory_track->IsRegionCpuModified(address + PAGE * 32, PAGE * 2)); | ||
| 419 | } | ||
| 420 | } | ||
| 421 | |||
| 422 | TEST_CASE("MemoryTracker: Single page in large region", "[video_core]") { | ||
| 423 | RasterizerInterface rasterizer; | ||
| 424 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 425 | memory_track->UnmarkRegionAsCpuModified(c, WORD * 16); | ||
| 426 | REQUIRE(!memory_track->IsRegionCpuModified(c, WORD * 16)); | ||
| 427 | |||
| 428 | memory_track->MarkRegionAsCpuModified(c + WORD * 12 + PAGE * 8, PAGE); | ||
| 429 | REQUIRE(memory_track->IsRegionCpuModified(c, WORD * 16)); | ||
| 430 | REQUIRE(memory_track->IsRegionCpuModified(c + WORD * 10, WORD * 2)); | ||
| 431 | REQUIRE(memory_track->IsRegionCpuModified(c + WORD * 11, WORD * 2)); | ||
| 432 | REQUIRE(memory_track->IsRegionCpuModified(c + WORD * 12, WORD * 2)); | ||
| 433 | REQUIRE(memory_track->IsRegionCpuModified(c + WORD * 12 + PAGE * 4, PAGE * 8)); | ||
| 434 | REQUIRE(memory_track->IsRegionCpuModified(c + WORD * 12 + PAGE * 6, PAGE * 8)); | ||
| 435 | REQUIRE(!memory_track->IsRegionCpuModified(c + WORD * 12 + PAGE * 6, PAGE)); | ||
| 436 | REQUIRE(memory_track->IsRegionCpuModified(c + WORD * 12 + PAGE * 7, PAGE * 2)); | ||
| 437 | REQUIRE(memory_track->IsRegionCpuModified(c + WORD * 12 + PAGE * 8, PAGE * 2)); | ||
| 438 | } | ||
| 439 | |||
| 440 | TEST_CASE("MemoryTracker: Wrap word regions") { | ||
| 441 | RasterizerInterface rasterizer; | ||
| 442 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 443 | memory_track->UnmarkRegionAsCpuModified(c, WORD * 32); | ||
| 444 | memory_track->MarkRegionAsCpuModified(c + PAGE * 63, PAGE * 2); | ||
| 445 | REQUIRE(memory_track->IsRegionCpuModified(c, WORD * 2)); | ||
| 446 | REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE * 62, PAGE)); | ||
| 447 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 63, PAGE)); | ||
| 448 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 64, PAGE)); | ||
| 449 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 63, PAGE * 2)); | ||
| 450 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 63, PAGE * 8)); | ||
| 451 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 60, PAGE * 8)); | ||
| 452 | |||
| 453 | REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE * 127, WORD * 16)); | ||
| 454 | memory_track->MarkRegionAsCpuModified(c + PAGE * 127, PAGE); | ||
| 455 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 127, WORD * 16)); | ||
| 456 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 127, PAGE)); | ||
| 457 | REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE * 126, PAGE)); | ||
| 458 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 126, PAGE * 2)); | ||
| 459 | REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE * 128, WORD * 16)); | ||
| 460 | } | ||
| 461 | |||
| 462 | TEST_CASE("MemoryTracker: Unaligned page region query") { | ||
| 463 | RasterizerInterface rasterizer; | ||
| 464 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 465 | memory_track->UnmarkRegionAsCpuModified(c, WORD); | ||
| 466 | memory_track->MarkRegionAsCpuModified(c + 4000, 1000); | ||
| 467 | REQUIRE(memory_track->IsRegionCpuModified(c, PAGE)); | ||
| 468 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 469 | REQUIRE(memory_track->IsRegionCpuModified(c + 4000, 1000)); | ||
| 470 | REQUIRE(memory_track->IsRegionCpuModified(c + 4000, 1)); | ||
| 471 | } | ||
| 472 | |||
| 473 | TEST_CASE("MemoryTracker: Cached write") { | ||
| 474 | RasterizerInterface rasterizer; | ||
| 475 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 476 | memory_track->UnmarkRegionAsCpuModified(c, WORD); | ||
| 477 | memory_track->CachedCpuWrite(c + PAGE, c + PAGE); | ||
| 478 | REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 479 | memory_track->FlushCachedWrites(); | ||
| 480 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 481 | memory_track->MarkRegionAsCpuModified(c, WORD); | ||
| 482 | REQUIRE(rasterizer.Count() == 0); | ||
| 483 | } | ||
| 484 | |||
| 485 | TEST_CASE("MemoryTracker: Multiple cached write") { | ||
| 486 | RasterizerInterface rasterizer; | ||
| 487 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 488 | memory_track->UnmarkRegionAsCpuModified(c, WORD); | ||
| 489 | memory_track->CachedCpuWrite(c + PAGE, PAGE); | ||
| 490 | memory_track->CachedCpuWrite(c + PAGE * 3, PAGE); | ||
| 491 | REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 492 | REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE * 3, PAGE)); | ||
| 493 | memory_track->FlushCachedWrites(); | ||
| 494 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 495 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE * 3, PAGE)); | ||
| 496 | memory_track->MarkRegionAsCpuModified(c, WORD); | ||
| 497 | REQUIRE(rasterizer.Count() == 0); | ||
| 498 | } | ||
| 499 | |||
| 500 | TEST_CASE("MemoryTracker: Cached write unmarked") { | ||
| 501 | RasterizerInterface rasterizer; | ||
| 502 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 503 | memory_track->UnmarkRegionAsCpuModified(c, WORD); | ||
| 504 | memory_track->CachedCpuWrite(c + PAGE, PAGE); | ||
| 505 | memory_track->UnmarkRegionAsCpuModified(c + PAGE, PAGE); | ||
| 506 | REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 507 | memory_track->FlushCachedWrites(); | ||
| 508 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 509 | memory_track->MarkRegionAsCpuModified(c, WORD); | ||
| 510 | REQUIRE(rasterizer.Count() == 0); | ||
| 511 | } | ||
| 512 | |||
| 513 | TEST_CASE("MemoryTracker: Cached write iterated") { | ||
| 514 | RasterizerInterface rasterizer; | ||
| 515 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 516 | memory_track->UnmarkRegionAsCpuModified(c, WORD); | ||
| 517 | memory_track->CachedCpuWrite(c + PAGE, PAGE); | ||
| 518 | int num = 0; | ||
| 519 | memory_track->ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { ++num; }); | ||
| 520 | REQUIRE(num == 0); | ||
| 521 | REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 522 | memory_track->FlushCachedWrites(); | ||
| 523 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 524 | memory_track->MarkRegionAsCpuModified(c, WORD); | ||
| 525 | REQUIRE(rasterizer.Count() == 0); | ||
| 526 | } | ||
| 527 | |||
| 528 | TEST_CASE("MemoryTracker: Cached write downloads") { | ||
| 529 | RasterizerInterface rasterizer; | ||
| 530 | std::unique_ptr<MemoryTracker> memory_track(std::make_unique<MemoryTracker>(rasterizer)); | ||
| 531 | memory_track->UnmarkRegionAsCpuModified(c, WORD); | ||
| 532 | REQUIRE(rasterizer.Count() == 64); | ||
| 533 | memory_track->CachedCpuWrite(c + PAGE, PAGE); | ||
| 534 | REQUIRE(rasterizer.Count() == 63); | ||
| 535 | memory_track->MarkRegionAsGpuModified(c + PAGE, PAGE); | ||
| 536 | int num = 0; | ||
| 537 | memory_track->ForEachDownloadRangeAndClear(c, WORD, [&](u64 offset, u64 size) { ++num; }); | ||
| 538 | memory_track->ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) { ++num; }); | ||
| 539 | REQUIRE(num == 0); | ||
| 540 | REQUIRE(!memory_track->IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 541 | REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE)); | ||
| 542 | memory_track->FlushCachedWrites(); | ||
| 543 | REQUIRE(memory_track->IsRegionCpuModified(c + PAGE, PAGE)); | ||
| 544 | REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE)); | ||
| 545 | memory_track->MarkRegionAsCpuModified(c, WORD); | ||
| 546 | REQUIRE(rasterizer.Count() == 0); | ||
| 547 | } \ No newline at end of file | ||