Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vulkan: Depalettize in shaders #10911

Merged
merged 8 commits into from
Apr 13, 2018
1 change: 1 addition & 0 deletions Core/Compatibility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions Core/Compatibility.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct CompatFlags {
bool DisableReadbacks;
bool DisableAccurateDepth;
bool MGS2AcidHack;
bool SonicRivalsHack;
};

class IniFile;
Expand Down
5 changes: 3 additions & 2 deletions GPU/Vulkan/GPU_Vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
4 changes: 4 additions & 0 deletions assets/compat.ini
Original file line number Diff line number Diff line change
Expand Up @@ -334,3 +334,7 @@ ULJM05001 = true
ULAS42007 = true
ULUS10006 = true
ULUS10077 = true

[SonicRivalsHack]
ULES00622 = true
ULUS10195 = true
93 changes: 89 additions & 4 deletions ext/native/thin3d/VulkanQueueRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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++) {
Expand Down Expand Up @@ -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]);
Expand All @@ -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++) {
Expand All @@ -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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is definitely more gross, heh. Reminds me of a certain other emulator's "skip codes"...

-[Unknown]


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++) {
Expand Down
2 changes: 2 additions & 0 deletions ext/native/thin3d/VulkanQueueRunner.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ struct VKRImage;

enum {
QUEUE_HACK_MGS2_ACID = 1,
QUEUE_HACK_SONIC = 2,
};

enum class VKRRenderCommand : uint8_t {
Expand Down Expand Up @@ -234,6 +235,7 @@ class VulkanQueueRunner {
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);
Expand Down