mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
48094495a0f2fde9f254fca82426329de895617d
24975
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
48094495a0 |
Patches: stop the online scan when you leave the browser
Reported by SNAKEATEROP (Helio G99): after using the online cheats/patches
browser, going back to the game left the device heating severely and a game that
had held full speed no longer did. Nothing in the emulator explained it.
The scan was UNSTOPPABLE, not merely slow. PatchRepo's fetch functions were
plain blocking calls with no isActive check, no ensureActive and not even
suspend. Kotlin cancellation is cooperative, so cancelling the scope did
nothing: the work ran to completion no matter what the user did. It walks four
community repositories, each a multi-megabyte GitHub tree that is downloaded and
then regex-scanned for paths — that is the CPU the game was competing with, and
it kept going long after anyone was looking at it.
Three parts:
· PatchRepo's entry points are suspend and check for cancellation between
every repository and every file. Between SOURCES is the one that matters —
that is where the time goes.
· The scan's Job is tracked, so a second search cannot stack on the first, and
the browser cancels it in onDispose. viewModelScope alone was not enough:
the ViewModel is Activity-scoped and shared with the settings tab, so it
does not clear merely because the user went back to the game — which is
exactly the case that was reported.
· The progress text now says it takes a minute or two AND that leaving is
safe. Users assumed it had hung, and several were told to just wait; nobody
should have to sit through it to protect their device.
This does not make the scan faster. It makes it stop, which is the part that was
damaging. Caching the repository trees on disk is the fix for the duration —
they are re-downloaded and re-parsed on every cold start today — and is worth
doing next.
|
||
|
|
879d07209c |
GS: size the texture cache as RAM minus a reserve, not a fraction of it
Third attempt at this budget, so the reasoning is written down properly.
Uncapped OOM-killed Android on a 5 GB uncompressed Persona 3 FES pack. Capping
at RAM/4, then RAM/2, stopped that and broke the same pack on 8 GB devices where
it had been working — 5 GB against a 4 GB budget evicts continuously, each load
dropping the previous one. That is the Persona 3 FES report: corruption first
(a failed upload injected with undefined contents, before
|
||
|
|
7bbe5b2fc1 |
GS: remove the texture-replacement cache cap
Reverses the 2026-07-20 policy. Reported by JustVibin247 for Persona 3 FES: mods worked on 2.6.6 and stopped on 2.6.6.1, first showing as corruption and later as simply not applying. The cap was added to stop a 5 GB uncompressed Persona 3 FES pack OOM-killing Android mid-load, and it did stop that. It also broke every setup where an oversized pack had been working. Budget was RAM/2, so on an 8 GB device that same 5 GB pack sat permanently about 1 GB over and evicted continuously — each load immediately dropping the previous one. That produced both reported symptoms in the order they were reported. The churn means constant re-upload; before |
||
|
|
aba5f201e6 |
Saves: hiding Save must not hide Load
Save and Load shared a single guard, so gating Save on a running VM hid Load with it — and Load is the entire reason the library's long-press menu opens this screen. They have different conditions and now have different guards. Load needs only that the state belongs to the game in context: with no VM it boots the game and loads into it. Save additionally needs a live VM, because there is nothing to snapshot without one. |
||
|
|
2443ad72cf |
Saves: only offer Save when a VM is actually running
Opened from the library's long-press menu the Save Manager showed a Save button next to Load, which cannot mean anything: nothing is booted, so there is no running game to snapshot. The button was gated on canUseWithActiveGame, which means 'this state belongs to the game in context' — a different question, and one that only started answering true here when contextGame was wired up in the previous commit. Saving needs a live VM; loading does not, because it can boot the game first. The two conditions were conflated and the fallback fix exposed it. Now gated on hasActiveVm, read from NativeApp.hasActiveVM() during refresh. Load and Delete are untouched: both are meaningful without a running game. |
||
|
|
208bf68f1b |
Saves: honour contextGame when listing, not just when launching
Long-press -> Load save state opened the Save Manager but nothing could be loaded from it. load() already fell back to contextGame; the LISTING did not. It read currentGame alone, which is null when nothing is booted — so every entry came back canUseWithActiveGame = false, which is what greys out Load, and the serial filter also stopped applying so the screen showed every game's saves at once rather than the one that was long-pressed. contextGame was added for exactly this case and the launch path already used it. The read here had simply never been updated, because until now the only way into this screen was from a running game or the drawer. importSaveStateToNextFreeSlot deliberately still requires currentGame: it resolves destination paths through NativeApp.getGamePathSlot, which answers for the running VM, so a context game would give it nowhere to write. |
||
|
|
146da3d2ef |
Library: open the real Save Manager, and make swipe-to-dismiss actually work
Both from testing feedback. The save-state feature itself worked — slots listed and booting into one loaded correctly — but two things around it did not. ★ The swipe did nothing, and the reason is worth writing down: Compose delivers pointer events to CHILDREN first. Every row in the sheet is clickable, so they consumed the drag in the Main pass and a detector on the parent Box never saw it. Watching PointerEventPass.Initial is the only way a parent wins that. Winning it everywhere would be worse than not having it — it would eat scrolling inside any modal that scrolls — so the gesture is claimed only when it STARTS in the top 64dp, where the drag handle is and where a sheet is grabbed anyway, and only once it has clearly travelled downward. The absorb-taps clickable also moved AFTER the detector; having it first gave it the events. This mattered more than a missing nicety: the game menu is nearly full-height, so there is almost no scrim left to tap, and without the swipe the only way out was the controller. A touch user was stuck. ★ 'Load save state' now opens the Save Manager rather than a bespoke list. That was the request, and it is also the better implementation: the Save Manager already renders slots as a grid with preview thumbnails and carries its own back button, so it cannot trap anyone. contextGame exists for precisely this — it is how the Save Manager already operates on a game that is not currently running — so this is wiring, not new UI. The bespoke picker and its modal are deleted. SaveSlotLookup stays: the menu still needs to know whether a game has any states at all, to decide whether to show the row. |
||
|
|
caaf80749e |
Library: find save states in both data roots, and restore swipe-to-dismiss
Two follow-ups from testing the long-press menu. ★ SaveSlotLookup only searched ONE root. A device with a configured system directory has two — assetCopyRoot resolves to that one (typically the SD card, where ROMs and most saves live) while others stay under getExternalFilesDir. On the test device 13 states sat in one and 5 in the other, so either root alone under-reports, and the failure is silent: it reads as 'this game has no save states' rather than as a bug. This is the same two-root trap that once made a patches investigation report a false 'clean'. Both are searched now, and when a slot exists in both the newer file wins. Swipe-to-dismiss is back for bottom-aligned modals. PadModal replaced ModalBottomSheet because that is its own focused Android window and every row inside it was unreachable by pad; the swipe was the one thing given up in the trade. But a panel that rises from the bottom edge with a rounded top and a drag handle is PROMISING a swipe, so its absence reads as broken rather than as a deliberate omission. The panel now follows the finger and dismisses past a threshold, without giving up focus ownership. Downward only, and only for BottomCenter: dragging a bottom sheet up should not lift it off the edge it is anchored to, and on centred or anchored menus a vertical drag means nothing and would fight scrolling inside them. Worth recording that the originally reported symptom was NOT a bug: God of War II has no save states on the test device, so an absent row was correct. The root bug was real but found by inspection while checking that. |
||
|
|
0f0f719bce |
Library: fix the selection highlight contrast, and offer save states on long-press
bmdhacks' two. Selection highlight was blue on blue. It drew a single ring in the theme's primary, and the library background is themed from the same palette — so on a blue theme the highlight was invisible, which matters because controller navigation is the only way that selection is moved. Now two rings: an outer one derived from inverseSurface, which contrasts with the background whatever hue the user picked, and the accent ring inside it. Whichever the background happens to match, the other still reads. The list rows had the same problem and get a thicker stroke blended toward inverseSurface. Long-press already opened the game menu; it now offers the game's save states and boots straight into one. Most of that already existed and only needed connecting: pendingSlotLoadOnBoot and launchCurrentGameFromSaveSlot have been driving the Save Manager's 'relaunch and load' for a while. The one thing that did not work from the library is that it resolved the game from currentGame/contextGame, and in the library nothing is booted so both are null — it could never have fired there. Split into launchGameFromSaveSlot(game, slot) which names the game explicitly. Enumerating the slots needed new code for the same reason: the in-game picker asks NativeApp.getGamePathSlot, which resolves against the RUNNING VM's serial. SaveSlotLookup reads the files instead, using the layout the save manager already walks — '<serial> (title).NN.p2s' under sstates/ or savestates/. The row only appears when states exist. A 'Load save state' entry that opens onto an empty list is worse than no entry. The picker is a second PadModal rather than a submenu inside the game menu: PadModal owns focus, so nesting one inside another leaves the inner rows unreachable by controller — the same trap that made the game menu a PadModal instead of a ModalBottomSheet in the first place. Both flavours compile. Not yet exercised on device. |
||
|
|
f6ddff79bc |
LSFG: expose adaptive frame pacing, and remove the diagnostic tracing
The pacer shipped in the previous commit but was inert: GSConfig.LsfgTargetRate defaulted to 0, which means "hold the multiplier fixed", and nothing in the Android settings could change it. So the port ran, but the specific problem it was brought over to solve — games that oscillate between 60 and 30fps on a 60Hz panel, where a fixed multiplier presents 120 then 60 and judders at every transition — was still there. Working but inert is the failure mode worth naming: nothing errors, the feature simply does not do the thing it was for. Plumbed through the usual twelve places (the field, INI read and write, the differs chain, toJson/fromJson, both per-game override paths, the reset list, the search index, the strings, and the two call sites), plus the two C++ ones in Pcsx2Config. Presented as a switch rather than a number. The pacer needs a concrete Hz, but picking one by hand is not a decision anyone can make usefully and the only sensible answer is the panel's own refresh rate — so the UI writes that when the toggle goes on, and 0 when it goes off. Off remains the default, so behaviour is unchanged until it is asked for. Also removes the step tracing added while chasing the Turnip crash. It did its job: five rounds of reading the code produced three wrong theories, and the trace produced the answer in two. The reasoning it uncovered is in the comments, which is where it belongs — the instrumentation is not. The new strings live in the github-only table, so the Play split still holds: playDebug has zero class files containing 'Lossless' or 'perf.lsfg', githubDebug has 2 and 4. |
||
|
|
2080bd1c44 |
LSFG: make frame generation actually run on device
Verified working on an Adreno 740, on BOTH the stock Qualcomm driver and Turnip:
an interpolated frame presented for every rendered frame, no crash.
Six real defects between 'compiles' and 'runs', all mine. Recording them because
every one of them compiled cleanly and several looked like somebody else's bug.
★ THE LAST ONE, and the least guessable. Waiting on a semaphore signalled by a
SECOND vkAcquireNextImageKHR within one frame segfaults inside Turnip at
vkQueueSubmit. Stock Qualcomm accepts it; Turnip does not. The extra acquire now
signals a FENCE which we block on before recording, so the submit waits only on
the caller's render-finished semaphore — exactly what a non-generating frame
does, and that shape always worked. It costs a short CPU stall per generated
frame, still far cheaper than the two full device idles per frame the old
implementation paid.
The tell was in the trace, not in the code: working frames submitted
waits=1 signals=1, the frame that died submitted waits=2 signals=2. Everything
else about that frame — the dispatch, the copy, the fences, the presents — was
identical.
The other five:
· __fi on a free function in a header. PCSX2's __forceinline is
__attribute__((always_inline, unused)) with NO inline keyword, so every
including TU emitted its own copy: duplicate symbol at link, from a header
that compiles perfectly alone. Pcsx2Defs.h provides __forceinline_odr for
exactly this and the rest of the renderer only uses __fi inside class
bodies, where members are implicitly inline.
· Acquire budget. Vulkan allows imageCount - minImageCount + 1 images held at
once and the presented frame already holds one, so with min=3 and 3 images
the budget was ZERO. Acquiring anyway is undefined behaviour, not a failed
call. GetImageCount() - 1 was simply the wrong bound.
· Swap chain image count. Asking for base + 1 does nothing: on FIFO the base
is 2, so it clamps straight back up to minImageCount. The request has to be
anchored to minImageCount, or the budget stays zero and frame generation
silently never runs with nothing reporting an error anywhere.
· One command buffer, one semaphore set, no fence. Resetting a buffer that is
still executing and resubmitting one that is still pending are both
undefined. The OLD implementation had the same single-slot arrangement and
got away with it because it called vkQueueWaitIdle twice a frame — removing
those idles is the entire point of this port, and it removed the accidental
serialisation that made reuse legal. Now one slot per swap chain image, each
with its own fence.
· Initialisation order. Moving image allocation into CreateResources without
moving the allocator ahead of it dereferenced an empty std::optional and
killed the GS thread during BIOS boot — before frame generation would ever
have produced a frame, so it presented as an entirely unrelated crash.
Generated frames also now go into images WE own and are copied into the acquired
swap chain image, rather than being dispatched straight into it through a
storage view. That theory did NOT fix the crash — but it is what both Eden and
the old implementation do, it asks nothing unusual of the WSI, and it let the
swap chain drop VK_IMAGE_USAGE_STORAGE_BIT entirely, which removed the
'enable it, then restart the renderer' wart along with it.
Diagnosis was step-tracing the present path, not reading it: five rounds of
reading produced three wrong theories, and the trace produced the answer in two.
The instrumentation is removed; the reasoning is in the comments.
|
||
|
|
0bfefd4b69 |
LSFG: run frame generation on our own device, and delete the old path
Completes the switch to the Eden port. GSLsfg keeps its entire public surface — availability, status text, display FPS, the settings and OSD plumbing all untouched — and only its internals change, so nothing above the renderer had to move. What actually changed on screen: the old implementation ran the interpolator on a SECOND VkDevice and shared images as AHardwareBuffers, and because Android offers no cross-device semaphore (Turnip rejects OPAQUE_FD export on AHB memory) the only barrier available was a full device idle — twice per frame, every frame. That is gone. Generation is now ordinary compute recorded into a command buffer on the device we already have, and interpolated frames are written STRAIGHT into an acquired swap chain image through a storage view, so the intermediate copy is gone too. The pacer comes with it, which is the fix for games that oscillate between 60 and 30fps on a 60Hz panel: the generation count now varies to hold the presented rate near a target instead of blindly multiplying whatever the game produced. ★ ONE submit, N+1 semaphores. All the generation work goes into a single command buffer, submitted once, waiting on the caller's render-finished semaphore plus every acquire, and signalling one semaphore per present that follows. The obvious alternative — a submit per generated frame — walks straight back into the binary-semaphore bug this file was bitten by before, where the real present and the first generated present both want to wait on the semaphore that says the source has been read. A binary semaphore may be waited exactly once. ★ The hook fires AFTER vkQueueSubmit, so FrameGen had to take its command buffer as a parameter. It was written against GSDeviceVK::GetCurrentCommandBuffer(), which at that point is in flight or already belongs to the next frame; recording into it is undefined and the symptom would have been interpolation running a frame late rather than anything resembling an error. Layout bracketing is ours: the ported passes speak Eden's convention where a presentable image lives in GENERAL, and PCSX2 hands them over in PRESENT_SRC_KHR and needs them back in it. The swap chain now requests VK_IMAGE_USAGE_STORAGE_BIT — but only when frame generation is on AND both the surface and the chosen format allow it. Asking unconditionally fails swap chain creation outright on drivers that do not, which would take the whole renderer down for a feature that is switched off. The format half is the easy one to miss: a surface can report STORAGE support while the sRGB format picked for it has no STORAGE_IMAGE feature bit, and that only shows up later as a validation error at image-view creation. Because usage is fixed at creation, switching the feature on mid-session needs a renderer restart; Initialize says so rather than failing silently. DELETED: platforms/android/app/src/main/cpp/3rdparty/lsfg in full — the lsfg-vk-android framegen library, the DXVK dxbc compiler, pe-parse, volk and its 759-symbol collision with VKLoader, the C ABI shim, the version script, the separate .so and the dlopen that found it, and the -fexceptions carve-out they needed. GSLsfg.cpp went from 1259 lines to 654. The ~130 MB configure-time fetch goes with it. build-play-aab.sh's guard was rewritten rather than dropped: it checked for a file that can no longer exist either way, so it would have passed forever without proving anything. It now looks inside the core for a symbol only the ported implementation defines. Verified: all 18 affected translation units compile without errors, with ARMSX2_HAS_LSFG on AND off (the play flavour still compiles the feature out entirely). Not yet run on hardware. |
||
|
|
5e1d979b4e |
LSFG: port Eden's frame generation (passes, pacer, DLL reader)
Ports the frame-generation implementation from Eden (eden-emu PR #4263), which is a substantially better design than the lsfg-vk-android one we currently ship. Why it is better, concretely. Ours runs framegen on its OWN VkDevice, shares images through AHardwareBuffer, and — because Android gives no cross-device semaphore, Turnip rejecting OPAQUE_FD on AHB memory — uses full device idles as its only barrier. Eden's runs as ordinary compute on the device we already have. It also needs none of what ours drags in: no DXVK dxbc compiler (its shader translate is a SPIR-V validate plus a descriptor-binding renumber, because current Lossless.dll ships SPIR-V in its RCDATA resources), no pe-parse, no volk and its 759-symbol collision with VKLoader, no separate .so, no C ABI, no dlopen, and no -fexceptions carve-out. It also brings a real frame PACER, which is the answer to games that oscillate between 60 and 30fps on a 60Hz panel. A fixed multiplier presents 120 then 60 there and judders at every transition; the pacer varies the generation count to hold the OUTPUT near a target instead. New GSConfig.LsfgTargetRate drives it, defaulting to 0 = the existing fixed-multiplier behaviour, so this is opt-in. Nothing is wired up yet — GSLsfg still drives the old path. This commit is the ported library only. ★ The load-bearing decision is LsfgVkCompat. The pass code is written against yuzu's RAII wrapper and its Device/MemoryAllocator, which PCSX2 has no analogue for. Rather than rewrite ~2000 lines of call sites, the slice of that API the code actually uses is reimplemented over PCSX2's raw handles and VMA — it came to five command-buffer methods, three Device queries, two allocator entry points and eight handle types. The result is that every pass body is BYTE-IDENTICAL to Eden's, so upstream fixes stay a readable diff instead of a merge puzzle. Deliberate departures, each commented at the site: · paths are std::string, not std::filesystem — the GS backend uses neither · CityHash -> GSXXH3_64bits, already used elsewhere in GS · the shader cache gained mtime + a flags field so a hit costs a stat() rather than a full read, hash and PE walk of the DLL on every launch; Eden keys on a content hash and so must read the whole file before it may look at the cache. GSLsfg.cpp already validates on size+mtime, so this matches the tree. · Eden's RemoveInstalledLosslessDll() is NOT ported. It deletes the DLL, which is safe there because Eden owns that file; here the path is whatever GSConfig.LsfgDllPath says and nothing checks it points inside our storage. Only the cache half is kept, as ClearShaderCache(). · vk::Buffer gained Flush(). The port initially dropped Eden's flush because the shim had nothing to flush through. That write is the shader's entire uniform block, and the failure mode is not a crash — it is interpolation reading stale constants, which reads as a motion artefact, not a bug. Verified: all 14 translation units compile clean against the real PCSX2 headers under -Wall -Wextra. The reconstructed util.cpp helpers were diffed against the genuine Eden source fetched from the merge commit — the extracted diff hunks in the working copy are PARTIAL, added lines only, so they were not safe to trust. |
||
|
|
517fa69c4c |
OSD: stop any settings change from wiping the active OSD mode
Changing any setting at all — brightness, a speedhack, a controller binding — made the on-screen display disappear. The OSD has two independent controls that both write the same native flags. The per-stat selection in settings, and the MODE picked from the in-game menu or the hotkey (Full / Minimal / Custom / Off). Settings.applyTo() pushes the per-stat osdShow* flags unconditionally, and applyTo runs on EVERY settings change, so it was overwriting whatever mode was active with the Custom flag set. On most setups the Custom set is mostly off, which is why the symptom reads as the OSD vanishing rather than as it changing. The mode STATE was never lost — InGameOverlay.osdMode still said Full, and the in-game menu still showed Full. Only the native flags had been replaced, so the UI and the screen disagreed and nothing looked wrong from the app's side. Fixed at the applyTo choke point rather than at its five call sites: a re-assert that reapplies the mode when it is anything other than Custom. Custom is left alone deliberately — applyTo has just written exactly what Custom means, and re-applying would be a redundant round trip through the CPU thread. This is the same shape as the boot-time applyStoredOsdMode() and the second-display reapplyOsdMode(), which already restore the mode after something else has pushed flags underneath it. applyTo was the third place that needed it and the only one that had no such guard. |
||
|
|
54d2850295 |
LSFG: keep it out of the Play build entirely, not just switched off
Play builds cannot carry LSFG at all, and they did. The gating was a
BuildConfig.LSFG check inside shared files, which is a weaker claim than it
reads as: the rows were never drawn, and all 22 frame-generation strings still
shipped in the Play dex in plain text — including "Lossless Scaling",
"Lossless.dll" and the requirements dialog naming the product, which is exactly
what a text search over the artifact finds. The native half was already
genuinely compiled out (-DARMSX2_ENABLE_LSFG=OFF); only the Kotlin half looked
like it was.
Moved to source sets, which is the arrangement that actually excludes:
LsfgSection.kt main -> github, with a no-op stub in play
the 22 EN strings -> I18nLsfg.kt, real in github and an EMPTY MAP in play
the 5 search rows -> SettingsSearchLsfg.kt, likewise
LsfgEmulationCard new, so the shared pause-menu file no longer even names
the section's string key (SectionCard became internal)
EN is now BASE_EN + LSFG_EN and the search index BASE + LSFG, so whichever
flavour is in scope supplies its half and no caller knows which build it is in.
Splitting the search rows is a behaviour fix as well: in the play build they were
indexed while the section they pointed at was compiled out, so searching would
offer a result that rendered its own key as its title and led nowhere.
The settings FIELDS stay shared on purpose — identifiers rather than product
names, and an identical config schema across flavours is what lets a config move
between builds without losing data.
Verified on compiled output rather than source: playDebug has zero class files
containing 'Lossless' and zero containing 'perf.lsfg'; githubDebug has 2 and 4.
I18nLsfgKt.class is 3633 bytes in github and 833 in play. build-play-aab.sh now
greps the AAB's dex for both strings and fails the build if either appears, so a
later edit to a shared file cannot quietly undo this.
★ That verification first came back clean for BOTH flavours, which was a false
negative: Xcode's strings(1) parses a .class as a Mach-O fat binary, errors, and
prints nothing — indistinguishable from a pass. LC_ALL=C grep -a is what the
check uses, and what the comment in the script warns about.
|
||
|
|
2a98726692 | Merge remote-tracking branch 'origin/master' into jit-android-catchup-gv7 2.6.6.7 nightly-20260817 | ||
|
|
5b790427dd |
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. |
||
|
|
da25cb84cc |
Android: call eeClampMode 4 Exact, the name the other frontends use
The desktop and Big Picture pickers landed the same tier as Exact, and GameIndex.md documents it under that name. Android was the only frontend calling it something else, which made the same setting look like two different ones depending on which screen the user was on. The translation key moves with the label rather than keeping the old name for a value it no longer matches, so the map stays alphabetical and there is nothing left to mislead the next reader. |
||
|
|
541b1abfaf |
Android: offer eeClampMode 4 as Ludicrous in the clamping pickers
The tier existed in the core but nowhere in the UI, on any frontend, so
reaching it meant hand-editing the settings file. Both Android pickers —
the Performance tab and the in-game pause menu — now carry a fifth
option, and the settings layer packs it.
The packing is the part that matters. emucore validates the four clamp
booleans as a cascade and silently resets an inconsistent set to the
defaults rather than rejecting it, so writing fpuExactMode without its
three predecessors would not fail loudly, it would quietly land the user
back on Normal. applyTo therefore writes all four cumulatively, and
readFromIni reads them back highest-first.
readFromIni treats a missing fpuExactMode as an older core rather than as
mode 3: a build without the key never wrote it, and inferring 3 there
would demote a Ludicrous setting every time the settings were reloaded
under a mixed pair of builds.
The chip row already scrolls horizontally, so a fifth option needs no
layout change.
⚠️ Not addressed here, and worth a decision: the GameDB overwrites the
whole tier for any title carrying an eeClampMode entry, and an entry
below 4 clears the exact bit outright. On those ~115 titles the new
option is inert unless game fixes are off — which is most of the titles
whose users would want it. The setting description says so; whether the
core should let a user's choice raise the database's is a separate call.
|
||
|
|
99299e556c |
Merge pull request #590 from pstef/mode-3-4
Widen FPRreg to host double |
||
|
|
c246b9a03c |
LSFG: let the generated frame wait for a display slot; unhide FSR on renderer=auto
Two bugs of mine, both found on-device with everything else working. ★ The zero-timeout acquire disabled frame generation entirely. Forcing FIFO fixed the MAILBOX discard, and the display rate still equalled the real rate. Under FIFO the presentation engine returns an image at a vblank, so at steady state nothing is ever free INSTANTLY — vkAcquireNextImageKHR with a zero timeout returns VK_NOT_READY every frame, the loop breaks, and every interpolated frame is dropped. Silently, because a dropped generated frame is a legitimate outcome and nothing logs it. The reasoning behind the zero was that an interpolated frame is a bonus not worth stalling for. That is backwards: presenting two frames per rendered frame MEANS waiting for the second display slot. Waiting is the mechanism, not the cost. Now a 50ms bound — six vblanks at 120Hz, so it expires only when something is genuinely wrong, while still keeping a lost surface from wedging the GS thread the way an unbounded wait would. ★ The in-game FSR row was gated on renderer == "vulkan", and the default is "auto". "auto" resolves to Vulkan on Android, so the row was hidden from anyone who had not explicitly pinned the renderer — which is nearly everyone, and was the reporter. Gated on the two backends that genuinely cannot run it instead. |
||
|
|
2f1a74c88a |
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. |
||
|
|
bc268a7e83 |
GameDB: Add Prioritize Lower depth fix to Steambot Chronicles
(cherry picked from commit cde2448a6cd0d27f6651c59b43102d27dcb45e48) |
||
|
|
34333fe6bd |
GS/HW: Avoid detecting shuffles as source of truth for target format
(cherry picked from commit ded263f98aa2862b56439ea3c0b552748e4e64f0) |
||
|
|
0d558ce69f |
GS/TC: Improve single pixel overlap detection in RT in RT
(cherry picked from commit ffa569065638312d9c01a47f760130a2109ce7cc) |