mirror of
https://github.com/ARMSX2/ARMSX3.git
synced 2026-08-24 16:58:52 -07:00
b4a552d697950fdfdbbd13b1c6bee8cf60dda4a1
20175
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b4a552d697 |
FrameGen: take the interpolation off the critical path, and fix the shader cache flags
The cache was written with one flag set and read with another. BuildShaderCache asked for allow_fp16 = true while LsfgShaders, the only consumer, asks for (false, false), and the header stores those flags and is rejected when they differ -- so the cache written at import could never satisfy the read after it. On a desktop that is invisible: the source DLL is still there, LoadShaderModules falls through to re-parsing the executable, and the cache is dead weight rewritten every launch. Android has nothing to fall through to, because the picked file is a copy in app cache that the system may clear, so it surfaced as "no shaders" with a valid cache sitting next to it. Worth telling Camille: Eden and ARMSX2 are both re-parsing Lossless.dll every launch rather than using their cache. The cache also survives a missing source now. It is validated against the source's size and mtime, which is right where an install stays put and wrong here; passing 0 skips those checks, matching what source_hash and variant already do. A replaced Lossless Scaling is no longer noticed automatically, which is the trade -- against losing the cache to a routine cache sweep, and re-importing is explicit. Performance: the fence wait moved from after the submit to before the next one. Waiting at the end put the whole interpolation on the critical path -- the thread sat idle until the GPU finished, every frame -- when nothing required it: frame generation and the present blits share one queue, so submission order already orders them. Waiting at the START only blocks when the previous frame's passes have not finished in time. The queue is now taken from the device rather than a second vkGetDeviceQueue, so that sharing is explicit rather than incidental. Settings: motion detail is a slider rather than three stops, and performance shaders is a switch rather than a pair of buttons. |
||
|
|
caaadbe266 |
FrameGen: fix the allocator crash and the shader gate, and expose the rest of the settings in-game
Three defects from the switchover, all mine. vmaCreateAllocator crashed at pc 0 the first time frame generation was switched on. The allocator was created with physicalDevice and device but no instance and no vulkanApiVersion; Android builds with VK_NO_PROTOTYPES, so VMA resolves its table dynamically through vkGetInstanceProcAddr, which answers only for global functions when the instance is null. It stored nulls and called one. memory.cpp documents this exact failure at its own vmaCreateAllocator -- the two getters were supplied and the instance beside them was not. shader_count() then answered for the wrong cache, twice. First it still counted g_shaders, which import_shaders stopped filling when it moved to the ported extractor: generated_frame_count() multiplies by it, so generate() returned on its first line and frame generation sat on "starting" with nothing logged, because it never got far enough to fail. Replacing that with GetInstalledLosslessStatus() was also wrong -- that validates the DLL PATH, and the UI copies the picked file into app cache, which Android may purge. A re-import wrote a good 322KB shader cache and it still said "no shaders". It now asks whether the cache LOADS, which is the actual question: the shaders are extracted once and the source is not needed again. The dead initialize() call in generate() is gone with it. It built the dlopen'd library's context, nothing uses it, and a failure there could still disable the feature. Settings: the in-game menu offered the multiplier alone. Someone opening it mid-game is there to answer "it is generating but the picture is unsteady" or "it is generating but it is too expensive", and neither is the multiplier. Target rate, flow scale and performance mode now sit beside it. Target rate is new -- 0 keeps the fixed multiplier, non-zero is Camille's adaptive pacing. |
||
|
|
b5f449ccb6 |
FrameGen: run the ported passes, and stop going through the separate device
Wires up the previous commit. Frame generation now runs on OUR VkDevice, in our own present path, instead of inside a dlopen'd library with a VkDevice of its own. What that removes: every frame used to cross between devices as an AHardwareBuffer -- allocated, imported as a VkImage on our device so the renderer could blit into it, handed over as a raw buffer, imported again on theirs. The capture images are plain device-local VkImages now, because the passes read the very images the renderer already wrote. The AHardwareBuffer external-memory extension was also the narrowest gate on the whole feature and is no longer required. Kept deliberately: - The capture itself. The swapchain image is presented and reused, so the passes still need a stable copy; only its backing changed. - commit_capture(), now near-vestigial. It existed because a second VkDevice had no semaphore joining it to ours. One device and one queue means submission order already says this, but the call site is where the capture becomes readable and that is worth keeping named. - The fence wait in generate(). The present path blits the generated images immediately after, so the old contract -- return only when they are ready -- still holds. A semaphore would do it without stalling the thread and is the obvious next step, on a path that has broken three times from partial fixes. Frame generation records into its OWN command buffer, as the ARMSX2 driver does: the passes have to run after the captured frame is complete and before the generated images are blitted, and the renderer's buffer is already closed by then. import_shaders now drives the ported extractor rather than the library. Both kept their own copy of the shaders, and importing through the library would have looked like it worked -- a count comes back, the settings screen agrees -- while the cache the passes actually read stayed empty. Its failures are now phrased for the person who chose the file. VKPresent.cpp is untouched: generate(), generated_frame_count(), generated_image(), capture_presented_frame() and commit_capture() all kept their signatures and their meaning, which is the whole reason the switchover is one commit and not five. Builds clean. NOT yet run on hardware -- neither this nor the device-feature change under it has drawn a frame. |
||
|
|
e05ea4d219 |
FrameGen: port Camille's native LSFG implementation from ARMSX2
Compiles; not yet wired. VKFrameGen still drives the old dlopen path and nothing calls these passes -- that is the next commit. Landing it here keeps the port and the switchover separable, because the present path is the part that has broken before. The implementation is Camille LaVey's, from eden-emu PR #4263, by way of ARMSX2 2.6.6.8. She licensed it GPL-2.0-or-later for use here: ARMSX3 derives from RPCS3, which is GPL-2.0-ONLY with no "or later" clause, so the original GPL-3.0-or-later terms could not be carried across. Every file records that. Eden is unaffected -- "or later" leaves its own use exactly as it was. Why it is worth having: the current implementation runs behind a dlopen'd .so with its OWN VkDevice, so every frame crosses devices as an AHardwareBuffer -- allocated, imported on our device, handed over, imported again on theirs. These passes run on our device in our own present path and that round-trip disappears. It also brings adaptive pacing: instead of a fixed x2, generate as many frames as it takes to hold a target refresh rate, which is the answer to a game oscillating between 60 and 30 on a 60Hz panel. Porting notes, all of it concentrated in three seams rather than spread: - LsfgVkCompat's Device adapter wrapped GSDeviceVK and now wraps vk::render_device. 28 of the 31 files never mention either and were not touched. - GSConfig lives in FrameGenConfig.h, mapping RPCS3's mode enum and cfg fields to the names the passes read, so a later merge from Eden touches passes not wiring. - LosslessDll's platform calls (FileSystem/Path/GSXXH) became fs:: and an inline FNV-1a; the hash only has to notice the DLL changed since the cache was written. Two changes outside the tree were prerequisites, not cleanups: - vkCreateDevice now ENABLES vulkanMemoryModel and robustness2's nullDescriptor when the device reports them. Both were already probed and never enabled, and a shader that declares the memory model on a device where it was not enabled is invalid usage rather than a soft fallback -- desktop drivers shrug it off while Adreno takes the device down mid-frame, so it would have looked fine until it was not. Only nullDescriptor is turned on, not robustness2's expensive half. - The Android Vulkan loader gained vkFreeDescriptorSets, which it never loaded. New settings: Frame Generation Target Rate (0 = fixed multiplier) and Frame Generation Lossless Path. Nothing ships the shaders; they are read from the user's own legitimately purchased copy, exactly as before. |
||
|
|
d8a98305b8 |
Library: fail a game the app cannot read, instead of hanging on its loading screen
A game that is visible but unreadable is the failure mode that costs the most time, because nothing about it looks like a permissions problem. The core opens games with ordinary file IO. Without All files access the scanner falls back to SAF document trees, and a title found that way has no filesystem path to open -- but it is still listed, still launches, and then sits on its first loading screen when the reads never arrive. The same shape appears when the grant is revoked after a folder was added, or when a disc sits on storage the app was never given. Moving the same files into the emulator's own games directory fixes all of it at once, which is what makes the cause so hard to see: the game works or does not depending only on where it lives. Boot now proves the content is readable first, at two offsets. Size alone proves nothing -- an entry can be listed with its real size and still refuse to deliver bytes -- so it reads byte 0 and byte 32769, the ISO descriptor, the first place any disc is read for real. Failure returns invalid_file_or_folder with a message naming the two fixes, rather than handing the core content it cannot read. The scanner says the same thing at the point it falls back, distinguishing "All files access is not granted" from "this tree has no filesystem path", because they need different fixes. Read-only probe, and directory-installed titles skip it: fs::is_file is false for them and they were never affected. Reported by a tester whose whole library started working after moving the ISOs into ARMSX3/config/games -- cover art, launching, and Prototype no longer locking up, all from the move alone.0.9.4.1 |
||
|
|
2f0c63ac1b |
ISO: stop treating a short magic read as "not an ISO"
Reverts upstream |
||
|
|
4b8ffa3702 | Release: 0.9.4.1 | ||
|
|
c01f2e9ba8 |
Boot: warn when PPU Threads is not 2
The PS3 has two PPU hardware threads and upstream's own config comment says this must be 2. With 1, SPURS does not get the concurrent PPU progress it expects and its task modules fail validation: the SPU executes its own HALT instruction and the graphics pipeline stops. It presents as an intermittent freeze after 10-30 minutes, on hardware where the same build with the default is fine. There is no UI for this value -- it is reachable only through a raw core override, so it is set deliberately and then forgotten. Nothing reported it, which meant an affected log was indistinguishable from a healthy one and the setting had to be found by eye in the config dump, after a diagnosis that went through the SPU halt, the reservation path and an instruction-level SPU test run before arriving at a configuration difference. |
||
|
|
71c694c9ab |
Really Slick Screensavers as library backgrounds, and rename the ARMSX2-era settings mirror
Six of Terry Welsh's screensavers (GPL-2.0-or-later) run as animated library backgrounds alongside Flurry: Flux, Plasma, SolarWinds, Hyperspace, Lattice and Skyrocket. They are GL 1.x -- immediate mode, the fixed-function matrix stack, display lists, texgen -- so savers/gl1.c answers all of that on GLES2 rather than the renderers being rewritten. Display lists are not an optimisation to skip here: each saver compiles its particle shape once and replays it per particle with a different matrix, so glCallList IS how they draw. Flux, Plasma, SolarWinds and Hyperspace are byte-identical to upstream. They build with RS_XSCREENSAVER, their own platform-neutral path, and everything it expects from an X11 host is answered by savers/compat. Lattice and Skyrocket ship Windows-only and were hand-ported; each carries a header listing exactly what was removed. rss-glx has neutral versions of those two but is GPL-2.0-only, which ARMSX2 (GPL-3.0) could not take. Every saver is compiled inside its own namespace by a *_unit.cpp. They all declare the same globals -- draw, idleProc, cleanUp, readyToDraw -- because each was built as a separate executable, and two in one .so collide at link time. Notes on the three bugs that were not obvious: - The render thread gets a 16MB stack. Skyrocket's World constructor declares a 1024x1024x3 starmap as a LOCAL, 3MB, then a 768KB sunsetmap. On a Windows main thread that was fine; here it was a SIGSEGV in memset before the first frame. - gl1_frame_begin clears the first frames and then masks alpha off. These savers fade the previous frame instead of clearing, and that fade writes destination alpha, dragging a composited surface toward transparent -- which reaches the screen as TV static. Same fix Flurry needed. - The saver lifecycle is serialised behind a mutex and a generation token. Each view owns a GL thread, so switching preset let the outgoing thread's teardown land after the incoming thread's init and wipe it; gl1 keeps its state in one global. A view may now only free the run it started. Also renames the settings mirror armsx2-settings.json to armsx3-settings.json (issue #82). The old name stays readable: after a reinstall it is the only copy of a user's settings, so it is still restored from, still collected into new backups, and now deleted alongside the new one -- leaving it behind would silently re-seed settings that had just been purged. Old backup archives restore unchanged. |
||
|
|
7673186c06 |
Flurry: preserve the EGL back buffer so the trails can accumulate
The library background rendered as full-screen TV static with the smoke faintly visible behind it. Flurry draws its trails by fading the PREVIOUS frame rather than clearing, so it needs the back buffer to still hold what it drew last time. EGL defaults EGL_SWAP_BEHAVIOR to EGL_BUFFER_DESTROYED, which leaves the buffer undefined after every eglSwapBuffers, so every frame started from uninitialised GPU memory -- which is what reached the screen as static. Measured: a single fade darkened the buffer by 3.17%, but sixty consecutive fades only achieved 6.5% in total, where sixty compounding 3.17% fades should have taken a corner reading 123 down to 17. The fade was working every frame; its result was not surviving the swap. A 64x64 readback of that corner went from mean=128 ndiff=41 to mean=0 ndiff=0 with preservation on. Preservation must be requested on the config and on the surface, and is then queried back rather than assumed, since a driver may refuse it. Also set the surface alpha once and mask further alpha writes off. Flurry fades with GL_SRC_ALPHA/GL_ONE_MINUS_SRC_ALPHA, which writes destination alpha as well as colour and drags it toward the fade's own value -- harmless for a screensaver that owns the display, wrong for a surface the window compositor blends. RGB is untouched, so the trails are unaffected. |
||
|
|
e9a21da302 |
Library: offer Flurry as the background
Calum Robinson's Flurry screensaver (2002), ported from the xscreensaver tree and offered alongside the XMB wave. Asked for by a tester who has wanted it on a handheld since the Mac original. The renderer is his, unmodified. It draws the way 2002 did -- client-side vertex arrays, a fixed-function ortho, GL_QUADS -- none of which GLES2 has, so gl_compat.c answers those calls with a shader, a matrix uniform and an index buffer instead. That keeps the diff against upstream to four lines: gluBuild2DMipmaps becomes glTexImage2D plus glGenerateMipmap, GETTIMEOFDAY_TWO_ARGS is set by hand rather than by xscreensaver's configure, DrawSpark is guarded because it is immediate-mode and upstream never defines DRAW_SPARKS, and the xlockmore shell is replaced by four entry points. Its own target rather than part of the JNI glue: BSD-3-clause next to GPL, and plain C that wants none of the C++20 around it. FlurryGlView is the same TextureView and EGL shell XmbGlView already uses, so it reports through onGlStatus the same way and a device that cannot bring GL up falls back to the 2D backdrop rather than showing a hole. Off by default, and the description says why. This is a live particle simulation, and an animated library background has been walked back here once before -- ARMSX2 shipped a looping video behind this same screen and removed it in 2.5.9 when the continuous decode turned out to cost real performance. The loop is capped at 60fps for the same reason XmbGlView caps itself at 30: Flurry already refuses to advance faster, but without a cap the thread still spins at panel rate. Also adds @JvmStatic to Rpcs3Bridge.deleteState, which NativeApp calls from Java. Kotlin-only compilation does not catch that. |
||
|
|
5d5b8aa4c1 |
Savestate: add a real delete for slots
Deleting a slot could never work. There was no delete entry point, so the picker
called java.io.File(getGamePathSlot(slot)).delete() -- and getGamePathSlot answers
OCCUPANCY, not a path. Its own declaration two lines below says so: "Not
getGamePathSlot, which answers a title id". So the call was
File("SHVH06660").delete(), which removes nothing and returns false. Every delete
failed, and the UI correctly reported that it had. Issue #80.
Added _rpcsx_deleteStateFromSlot, which resolves the file through
armsx3_slot_find, the same function load uses. That matters: the extension
depends on which build wrote the state -- .zst today, .gz and bare historically --
and building the path by hand is how this went wrong to begin with. The thumbnail
beside it goes too, best effort, so a removed state cannot leave a slot still
showing as occupied.
|
||
|
|
a46dae38bc |
Savestate: do not resume while one is being written
Saving arms after_kill_callback with Emu.Restart and then kills the VM. The restart runs BootGame, whose restore_on_no_boot does ensure(IsStopped()) -- and that overload accepts only stopped, loading or stopping. A Resume landing anywhere in that window puts the state at running and turns the assert into a process abort. Issue #81, from the log: "Emulation has been resumed!" at 0:03:23.275950 and "{Savestate Prepare Thread} Verification failed (object: 0x0)" at 0:03:23.275981. Thirty one microseconds apart, on different threads. Android makes the window far easier to hit than desktop. CallFromMainThread runs its callback INLINE on the calling thread here rather than deferring it, so the whole kill-and-restart chain executes on the savestate thread while the UI thread stays free to resume underneath it. Guarded on m_emu_state_close_pending, which is the emulator's own marker for that window and is cleared on every failure path, so this cannot leave a game stuck unresumable. Placed in Resume() rather than in the Android entry point so it also covers the resume that surface-loss recovery issues. |
||
|
|
b2caae9da2 |
NP: derive an Ethernet address on Android instead of failing
discover_ether_address() reads the MAC with SIOCGIFHWADDR. Android has not let an
app do that since Android 6 and enforces it hard from 10 -- the ioctl returns
EPERM and /sys/class/net/*/address is unreadable -- so on every modern Android
device that branch failed, np_handler logged
NPHandler: Failed to discover ethernet or ip address!
and gave up. That leaves the network stack unidentified and blocks RPCN and any
game that asks it who it is. Reported as issue #79 against two unrelated titles,
with network settings that looked correct and could not have helped, because
nothing exposed in them reaches this.
The IP half was never the problem: it learns the local address from a UDP connect
to 8.8.8.8, which is a routing lookup and sends nothing.
Derive the address from Console PSID, exactly as the derive_mac_from_psid path at
the top of the same function already does. Nothing validates it against hardware
-- it identifies the console to the network stack and to peers -- and a locally
administered address is the correct thing to present when the platform refuses
the real one. Console PSID defaults to a per-install random value, so two users
do not end up sharing one.
Tried after the ioctl rather than in place of it, so a device or ROM that does
answer still uses its own.
|
||
|
|
0262053a91 |
Revert "VK: make the fence poll mechanism selectable at runtime"
This reverts commit
|
||
|
|
b91c6551ed |
VK: make the fence poll mechanism selectable at runtime
"Is this submission finished" costs 1.9ms per call and returns not-ready 0.0% of the time on Adreno 740 -- about 5ms a frame in Minecraft, a quarter of the RSX thread. Measured with the profiler's own counters (fence polls 2.6/frame, 1903712 ns each). That is the same signature this code already carries a comment about: vkGetFenceStatus measured 19.7ms per call and never once returned VK_NOT_READY, "a wait wearing a query's name". The zero-timeout vkWaitForFences that replaced it is ten times better and still, evidently, a wait -- the driver appears not to honour a zero timeout either way. That is driver behaviour, so which call is best is a per-device question and not something to decide here. ARMSX3_FENCE_POLL in driver_env.txt selects between them: wait0 default, today's zero-timeout wait status vkGetFenceStatus, what this used before defer speculative callers do not ask the driver at all The third is the interesting one. check_present_status walks the queued frames looking for ones that have already finished and gives up on the first that has not, and poke_all discards the result entirely -- neither wants to wait, so neither should be the thing that does. They now pass allow_block=false. next() and reset() keep the blocking form, so the command buffer ring cannot be starved by this and "CB chain has run out of free entries" cannot fire because of it. Default behaviour is unchanged. This ships as a lever rather than a fix on purpose: the last renderer change justified by one game on one device was reverted in 0.7.1 after wider testing, and the note on that revert asked for pieces that come back one at a time with testing behind each. The profiler already prints per-call timing, so each mode can be judged on the device in front of whoever is testing. |
||
|
|
72410638ff |
cellAudio: let the untouched baseline come back down, but not on a flicker
|
||
|
|
0a3fcc622f |
Audio: stop the Oboe backend failing silently and permanently
Issue #73: F1 Championship Edition silent since v0.8 except during videos, on every audio backend. The reporter also notes the races run at 10fps and the videos are "a bit choppy" -- so audio dies when the machine is saturated and survives when it is not. That is a load correlation, not a code-path split, and it rules out the theory that cellAudio is never reached. cellAudio.cpp has no commits at all in the v0.6..v0.8 window. Across every audio setting the Android UI writes, the only delta is the default backend moving from Cubeb to Oboe, with a migration that moved existing users too. Cubeb starts the OS stream in Open() and never stops it while open; its Play and Pause only flip a bool. Oboe's call requestStart and requestPause for real, and this backend asked for an Exclusive low-latency stream with a two-burst buffer -- 4 to 10ms. An Exclusive AAudio stream holds the app to the callback deadline and the platform disconnects it when that is missed for long enough, which at 10fps is continuous. ARMSX2's own Oboe backend, same team and same device class, uses Shared with a 4096-frame capacity. Three fixes here: Open() asks for Shared, and sizes the buffer from the emulator's own Desired Audio Buffer Duration rather than a burst multiple. cellAudio fills ahead by that much, so a stream that cannot hold it underruns however the trigger is set. Play() started the stream AFTER committing m_playing, and never rolled it back on failure. onAudioReady requires m_playing but a stream that never started does not call it, so cellAudio's backend_active never armed, every block it enqueued was discarded by the !backend_active check in enqueue(), and the early return at the top of Play() made that permanent for the session. Start first, claim second. Operational() answered `m_stream && !m_reset_req`, which is true for a stream that failed to start or was disconnected -- so cellAudio's "backend stopped unexpectedly" recovery never ran. It now reports the stream state. Also: audio::configure_audio() is what turns a changed audio node into a rebuilt backend, and its only caller is main_application.cpp, which is Qt and not part of this build. Writing Audio Renderer changed the YAML and nothing else until the next boot, so "try another backend" was a null experiment -- which is how that issue collected three backends' worth of identical results. Call it from the Android settings path, alongside the overlay resets that had the same gap. And the "Audio Backend (advanced)" row only affects Cubeb, since cubeb_backend is read once in CubebBackend's constructor. Under Oboe it did nothing while staying interactive and showing a selection. Hidden unless the renderer is Cubeb. |
||
|
|
43df8b0dc2 |
Android: say why an ARMv8.0 device cannot run, instead of dying on SIGILL
The core is built for armv8.1-a and that is a floor, not a preference: util/simd.hpp emits SQRDMLAH and util/asm.hpp carries inline LSE atomics. On ARMv8.0 silicon -- Cortex-A53/A57/A73, so Exynos 9610, Snapdragon 660 and the like -- those are illegal opcodes. What the user saw was a bare crash. The fault is a SIGILL inside a static constructor while the linker is still running libarmsx3-core.so's initialisers, so it happens before any of our code can report anything, and the top frame names a log-channel registration rather than a CPU problem. Because the core is dlopen'd lazily, it surfaced at whatever first needed it -- issue #15 filed it as "crashes when selecting the firmware .pup file", which is where the crash appears and not what it is about. Check /proc/cpuinfo for atomics and asimdrdm before that dlopen and report it. Checked across every core listed, not just the first, since emulator threads are scheduled on all of them. Fails OPEN by design: an unreadable or unfamiliar /proc/cpuinfo returns null and loads as before. Blocking a device that would have worked is worse than the crash this replaces. Verified on a Snapdragon 8 Gen 2 that all eight cores report both flags, so nothing changes there. The reason is also held in unsupportedCpuMessage so a screen can show it later; a toast is easy to miss for something this final. |
||
|
|
a14670c282 |
Config database: add ARMSX3-local per-title overrides, starting with issue #77
The RPCS3 config database is maintained against desktop, so a fix specific to this port has nowhere upstream to live. Add a small local map layered on top of whatever the database says. First entry: Tales of Symphonia Chronicles (BLUS31213, BLES01935) gets Frame limit "PS3 Native". That is the only mode which honours the game's own cellGcmSetFlipMode(CELL_GCM_DISPLAY_VSYNC) request -- every other mode flips immediately, so a title pacing itself by flipping on alternate vblanks free-runs to the 60 cap, which is issue #77: 60fps in a 30fps game and battles at double speed. Applied in three places because none of them alone is enough: after refresh(), which clears the directory before writing; after setEnabled(), which moves the whole directory aside; and at startup, so it works for users who never downloaded the database at all. Merged rather than overwritten, and skipped entirely if the database already sets a Frame limit for that title. UNVERIFIED against the reporter's device. The mechanism is read from the code, not measured, and the failure mode matters: PS3 Native applies NO limit when a game does not request vsync, so if this title turns out not to, it would run unbounded rather than capped at 60. Drop the serials from the map if the reporter says it is worse. |
||
|
|
8c1952deae |
Frame limit: offer PS3 Native from the FPS cap row
PS3 Native is the only Frame limit mode that honours the game's own cellGcmSetFlipMode(CELL_GCM_DISPLAY_VSYNC) request: in handle_emu_flip every other mode falls through and flips immediately, while that one defers the flip to a real vblank. A title that paces itself to 30fps by flipping on alternate vblanks therefore free-runs to the 60 cap under Auto, our default -- reported in issue #77 as Tales of Symphonia running at 60 and battles playing too fast. The mode already existed and Rpcs3Settings could already write it, but nothing reachable from the UI ever did: the only control is the Display FPS Cap row, which maps to numeric presets or Second Frame Limit. It was reachable solely as a raw core override. That also explains the reporter's follow-up -- capping by hand does slow the game, but through the wall-clock limiter, which pushes flips off the vblank boundary and brings tearing and audio glitches with it. Added as -1 in that row rather than as a new setting, since it is mutually exclusive with a numeric cap. Both clamps on the way to the core floored at 0 and would have quietly turned it into "no cap". setFrameLimitEnabled needed the same widening. It runs last, so its `cap > 0` test read -1 as "no explicit rate" and wrote Auto back over PS3 Native -- the collision its own comment describes, one value along. Deliberately NOT the default: with no vsync request from the game this mode applies no limit at all, so titles that never ask for vsync would run unbounded. |
||
|
|
c6a0878a97 |
RSX: restore two hunks lost resolving the ROP remap merge conflict
Both sat inside set_transform_program, the handler upstream rewrote for
ROP_OUTPUT_REMAP. Resolving that conflict took upstream's version as the base and
re-applied our profiler scopes, which put the scopes back and quietly dropped
these.
The first is the one that matters.
|
||
|
|
b9689d07fd |
VK: allow the driver pipeline cache to be switched off at runtime
ARMSX3_PIPELINE_CACHE=0, read through driver_env.txt like the compute group size override, so a suspected regression can be A/B'd on a single build. Issue #78 reports Wipeout HD Fury running far worse on 0.9.4 than 0.9.3 with much higher CPU. That window holds 28 commits, and most of them only remove work, so the plausible suspects are this cache, the upstream ROP output remap, and the ISO reader revert. Guessing between them is not worth a release each. This one is worth being able to eliminate first because it is the only change that introduces a structure shared between threads that previously shared none: up to eight shader cache loader workers at boot, plus the async pipeline compiler workers during play, all now insert into one VkPipelineCache. Concurrent use is permitted by the spec, but the driver still has to serialise its own inserts. Not evidence that it IS the cause -- it is the cheapest candidate to rule out. |
||
|
|
82f21b16d2 |
VK: credit sashkinbro for the pipeline cache format and the Adreno split
Both landed as our own commits and both owe him more than they said. The on-disk pipeline cache header -- length, version, vendorID, deviceID and pipelineCacheUUID -- is his design from EmuCoreC 47220b153, used as-is, including using the UUID as the invalidation key so a driver swap rebuilds rather than feeding a driver a blob it cannot read. What was missing there was the wiring: nothing passed the cache to vkCreate*Pipelines, so it saved an empty file. That part, and sharing it with the shader interpreter, are ours. Splitting Adreno and Turnip out to a 64-wide group size is his too (b9f0f3631). Our comment had held all of mobile at 32 on the claim that Mali was also 64-wide, which is wrong -- Valhall warps are 16 lanes and Bifrost 4-8. His split was the better call and the reason ours changed.0.9.4 |
||
|
|
2ed8442c11 | Release: 0.9.4 (versionCode 20) |