test(agc): add unit test for copied writer indirect overlap disambiguation

This commit is contained in:
Kikoarl 2026-10-12 02:06:41 +02:00
parent a057eede19
commit d906ee2f6d
1 changed files with 95 additions and 0 deletions

View File

@ -20,6 +20,7 @@
#include "CacheKey.hpp"
#include "Optimization/ResourceProgram.hpp"
#include "BdaAbi.hpp"
#include "prx/libc/include/GuestAllocations.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include <spirv/unified1/spirv.hpp>
#include <algorithm>
@ -3238,6 +3239,99 @@ void barycentricEmulationTests() {
expectFailure([&] { static_cast<void>(BuildBarycentricGeometryShader(vertex, fragment, target, limits)); }, "not exported by the vertex shader");
}
void copiedWriterIndirectOverlapTests() {
using namespace ShaderRecompiler;
using namespace AgcDriver::Graphics;
constexpr std::size_t half = 65536;
void* directBlock = ::operator new(half, std::align_val_t{half});
std::memset(directBlock, 0xaa, half);
const auto directAddress = reinterpret_cast<std::uintptr_t>(directBlock);
void* copiedBlock = ::operator new(half, std::align_val_t{half});
std::memset(copiedBlock, 0xbb, half);
const auto copiedAddress = reinterpret_cast<std::uintptr_t>(copiedBlock);
{
auto* mutation = GuestAllocations::GuestAllocationsBegin_nid_postfix();
GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, directBlock, half, true, true, true);
GuestAllocations::GuestAllocationsEnd_nid_postfix(mutation);
}
mock = MockVulkan{};
auto context = mockContext();
context.hostImportAlignment = half;
context.limits.minStorageBufferOffsetAlignment = 16;
context.limits.maxStorageBufferRange = 1u << 27;
{
GuestBufferMemory memory(context);
memory.AcquireRegistered();
Require(HostImportCovers(context, directAddress, half), "direct registered range must be covered by host import");
Require(!HostImportCovers(context, copiedAddress, half), "copied unregistered range must NOT be covered by host import");
memory.AddWritable(copiedAddress, 1024);
memory.AddWritable(directAddress, 1024);
memory.Upload(false);
Require(memory.HasCopiedWrites(), "writer with one copied region must report HasCopiedWrites() == true");
Require(memory.WritesOverlap(directAddress, 16), "WritesOverlap must return true for direct written region");
Require(memory.WritesOverlap(copiedAddress, 16), "WritesOverlap must return true for copied written region");
Require(!memory.WritesOverlap(directAddress + 2048, 16), "WritesOverlap must return false for unwritten range");
Require(!memory.CopiedWritesOverlap(directAddress, 16), "CopiedWritesOverlap must return false for direct written region");
Require(memory.CopiedWritesOverlap(copiedAddress, 16), "CopiedWritesOverlap must return true for copied written region");
Require(!memory.CopiedWritesOverlap(directAddress + 2048, 16), "CopiedWritesOverlap must return false for unwritten range");
memory.WriteBack();
}
{
RecompileResult shader;
shader.runtimeAbiVersion = RuntimeAbi::Version;
auto copiedBinding = makeBinding(Role::GuestBuffers, 0, 1, vsharp(copiedBlock, 1024));
copiedBinding.bufferWritten = {true};
auto directBinding = makeBinding(Role::GuestBuffers, 1, 1, vsharp(directBlock, 1024));
directBinding.bufferWritten = {true};
shader.bindings = {copiedBinding, directBinding};
CompiledShader compiled{ShaderStage::Compute, &shader, 0};
auto writer = std::make_shared<ShaderResources>(context, compiled);
Require(writer->HasCopiedWrites(), "ShaderResources with copied region must report HasCopiedWrites() == true");
Require(writer->WritesOverlap(directAddress, 16), "ShaderResources must report WritesOverlap for direct region");
Require(!writer->CopiedWritesOverlap(directAddress, 16), "ShaderResources must NOT report CopiedWritesOverlap for direct region");
Require(writer->CopiedWritesOverlap(copiedAddress, 16), "ShaderResources must report CopiedWritesOverlap for copied region");
auto copiedWriters = DrawCopiedWriters();
copiedWriters->push_back(writer);
const auto overlapsMain = [&](const auto& w) { return w->WritesOverlap(directAddress, 16); };
const auto overlapsPR = [&](const auto& w) { return w->CopiedWritesOverlap(directAddress, 16); };
const bool mainOverlaps = std::any_of(copiedWriters->begin(), copiedWriters->end(), overlapsMain);
const bool prOverlaps = std::any_of(copiedWriters->begin(), copiedWriters->end(), overlapsPR);
Require(mainOverlaps, "main's check (WritesOverlap) must flag an overlap over direct arguments");
Require(!prOverlaps, "PR's check (CopiedWritesOverlap) must disambiguate and NOT flag an overlap over direct arguments");
const auto copiedOverlapsPR = [&](const auto& w) { return w->CopiedWritesOverlap(copiedAddress, 16); };
Require(std::any_of(copiedWriters->begin(), copiedWriters->end(), copiedOverlapsPR), "PR's check must flag an overlap over copied arguments");
copiedWriters->erase(std::remove(copiedWriters->begin(), copiedWriters->end(), writer), copiedWriters->end());
writer->WriteBack();
}
{
auto* mutation = GuestAllocations::GuestAllocationsBegin_nid_postfix();
GuestAllocations::GuestAllocationsRemove_nid_postfix(mutation, directBlock);
GuestAllocations::GuestAllocationsEnd_nid_postfix(mutation);
}
::operator delete(directBlock, std::align_val_t{half});
::operator delete(copiedBlock, std::align_val_t{half});
}
void rectListTests() {
using namespace ShaderRecompiler;
using namespace AgcDriver::Graphics;
@ -4642,6 +4736,7 @@ int main(int argc, char** argv) {
rectListTests();
floatControlsModeTests();
barycentricEmulationTests();
copiedWriterIndirectOverlapTests();
mock = MockVulkan{};
auto bdaContext = mockContext();
bdaContext.bufferDeviceAddress = true;