test(agc): check that a buffer written over pending storage results keeps both
A storage image is written on the GPU and left pending, then a leased address-based use writes the first 40800 bytes of the same memory as a buffer and every pending image is flushed: guest memory must hold the buffer's bytes where it wrote and the image's texels everywhere else. Runs with watched and with compared imports and returns 77 when host imports or write watching are unavailable.
This commit is contained in:
parent
f4ff589679
commit
554e615524
|
|
@ -810,6 +810,12 @@ if(BUILD_TESTING)
|
|||
set_tests_properties(agc_storage_baseline_settled PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
add_test(NAME agc_storage_written_buffer_order COMMAND agc_driver_recorder_tests --written-buffer-order-only)
|
||||
set_tests_properties(agc_storage_written_buffer_order PROPERTIES SKIP_RETURN_CODE 77 TIMEOUT 30)
|
||||
if(WIN32)
|
||||
set_tests_properties(agc_storage_written_buffer_order PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
add_test(NAME agc_host_import_unmap COMMAND agc_driver_recorder_tests --host-import-unmap-only)
|
||||
set_tests_properties(agc_host_import_unmap PROPERTIES SKIP_RETURN_CODE 77)
|
||||
add_test(NAME agc_parked_import_unmap COMMAND agc_driver_recorder_tests --parked-import-unmap-only)
|
||||
|
|
|
|||
|
|
@ -2482,6 +2482,103 @@ void storageRefreshTests(const Device& device, Recorder& recorder, bool watched)
|
|||
recorder.Sync();
|
||||
}
|
||||
|
||||
bool writtenBufferOrderTests(const Device& device, Recorder& recorder) {
|
||||
const auto& base = device.GetContext();
|
||||
if (base.hostImportAlignment == 0) {
|
||||
std::cout << "host imports unavailable: written buffer order not tested\n";
|
||||
return false;
|
||||
}
|
||||
constexpr std::uint32_t side = 256;
|
||||
constexpr std::size_t bytes = side * side * 4;
|
||||
void* block = AllocateWatched(bytes, 65536);
|
||||
if (block == nullptr) {
|
||||
std::cout << "no write watching: written buffer order not tested\n";
|
||||
return false;
|
||||
}
|
||||
std::memset(block, 0x55, bytes);
|
||||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Add(block, bytes, true, true, true);
|
||||
}
|
||||
struct Unregister {
|
||||
const Context& context;
|
||||
void* block;
|
||||
std::uint64_t address;
|
||||
~Unregister() {
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Remove(block);
|
||||
}
|
||||
HostImportFor(context, address, bytes);
|
||||
}
|
||||
} unregister{base, block, address};
|
||||
if (HostImportFor(base, address, bytes) == nullptr) {
|
||||
std::cout << "host import of the written buffer order block refused: written buffer order not tested\n";
|
||||
return false;
|
||||
}
|
||||
std::cout << "written buffer order: host imports are " << (AgcDriver::GuestMemory::Watched(address, bytes) ? "watched" : "compared") << "\n";
|
||||
TextureDetiler detiler(base);
|
||||
auto context = base;
|
||||
context.detiler = &detiler;
|
||||
GuestTextureResource resource{};
|
||||
resource.baseAddress = address;
|
||||
resource.width = side;
|
||||
resource.height = side;
|
||||
resource.mipCount = 1;
|
||||
resource.tileMode = TextureTileMode::kR64KBX;
|
||||
resource.dimension = TextureDimension::k2D;
|
||||
resource.format = 56;
|
||||
resource.dstSelX = 4;
|
||||
resource.dstSelY = 5;
|
||||
resource.dstSelZ = 6;
|
||||
resource.dstSelW = 7;
|
||||
Require(DescribeSurface(resource).guestBytes == bytes, "the written buffer order surface has an unexpected size");
|
||||
const auto settle = [&] {
|
||||
recorder.Submit();
|
||||
device.WaitQueue();
|
||||
recorder.Sync();
|
||||
};
|
||||
{
|
||||
auto image = StorageTexture::Create(context, detiler, resource, 0);
|
||||
const VkImageSubresourceRange range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
const VkClearColorValue red{{1.0f, 0.0f, 0.0f, 1.0f}};
|
||||
{
|
||||
const auto commands = recorder.Commands();
|
||||
recorder.Keep(image);
|
||||
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
context.Function<PFN_vkCmdClearColorImage>("vkCmdClearColorImage")(commands, image->Image(), VK_IMAGE_LAYOUT_GENERAL, &red, 1, &range);
|
||||
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
image->MarkDirty();
|
||||
}
|
||||
constexpr std::size_t written = 40800;
|
||||
GuestBufferMemory memory(context);
|
||||
memory.AcquireRegistered();
|
||||
memory.AddWritable(address, written, false, false);
|
||||
memory.Upload(true);
|
||||
std::uint32_t adjustment = 0;
|
||||
const auto view = memory.Descriptor(address, written, adjustment);
|
||||
Require(adjustment == 0, "the written buffer view is not aligned to its element");
|
||||
{
|
||||
const auto commands = recorder.Commands();
|
||||
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
context.Function<PFN_vkCmdFillBuffer>("vkCmdFillBuffer")(commands, view.buffer, view.offset, written, 0xa5a5a5a5u);
|
||||
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
}
|
||||
memory.RecordCopyBacks(recorder);
|
||||
memory.MarkDirectWrites();
|
||||
settle();
|
||||
StorageTexture::FlushAllPending("written buffer order test");
|
||||
settle();
|
||||
std::vector<std::byte> read(bytes);
|
||||
AgcDriver::GuestMemory::Read(address, read);
|
||||
Require(std::all_of(read.begin(), read.begin() + written, [](std::byte value) { return value == std::byte{0xa5}; }), "storage results pending under a buffer a later use wrote were stored over the buffer's contents");
|
||||
for (std::size_t i = written; i < bytes; ++i) Require(std::to_integer<std::uint8_t>(read[i]) == (i % 4 == 1 || i % 4 == 2 ? 0 : 255), "the storage results outside the written buffer did not reach guest memory");
|
||||
}
|
||||
recorder.Sync();
|
||||
return true;
|
||||
}
|
||||
|
||||
void hostImportUnmapTests(const Device& device, Recorder& recorder) {
|
||||
const auto& context = device.GetContext();
|
||||
if (context.hostImportAlignment == 0) {
|
||||
|
|
@ -5491,6 +5588,11 @@ int main(int argc, char** argv) {
|
|||
std::cout << "Completion label storage and ordering tests passed\n";
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::string_view(argv[1]) == "--written-buffer-order-only") {
|
||||
if (!writtenBufferOrderTests(device, recorder)) return 77;
|
||||
std::cout << "written buffer order tests passed\n";
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::string_view(argv[1]) == "--host-import-unmap-only") {
|
||||
gpu.unlock();
|
||||
hostImportUnmapTests(device, recorder);
|
||||
|
|
@ -5571,6 +5673,7 @@ int main(int argc, char** argv) {
|
|||
unitShadowTests(device, recorder);
|
||||
storageRefreshTests(device, recorder, false);
|
||||
storageRefreshTests(device, recorder, true);
|
||||
static_cast<void>(writtenBufferOrderTests(device, recorder));
|
||||
writeBackPaddingTests(device, recorder, false);
|
||||
writeBackPaddingTests(device, recorder, true);
|
||||
singlePassTests(device, recorder, false);
|
||||
|
|
|
|||
Loading…
Reference in New Issue