Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Common/Common.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,9 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</None>
</ItemGroup>
<ItemGroup>
<Natvis Include="Data\Collections\FastVec.natvis" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
Expand Down
5 changes: 5 additions & 0 deletions Common/Common.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -1487,4 +1487,9 @@
<Filter>ext\lua</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Natvis Include="Data\Collections\FastVec.natvis">
<Filter>Data\Collections</Filter>
</Natvis>
</ItemGroup>
</Project>
17 changes: 17 additions & 0 deletions Common/Data/Collections/FastVec.natvis
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">

<!-- FastVec -->
<Type Name="FastVec&lt;*&gt;">
<DisplayString>{{ size = {size_}, capacity = {capacity_} }}</DisplayString>
<Expand>
<Item Name="[size]">size_</Item>
<Item Name="[capacity]">capacity_</Item>
<ArrayItems>
<Size>size_</Size>
<ValuePointer>data_</ValuePointer>
</ArrayItems>
</Expand>
</Type>

</AutoVisualizer>
61 changes: 58 additions & 3 deletions Common/GPU/Vulkan/VulkanQueueRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ void VulkanQueueRunner::PreprocessSteps(std::vector<VKRStep *> &steps) {
// Queue hacks.
if (hacksEnabled_) {
if (hacksEnabled_ & QUEUE_HACK_MGS2_ACID) {
// Massive speedup.
// Massive speedup due to re-ordering.
ApplyMGSHack(steps);
}
if (hacksEnabled_ & QUEUE_HACK_SONIC) {
Expand Down Expand Up @@ -438,6 +438,8 @@ 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).

// TODO: Where does this first part trigger? The below depal part triggers reliably in Acid2.

for (int i = 0; i < (int)steps.size() - 3; i++) {
int last = -1;
if (!(steps[i]->stepType == VKRStepType::COPY &&
Expand Down Expand Up @@ -507,6 +509,7 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector<VKRStep *> &steps) {
steps[firstRender + j]->commands.clear();
}
// We're done.
// INFO_LOG(Log::G3D, "MGS HACK part 1: copies: %d renders: %d", (int)copies.size(), (int)renders.size());
break;
}
}
Expand All @@ -523,8 +526,9 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector<VKRStep *> &steps) {
steps[i + 2]->render.numDraws == 1 &&
steps[i]->render.colorLoad == VKRRenderPassLoadAction::DONT_CARE &&
steps[i + 1]->render.colorLoad == VKRRenderPassLoadAction::KEEP &&
steps[i + 2]->render.colorLoad == VKRRenderPassLoadAction::DONT_CARE))
steps[i + 2]->render.colorLoad == VKRRenderPassLoadAction::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.
Expand All @@ -533,6 +537,8 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector<VKRStep *> &steps) {
// This should be a depal draw.
if (steps[j]->render.numDraws != 1)
break;
if (steps[j]->commands.size() > 5) // TODO: Not the greatest heuristic! This may change if we merge commands.
break;
if (steps[j]->render.colorLoad != VKRRenderPassLoadAction::DONT_CARE)
break;
if (steps[j]->render.framebuffer != depalFramebuffer)
Expand All @@ -542,6 +548,8 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector<VKRStep *> &steps) {
// This should be a target draw.
if (steps[j]->render.numDraws != 1)
break;
if (steps[j]->commands.size() > 5) // TODO: Not the greatest heuristic! This may change if we merge commands.
break;
if (steps[j]->render.colorLoad != VKRRenderPassLoadAction::KEEP)
break;
if (steps[j]->render.framebuffer != targetFramebuffer)
Expand All @@ -553,14 +561,43 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector<VKRStep *> &steps) {
if (last == -1)
continue;

// Combine the depal renders.
if (last > 479) {
// Avoid some problems with the hack (oil slick crash). Some additional commands get added there that
// confuses this merging. NOTE: This is not really a solution! See #20306.
last = 479;
}

int minScissorX = 10000;
int minScissorY = 10000;
int maxScissorX = 0;
int maxScissorY = 0;

// Combine the depal renders. Also record scissor bounds.
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;
case VKRRenderCommand::SCISSOR:
{
// TODO: Merge scissor rectangles.
const auto &rc = steps[j]->commands[k].scissor.scissor;
if (rc.offset.x < minScissorX) {
minScissorX = rc.offset.x;
}
if (rc.offset.y < minScissorY) {
minScissorY = rc.offset.y;
}
if (rc.offset.x + rc.extent.width > maxScissorX) {
maxScissorX = rc.offset.x + rc.extent.width;
}
if (rc.offset.y + rc.extent.height > maxScissorY) {
maxScissorY = rc.offset.y + rc.extent.height;
}
break;
}
default:
break;
}
Expand All @@ -569,6 +606,22 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector<VKRStep *> &steps) {
steps[j]->stepType = VKRStepType::RENDER_SKIP;
}

// Update the scissor in the first draw.
minScissorX = std::max(0, minScissorX);
minScissorY = std::max(0, minScissorY);
if (maxScissorX > minScissorX && maxScissorY > minScissorY) {
for (int k = 0; k < steps[i]->commands.size(); k++) {
if (steps[i]->commands[k].cmd == VKRRenderCommand::SCISSOR) {
auto &rc = steps[i]->commands[k].scissor.scissor;
rc.offset.x = minScissorX;
rc.offset.y = minScissorY;
rc.extent.width = maxScissorX - minScissorX;
rc.extent.height = maxScissorY - minScissorY;
break;
}
}
}

// Combine the target renders.
for (int j = i + 3; j <= last; j += 2) {
for (int k = 0; k < (int)steps[j]->commands.size(); k++) {
Expand All @@ -585,6 +638,8 @@ void VulkanQueueRunner::ApplyMGSHack(std::vector<VKRStep *> &steps) {
steps[j]->stepType = VKRStepType::RENDER_SKIP;
}

// INFO_LOG(Log::G3D, "MGS HACK part 2: %d-%d : %d (total steps: %d)", i, last, (last - i), (int)steps.size());

// We're done - we only expect one of these sequences per frame.
break;
}
Expand Down
5 changes: 4 additions & 1 deletion UI/EmuScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1985,8 +1985,11 @@ void EmuScreen::AutoLoadSaveState() {
}

if (g_Config.iAutoLoadSaveState && autoSlot != -1) {
SaveState::LoadSlot(gamePath_, autoSlot, [this](SaveState::Status status, std::string_view message) {
SaveState::LoadSlot(gamePath_, autoSlot, [this, autoSlot](SaveState::Status status, std::string_view message) {
AfterSaveStateAction(status, message);
auto sy = GetI18NCategory(I18NCat::SYSTEM);
std::string msg = std::string(sy->T("Auto Load Savestate")) + ": " + StringFromFormat("%d", autoSlot);
g_OSD.Show(OSDType::MESSAGE_SUCCESS, msg);
if (status == SaveState::Status::FAILURE) {
autoLoadFailed_ = true;
}
Expand Down
Loading