From ebe64c60e9c557645a5e6f44b9d3de3c2d2483f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 8 Aug 2019 11:49:35 +0200 Subject: [PATCH] Vulkan: Improve the Metal Gear Acid 2 performance hack. --- assets/compat.ini | 26 +++++---- ext/native/thin3d/VulkanQueueRunner.cpp | 74 +++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 12 deletions(-) diff --git a/assets/compat.ini b/assets/compat.ini index f1917c588254..74e11597fde1 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -403,13 +403,13 @@ NPJH50036 = true # Burnout games have problems with this on Mali, and have no use for it # Legends -ULES00125 = true -ULUS10025 = true -ULJM05228 = true -NPJH50305 = true -ULJM05049 = true -ULKS46027 = true -ULAS42019 = true +#ULES00125 = true +#ULUS10025 = true +#ULJM05228 = true +#NPJH50305 = true +#ULJM05049 = true +#ULKS46027 = true +#ULAS42019 = true # Dominator ULUS10236 = true @@ -441,15 +441,17 @@ ULES01376 = true ULUS10466 = true [MGS2AcidHack] +ULUS10006 = true # Metal Gear Acid ULES00008 = true +ULJM05001 = true +ULAS42007 = true +ULJM08001 = true +ULUS10077 = true # Metal Gear Acid 2 +ULAS42035 = true ULES00284 = true ULJM05047 = true ULKS46065 = true -ULJM08001 = true -ULJM05001 = true -ULAS42007 = true -ULUS10006 = true -ULUS10077 = true +ULJM08011 = true [SonicRivalsHack] ULES00622 = true # SR1 diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index a0042faf4e64..1a36d139cf18 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -463,6 +463,8 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector &st } void VulkanQueueRunner::ApplyMGSHack(std::vector &steps) { + // Really need a sane way to express transforms of steps. + // We want to turn a sequence of copy,render(1),copy,render(1),copy,render(1) to copy,copy,copy,render(n). for (int i = 0; i < (int)steps.size() - 3; i++) { @@ -530,6 +532,78 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector &steps) { break; } } + + // There's also a post processing effect using depals that's just brutal in some parts + // of the game. + for (int i = 0; i < (int)steps.size() - 3; i++) { + int last = -1; + if (!(steps[i]->stepType == VKRStepType::RENDER && + steps[i + 1]->stepType == VKRStepType::RENDER && + steps[i + 2]->stepType == VKRStepType::RENDER && + steps[i]->render.numDraws == 1 && + steps[i + 1]->render.numDraws == 1 && + steps[i + 2]->render.numDraws == 1 && + steps[i]->render.color == VKRRenderPassAction::DONT_CARE && + steps[i + 1]->render.color == VKRRenderPassAction::KEEP && + steps[i + 2]->render.color == VKRRenderPassAction::DONT_CARE)) + continue; + VKRFramebuffer *depalFramebuffer = steps[i]->render.framebuffer; + VKRFramebuffer *targetFramebuffer = steps[i + 1]->render.framebuffer; + // OK, found the start of a post-process sequence. Let's scan until we find the end. + for (int j = i; j < steps.size() - 3; j++) { + if (((j - i) & 1) == 0) { + // This should be a depal draw. + if (steps[j]->render.numDraws != 1) + break; + if (steps[j]->render.color != VKRRenderPassAction::DONT_CARE) + break; + if (steps[j]->render.framebuffer != depalFramebuffer) + break; + last = j; + } else { + // This should be a target draw. + if (steps[j]->render.numDraws != 1) + break; + if (steps[j]->render.color != VKRRenderPassAction::KEEP) + break; + if (steps[j]->render.framebuffer != targetFramebuffer) + break; + last = j; + } + } + + if (last == -1) + continue; + + // Combine the depal renders. + for (int j = i + 2; j <= last + 1; j += 2) { + for (int k = 0; k < (int)steps[j]->commands.size(); k++) { + switch (steps[j]->commands[k].cmd) { + case VKRRenderCommand::DRAW: + case VKRRenderCommand::DRAW_INDEXED: + steps[i]->commands.push_back(steps[j]->commands[k]); + break; + } + } + steps[j]->stepType = VKRStepType::RENDER_SKIP; + } + + // Combine the target renders. + for (int j = i + 3; j <= last; j += 2) { + for (int k = 0; k < (int)steps[j]->commands.size(); k++) { + switch (steps[j]->commands[k].cmd) { + case VKRRenderCommand::DRAW: + case VKRRenderCommand::DRAW_INDEXED: + steps[i + 1]->commands.push_back(steps[j]->commands[k]); + break; + } + } + steps[j]->stepType = VKRStepType::RENDER_SKIP; + } + + // We're done - we only expect one of these sequences per frame. + break; + } } void VulkanQueueRunner::ApplySonicHack(std::vector &steps) {