Commit Graph
10307 Commits
Author SHA1 Message Date
Henrik Rydgård 9df6ba2031 Merge pull request #22587 from hrydgard/ir-interp-chain
No-JIT speedups: IR interpreter block chaining, SIMD exact multi-dot, branchless skinning
2026-10-15 22:26:03 +02:00
Henrik Rydgård 5fa79c6871 Merge pull request #22574 from LunaMoo/texture-replacement-indexed
Add's support for indexed textures, luma-only texture replacement
2026-10-15 17:46:17 +02:00
Henrik RydgårdandClaude Opus 5.5 bf7e32cdae Vertex decoder: Build the skin matrix without a branch per weight on ARM64
The steps skipped bones with a zero weight. With weights that vary from vertex to vertex that
branch mispredicts a lot, and it saves only a few multiplies. Now every weight is applied, with
fused multiply-adds, as the vertex JIT does. Without the vertex JIT (as on iOS): Tekken 4.5% fewer
cycles, God Eater 2.6%, God of War 1.7%.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 17:05:52 +02:00
Claude 1692aad51e Texture replacement: Optionally dump paletted textures as 8-bit palette PNGs
saveIndexed = true in [options] saves the CLUT4/CLUT8 textures listed in
[indexed] as palette PNGs, saveIndexed = all saves every one of them.
The file is named <hash>_indexed.png, with the CLUT hash zeroed so one
file serves every palette of the texture. The other textures are dumped
as before.

The indices are decoded from PSP memory and the palette comes from the
current CLUT, so the dump looks like the game's texture. Add the file to
[hashes] and [indexed] to use it as a replacement.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 16:15:11 +02:00
Henrik RydgårdandClaude Opus 5.5 cd1f3b0929 Vertex decoder: Handwritten decoder for God of War's one-weight skinned format
For where there's no vertex JIT. It skins the same way as the steps:
the skin matrix is 0 + bone * weight, kept as the columns that
Vec3ByMatrix43() and Norm3ByMatrix43() multiply and add unfused in the
same order (by lane on ARM64, like those), and only rebuilt when the
weight changes. 2.2 ns a vertex in God of War against the JIT's 1.95
and the steps' 12-18.

Without the vertex JIT, God of War's instructions drop by 6.8% per 10
emulated seconds.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 14:40:31 +02:00
Henrik RydgårdandClaude Opus 5.5 5f410479ce Vertex decoder: Fix the full alpha flag in the older handwritten decoders
The decoders clear gstate_c.vertexFullAlpha when a vertex has less than
full alpha, and a batch decodes each of its draws in turn. The God of War
and GTA decoders assigned it instead, so a draw with full alpha set it
back after an earlier one had cleared it. God of War's also read the
alpha from the normal: its struct had color and normal swapped (the
output came out right, as each went to the matching slot), so the flag
never got set for its most used format.

The vertex decoder test now decodes a vertex with full alpha after a
draw that cleared the flag and after one that didn't.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 14:40:31 +02:00
Henrik RydgårdandClaude Opus 5.5 3bd660c251 Vertex decoder: Handwritten decoders for ATV's, Wipeout's and Killzone's top formats
For where there's no vertex JIT (iOS), as they're a few percent slower
than the JIT's but four to eleven times faster than the steps. The
formats carry most of the vertices of ATV Offroad Fury: Blazin' Trails,
Wipeout Pure and Killzone: Liberation, and a lot of Gods Eater Burst's.
They convert like the steps (PrescaleUV moves to the header for that),
and the vertex decoder test now also compares each format's decoder
without the JIT against the steps.

Without the vertex JIT, 10 emulated seconds on an M1, instructions:
ATV -9.9%, Wipeout -6.0%, Killzone -5.4%, Gods Eater -2.2%.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 14:40:31 +02:00
Henrik RydgårdandClaude Opus 5.5 253aba2a60 Vertex decoder: Use the handwritten decoders with every UV generation mode
They were only used for UV from texture coordinates. With the texture
matrix or environment map, UV isn't prescaled, which is the same as a
scale of 1 and no offset, so NoPrescale versions pass that. God of War
draws 5 million of its vertices per 10 seconds this way, which without
the vertex JIT took 9.6 ns each through the steps and now 2.4.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 14:40:31 +02:00
Claude b383377039 Texture replacement: Color indexed replacements on the GPU
An [indexed] entry set to gpu uploads the indices as an R8 image, and
the CLUT8_INDEXED depal shader applies the palette. A texture whose
palette changes a lot then costs no CPU time per palette, and keeps one
texture instead of one per palette.

