mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Vulkan: Semi-gross hack that massively improves the perf of MGS2:Acid.
This commit is contained in:
parent
81276c8862
commit
413a204138
8 changed files with 111 additions and 5 deletions
|
@ -57,6 +57,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
|
|||
CheckSetting(iniFile, gameID, "RequireDefaultCPUClock", &flags_.RequireDefaultCPUClock);
|
||||
CheckSetting(iniFile, gameID, "DisableReadbacks", &flags_.DisableReadbacks);
|
||||
CheckSetting(iniFile, gameID, "DisableAccurateDepth", &flags_.DisableAccurateDepth);
|
||||
CheckSetting(iniFile, gameID, "MGS2AcidHack", &flags_.MGS2AcidHack);
|
||||
}
|
||||
|
||||
void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) {
|
||||
|
|
|
@ -57,6 +57,7 @@ struct CompatFlags {
|
|||
bool RequireDefaultCPUClock;
|
||||
bool DisableReadbacks;
|
||||
bool DisableAccurateDepth;
|
||||
bool MGS2AcidHack;
|
||||
};
|
||||
|
||||
class IniFile;
|
||||
|
|
|
@ -372,7 +372,7 @@ VkResult DrawEngineVulkan::RecreateDescriptorPool(FrameData &frame, int newSize)
|
|||
VkDescriptorPoolSize dpTypes[3];
|
||||
dpTypes[0].descriptorCount = frame.descPoolSize * 3;
|
||||
dpTypes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
||||
dpTypes[1].descriptorCount = frame.descPoolSize * 2; // Don't use these for tess anymore, need max two per set.
|
||||
dpTypes[1].descriptorCount = frame.descPoolSize * 3; // Don't use these for tess anymore, need max three per set.
|
||||
dpTypes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
dpTypes[2].descriptorCount = frame.descPoolSize;
|
||||
dpTypes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
#include "GPU/Vulkan/FramebufferVulkan.h"
|
||||
#include "GPU/Vulkan/DrawEngineVulkan.h"
|
||||
#include "GPU/Vulkan/TextureCacheVulkan.h"
|
||||
#include "thin3d/VulkanRenderManager.h"
|
||||
#include "thin3d/VulkanQueueRunner.h"
|
||||
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/HLE/sceKernelThread.h"
|
||||
|
@ -456,6 +458,15 @@ void GPU_Vulkan::InitDeviceObjects() {
|
|||
assert(!frameData_[i].push_);
|
||||
frameData_[i].push_ = new VulkanPushBuffer(vulkan_, 64 * 1024);
|
||||
}
|
||||
|
||||
VulkanRenderManager *rm = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
uint32_t hacks = 0;
|
||||
if (PSP_CoreParameter().compat.flags().MGS2AcidHack) {
|
||||
hacks |= QUEUE_HACK_MGS2_ACID;
|
||||
}
|
||||
if (hacks) {
|
||||
rm->GetQueueRunner()->EnableHacks(hacks);
|
||||
}
|
||||
}
|
||||
|
||||
void GPU_Vulkan::DestroyDeviceObjects() {
|
||||
|
@ -467,6 +478,10 @@ void GPU_Vulkan::DestroyDeviceObjects() {
|
|||
frameData_[i].push_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Need to turn off hacks when shutting down the GPU. Don't want them running in the menu.
|
||||
VulkanRenderManager *rm = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
rm->GetQueueRunner()->EnableHacks(0);
|
||||
}
|
||||
|
||||
void GPU_Vulkan::DeviceLost() {
|
||||
|
|
|
@ -325,4 +325,12 @@ NPHG00092 = true
|
|||
NPEG00044 = true
|
||||
NPJG00120 = true
|
||||
UCJS10114 = true
|
||||
UCES01401 = true
|
||||
UCES01401 = true
|
||||
|
||||
[MGS2AcidHack]
|
||||
ULES00008 = true
|
||||
ULJM08001 = true
|
||||
ULJM05001 = true
|
||||
ULAS42007 = true
|
||||
ULUS10006 = true
|
||||
ULUS10077 = true
|
||||
|
|
|
@ -472,6 +472,7 @@ void GLRenderManager::Run(int frame) {
|
|||
auto &initStepsOnThread = frameData_[frame].initSteps;
|
||||
// queueRunner_.LogSteps(stepsOnThread);
|
||||
queueRunner_.RunInitSteps(initStepsOnThread);
|
||||
initStepsOnThread.clear();
|
||||
|
||||
// Run this after RunInitSteps so any fresh GLRBuffers for the pushbuffers can get created.
|
||||
for (auto iter : frameData.activePushBuffers) {
|
||||
|
@ -481,7 +482,6 @@ void GLRenderManager::Run(int frame) {
|
|||
|
||||
queueRunner_.RunSteps(stepsOnThread);
|
||||
stepsOnThread.clear();
|
||||
initStepsOnThread.clear();
|
||||
|
||||
for (auto iter : frameData.activePushBuffers) {
|
||||
iter->MapDevice(bufferStrategy_);
|
||||
|
|
|
@ -347,7 +347,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) {
|
|||
return pass;
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, const std::vector<VKRStep *> &steps) {
|
||||
void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &steps) {
|
||||
// Optimizes renderpasses, then sequences them.
|
||||
// Planned optimizations:
|
||||
// * Create copies of render target that are rendered to multiple times and textured from in sequence, and push those render passes
|
||||
|
@ -397,6 +397,12 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, const std::vector<VKRStep
|
|||
}
|
||||
}
|
||||
|
||||
// Queue hacks.
|
||||
if (hacksEnabled_ & QUEUE_HACK_MGS2_ACID) {
|
||||
// Massive speedup.
|
||||
ApplyMGSHack(steps);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < steps.size(); i++) {
|
||||
const VKRStep &step = *steps[i];
|
||||
switch (step.stepType) {
|
||||
|
@ -422,6 +428,66 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, const std::vector<VKRStep
|
|||
}
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::ApplyMGSHack(std::vector<VKRStep *> &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++) {
|
||||
int last = -1;
|
||||
if (!(steps[i]->stepType == VKRStepType::COPY &&
|
||||
steps[i + 1]->stepType == VKRStepType::RENDER &&
|
||||
steps[i + 2]->stepType == VKRStepType::COPY &&
|
||||
steps[i + 1]->render.numDraws == 1 &&
|
||||
steps[i]->copy.dst == steps[i + 2]->copy.dst))
|
||||
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 (steps[j]->render.numDraws > 1)
|
||||
last = j - 1;
|
||||
break;
|
||||
case VKRStepType::COPY:
|
||||
if (steps[j]->copy.dst != steps[i]->copy.dst)
|
||||
last = j - 1;
|
||||
break;
|
||||
}
|
||||
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 *> copies;
|
||||
std::vector<VKRStep *> renders;
|
||||
for (int n = i; n <= last; n++) {
|
||||
if (steps[n]->stepType == VKRStepType::COPY)
|
||||
copies.push_back(steps[n]);
|
||||
else if (steps[n]->stepType == VKRStepType::RENDER)
|
||||
renders.push_back(steps[n]);
|
||||
}
|
||||
// Write the copies back. TODO: Combine them too.
|
||||
for (int j = 0; j < (int)copies.size(); j++) {
|
||||
steps[i + j] = copies[j];
|
||||
}
|
||||
// Write the renders back (so they will be deleted properly).
|
||||
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);
|
||||
// Combine the renders.
|
||||
for (int j = 1; j < (int)renders.size(); j++) {
|
||||
for (int k = 0; k < renders[j]->commands.size(); k++) {
|
||||
steps[i + copies.size()]->commands.push_back(renders[j]->commands[k]);
|
||||
}
|
||||
steps[i + copies.size() + j]->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++) {
|
||||
|
|
|
@ -10,6 +10,10 @@
|
|||
class VKRFramebuffer;
|
||||
struct VKRImage;
|
||||
|
||||
enum {
|
||||
QUEUE_HACK_MGS2_ACID = 1,
|
||||
};
|
||||
|
||||
enum class VKRRenderCommand : uint8_t {
|
||||
BIND_PIPELINE,
|
||||
STENCIL,
|
||||
|
@ -152,7 +156,9 @@ public:
|
|||
backbuffer_ = fb;
|
||||
backbufferImage_ = img;
|
||||
}
|
||||
void RunSteps(VkCommandBuffer cmd, const std::vector<VKRStep *> &steps);
|
||||
|
||||
// RunSteps can modify steps but will leave it in a valid state.
|
||||
void RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &steps);
|
||||
void LogSteps(const std::vector<VKRStep *> &steps);
|
||||
|
||||
void CreateDeviceObjects();
|
||||
|
@ -205,6 +211,10 @@ public:
|
|||
return found;
|
||||
}
|
||||
|
||||
void EnableHacks(uint32_t hacks) {
|
||||
hacksEnabled_ = hacks;
|
||||
}
|
||||
|
||||
private:
|
||||
void InitBackbufferRenderPass();
|
||||
|
||||
|
@ -223,6 +233,8 @@ private:
|
|||
|
||||
void ResizeReadbackBuffer(VkDeviceSize requiredSize);
|
||||
|
||||
void ApplyMGSHack(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);
|
||||
|
||||
|
@ -244,4 +256,7 @@ private:
|
|||
VkDeviceMemory readbackMemory_ = VK_NULL_HANDLE;
|
||||
VkBuffer readbackBuffer_ = VK_NULL_HANDLE;
|
||||
VkDeviceSize readbackBufferSize_ = 0;
|
||||
|
||||
// TODO: Enable based on compat.ini.
|
||||
uint32_t hacksEnabled_ = 0;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue