Commit Graph
47447 Commits
Author SHA1 Message Date
HalexxanderandClaude Opus 5 e5bd8e8e58 Add optional controller rumble on button press
New "Vibrate controller on button press" setting under Controls. When enabled,
pressing a gamepad button rumbles that pad for as long as it's held - something
the PSP hardware never had, but which some people want from a modern pad.

Implemented per platform behind System_ControllerRumbleStart/Stop: SDL uses
SDL_RumbleGamepad, Windows feeds it into XinputDevice's existing vibration path
so it doesn't fight with the vibration games request through sceCtrl, and
Android goes through InputDevice.getVibrator() in Java. Stubbed elsewhere.

The D-pad is excluded, since it gets tapped constantly while navigating.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01GgACRqkQNpfJQ4fjwyoEup
2026-09-05 12:08:09 -06:00
Henrik Rydgård 6d4bc5f261 Merge pull request #22207 from acts-1631/security/fix-pgf-bpe-validation
Validate PGF bits-per-entry fields
2026-09-05 09:48:59 -06:00
Henrik Rydgård 8b69031197 Merge pull request #22215 from hrydgard/shutdown-crash-fixes
Misc shutdown fixes on Windows
2026-09-05 09:47:39 -06:00
Henrik Rydgård 5d608e39a3 Merge pull request #22223 from hrydgard/iso-metadata-hardening
Clamp ISO metadata and file sizes to the max possible extent
2026-09-05 09:28:29 -06:00
Henrik Rydgård 64cdcbfca2 Merge pull request #22225 from hrydgard/misc-fixes
Assortment of minor fixes
2026-09-05 09:28:10 -06:00
Henrik Rydgård 28109855f0 Merge pull request #22228 from hrydgard/restart-args-fix
Fix the restart-into-a-screen arguments, broken by the cmdline refactor
2026-09-05 09:27:29 -06:00
Henrik Rydgård d789696405 Fix the restart-into-a-screen arguments, broken by the cmdline refactor
Centralizing command line parsing replaced the hand-rolled --gamesettings and
--touchscreentest argv checks in NativeInit with a single --start-screen=<name>
option, and made an unrecognized "--" argument a hard parse error. The two
System_RestartApp callers still passed the old flags.

So changing the graphics backend killed PPSSPP for good: the new process starts,
fails to parse --gamesettings, and returns 1 from WinMain before a window ever
exists. The error goes to stderr, which nobody sees in a GUI build, so it just
looks like the app quit instead of restarting.

Restarts that pass no arguments (the memstick screen, and the edit-then-restore
path) were unaffected, since an empty argument string makes ExitAndRestart reuse
the original command line.

Also move the TouchTestScreen push inside the touchscreentest branch - it looks
like a brace that didn't move during the refactor, and it would otherwise push a
touch test screen for every --start-screen value.
2026-09-05 08:28:43 -06:00
Henrik Rydgård 9368198d90 Merge pull request #22226 from 4RH1T3CT0R7/fix/sdl-launch-folder-linux
SDL: Open local files and folders with xdg-open on Linux
2026-09-05 07:58:01 -06:00
Henrik Rydgård f929a74780 Merge pull request #22221 from 4RH1T3CT0R7/fix/debugger-breakpoint-list-refresh
Win32 debugger: refresh the breakpoint list after memcheck changes
2026-09-04 18:17:31 -06:00
Henrik RydgårdandClaude Opus 5 2389b8ce96 headless: add --save-state, the counterpart to --state
--state could load a savestate but nothing could produce one without a
GUI, so savestate bugs couldn't be reproduced or regression-tested from
a script. This saves one partway through the run, once the game is
actually up.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 18:14:41 -06:00
Henrik RydgårdandClaude Opus 5 5a84f287c4 sceIoRename: refuse wildcards, an existing destination, and don't wait on XDEV
Three ways our rename differed from the PSP's:

