mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
LSFG: force FIFO presentation, and surface FSR in the in-game menu
★ Frame generation produced nothing on a MAILBOX swapchain, silently. Reported on an Adreno 740: LSFG logged 'active: 1920x1080 x2 frames, 3.1p', cached its 52 shaders, never logged a single failure — and both the FPS and the LSFG display counters read 59. The interpolator was working perfectly and its output was being thrown away. MAILBOX keeps only the most recent image queued for a given refresh. Presenting an interpolated frame and then the real frame immediately after replaces the interpolated one, so it is generated, costs its full GPU time, and is never displayed. IMMEDIATE discards the same way. Nothing errors anywhere along that path, which is why the only symptom is a display rate identical to the real one. The device landed on MAILBOX because vsync was off — 'Immediate not supported for vsync-disabled, using mailbox'. SelectPresentMode now forces FIFO while frame generation is enabled. Eden reached the same conclusion; their setting text reads 'Forces FIFO presentation while enabled'. Gated on the setting rather than GSLsfg::IsAvailable(), which cannot answer at swapchain-creation time: the DLL path only reaches GSLsfg from EndPresent. Also adds the FSR rows to the in-game GraphicsPane. In full settings FSR sits under Display Effects beside CAS, which is the right shelf for a post-effect and the wrong one for finding it — it is an upscaler, so in the quick menu it goes with the internal-resolution controls, which is where you reach while watching the framerate. Vulkan-only, so it is never a dead toggle on OpenGL.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
|
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
|
||||||
// SPDX-License-Identifier: GPL-3.0+
|
// SPDX-License-Identifier: GPL-3.0+
|
||||||
|
|
||||||
|
#include "GS/GS.h" // GSConfig, for the frame-generation FIFO override below
|
||||||
#include "GS/Renderers/Vulkan/GSDeviceVK.h"
|
#include "GS/Renderers/Vulkan/GSDeviceVK.h"
|
||||||
#include "GS/Renderers/Vulkan/VKBuilders.h"
|
#include "GS/Renderers/Vulkan/VKBuilders.h"
|
||||||
#include "GS/Renderers/Vulkan/VKSwapChain.h"
|
#include "GS/Renderers/Vulkan/VKSwapChain.h"
|
||||||
@@ -513,6 +514,26 @@ bool VKSwapChain::SelectPresentMode(VkSurfaceKHR surface, GSVSyncMode* vsync_mod
|
|||||||
return it != present_modes.end();
|
return it != present_modes.end();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ★ Frame generation requires FIFO, and silently produces nothing without it.
|
||||||
|
//
|
||||||
|
// MAILBOX keeps only the most recent image queued for a given refresh: presenting an
|
||||||
|
// interpolated frame and then the real frame replaces the interpolated one, so it is
|
||||||
|
// generated, costs its full GPU time, and is never displayed. IMMEDIATE is no better — it
|
||||||
|
// tears the newest image in, discarding the same way. The failure is completely silent,
|
||||||
|
// because nothing errors: the interpolator succeeds, the present succeeds, and the display
|
||||||
|
// rate simply equals the real frame rate. Observed exactly that on an Adreno 740 with vsync
|
||||||
|
// off, which resolves to MAILBOX here — LSFG reported "active" and both counters read 59.
|
||||||
|
//
|
||||||
|
// Gated on the setting rather than GSLsfg::IsAvailable(), which cannot answer yet: the DLL
|
||||||
|
// path only reaches GSLsfg from EndPresent, which has not run when the swapchain is built.
|
||||||
|
// The user asking for frame generation is the intent worth honouring here.
|
||||||
|
if (GSConfig.LsfgEnabled && *vsync_mode != GSVSyncMode::FIFO)
|
||||||
|
{
|
||||||
|
WARNING_LOG("Frame generation is enabled; forcing FIFO presentation so interpolated "
|
||||||
|
"frames are actually displayed.");
|
||||||
|
*vsync_mode = GSVSyncMode::FIFO;
|
||||||
|
}
|
||||||
|
|
||||||
switch (*vsync_mode)
|
switch (*vsync_mode)
|
||||||
{
|
{
|
||||||
case GSVSyncMode::Disabled:
|
case GSVSyncMode::Disabled:
|
||||||
|
|||||||
@@ -819,6 +819,32 @@ private fun GraphicsPane(state: EmulationMenuUiState, viewModel: EmulationMenuVi
|
|||||||
onReset = { viewModel.setUpscale(1.0f) },
|
onReset = { viewModel.setUpscale(1.0f) },
|
||||||
onChange = { pct -> viewModel.setUpscale(pct / 100f) },
|
onChange = { pct -> viewModel.setUpscale(pct / 100f) },
|
||||||
)
|
)
|
||||||
|
// FSR sits with the resolution controls rather than the effects, because that is what it
|
||||||
|
// is: the two rows above choose how big the frame is RENDERED, and this chooses how it
|
||||||
|
// gets to the screen. In full settings it lives under Display Effects next to CAS, which
|
||||||
|
// is the wrong shelf for finding it while you are looking at the framerate.
|
||||||
|
if (settings.renderer == "vulkan") {
|
||||||
|
val fsr1On = settings.upscaler == com.armsx2.config.Settings.UPSCALER_FSR1
|
||||||
|
MenuSwitchRow(
|
||||||
|
str("renderer.fsr1.label"),
|
||||||
|
fsr1On,
|
||||||
|
description = str("renderer.fsr1.description"),
|
||||||
|
) { on ->
|
||||||
|
viewModel.updateSettings {
|
||||||
|
it.copy(upscaler = if (on) com.armsx2.config.Settings.UPSCALER_FSR1 else com.armsx2.config.Settings.UPSCALER_OFF)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fsr1On) {
|
||||||
|
com.armsx2.ui.settings.IntSliderRow(
|
||||||
|
label = str("renderer.fsr1.sharpness.label"),
|
||||||
|
value = settings.fsrSharpness.coerceIn(0, 100),
|
||||||
|
min = 0,
|
||||||
|
max = 100,
|
||||||
|
valueFormatter = { "$it%" },
|
||||||
|
onChange = { pct -> viewModel.updateSettings { it.copy(fsrSharpness = pct) } },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
HorizontalOptions(
|
HorizontalOptions(
|
||||||
title = str("renderer.displayMode.label"),
|
title = str("renderer.displayMode.label"),
|
||||||
options = listOf(
|
options = listOf(
|
||||||
|
|||||||
Reference in New Issue
Block a user