Add a queue processing hack for Sonic Rivals too. Now it's fast.

This commit is contained in:
Henrik Rydgård 2018-04-13 18:05:04 +02:00
parent 413a204138
commit 0ac6cea34d
6 changed files with 100 additions and 6 deletions

View file

@ -58,6 +58,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
CheckSetting(iniFile, gameID, "DisableReadbacks", &flags_.DisableReadbacks);
CheckSetting(iniFile, gameID, "DisableAccurateDepth", &flags_.DisableAccurateDepth);
CheckSetting(iniFile, gameID, "MGS2AcidHack", &flags_.MGS2AcidHack);
CheckSetting(iniFile, gameID, "SonicRivalsHack", &flags_.SonicRivalsHack);
}
void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) {

View file

@ -58,6 +58,7 @@ struct CompatFlags {
bool DisableReadbacks;
bool DisableAccurateDepth;
bool MGS2AcidHack;
bool SonicRivalsHack;
};
class IniFile;

View file

@ -461,9 +461,10 @@ void GPU_Vulkan::InitDeviceObjects() {
VulkanRenderManager *rm = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
uint32_t hacks = 0;
if (PSP_CoreParameter().compat.flags().MGS2AcidHack) {
if (PSP_CoreParameter().compat.flags().MGS2AcidHack)
hacks |= QUEUE_HACK_MGS2_ACID;
}
if (PSP_CoreParameter().compat.flags().SonicRivalsHack)
hacks |= QUEUE_HACK_SONIC;
if (hacks) {
rm->GetQueueRunner()->EnableHacks(hacks);
}

View file

@ -334,3 +334,7 @@ ULJM05001 = true
ULAS42007 = true
ULUS10006 = true
ULUS10077 = true
[SonicRivalsHack]
ULES00622 = true
ULUS10195 = true

View file

@ -398,9 +398,14 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &st
}
// Queue hacks.
if (hacksEnabled_ & QUEUE_HACK_MGS2_ACID) {
// Massive speedup.
ApplyMGSHack(steps);
if (hacksEnabled_) {
if (hacksEnabled_ & QUEUE_HACK_MGS2_ACID) {
// Massive speedup.
ApplyMGSHack(steps);
}
if (hacksEnabled_ & QUEUE_HACK_SONIC) {
ApplySonicHack(steps);
}
}
for (size_t i = 0; i < steps.size(); i++) {
@ -460,6 +465,8 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector<VKRStep *> &steps) {
// First, let's sort it, keeping the same length.
std::vector<VKRStep *> copies;
std::vector<VKRStep *> renders;
copies.reserve((last - i) / 2);
renders.reserve((last - i) / 2);
for (int n = i; n <= last; n++) {
if (steps[n]->stepType == VKRStepType::COPY)
copies.push_back(steps[n]);
@ -474,7 +481,7 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector<VKRStep *> &steps) {
for (int j = 0; j < (int)renders.size(); j++) {
steps[i + j + copies.size()] = renders[j];
}
assert(steps[i + j + copies.size()]->stepType == VKRStepType::RENDER);
assert(steps[i + copies.size()]->stepType == VKRStepType::RENDER);
// Combine the renders.
for (int j = 1; j < (int)renders.size(); j++) {
for (int k = 0; k < renders[j]->commands.size(); k++) {
@ -488,6 +495,84 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector<VKRStep *> &steps) {
}
}
void VulkanQueueRunner::ApplySonicHack(std::vector<VKRStep *> &steps) {
// We want to turn a sequence of render(3),render(1),render(6),render(1),render(6),render(1),render(3) to
// render(1), render(1), render(1), render(6), render(6), render(6)
for (int i = 0; i < (int)steps.size() - 4; i++) {
int last = -1;
if (!(steps[i]->stepType == VKRStepType::RENDER &&
steps[i + 1]->stepType == VKRStepType::RENDER &&
steps[i + 2]->stepType == VKRStepType::RENDER &&
steps[i + 3]->stepType == VKRStepType::RENDER &&
steps[i]->render.numDraws == 3 &&
steps[i + 1]->render.numDraws == 1 &&
steps[i + 2]->render.numDraws == 6 &&
steps[i + 3]->render.numDraws == 1 &&
steps[i]->render.framebuffer == steps[i + 2]->render.framebuffer &&
steps[i + 1]->render.framebuffer == steps[i + 3]->render.framebuffer))
continue;
// Looks promising! Let's start by finding the last one.
for (int j = i; j < (int)steps.size(); j++) {
switch (steps[j]->stepType) {
case VKRStepType::RENDER:
if ((j - i) & 1) {
if (steps[j]->render.framebuffer != steps[i + 1]->render.framebuffer)
last = j - 1;
if (steps[j]->render.numDraws != 1)
last = j - 1;
} else {
if (steps[j]->render.framebuffer != steps[i]->render.framebuffer)
last = j - 1;
if (steps[j]->render.numDraws != 3 && steps[j]->render.numDraws != 6)
last = j - 1;
}
}
if (last != -1)
break;
}
if (last != -1) {
// We've got a sequence from i to last that needs reordering.
// First, let's sort it, keeping the same length.
std::vector<VKRStep *> type1;
std::vector<VKRStep *> type2;
type1.reserve((last - i) / 2);
type2.reserve((last - i) / 2);
for (int n = i; n <= last; n++) {
if (steps[n]->render.framebuffer == steps[i]->render.framebuffer)
type1.push_back(steps[n]);
else
type2.push_back(steps[n]);
}
// Write the renders back in order. Same amount, so deletion will work fine.
for (int j = 0; j < (int)type1.size(); j++) {
steps[i + j] = type1[j];
}
for (int j = 0; j < (int)type2.size(); j++) {
steps[i + j + type1.size()] = type2[j];
}
// Combine the renders.
for (int j = 1; j < (int)type1.size(); j++) {
for (int k = 0; k < (int)type1[j]->commands.size(); k++) {
steps[i]->commands.push_back(type1[j]->commands[k]);
}
steps[i + j]->stepType = VKRStepType::RENDER_SKIP;
}
for (int j = 1; j < (int)type2.size(); j++) {
for (int k = 0; k < (int)type2[j]->commands.size(); k++) {
steps[i + type1.size()]->commands.push_back(type2[j]->commands[k]);
}
steps[i + j + type1.size()]->stepType = VKRStepType::RENDER_SKIP;
}
// We're done.
break;
}
}
}
void VulkanQueueRunner::LogSteps(const std::vector<VKRStep *> &steps) {
ILOG("=======================================");
for (size_t i = 0; i < steps.size(); i++) {

View file

@ -12,6 +12,7 @@ struct VKRImage;
enum {
QUEUE_HACK_MGS2_ACID = 1,
QUEUE_HACK_SONIC = 2,
};
enum class VKRRenderCommand : uint8_t {
@ -234,6 +235,7 @@ private:
void ResizeReadbackBuffer(VkDeviceSize requiredSize);
void ApplyMGSHack(std::vector<VKRStep *> &steps);
void ApplySonicHack(std::vector<VKRStep *> &steps);
static void SetupTransitionToTransferSrc(VKRImage &img, VkImageMemoryBarrier &barrier, VkPipelineStageFlags &stage, VkImageAspectFlags aspect);
static void SetupTransitionToTransferDst(VKRImage &img, VkImageMemoryBarrier &barrier, VkPipelineStageFlags &stage, VkImageAspectFlags aspect);