- A wildcard in either path was passed through to the host, so
  renaming "test*.txt" could quietly rename a real file. The PSP
  doesn't expand them here, it rejects them outright.
- Renaming onto a file that already exists succeeded, because the host
  rename() replaces the destination. The PSP refuses, and renaming a
  file onto itself counts as that too.
- Crossing devices returned the right error, but after the same wait
  as everything else. The hardware fails that one immediately.

Fixes io/file/rename, moved to tests_good.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 18:13:10 -06:00
Henrik RydgårdandClaude Opus 5 fd72f308af sceAudio: fix a crash when reserving a channel with none free
GetFreeChannel counted down with an unsigned loop variable, so i >= 0
was always true. With every channel already reserved it wrapped past
zero and kept indexing g_audioChans until it walked off the end -
sceAudioChReserve(-1, ...) segfaulted the emulator instead of returning
"no channels available". Reproduces on audio/sceaudio/reserve, which
crashed before printing anything.

Also gives sceVaudioChReserve the parameter checks it never had. It
took any sample count, channel count and frequency; the hardware allows
256, 1024 or 2048 samples, stereo only, and the same sample rates the
SRC channel accepts. Every value in the test now matches - what's left
there is only reschedule markers.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 18:12:31 -06:00
Henrik RydgårdandClaude Opus 5 d675b467c1 sceUtility: fix the system param string size check and the adhoc channel error
Two things utility/systemparam caught:

A negative size passed to sceUtilityGetSystemParamString went through
Memory::IsValidRange, where it became an enormous range and came back
as a generic -1. The PSP just reports that the string doesn't fit, same
as any other size too small to hold it.

sceUtilityGetSystemParamInt returned 0x800ADF4 for an automatic adhoc
channel unconditionally. The FIXME there wondered whether the hardware
only does that once adhocctl is initialized - it does. Before any adhoc
module is up, which is the state nearly every game asks this in, the
hardware returns 0 and writes the channel out.

Fixes utility/systemparam/systemparam, moved to tests_good.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 18:12:24 -06:00
Henrik Rydgård 68fd30bbba Merge pull request #22217 from hrydgard/gpu-fixes
Claude code review: Vulkan
2026-09-04 18:03:47 -06:00
Henrik Rydgård a807ffa984 Merge pull request #22220 from hrydgard/easy-fixes-1.21
Assorted easy fixes for 1.21
2026-09-04 17:52:09 -06:00
Artem Lytkin ec9eb7230e SDL: Open local files and folders with xdg-open on Linux
Since 1.20 the "Show Memory Stick folder" button and the log folder
button in developer tools call System_LaunchUrl with LOCAL_FOLDER or
LOCAL_FILE. The SDL implementation only handled macOS there, so on
Linux the click did nothing. Before that they went through the
SHOW_FILE_IN_FOLDER request, which already forks xdg-open.

