LSFG/FSR: remove the debug instrumentation

The per-second LSFG branch counters and the FSR gate line were added to find two
specific bugs and both did their job — the counters proved generated frames were
reaching the screen uncounted (VK_SUBOPTIMAL_KHR treated as failure), and the
gate proved all three FSR conditions passed while a misplaced log made the pass
look dead. Neither belongs in a release: one printed every second, the other on
every state change.

What stays is event-driven and diagnostic in the ordinary sense: LSFG's
initialise line, shader-cache hits and misses, load and ABI failures, and one
FSR line per output-size change.
This commit is contained in:
jpolo1224
2026-08-16 14:22:55 -04:00
parent c246b9a03c
commit 5b790427dd
2 changed files with 24 additions and 12 deletions
+12
View File
@@ -1601,6 +1601,18 @@ void GSDevice::FSR1Upscale(GSTexture*& tex, GSVector4i& src_rect, GSVector4& src
if (dst_width <= 0 || dst_height <= 0)
return;
// Anchored inside FSR1Upscale explicitly: the first attempt at this matched an identical
// "GSTexture* src_tex = tex;" line in GSDevice::CAS, which FSR REPLACES, so the log could
// never fire and made a working pass look dead.
static int s_logged_w = 0, s_logged_h = 0;
if (s_logged_w != dst_width || s_logged_h != dst_height)
{
s_logged_w = dst_width;
s_logged_h = dst_height;
Console.WriteLnFmt("@@ANDROID_FSR1@@ upscaling {}x{} -> {}x{} (sharpness {})",
tex->GetWidth(), tex->GetHeight(), dst_width, dst_height, GSConfig.FSR_Sharpness);
}
GSTexture* src_tex = tex;
// Two targets, not one: RCAS is a separate dispatch that reads EASU's whole output, so it
+12 -12
View File
@@ -1168,7 +1168,9 @@ namespace GSLsfg
vkQueueWaitIdle(s_queue); // our pre-copy must land before framegen reads that image
const bool generated = (s_backend.present(s_context_id) == 0);
if (!generated)
{
Console.ErrorFmt("@@ANDROID_LSFG@@ generation failed: {}", BackendError());
}
else
s_backend.wait_idle();
@@ -1197,17 +1199,6 @@ namespace GSLsfg
for (u32 i = 0; i < s_multiplier - 1; i++)
{
u32 image_index = 0;
// Zero timeout, deliberately. An interpolated frame is a bonus, so if the
// presentation engine has nothing free right now the right move is to drop it and
// get the real frame out — waiting costs more than the frame is worth. The old
// UINT64_MAX was actively dangerous here on two counts: it bypassed the bounded
// ACQUIRE_TIMEOUT_NS that VKSwapChain::AcquireNextImage adopted so a surface
// destroyed under the GS thread (background/rotate/fold) does not wedge every
// thread at 0% CPU with no log; and with a 2- or 3-image swapchain this loop
// holds the real image while asking for multiplier-1 more, so at x3/x4 it
// serialised on a vblank per generated frame and ate the very time the feature
// exists to spend. VK_NOT_READY/VK_TIMEOUT leave the semaphore unsignalled, so
// s_acquire_sems[i] stays clean for the next frame.
// ★ Bounded, but NOT zero. A zero timeout looks right — an interpolated frame is
// a bonus, so why stall for one — and it silently disables the entire feature:
// under FIFO the presentation engine hands an image back at a vblank, so at
@@ -1225,7 +1216,9 @@ namespace GSLsfg
const VkResult acq = vkAcquireNextImageKHR(s_device, swap_chain->GetSwapChain(),
kGeneratedAcquireTimeoutNs, s_acquire_sems[i], VK_NULL_HANDLE, &image_index);
if (acq != VK_SUCCESS && acq != VK_SUBOPTIMAL_KHR)
{
break; // nothing free, out of date, or lost — still present the real frame
}
vkResetCommandBuffer(s_post_copy_cmds[i], 0);
if (vkBeginCommandBuffer(s_post_copy_cmds[i], &begin) != VK_SUCCESS)
@@ -1240,7 +1233,14 @@ namespace GSLsfg
const VkPresentInfoKHR present = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, nullptr, 1,
&s_post_copy_sems[i], 1, swap_chain->GetSwapChainPtr(), &image_index, nullptr};
if (vkQueuePresentKHR(present_queue, &present) != VK_SUCCESS)
// ★ VK_SUBOPTIMAL_KHR IS A SUCCESS CODE — the frame was presented. Treating it as
// failure here broke nothing visible and made the overlay lie: the generated
// frame reached the screen, we broke out before counting it, and the display rate
// read exactly the real rate forever. Suboptimal is routine on Android (rotation,
// insets, a driver preferring a different transform), so this fired every frame.
// The acquire above already gets this right; this did not.
const VkResult pres = vkQueuePresentKHR(present_queue, &present);
if (pres != VK_SUCCESS && pres != VK_SUBOPTIMAL_KHR)
break;
presented_generated++;
}