Once such a replacement is found, the texture is looked up without the
CLUT hash, like with the TextureCLUTInShader compat flag. Only the first
mip level is used, and the replacer's filtering overrides are skipped
since filtering indices mixes up palette entries. Without shader bitwise
ops it falls back to coloring on the CPU.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 11:05:12 +02:00
Henrik RydgårdandClaude Opus 5.5 0edfd93a3a Depth raster: Stop a row once it has left the triangle
The triangle is convex, so once a row has been entered and left, the
rest of it is outside. This cut cycles by 5% in Wipeout Pure, where depth
raster is on for the lens flares.

The test checks the covered pixels against a per-pixel edge test.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 10:14:54 +02:00
Henrik RydgårdandClaude Opus 5.5 83639a73e8 GPU: Cull-test draws four vertices at a time
TestBoundingBoxFast transformed and tested one vertex per iteration,
with a scalar divide and a min/max chain each vertex had to wait on.
It now transposes four vertices into lanes and does it all as vectors,
with the same operations in the same order, so the results don't change.
It was 16.6% of the emulator thread in Wipeout Pure (with depth raster
off) and 5% in GTA: Vice City Stories.

Per vertex, it's 1.8x faster on an M1, 2x on x86-64, 1.7x on a Galaxy S8+
and 10% faster in 32-bit mode there.

The test compares it with the old version on random draws in every
position and index format.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 10:14:51 +02:00
Claude 2be7e58a8e Texture replacement: Support lossless KTX2 for indexed replacements
Indexed replacements can now also be KTX2 files in the R8_UNORM format,
uncompressed or zstd supercompressed, with the mip levels stored in the
file. Lossy formats (Basis, BC) are not usable, since an error in an index
picks the wrong color.

The template textures.ini documents the supported files.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 02:50:22 +02:00
Claude 91c1be0ebd Texture replacement: Add [indexed] to the generated textures.ini
Document the section and the supported files in the template.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 02:30:54 +02:00
Henrik RydgårdandClaude Opus 5.5 f3c69fc5d1 Remove FakeJit and the pre-IR JitBlockCache
FakeJit was the native JIT for architectures without one, but the config
already forces those onto the IR interpreter, so CreateNativeJit() now
returns that instead. The vertex decoder fallback no longer needs
FakeEmitter.

JitBlockCache was the block cache of the pre-IR JITs. Its header keeps
the debug interface types the IR block caches use. Also removes the
JitInterface link hooks only it called, and the JitState fields tied to
it. This fixes a null dereference in the ImDebugger memory section,
which read GetBlockCache(), always null with the IR JITs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 02:24:25 +02:00
Henrik Rydgård 831d8f4654 Merge pull request #22569 from hrydgard/readback-shadow
Add a ReadbackShadow compat flag, for games that read many pieces of a buffer
2026-10-15 00:10:06 +02:00
Henrik RydgårdandClaude Opus 5.5 fe61574a02 D3D11: Include CommonWindows.h before the Windows SDK headers
DrawEngineD3D11.cpp started with <wrl/client.h>, which brought in windows.h
without NOMINMAX, so its min macro broke the std::min in an inline function
of FramebufferManagerCommon.h. D3D11Util and ShaderManagerD3D11 had the same
order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 23:36:45 +02:00
Henrik RydgårdandClaude Opus 5.5 5d0873d95d Depth raster: Clip to the drawing region as well as the scissor
Resistance: Retribution sets its scissor to end at 480,272, one past its
drawing region. The CPU depth rasterizer (SoftwareRasterDepth) only
clipped to the scissor, so it wrote row 272 of the depth buffer, which is
where the game keeps its logo textures. The startup logos got a garbage
strip on hardware backends and failed to fade out.

