tests: Add unit tests for the GPU range tracking buffer container
Due to how error prone the container design is, this commit adds unit tests for it. Some tests taken from here are based on bugs from using this buffer container in games, so if we ever break it in the future in a way that might harm games, the tests should fail.
This commit is contained in:
parent
a4bfae1b55
commit
7bd603061c
|
@ -6,6 +6,7 @@ add_executable(tests
|
||||||
common/ring_buffer.cpp
|
common/ring_buffer.cpp
|
||||||
core/core_timing.cpp
|
core/core_timing.cpp
|
||||||
tests.cpp
|
tests.cpp
|
||||||
|
video_core/buffer_base.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
create_target_directory_groups(tests)
|
create_target_directory_groups(tests)
|
||||||
|
|
|
@ -0,0 +1,473 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#include "common/alignment.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "video_core/buffer_cache/buffer_base.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
using VideoCommon::BufferBase;
|
||||||
|
using Range = std::pair<u64, u64>;
|
||||||
|
|
||||||
|
constexpr u64 PAGE = 4096;
|
||||||
|
constexpr u64 WORD = 4096 * 64;
|
||||||
|
|
||||||
|
constexpr VAddr c = 0x1328914000;
|
||||||
|
|
||||||
|
class RasterizerInterface {
|
||||||
|
public:
|
||||||
|
void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
|
||||||
|
const u64 page_start{addr >> Core::Memory::PAGE_BITS};
|
||||||
|
const u64 page_end{(addr + size + Core::Memory::PAGE_SIZE - 1) >> Core::Memory::PAGE_BITS};
|
||||||
|
for (u64 page = page_start; page < page_end; ++page) {
|
||||||
|
int& value = page_table[page];
|
||||||
|
value += delta;
|
||||||
|
if (value < 0) {
|
||||||
|
throw std::logic_error{"negative page"};
|
||||||
|
}
|
||||||
|
if (value == 0) {
|
||||||
|
page_table.erase(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] int Count(VAddr addr) const noexcept {
|
||||||
|
const auto it = page_table.find(addr >> Core::Memory::PAGE_BITS);
|
||||||
|
return it == page_table.end() ? 0 : it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] unsigned Count() const noexcept {
|
||||||
|
unsigned count = 0;
|
||||||
|
for (const auto [index, value] : page_table) {
|
||||||
|
count += value;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<u64, int> page_table;
|
||||||
|
};
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Small buffer", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD);
|
||||||
|
REQUIRE(rasterizer.Count() == 0);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD);
|
||||||
|
REQUIRE(rasterizer.Count() == WORD / PAGE);
|
||||||
|
REQUIRE(buffer.ModifiedCpuRegion(c, WORD) == Range{0, 0});
|
||||||
|
|
||||||
|
buffer.MarkRegionAsCpuModified(c + PAGE, 1);
|
||||||
|
REQUIRE(buffer.ModifiedCpuRegion(c, WORD) == Range{PAGE * 1, PAGE * 2});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Large buffer", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD * 32);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD * 32);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + 4096, WORD * 4);
|
||||||
|
REQUIRE(buffer.ModifiedCpuRegion(c, WORD + PAGE * 2) == Range{PAGE, WORD + PAGE * 2});
|
||||||
|
REQUIRE(buffer.ModifiedCpuRegion(c + PAGE * 2, PAGE * 6) == Range{PAGE * 2, PAGE * 8});
|
||||||
|
REQUIRE(buffer.ModifiedCpuRegion(c, WORD * 32) == Range{PAGE, WORD * 4 + PAGE});
|
||||||
|
REQUIRE(buffer.ModifiedCpuRegion(c + WORD * 4, PAGE) == Range{WORD * 4, WORD * 4 + PAGE});
|
||||||
|
REQUIRE(buffer.ModifiedCpuRegion(c + WORD * 3 + PAGE * 63, PAGE) ==
|
||||||
|
Range{WORD * 3 + PAGE * 63, WORD * 4});
|
||||||
|
|
||||||
|
buffer.MarkRegionAsCpuModified(c + WORD * 5 + PAGE * 6, PAGE);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + WORD * 5 + PAGE * 8, PAGE);
|
||||||
|
REQUIRE(buffer.ModifiedCpuRegion(c + WORD * 5, WORD) ==
|
||||||
|
Range{WORD * 5 + PAGE * 6, WORD * 5 + PAGE * 9});
|
||||||
|
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c + WORD * 5 + PAGE * 8, PAGE);
|
||||||
|
REQUIRE(buffer.ModifiedCpuRegion(c + WORD * 5, WORD) ==
|
||||||
|
Range{WORD * 5 + PAGE * 6, WORD * 5 + PAGE * 7});
|
||||||
|
|
||||||
|
buffer.MarkRegionAsCpuModified(c + PAGE, WORD * 31 + PAGE * 63);
|
||||||
|
REQUIRE(buffer.ModifiedCpuRegion(c, WORD * 32) == Range{PAGE, WORD * 32});
|
||||||
|
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c + PAGE * 4, PAGE);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c + PAGE * 6, PAGE);
|
||||||
|
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD * 32);
|
||||||
|
REQUIRE(buffer.ModifiedCpuRegion(c, WORD * 32) == Range{0, 0});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Rasterizer counting", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, PAGE * 2);
|
||||||
|
REQUIRE(rasterizer.Count() == 0);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, PAGE);
|
||||||
|
REQUIRE(rasterizer.Count() == 1);
|
||||||
|
buffer.MarkRegionAsCpuModified(c, PAGE * 2);
|
||||||
|
REQUIRE(rasterizer.Count() == 0);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, PAGE);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c + PAGE, PAGE);
|
||||||
|
REQUIRE(rasterizer.Count() == 2);
|
||||||
|
buffer.MarkRegionAsCpuModified(c, PAGE * 2);
|
||||||
|
REQUIRE(rasterizer.Count() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Basic range", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD);
|
||||||
|
buffer.MarkRegionAsCpuModified(c, PAGE);
|
||||||
|
int num = 0;
|
||||||
|
buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == 0U);
|
||||||
|
REQUIRE(size == PAGE);
|
||||||
|
++num;
|
||||||
|
});
|
||||||
|
REQUIRE(num == 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Border upload", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD * 2);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD * 2);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
|
||||||
|
buffer.ForEachUploadRange(c, WORD * 2, [](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == WORD - PAGE);
|
||||||
|
REQUIRE(size == PAGE * 2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Border upload range", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD * 2);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD * 2);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
|
||||||
|
buffer.ForEachUploadRange(c + WORD - PAGE, PAGE * 2, [](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == WORD - PAGE);
|
||||||
|
REQUIRE(size == PAGE * 2);
|
||||||
|
});
|
||||||
|
buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
|
||||||
|
buffer.ForEachUploadRange(c + WORD - PAGE, PAGE, [](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == WORD - PAGE);
|
||||||
|
REQUIRE(size == PAGE);
|
||||||
|
});
|
||||||
|
buffer.ForEachUploadRange(c + WORD, PAGE, [](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == WORD);
|
||||||
|
REQUIRE(size == PAGE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Border upload partial range", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD * 2);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD * 2);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
|
||||||
|
buffer.ForEachUploadRange(c + WORD - 1, 2, [](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == WORD - PAGE);
|
||||||
|
REQUIRE(size == PAGE * 2);
|
||||||
|
});
|
||||||
|
buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
|
||||||
|
buffer.ForEachUploadRange(c + WORD - 1, 1, [](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == WORD - PAGE);
|
||||||
|
REQUIRE(size == PAGE);
|
||||||
|
});
|
||||||
|
buffer.ForEachUploadRange(c + WORD + 50, 1, [](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == WORD);
|
||||||
|
REQUIRE(size == PAGE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Partial word uploads", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, 0x9d000);
|
||||||
|
int num = 0;
|
||||||
|
buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == 0U);
|
||||||
|
REQUIRE(size == WORD);
|
||||||
|
++num;
|
||||||
|
});
|
||||||
|
REQUIRE(num == 1);
|
||||||
|
buffer.ForEachUploadRange(c + WORD, WORD, [&](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == WORD);
|
||||||
|
REQUIRE(size == WORD);
|
||||||
|
++num;
|
||||||
|
});
|
||||||
|
REQUIRE(num == 2);
|
||||||
|
buffer.ForEachUploadRange(c + 0x79000, 0x24000, [&](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == WORD * 2);
|
||||||
|
REQUIRE(size == PAGE * 0x1d);
|
||||||
|
++num;
|
||||||
|
});
|
||||||
|
REQUIRE(num == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Partial page upload", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD);
|
||||||
|
int num = 0;
|
||||||
|
buffer.MarkRegionAsCpuModified(c + PAGE * 2, PAGE);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + PAGE * 9, PAGE);
|
||||||
|
buffer.ForEachUploadRange(c, PAGE * 3, [&](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == PAGE * 2);
|
||||||
|
REQUIRE(size == PAGE);
|
||||||
|
++num;
|
||||||
|
});
|
||||||
|
REQUIRE(num == 1);
|
||||||
|
buffer.ForEachUploadRange(c + PAGE * 7, PAGE * 3, [&](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == PAGE * 9);
|
||||||
|
REQUIRE(size == PAGE);
|
||||||
|
++num;
|
||||||
|
});
|
||||||
|
REQUIRE(num == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Partial page upload with multiple words on the right") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD * 8);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD * 8);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + PAGE * 13, WORD * 7);
|
||||||
|
int num = 0;
|
||||||
|
buffer.ForEachUploadRange(c + PAGE * 10, WORD * 7, [&](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == PAGE * 13);
|
||||||
|
REQUIRE(size == WORD * 7 - PAGE * 3);
|
||||||
|
++num;
|
||||||
|
});
|
||||||
|
REQUIRE(num == 1);
|
||||||
|
buffer.ForEachUploadRange(c + PAGE, WORD * 8, [&](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == WORD * 7 + PAGE * 10);
|
||||||
|
REQUIRE(size == PAGE * 3);
|
||||||
|
++num;
|
||||||
|
});
|
||||||
|
REQUIRE(num == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Partial page upload with multiple words on the left", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD * 8);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD * 8);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + PAGE * 13, WORD * 7);
|
||||||
|
int num = 0;
|
||||||
|
buffer.ForEachUploadRange(c + PAGE * 16, WORD * 7, [&](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == PAGE * 16);
|
||||||
|
REQUIRE(size == WORD * 7 - PAGE * 3);
|
||||||
|
++num;
|
||||||
|
});
|
||||||
|
REQUIRE(num == 1);
|
||||||
|
buffer.ForEachUploadRange(c + PAGE, WORD, [&](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == PAGE * 13);
|
||||||
|
REQUIRE(size == PAGE * 3);
|
||||||
|
++num;
|
||||||
|
});
|
||||||
|
REQUIRE(num == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Partial page upload with multiple words in the middle", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD * 8);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD * 8);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + PAGE * 13, PAGE * 140);
|
||||||
|
int num = 0;
|
||||||
|
buffer.ForEachUploadRange(c + PAGE * 16, WORD, [&](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == PAGE * 16);
|
||||||
|
REQUIRE(size == WORD);
|
||||||
|
++num;
|
||||||
|
});
|
||||||
|
REQUIRE(num == 1);
|
||||||
|
buffer.ForEachUploadRange(c, WORD, [&](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == PAGE * 13);
|
||||||
|
REQUIRE(size == PAGE * 3);
|
||||||
|
++num;
|
||||||
|
});
|
||||||
|
REQUIRE(num == 2);
|
||||||
|
buffer.ForEachUploadRange(c, WORD * 8, [&](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == WORD + PAGE * 16);
|
||||||
|
REQUIRE(size == PAGE * 73);
|
||||||
|
++num;
|
||||||
|
});
|
||||||
|
REQUIRE(num == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Empty right bits", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD * 2048);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD * 2048);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + WORD - PAGE, PAGE * 2);
|
||||||
|
buffer.ForEachUploadRange(c, WORD * 2048, [](u64 offset, u64 size) {
|
||||||
|
REQUIRE(offset == WORD - PAGE);
|
||||||
|
REQUIRE(size == PAGE * 2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Out of bound ranges 1", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD);
|
||||||
|
buffer.MarkRegionAsCpuModified(c, PAGE);
|
||||||
|
int num = 0;
|
||||||
|
buffer.ForEachUploadRange(c - WORD, WORD, [&](u64 offset, u64 size) { ++num; });
|
||||||
|
buffer.ForEachUploadRange(c + WORD, WORD, [&](u64 offset, u64 size) { ++num; });
|
||||||
|
buffer.ForEachUploadRange(c - PAGE, PAGE, [&](u64 offset, u64 size) { ++num; });
|
||||||
|
REQUIRE(num == 0);
|
||||||
|
buffer.ForEachUploadRange(c - PAGE, PAGE * 2, [&](u64 offset, u64 size) { ++num; });
|
||||||
|
REQUIRE(num == 1);
|
||||||
|
buffer.MarkRegionAsCpuModified(c, WORD);
|
||||||
|
REQUIRE(rasterizer.Count() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Out of bound ranges 2", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, 0x22000);
|
||||||
|
REQUIRE_NOTHROW(buffer.UnmarkRegionAsCpuModified(c + 0x22000, PAGE));
|
||||||
|
REQUIRE_NOTHROW(buffer.UnmarkRegionAsCpuModified(c + 0x28000, PAGE));
|
||||||
|
REQUIRE(rasterizer.Count() == 0);
|
||||||
|
REQUIRE_NOTHROW(buffer.UnmarkRegionAsCpuModified(c + 0x21100, PAGE - 0x100));
|
||||||
|
REQUIRE(rasterizer.Count() == 1);
|
||||||
|
REQUIRE_NOTHROW(buffer.UnmarkRegionAsCpuModified(c - 0x1000, PAGE * 2));
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c - 0x3000, PAGE * 2);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c - 0x2000, PAGE * 2);
|
||||||
|
REQUIRE(rasterizer.Count() == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Out of bound ranges 3", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, 0x310720);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, 0x310720);
|
||||||
|
REQUIRE(rasterizer.Count(c) == 1);
|
||||||
|
REQUIRE(rasterizer.Count(c + PAGE) == 1);
|
||||||
|
REQUIRE(rasterizer.Count(c + WORD) == 1);
|
||||||
|
REQUIRE(rasterizer.Count(c + WORD + PAGE) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Sparse regions 1", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + PAGE * 1, PAGE);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + PAGE * 3, PAGE * 4);
|
||||||
|
buffer.ForEachUploadRange(c, WORD, [i = 0](u64 offset, u64 size) mutable {
|
||||||
|
static constexpr std::array<u64, 2> offsets{PAGE, PAGE * 3};
|
||||||
|
static constexpr std::array<u64, 2> sizes{PAGE, PAGE * 4};
|
||||||
|
REQUIRE(offset == offsets.at(i));
|
||||||
|
REQUIRE(size == sizes.at(i));
|
||||||
|
++i;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Sparse regions 2", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, 0x22000);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, 0x22000);
|
||||||
|
REQUIRE(rasterizer.Count() == 0x22);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + PAGE * 0x1B, PAGE);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + PAGE * 0x21, PAGE);
|
||||||
|
buffer.ForEachUploadRange(c, WORD, [i = 0](u64 offset, u64 size) mutable {
|
||||||
|
static constexpr std::array<u64, 2> offsets{PAGE * 0x1B, PAGE * 0x21};
|
||||||
|
static constexpr std::array<u64, 2> sizes{PAGE, PAGE};
|
||||||
|
REQUIRE(offset == offsets.at(i));
|
||||||
|
REQUIRE(size == sizes.at(i));
|
||||||
|
++i;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Single page modified range", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, PAGE);
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c, PAGE));
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, PAGE);
|
||||||
|
REQUIRE(!buffer.IsRegionCpuModified(c, PAGE));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Two page modified range", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, PAGE * 2);
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c, PAGE));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c, PAGE * 2));
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, PAGE);
|
||||||
|
REQUIRE(!buffer.IsRegionCpuModified(c, PAGE));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Multi word modified ranges", "[video_core]") {
|
||||||
|
for (int offset = 0; offset < 4; ++offset) {
|
||||||
|
const VAddr address = c + WORD * offset;
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, address, WORD * 4);
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(address, PAGE));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 48, PAGE));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 56, PAGE));
|
||||||
|
|
||||||
|
buffer.UnmarkRegionAsCpuModified(address + PAGE * 32, PAGE);
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(address + PAGE, WORD));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 31, PAGE));
|
||||||
|
REQUIRE(!buffer.IsRegionCpuModified(address + PAGE * 32, PAGE));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 33, PAGE));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 31, PAGE * 2));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(address + PAGE * 32, PAGE * 2));
|
||||||
|
|
||||||
|
buffer.UnmarkRegionAsCpuModified(address + PAGE * 33, PAGE);
|
||||||
|
REQUIRE(!buffer.IsRegionCpuModified(address + PAGE * 32, PAGE * 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Single page in large buffer", "[video_core]") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD * 16);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD * 16);
|
||||||
|
REQUIRE(!buffer.IsRegionCpuModified(c, WORD * 16));
|
||||||
|
|
||||||
|
buffer.MarkRegionAsCpuModified(c + WORD * 12 + PAGE * 8, PAGE);
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c, WORD * 16));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + WORD * 10, WORD * 2));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + WORD * 11, WORD * 2));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + WORD * 12, WORD * 2));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + WORD * 12 + PAGE * 4, PAGE * 8));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + WORD * 12 + PAGE * 6, PAGE * 8));
|
||||||
|
REQUIRE(!buffer.IsRegionCpuModified(c + WORD * 12 + PAGE * 6, PAGE));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + WORD * 12 + PAGE * 7, PAGE * 2));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + WORD * 12 + PAGE * 8, PAGE * 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Out of bounds region query") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD * 16);
|
||||||
|
REQUIRE(!buffer.IsRegionCpuModified(c - PAGE, PAGE));
|
||||||
|
REQUIRE(!buffer.IsRegionCpuModified(c - PAGE * 2, PAGE));
|
||||||
|
REQUIRE(!buffer.IsRegionCpuModified(c + WORD * 16, PAGE));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + WORD * 16 - PAGE, WORD * 64));
|
||||||
|
REQUIRE(!buffer.IsRegionCpuModified(c + WORD * 16, WORD * 64));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Wrap word regions") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD * 2);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD * 2);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + PAGE * 63, PAGE * 2);
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c, WORD * 2));
|
||||||
|
REQUIRE(!buffer.IsRegionCpuModified(c + PAGE * 62, PAGE));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 63, PAGE));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 64, PAGE));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 63, PAGE * 2));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 63, PAGE * 8));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 60, PAGE * 8));
|
||||||
|
|
||||||
|
REQUIRE(!buffer.IsRegionCpuModified(c + PAGE * 127, WORD * 16));
|
||||||
|
buffer.MarkRegionAsCpuModified(c + PAGE * 127, PAGE);
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 127, WORD * 16));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 127, PAGE));
|
||||||
|
REQUIRE(!buffer.IsRegionCpuModified(c + PAGE * 126, PAGE));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + PAGE * 126, PAGE * 2));
|
||||||
|
REQUIRE(!buffer.IsRegionCpuModified(c + PAGE * 128, WORD * 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BufferBase: Unaligned page region query") {
|
||||||
|
RasterizerInterface rasterizer;
|
||||||
|
BufferBase buffer(rasterizer, c, WORD);
|
||||||
|
buffer.UnmarkRegionAsCpuModified(c, WORD);
|
||||||
|
buffer.MarkRegionAsCpuModified(c + 4000, 1000);
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c, PAGE));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + PAGE, PAGE));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + 4000, 1000));
|
||||||
|
REQUIRE(buffer.IsRegionCpuModified(c + 4000, 1));
|
||||||
|
}
|
Loading…
Reference in New Issue