mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-06 13:30:00 +00:00
test(agc): check that a checkerboard depth pass through the exact sample order path builds no recipe
This commit is contained in:
1 parent
0700f72070
commit
aaffe035ac
1 file changed
+75
-41
@@ -715,6 +715,7 @@ struct Pass {
|
||||
std::optional<SampleOrder> order;
|
||||
bool storesInvocations = false;
|
||||
std::function<void()> beforeReplay;
|
||||
bool buildsNoRecipe = false;
|
||||
};
|
||||
|
||||
void Draw(AgcDriver::VulkanDevice& device, const Context& context, const Pass& pass) {
|
||||
@@ -799,12 +800,16 @@ void Draw(AgcDriver::VulkanDevice& device, const Context& context, const Pass& p
|
||||
}
|
||||
shaders.push_back({ShaderStage::Fragment, &pixelResult, PixelPushOffset(vertexPush, target)});
|
||||
const AgcDriver::Pm4::DrawParameters draw{0, static_cast<std::uint32_t>(pass.vertices->size()), 0, 1, 0, false};
|
||||
if (!pass.beforeReplay) {
|
||||
if (!pass.beforeReplay && !pass.buildsNoRecipe) {
|
||||
AgcDriver::Graphics::Draw(context, state, draw, shaders);
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<const AgcDriver::DrawRecipe> recipe;
|
||||
AgcDriver::Graphics::Draw(context, state, draw, shaders, {}, &recipe);
|
||||
if (pass.buildsNoRecipe) {
|
||||
Require(recipe == nullptr, "a draw that reorders its samples built a recipe");
|
||||
return;
|
||||
}
|
||||
Require(recipe != nullptr, "the recorded draw built no recipe");
|
||||
pass.beforeReplay();
|
||||
const auto replayed = AgcDriver::Graphics::DrawWithRecipe(context, state, draw, shaders, {}, *recipe);
|
||||
@@ -1252,6 +1257,57 @@ int GridReference(AgcDriver::VulkanDevice& device) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CheckRecipeDepth(AgcDriver::VulkanDevice& device, const Context& context, const std::array<std::uint8_t, 32>& locations, std::size_t run, const std::string& what, bool reordered) {
|
||||
constexpr std::uint32_t samples = 2u;
|
||||
AgcDriver::Graphics::DepthTarget depth{reinterpret_cast<std::uintptr_t>(DepthMemory.data()) + 256u * 1024u * run, 0u, ReferenceExtent, VK_FORMAT_D32_SFLOAT, 1.0f, 0};
|
||||
depth.samples = samples;
|
||||
const Vertices clear = Screen(ClearDepth);
|
||||
Pass clearPass;
|
||||
clearPass.vertices = &clear;
|
||||
clearPass.code = NullExportCode;
|
||||
clearPass.samples = samples;
|
||||
clearPass.extent = ReferenceExtent;
|
||||
clearPass.depth = depth;
|
||||
clearPass.depthWrite = true;
|
||||
clearPass.locations = locations;
|
||||
auto slopes = clearPass;
|
||||
slopes.vertices = &Slopes;
|
||||
auto& vertexBlock = NewBlock(Slopes.size() * sizeof(Slopes[0]));
|
||||
std::memcpy(reinterpret_cast<void*>(static_cast<std::uintptr_t>(vertexBlock.Address())), Slopes.data(), Slopes.size() * sizeof(Slopes[0]));
|
||||
slopes.vertexMemory = reinterpret_cast<const void*>(static_cast<std::uintptr_t>(vertexBlock.Address()));
|
||||
if (reordered) {
|
||||
slopes.buildsNoRecipe = true;
|
||||
Draw(device, context, clearPass);
|
||||
Draw(device, context, slopes);
|
||||
Settle(device);
|
||||
std::printf("%s: builds no recipe, since a draw that reorders its samples is built in full each time, with its sample swaps\n", what.c_str());
|
||||
return;
|
||||
}
|
||||
const auto read = [&] { return ReadTarget(context, AgcDriver::Graphics::DepthSurfaceOrderTarget(context, depth).view, false, samples); };
|
||||
Samples recorded;
|
||||
slopes.beforeReplay = [&] {
|
||||
Settle(device);
|
||||
recorded = read();
|
||||
Draw(device, context, clearPass);
|
||||
Settle(device);
|
||||
const auto cleared = read();
|
||||
Require(std::all_of(cleared.begin(), cleared.end(), [](const std::array<std::uint32_t, 4>& value) { return std::bit_cast<float>(value[0]) == ClearDepth; }), what + ": the clear between the recorded draw and its replay left depth other than the clear value");
|
||||
};
|
||||
Draw(device, context, clearPass);
|
||||
Draw(device, context, slopes);
|
||||
Settle(device);
|
||||
const auto replayed = read();
|
||||
const auto first = PrintDepthLocations(what + ", the recorded draw", LocateDepth(recorded, locations));
|
||||
PrintDepthLocations(what + ", the recipe's replay as the first draw of a pass", LocateDepth(replayed, locations));
|
||||
Require(first.sloped != 0u, what + ": the recorded draw left no sloped depth");
|
||||
const bool readAtGuestLocations = first.guest == first.sloped;
|
||||
if (!readAtGuestLocations) std::printf("%s: the device reads depth drawn at custom sample locations back at other locations, even after a transition that names them: the replay is compared with the recorded draw as the device reads both back\n", what.c_str());
|
||||
const auto differences = Differences(recorded, replayed, samples, what + ", depth replayed from the recipe", true);
|
||||
std::printf("%s, %ux%u: the recipe's replay differs from the recorded draw in %zu of %zu samples\n", what.c_str(), ReferenceExtent.width, ReferenceExtent.height, differences, recorded.size());
|
||||
Require(differences == 0u, what + (readAtGuestLocations ? ": the recipe's replay did not leave the depth the recorded draw left at the guest's sample locations" : ": the recipe's replay did not leave the depth the recorded draw left, as the device reads both back"));
|
||||
std::printf("%s: a depth-only 2x draw replayed from its recipe as the first draw of a pass leaves the depth the recorded draw left%s, bit for bit\n", what.c_str(), readAtGuestLocations ? "" : " as the device reads both back");
|
||||
}
|
||||
|
||||
int RecipeDepthLocations(AgcDriver::VulkanDevice& device) {
|
||||
const auto context = AgcDriver::VulkanDeviceTestAccess::ContextOf(device);
|
||||
ClearTargets clearTargets{device, context.device};
|
||||
@@ -1268,46 +1324,24 @@ int RecipeDepthLocations(AgcDriver::VulkanDevice& device) {
|
||||
std::printf("skipped, draw recipes are off (APS5_NO_DRAW_RECIPE)\n");
|
||||
return VulkanTestSkipped;
|
||||
}
|
||||
const auto locations = UniformLocations(VillageLocations, 0u);
|
||||
AgcDriver::Graphics::DepthTarget depth{reinterpret_cast<std::uintptr_t>(DepthMemory.data()), 0u, ReferenceExtent, VK_FORMAT_D32_SFLOAT, 1.0f, 0};
|
||||
depth.samples = samples;
|
||||
const Vertices clear = Screen(ClearDepth);
|
||||
Pass clearPass;
|
||||
clearPass.vertices = &clear;
|
||||
clearPass.code = NullExportCode;
|
||||
clearPass.samples = samples;
|
||||
clearPass.extent = ReferenceExtent;
|
||||
clearPass.depth = depth;
|
||||
clearPass.depthWrite = true;
|
||||
clearPass.locations = locations;
|
||||
auto slopes = clearPass;
|
||||
slopes.vertices = &Slopes;
|
||||
auto& vertexBlock = NewBlock(Slopes.size() * sizeof(Slopes[0]));
|
||||
std::memcpy(reinterpret_cast<void*>(static_cast<std::uintptr_t>(vertexBlock.Address())), Slopes.data(), Slopes.size() * sizeof(Slopes[0]));
|
||||
slopes.vertexMemory = reinterpret_cast<const void*>(static_cast<std::uintptr_t>(vertexBlock.Address()));
|
||||
const auto read = [&] { return ReadTarget(context, AgcDriver::Graphics::DepthSurfaceOrderTarget(context, depth).view, false, samples); };
|
||||
Samples recorded;
|
||||
slopes.beforeReplay = [&] {
|
||||
Settle(device);
|
||||
recorded = read();
|
||||
Draw(device, context, clearPass);
|
||||
Settle(device);
|
||||
const auto cleared = read();
|
||||
Require(std::all_of(cleared.begin(), cleared.end(), [](const std::array<std::uint32_t, 4>& value) { return std::bit_cast<float>(value[0]) == ClearDepth; }), "the clear between the recorded draw and its replay left depth other than the clear value");
|
||||
};
|
||||
Draw(device, context, clearPass);
|
||||
Draw(device, context, slopes);
|
||||
Settle(device);
|
||||
const auto replayed = read();
|
||||
const auto first = PrintDepthLocations("the recorded draw", LocateDepth(recorded, locations));
|
||||
PrintDepthLocations("the recipe's replay as the first draw of a pass", LocateDepth(replayed, locations));
|
||||
Require(first.sloped != 0u, "the recorded draw left no sloped depth");
|
||||
const bool readAtGuestLocations = first.guest == first.sloped;
|
||||
if (!readAtGuestLocations) std::printf("the device reads depth drawn at custom sample locations back at other locations, even after a transition that names them: the replay is compared with the recorded draw as the device reads both back\n");
|
||||
const auto differences = Differences(recorded, replayed, samples, "depth replayed from the recipe", true);
|
||||
std::printf("2x depth at custom sample locations, %ux%u: the recipe's replay differs from the recorded draw in %zu of %zu samples\n", ReferenceExtent.width, ReferenceExtent.height, differences, recorded.size());
|
||||
Require(differences == 0u, readAtGuestLocations ? "the recipe's replay did not leave the depth the recorded draw left at the guest's sample locations" : "the recipe's replay did not leave the depth the recorded draw left, as the device reads both back");
|
||||
std::puts(readAtGuestLocations ? "a depth-only 2x draw replayed from its recipe as the first draw of a pass leaves the depth the recorded draw left, bit for bit" : "a depth-only 2x draw replayed from its recipe as the first draw of a pass leaves the depth the recorded draw left as the device reads both back, bit for bit");
|
||||
CheckRecipeDepth(device, context, UniformLocations(VillageLocations, 0u), 0u, "pixel (0,0)'s locations in every pixel", false);
|
||||
auto emulated = context;
|
||||
emulated.sampleLocationGridSampleCounts = 0u;
|
||||
AgcDriver::Graphics::State probe{};
|
||||
probe.samples = samples;
|
||||
probe.customSampleLocations = true;
|
||||
probe.sampleLocationGrid = true;
|
||||
probe.sampleLocations = VillageLocations;
|
||||
probe.depth = AgcDriver::Graphics::DepthTarget{0x100000u, 0u, ReferenceExtent, VK_FORMAT_D32_SFLOAT, 1.0f, 0};
|
||||
probe.depth->samples = samples;
|
||||
const auto refusal = AgcDriver::Graphics::SampleOrderRefusal(emulated, probe);
|
||||
if (!refusal.empty()) {
|
||||
std::printf("the checkerboard through the exact path is not checked: the device does not put its samples in the guest's order: %s\n", refusal.c_str());
|
||||
return 0;
|
||||
}
|
||||
Require(AgcDriver::Graphics::ReordersSamples(AgcDriver::Graphics::HostSampleLocationsFor(emulated, probe).order), "the context without a 2x2 grid did not take the exact path");
|
||||
CheckRecipeDepth(device, emulated, UniformLocations(VillageLocations, 0u), 1u, "pixel (0,0)'s locations in every pixel, without a 2x2 grid", false);
|
||||
CheckRecipeDepth(device, emulated, VillageLocations, 2u, "the 2x checkerboard through the exact path", true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user