Move that fork/exec into a LaunchXdgOpen helper and use it from both
places. The child now calls _exit after a failed exec so it doesn't
run the parent's atexit handlers.
2026-09-05 01:07:46 +03:00
Artem Lytkin 20e0185707 Win32 debugger: refresh the breakpoint list after memcheck changes
The list reloads on SystemNotification::DISASSEMBLY, which every CPU
breakpoint mutation in BreakpointManager has posted since 8d0d601b5, but
none of the MemCheck ones do, so a memory breakpoint added from the list
(or the disasm view's dialog, the ImDebugger, the WebSocket API) only
showed up after the next Break. The enable checkbox then toggled against
the list's stale copy of the memcheck, so re-enabling one it had just
disabled disabled it again. Post the notification from the memcheck
mutations too, and from the condition setters of both kinds, since the
list's cached copy also feeds the edit dialog.
2026-09-05 00:54:50 +03:00
Henrik RydgårdandClaude Opus 5 fbdb54300e Put a ceiling on the CSO frame size
Follow-up to #22208, which bounded the index table but left the frame
size itself unbounded - readBuffer and zlibBuffer are sized straight
from it, so a 96-byte header could still ask for a couple of gigabytes.
Harmless enough on 64-bit, where the pages never get touched, but a
32-bit build would just fail the allocation.

Real images use 2KB to 64KB frames, so 16MB leaves plenty of headroom.
All 19 CSOs I have on hand still load.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 13:10:54 -06:00
Henrik RydgårdandClaude Opus 5 30bea36141 docs: explain the [x]/[r] markers in pspautotests output
They record whether a reschedule happened while the code under test
ran, so a diff where only the marker differs is a scheduling
difference, not a wrong value - worth knowing before going looking for
a value bug that isn't there.

Also fixes the O/E description, which had them the wrong way round: O
is PPSSPP's output, E is the expected file.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 13:10:54 -06:00
Henrik RydgårdandClaude Opus 5 c93b0de8cb Translate "Show timestamps in chat"
31 languages, following each file's existing chat terminology (chatt,
bate-papo, obrolan, sembang, 聊天, الشات, ...). The rest are left to fall
back to English rather than guessed at.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 13:10:54 -06:00
Henrik RydgårdandClaude Opus 5 a506d0be6f Lowercase the extension reported by ZipFileLoader
Identify_File and friends compare against lowercase extensions, the way
Path::GetFileExtension returns them, but ZipFileLoader passed the name
from the zip through unchanged. So a file stored as e.g. "DUMP.PPDMP"
inside a zip failed to load, while "dump.ppdmp" worked.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 13:10:54 -06:00
Henrik RydgårdandClaude Opus 5 fbdf611fc4 Chat: keep more lines of history, and add timestamps
The log was trimmed to 50 lines, which isn't enough to scroll back
through a conversation - now 250. Chat entries also carry the time they
arrived, shown as a dimmed HH:MM in front of the name, behind a new
"Show timestamps in chat" setting.

The timestamp is kept next to the text rather than baked into it, since
the chat view finds the sender by splitting the line at the first colon.

Fixes #15444

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 13:10:54 -06:00
Henrik RydgårdandClaude Opus 5 eb1bc34123 Map the right analog stick by default on Android pads
The generic Android pad map and the Retroid map were the only pad
defaults without it, so the right stick did nothing until mapped by
hand. Uses the same axes and directions as the desktop pad default.

Fixes #21591

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 13:10:54 -06:00
Henrik RydgårdandClaude Opus 5 b115206a66 SDL: Release all input when a controller is disconnected
The last platform that was missing this - it was held back waiting for
the SDL 3.0 migration, which has now happened. Without it, whatever was
held when the pad vanished stays held, which tends to walk the player
off a cliff.

Fixes #20418

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 13:10:54 -06:00
Henrik RydgårdandClaude Opus 5 b5bafa43b8 Prefer upper case PSP/SHADERS and PSP/THEMES
These two were lower case for legacy reasons, unlike every other
directory, which actually matters on case sensitive file systems like
the one iOS uses. An existing lower case directory is still used if
there's no upper case one, so nobody has to move their files.

Fixes #20527

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 13:10:53 -06:00
Henrik RydgårdandClaude Opus 5 f10a62f23e SDL: Auto-hide the mouse cursor in fullscreen, like on Windows
Previously the cursor was only hidden when entering fullscreen or
starting a game, and never came back on mouse movement. Now it hides
half a second after the mouse stops moving and reappears when it moves
again, which also covers the touch-controls case that used to be
excluded entirely.

Fixes #20572

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 13:10:53 -06:00
Henrik RydgårdandClaude Opus 5 6bb91bf2f0 Remove the "Up to 2" buffered frames option
Three frames in flight showed no performance benefit over two, so drop
the option and clamp existing configs (and the default) down to 2.
The now-unused "Up to 2" translation keys are left in place.