SoftGPU already clips to the minimum of the two.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 23:10:54 +02:00
Henrik RydgårdandClaude Opus 5.5 20530d35c0 Add a ReadbackShadow compat flag, for games that read many pieces of a buffer
Since the sequential copies heuristic went (50696c5b1f), every partial readback
waits for the GPU. Motorstorm reads parts of the screen about 18 times a frame,
and ran about 75% slower than 1.20.4: 5403 blocking readbacks in 10 emulated
seconds, against 156.

With the flag, the first partial color readback of a buffer reads all of it into
a copy outside PSP memory, and the pieces until the next render to the buffer
are copied from there. Unlike the old heuristic, only what the game asked for is
written to PSP memory. Motorstorm is back to 153 blocking readbacks and 1.20.4's
speed, with identical output. Grand Knights History, which the heuristic was
added for, gets the flag too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 22:56:32 +02:00
Claude 03391c66cb Texture replacement: Support palette-indexed replacement images
- Fixes #15145

A replacement listed in a new [indexed] section of textures.ini holds
palette indices instead of colors: a palette PNG (the file's palette index)
or an 8-bit grayscale PNG (the gray value), at any resolution. When the
texture is built, the indices go through the game's current CLUT, including
the CLUT index shift, mask and start position, and the result is uploaded as
an ordinary RGBA texture. A game that swaps or customizes a palette keeps
working with a high-resolution replacement.

[indexed] keys use the [hashes] format and are matched with the same
wildcards, so a key with a zero CLUT hash covers every palette of the
texture. The contents hash only covers the indices, so one image is shared
by all palettes (the loaded data is shared, each palette still has its own
texture cache entry).

Saving does not dump indexed textures yet.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 21:42:39 +02:00
Henrik RydgårdandClaude Opus 5.5 d0266580d9 CMake: List the headers that were missing
Each next to its .cpp, or with its neighbours in the unconditional list for
its directory. They're only for IDEs, so this changes nothing in the build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 21:05:52 +02:00
Henrik Rydgård 88f4c12437 Merge pull request #22553 from hrydgard/gpu-fallback-fixes
GLES and fallback rendering fixes from running the framedumps on Android
2026-10-14 09:20:38 +02:00
Henrik RydgårdandClaude Opus 5.5 e48086484c Blend in the shader where stencil to alpha needs dual source blending we lack
A draw that blends with the source alpha while setting the stencil (the
alpha on the PSP) needs dual source blending to write both. Without it the
alpha came out wrong, and later draws that blend with the destination alpha
differed: WipEout Pure, Juiced 2 and 16131 UCES00001 on a Mali-G71 and a
PowerVR GE8320. With framebuffer fetch, blend those in the shader instead,
which matches the Mac's Vulkan render now. Without fetch it would take a
framebuffer copy per draw, too slow for something this common.

A draw that writes no color can't need the source alpha, so it writes the
stencil as alpha directly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:33:33 +02:00
Henrik RydgårdandClaude Opus 5.5 6b989f9d12 Don't use BlueToAlpha with framebuffer fetch
With fetch, the shader applies the colour masks and logic ops to the real
bits, and OutRun 2006's water mask comes out like the software renderer's.
BlueToAlpha put the first step in alpha while the masked logic-op steps after
it worked on blue, so on the Adreno 840's OpenGL the water was off by twice as
much as on Vulkan. Now it matches or beats Vulkan there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:33:33 +02:00
Henrik RydgårdandClaude Opus 5.5 b9780bc132 Keep the stencil when resizing a framebuffer
ResizeFramebufFBO copied color and depth into the new FBO but left its
stencil cleared. Need for Speed Shift grows its framebuffer from 480 to 512
wide just before stencil testing, and the frame came out far too dark on
Android (112k px off the PSP on an Adreno 840, now 4k). MoltenVK happened
to keep it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:33:33 +02:00
Henrik RydgårdandClaude Opus 5.5 3e4458c7b7 Rebind the render target after writing stencil to another framebuffer
PerformWriteStencilFromMemory bound the framebuffer it wrote the stencil to
and, unless it blitted, left it bound. When that wasn't the current render
target, the following draws landed in it. Draws that copy the target for
shader blending rebind it themselves, which hid this; with framebuffer fetch
they don't, and OutRun 2006's masked water draws went into the old 5551
buffer at the address instead of the new 565 one.

Over the framedumps set on Vulkan, 9 dumps get closer to the PSP (OutRun
ULUS10064_0002 12295 -> 483 px, F1 2009, God of War) and one a little further
(16131 ULUS10193, a slight brightness shift).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:33:32 +02:00
Henrik RydgårdandClaude Opus 5.5 b25344ab7b Discard against one-sided depth ranges in the fragment fallback
Without clip distances, the fragment shader's min/max Z discard only came on
when both minz and maxz were set, while the clip planes take each side on
its own. Pursuit Force's sky has minz 0 and maxz 300 and lies past 300, so
the PSP drops it (its replays of 11399 UCES00019 and 11216 UCUS98703 show
that), but GPUs without clip distances drew it over the scene: 13.9k px off
the PSP on a Mali-G71, now 8 as with clip distances. The discard can now
come with the fragment depth clamp, for the side that's at the limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:33:32 +02:00
Henrik RydgårdandClaude Opus 5.5 026bbf56d6 GLES: Declare u_minZmaxZ highp in both shaders
The fragment shader's min/max Z discard declared it with the default
precision, the vertex shader with highp, and PowerVR refuses to link such a
program, so every draw that needed the discard was dropped. On a PowerVR
GE8320 that was Street Riders, Valkyria Chronicles, Flatout and Frontier
Gate, and with the discard taking one-sided depth ranges too (next commit),
most of Pursuit Force.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:33:32 +02:00
Henrik RydgårdandClaude Opus 5.5 5fb61b4e40 GLES: Use highp for the texcoord and the math in CLUT8 depal
Picking a byte out of a 16-bit framebuffer needs more than the defaults. The
texcoord reached the shader as a mediump varying, which Adreno keeps in fp16:
its byte coordinate (u times up to 2048) then picks the wrong byte for every
other one past 512, and SOCOM Tactical Strike's night vision came out striped
in the right half. On a PowerVR GE8320 the default lowp in the rest of the
shader made SOCOM's night vision and full screen effect far too bright (53k
and 17k px off the Mac's Vulkan render, now 0). Vulkan already uses highp.

Where the fragment shader has full precision, the vertex shader now writes the
texcoord in highp, and CLUT8 depal reads it that way and computes in highp.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:33:32 +02:00
Henrik RydgårdandClaude Opus 5.5 9bef51177b GLES: Don't skip uniform updates while a program's locations aren't known
UpdateUniforms checked some locations against -1 before queueing the update,
but the GL thread fills them in when it links the program, which can be
later. On drivers that link slowly the check saw -1, the update was dropped
along with its dirty flag, and the uniform stayed unset. On a PowerVR GE8320
and a Mali-G71 the texture clamp values never arrived, so Harvest Moon's and
11655's composites sampled one point of the framebuffer (122k and 76k px off
the Mac's Vulkan render, now 0). The GL thread already skips -1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:33:32 +02:00
Henrik RydgårdandClaude Opus 5.5 7080085571 GLES: Apply the texture LOD bias in the shader
GL_TEXTURE_LOD_BIAS is desktop GL only, and the queue runner skipped it on
GLES, but GLES still reported sampler LOD bias as supported, so the bias was
dropped and textures used the wrong mip levels: Super Monkey Ball Adventure's
intro came out blurred on the Adreno 840. Report it unsupported, so the shader
applies it (GPU_USE_SHADER_LOD_BIAS), and give the GL backend the uniform that
Vulkan has in its uniform block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:33:32 +02:00
Henrik Rydgård 9b07e78604 Merge remote-tracking branch 'origin/master' into cpu-equiv-1
# Conflicts:
#	pspautotests
2026-10-14 01:22:31 +02:00
Henrik RydgårdandClaude Opus 5.5 9237bade22 x86 vertex decoder JIT: Fix the paths for constants out of RIP range
PosFloat loaded its clamp constants into XMM4/XMM5 but clamped with XMM2/XMM3,
and the S8/S16 morphs overwrote the morph weight pointer with the constant's
address. These only run when the JIT cache lands more than 2GB from the
constants, which CPUEquivalence's allocations made happen on Linux CI
(SplineTessellation). Checked by forcing every RipAccessible() false, which
SplineTessellation and VertexJit now pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:11:59 +02:00
Henrik RydgårdandClaude Opus 5.5 d0567e2dfb GE: Nest CALLs only two deep, like the hardware
- Fixes #7395

The GE has two return address registers, and a CALL beyond them does
nothing: the list carries on after it. A signal CALL is done by the
firmware, which saves and clears them, so it starts the count over,
and the signal RET restores it. Shown on a PSP by the new
gpu/callstack/depth test.

Soul Calibur: Broken Destiny turns lighting on for its weapon trails
from a third-level CALL, so on hardware the trails stay unlit and take
their colors from the vertices. We ran that CALL and drew them white.

Plain CALLs now store a 0 base address in their stack entry, which a
signal CALL never does, so the depth can be counted without changing
the savestate layout.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 00:54:01 +02:00
Henrik RydgårdandClaude Opus 5.5 60100c4254 - Fixes #13676
Vulkan: Batch Jackass' tiled in-place color grade

Jackass: The Game color grades the framebuffer in 32x64 tiles, one channel
per pass, texturing from the framebuffer it renders to. Each of the 225
draws became a depal pass plus a pass drawing it back, 450 render passes
per frame. A new queue hack, enabled by the TiledDepalHack compat flag,
sorts these pairs into waves of non-overlapping tiles and runs each wave
as one depal pass and one draw pass, leaving 6.

Output is byte-identical to before on both dumps from the issue, at 1x
and 3x on desktop, and at 1x on both phones below.

Time saved per post-processed frame, from replaying the dumps from the
issue with headless --bench (each replay renders that frame once):

  Redmi 9A (PowerVR GE8320):  ~145ms at 1x, ~180ms at 2x
  Unisoc UMS9632 (Mali-G57):  ~55ms at 1x and 2x

Either is more than a whole 33ms frame, so on those GPUs this pass alone
ruled out 30fps.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 17:08:58 +02:00
Henrik Rydgård 4585f70500 Merge pull request #22545 from hrydgard/gpu-fallback-fixes
Fixes to GPU feature fallbacks
2026-10-13 16:46:34 +02:00
Henrik RydgårdandClaude Opus 5.5 85d751ebe1 Keep near plane clipping in the fragment depth clamp fallback
The fallback set the rasterizer's Z to a constant so nothing would clip, which
lost the clipping at the PSP's near plane too. Hardware depth clamp loses it
the same way, which the vertex shader can only make up for with a clip plane.

Give the rasterizer (z + w) / 65536 instead: 0 at the near plane, so it clips
there, and past w only beyond 65535 * w. And without clip distances, use the
fragment fallback instead of hardware depth clamp.

With --disable-gpu-features for all three on the Mac, the framedumps set now
differs from the full render by 15570 px instead of 184229 (WALL-E, Hokuto no
Ken, Frontier Gate, FF Zero). The full render doesn't change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:06:49 +02:00
Henrik Rydgård b4b4390c49 Merge pull request #22543 from hrydgard/android-headless-gpu
Android: Add setup for headless GPU rendering test
2026-10-13 15:02:11 +02:00
Henrik RydgårdandClaude Opus 5.5 2d61d58bbe Make the fragment depth clamp fallback match hardware depth clamp
For GPUs without depth clamp (old Mali), found by comparing with
--disable-gpu-features=depth-clamp on the Mac:

- Write Z / 65536 like the vertex shader, not / 65535.
- Pass the fragment shader Z after the vertex depth rounding, which hardware
  clamp sees too (Puyo Puyo Fever 2's ground at Z = 0).
- Also clamp draws whose Z only touches 0 or 65535.
- Draws that skip the bounds check (skinned, morphed) get the fragment clamp
  and min/max discard wherever the hardware versions would be on, since those
  don't depend on the check either.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:44:34 +02:00
Henrik RydgårdandClaude Opus 5.5 7c118f2ee3 Headless: Add --hardware-transform and --disable-gpu-features
--disable-gpu-features=clip-distance,cull-distance,depth-clamp acts as if the
GPU lacked those, to test the fallbacks for old Mali on any machine. It
replaces the simulateOldMali constant. --hardware-transform=false runs every
draw through software transform.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:44:34 +02:00
Henrik RydgårdandClaude Opus 5.5 3193031e7b Bounds-check PRIM draws of any size, not only up to 2500 vertices
Bigger draws skipped the check and kept whatever clip flags the previous draw
left. Checked, the ones that cross the clip volume in Z get software clipping
where the GPU needs it: on the Mac (no cull distances), Valkyria Chronicles II
and Street Riders get closer to the PSP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:44:34 +02:00
Henrik RydgårdandClaude Opus 5.5 9073aad504 Cull and clip check Bezier and spline patches like PRIM
Curves skipped the per-draw bounding box check and relied on the vertex
shader's near clip plane. On old Mali (no clip distances), that left the
geometry behind the PSP's near plane to the GPU: Test Drive's hills reached
over the sky.

A patch lies within the convex hull of its control points, so run the PRIM
check on those: a patch entirely outside is skipped, and only one with points
outside the clip volume in Z goes through software transform. Missing clip
distances are now also a reason to software-clip, for PRIM too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 14:44:34 +02:00
Henrik Rydgård 0af0d86470 Merge pull request #22542 from hrydgard/faster-build
Faster CMake builds: libc++ transitive includes, less glslang/SPIRV-Cross, include cleanup
2026-10-13 12:57:43 +02:00
Henrik RydgårdandClaude Opus 5.5 e602aa1548 Add includes that were only arriving transitively
VertexDecoderRiscV.cpp got <cfloat> through SmallDataConvert.h, and three
headers used malloc/free without <cstdlib>, which libc++ no longer brings in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:36:06 +02:00
Henrik Rydgård 3c25f21bae Merge pull request #22541 from hrydgard/libretro-fork-fixes
Various bugfixes from libretro's experimental fork
2026-10-13 12:26:27 +02:00
Henrik RydgårdandClaude Opus 5.5 a361dfc490 Drop unused Config.h and SmallDataConvert.h includes
Config.h is edited about 100 times a year and each edit recompiled 198
files; now 172. SmallDataConvert.h pulls in arm_neon.h and was included by
headers that don't use it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:13:42 +02:00
Henrik RydgårdandClaude Opus 5.5 ec76a4d56e GE dump playback: Refuse sections over 1 GB
A zstd frame doesn't always declare its size, and a small one can expand to
gigabytes, so this is the limit that keeps a crafted dump from exhausting
memory. The largest section in the 1042-dump test set is 82 MB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:05:35 +02:00
Henrik RydgårdandClaude Opus 5.5 9c2cf98b84 GE dump playback: Clamp the remaining writes, bound the loader's allocations
Follows up the command range validation:
- Don't require anything of the data commands' sizes or alignment. Version 2
  dumps have empty VERTICES and CLUT commands, and old recorders didn't align
  anything. Registers() drops a trailing partial word instead.
- Split register blocks bigger than the list buffer, which they overran.
- Clamp MEMCPYDATA and MEMSET to valid memory. Only their start was checked.
- Check the compressed sizes against the file, and the decompressed sizes
  against what the frame declares, before allocating. Some version 5 dumps
  leave the size out of the zstd frame; those are checked after decompressing.
- Don't let a large FRAMEBUF size wrap around in MarkNeededTargets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:01:29 +02:00
Acts1631 80b813f507 Validate GE replay commands before execution
Crafted ppdmp command ranges can extend past the decompressed push
buffer. Frame buffer playback can then copy adjacent host heap data
into emulated VRAM, exposing process memory through rendered output.

Validate each command's type, range, and minimum payload size before
constructing the replay executor.
2026-10-13 09:21:14 +02:00
LibretroAdmin 664f6ff5ad D3D11: work on a context that refuses ID3D11DeviceContext1
D3D11DrawContext takes its base context from the deviceContext
argument, and the blend state is bound through the base context, which
accepts an ID3D11BlendState1 as is. ID3D11DeviceContext1 is optional:
RetroArch's threaded video hands v1 cores a deferred-context proxy that
answers ID3D11DeviceContext only, and the core now starts on it.
2026-10-13 02:23:48 +02:00
Henrik RydgårdandClaude Opus 5.5 531a75f045 Add AccurateSplines compat flag, enable for Coded Arms
- Fixes #21391

Makes the hardware backends tessellate Bezier patches and splines with the
GE-exact evaluation the software renderer uses. Fixes the z-fighting glow
under the floor grates in Coded Arms.

AGENTS.md: Put "- Fixes #N" first in commit messages

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 14:04:38 +02:00