Fixes #21419

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 13:08:21 -06:00
Henrik RydgårdandClaude Opus 5 f7548ea7e2 UI: Let PopupMultiChoice mark choices as untranslated
Choices that are just numbers have no translation, so every lookup got
logged as a missing translation - the Graphics settings screen spammed
the log once per frame as long as Frame Skipping was on.

Fixes #21455

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
2026-09-04 13:08:21 -06:00
Henrik RydgårdandClaude Opus 5 1c7f393e2b Misc shutdown fixes
* Destroy the ImGui debugger explicitly, not at static destruction time

* Windows: destroy the debugger windows before NativeShutdown()

* Clear the disassembly cache where it goes stale, not in view destructors
  (behind a no-op stub for libretro, which doesn't build DisassemblyManager.cpp)

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-04 13:06:24 -06:00
Henrik Rydgård 2994145f86 ISOFileSystem: Don't copy out uninitialized stack on a failed block read
ReadFile and the read-path-table ioctl both read a sector into a stack buffer
and memcpy it to the destination without checking whether the read succeeded.
FileBlockDevice::ReadBlock returns false on a short read and leaves the buffer
untouched, so a read past the end of a truncated or crafted image copies 2KB of
uninitialized host stack into guest-visible memory.

Zero the buffer on failure, and bail out of the ioctl if the volume descriptor
can't be read instead of using a garbage path table length. The constructor
already checked that same read.

ReadBlocks writes straight into the caller's buffer, so a partial read there
leaves stale data rather than host memory - left alone deliberately, since
zeroing it would throw away the valid prefix on a truncated image.
2026-09-04 13:02:57 -06:00
Henrik Rydgård ceb3fb2a4a Merge pull request #22216 from hrydgard/d3d11-fixes
Claude code review: D3D11
2026-09-04 13:01:55 -06:00
Henrik Rydgård 9c1f55ed76 ISOFileSystem: Clamp file sizes to what the image actually contains
The size in an ISO directory record is untrusted, and callers allocate host
buffers from it - GetISOGameID and ReadFileToString did so directly until the
previous commit, and ReadFile clamps reads to the claimed size rather than to
the image.

We've warned about out-of-range extents since c766536914, but deliberately kept
the file, and rounded down so the warning wouldn't fire on borderline images.
Keep that behavior and just clamp the recorded size to the bytes that really
exist. For a well-formed file the extent always fits within its sectors, so this
never triggers; for a truncated one the game keeps booting instead of losing the
file entirely.
2026-09-04 12:59:24 -06:00
Henrik Rydgård 5986789448 Merge pull request #22218 from hrydgard/more-misc-fixes
Correct handling of CORE_REENTER_DISPATCH in NextFrame
2026-09-04 12:59:16 -06:00
Acts1631 497dd8c1e7 Reject implausibly large ISO metadata files
GameManager::GetISOGameID() and GameInfoCache::ReadFileToString() resized host
buffers directly from the size reported by the ISO directory record, which is
untrusted. A crafted image can advertise a huge PARAM.SFO or icon and cause an
excessive allocation just from inspecting the file in the game list.

Cap both at a size well above anything real, and skip the read instead. Follows
the pattern PSARUnpack::ReadWholeFile already uses.

Taken from #22209.
2026-09-04 12:58:27 -06:00
Henrik Rydgård e47a1aa24d Core: Handle CORE_REENTER_DISPATCH in Core_NextFrame
Also add the missing case to CoreStateToString.
2026-09-04 12:20:11 -06:00
Henrik Rydgård 6cf02358ba docs: Add a feasibility analysis of a native Metal backend
Sizes up the work against the existing backends, lays out the shader generation
vs. SPIRV-Cross translation choice, and argues that programmable blending (the
framebufferFetchSupported cap that Vulkan hardcodes to false) is a better reason
to do it than dropping the MoltenVK dependency.
2026-09-04 12:18:46 -06:00
Henrik RydgårdandClaude Opus 5 3e87c79c89 AGENTS.md: Add a rule about branching off master before writing code
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01SGz54K3ZXa2Qzyc3aMEYyY
2026-09-04 12:18:46 -06:00
Henrik RydgårdandClaude Opus 5 859d09cc75 Vulkan: Two small fixes
The pipeline debug listing printed the color blend factors in the alpha slot,
which is doubly unhelpful since that branch is only taken when the alpha factors
differ from the defaults.

CompileShaderModuleAsync takes ownership of the tag but only deleted it on the
success path, leaking it whenever GLSLtoSPV failed.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01SGz54K3ZXa2Qzyc3aMEYyY
2026-09-04 12:10:03 -06:00
Henrik RydgårdandClaude Opus 5 9273764a3b Vulkan: Don't insert the same key twice when compute pipeline creation fails
The failure branch inserted a null pipeline and then fell through to the normal
insert of the same key, which trips DenseHashMap's duplicate-key assert - and
_assert_msg_ is live in release builds, so a logged error became a crash.

Also skip the null entries when deleting cached pipelines.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01SGz54K3ZXa2Qzyc3aMEYyY
2026-09-04 12:10:03 -06:00
Henrik RydgårdandClaude Opus 5 41d69e61e1 Vulkan: Set USES_DEPTH_STENCIL/USES_BLEND_CONSTANT before creating the pipeline
They were OR-ed into pipelineFlags just after the CreateGraphicsPipeline call that
consumes them, so the render manager's "don't compile a pipeline that requires
depth for a non-depth renderpass type" check could never fire for game pipelines.
thin3d_vulkan.cpp sets the flag before its call, which is the intended order.

Note this can now legitimately skip some variants when loading the shader cache -
those were invalid combinations that the check was written to reject.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01SGz54K3ZXa2Qzyc3aMEYyY
2026-09-04 12:10:03 -06:00
Henrik RydgårdandClaude Opus 5 38d5ab657e Vulkan: Disable hardware texture scaling if the constant buffer fails to load
If reading the shader's constant buffer file failed, we'd skip writing descriptor
binding 4 but still dispatch the compute shader, which declares it - a statically
used but unwritten descriptor. It also re-read the missing file on every single
texture upload. Now we drop the scaling shaders instead, so following textures
take the CPU scaling path.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01SGz54K3ZXa2Qzyc3aMEYyY
2026-09-04 12:10:03 -06:00
Henrik RydgårdandClaude Opus 5 79a48c7dbe Vulkan: Fix crash when a replaced texture fails to allocate
The out-of-VRAM retry path cleared plan.replaced but left plan.doReplace set.
GetMipSize() dereferences plan.replaced when doReplace is true, so the fallback
crashed instead of recovering. The common code sets both together.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01SGz54K3ZXa2Qzyc3aMEYyY
2026-09-04 12:10:03 -06:00
Henrik Rydgård 425f6e2c37 D3D11: Don't silently draw with a shader that failed to compile
The shader creation helpers returned S_FALSE when compilation produced no
bytecode - but S_FALSE is a success code, so the FAILED() checks in the
D3D11VertexShader/D3D11FragmentShader constructors never fired and failed_ was
never set. Return E_FAIL instead, and only hand out the bytecode when the shader
object was actually created.

Failed() had no callers at all, so a failed shader was handed to the draw as
usual: VSSetShader(nullptr), CreateInputLayout on empty bytecode, and the
ignored HRESULT from SetupDecFmtForDraw meant IASetInputLayout(nullptr). The
draw then did nothing, with no log line to explain it. Skip the draw and warn
instead, like the GL backend does.
2026-09-04 12:08:21 -06:00
Henrik Rydgård 15c702f203 D3D11: Fix texture upload buffer leaks
The cleanup loop was hardcoded to 12 entries while the array holds more and
levels can exceed that with a texture replacement pack - a 8192-pixel
replacement has 14 mip levels, so every level from 12 up leaked on each texture
build. Use ARRAY_SIZE, and shrink the array to 16 since D3D11 caps textures at
16384 pixels anyway.

The out-of-memory bail-out returned before that loop, leaking every level
decoded so far. Since the entry ends up without a texture it gets rebuilt, and
leaks again, every following frame.
2026-09-04 12:07:50 -06:00
Henrik Rydgård 050cacbbdf Merge pull request #22214 from hrydgard/gles-fixes
Claude code review: OpenGL backend
2026-09-04 11:45:42 -06:00
Henrik Rydgård 256984d561 Fix some Claude-isms 2026-09-04 10:41:31 -06:00
Henrik Rydgård ac016201dc GLES: Small cleanups
Scissor the stencil readback to the region actually being read back - latent,
every caller passes a zero origin today.

Remove a DecodeVerts call that can never do anything: both branches above it
have already advanced decodeVertsCounter_ to numDrawVerts_. Worse than useless,
since in the non-skinning branch the vertices went to the push buffer, so
decoded_ doesn't hold them.
2026-09-04 10:41:31 -06:00
Henrik Rydgård 78692deca2 GLES: Set IS_3D when creating the 3D texture, not after uploading it
The out-of-memory bail-out added in the previous commit returned before the
status flag was set, leaving a GL_TEXTURE_3D object bound while ApplyTexture
told the shader generator it was a 2D texture. The entry stays cached, so it
would repeat every frame, not just the one that failed to allocate.
2026-09-04 10:41:31 -06:00
Henrik Rydgård 89ebb8acc6 GLES: Actually apply anisotropic filtering
TextureCacheGLES passed a hardcoded 0.0f instead of key.aniso, so the
Anisotropic Filtering setting did nothing at all on the OpenGL backend, even
though GPU_USE_ANISOTROPY was advertised and D3D11/Vulkan both honor it. Looks
like it was left behind by the 2017 render manager refactor.

The queue runner now clamps to the device maximum it already queried into
maxAnisotropyLevel_ (until now unused), and only touches the parameter when the
extension is actually supported - the anisotropy branch there has been dead
since every caller passed 0.0f, so this is the first time it runs.

0.0f keeps its meaning of "don't care" for the CLUT/fragment-test/thin3d
callers; the texture cache now passes 1.0f when the setting is off, so turning
it off takes effect on already-uploaded textures instead of only new ones.

TexCache: Never use anisotropic filtering for CLUT8-indexed textures

What gets sampled for those is palette indices, depalettized by the shader
afterwards - averaging indices across an anisotropic footprint produces garbage
colors. Affects all backends, not just the GL one that just started honoring
key.aniso.

TexCache: Clear key.aniso wherever filtering is forced to nearest

It was only cleared in the two places inside the AUTO_MAX_QUALITY branch, so the
TEX_FILTER_AUTO path (pixel-mapped textures, the ugly color test heuristic), the
FORCE_NEAREST setting and the replacement-texture override could all end up
requesting nearest filtering with anisotropy still on.

Doing it in the switch that applies forceFiltering covers every path, so it
can't drift apart again.

GLES: Only record the applied anisotropy, and log skipped draws

The queue runner updated tex->anisotropy even when it skipped the call because
the value was 0.0f ("don't care") - harmless while nothing ever set anisotropy,
but now it would make the tracked state disagree with GL, so a later request for
the value it thinks is set would be wrongly skipped.

Also log when a draw is skipped for a missing vertex shader. The failure is
cached per shader ID, so without it geometry silently disappears for the rest of
the session after the one-shot OSD message.
2026-09-04 10:41:15 -06:00
Henrik Rydgård 172cea4b31 Merge pull request #22213 from hrydgard/remove-geometry-shaders
Remove the leftover geometry shader scaffolding
2026-09-04 10:19:46 -06:00