Skip to content

OpenGL and Vulkan rendering fixes on MacOS, upgrade MoltenVK, raise iOS/Mac min versions - #22452

Merged
hrydgard merged 12 commits into
masterfrom
hw-render-fixes
Oct 8, 2026
Merged

hrydgard merged 12 commits into
masterfrom
hw-render-fixes

Conversation

@hrydgard

@hrydgard hrydgard commented Oct 8, 2026

Copy link
Copy Markdown
Owner

Followup to #22446 with more fixes.

Unfortunately, upgrading MoltenVK with a version that fixes some of these bugs requires us to raise the minimum MacOS version to 12 and the minimum iOS version to 15. But it is what it is. Almost all devices in real use out there can be upgraded to these OS versions.

hrydgard and others added 12 commits October 8, 2026 16:16
The vertex shader puts min/max Z in clip distances 0 and 1 and the near plane
in 2, but the program flags still followed an older layout and never enabled
plane 2. Geometry crossing the near plane was then only depth clamped, and
smeared across the screen (Hellboy, FIFA Soccer, Hoto no Ken frame dumps).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing writes depth then, so the shader write is wasted. On Apple's OpenGL
it also broke Tales of Phantasia (PixelDepthRounding): once the shader writes
gl_FragDepth, a discarded fragment still writes stencil, so a color-tested
stencil pass marked the whole area and the background tiles drawn with
stencil EQUAL 0 vanished.

New FS ID bit, so both shader caches get a version bump.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…yond far first

With one vertex behind the near plane, the GE splits the remaining quad from
the vertex before the clipped one (gpu/probe exp43, exp44, as in SoftGPU's
Clipper.cpp). The other diagonal could put a far off-screen near-plane vertex
in both halves, so range culling dropped the whole triangle: the floor in
#16131's box test vanished. The index generator reverses triangles to flip
culling, so the batch's order is passed along.

Triangles entirely beyond the far plane are now culled even when in front of
the near plane, with the cull-distance epsilon, so z/w = 1.0000172 (exactly
1.0 to the GE) still counts as inside.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without them nothing culls triangles beyond the far plane: depth clamp draws
them, as with the stands over the pitch in FIFA Soccer on macOS. Fixes FIFA
and Hellboy on OpenGL there, and DBZ Tenkaichi Tag Team, Monster Hunter 3rd
and Street Riders on both backends.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
So the hardware backends' software transform can use them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A rectangle's depth is flat, so right at a depth range limit our float
rounding drops or keeps the whole thing. Mana Khemia 2 draws a conversation
background at GE screen Z 1 with minz 1, and we computed 0, so it vanished
(#12858). When the GE's depth would land on the other side of the range
check, use it; otherwise keep ours, which matches the hardware-transformed
draws a rectangle may be depth tested against (rounding all rectangle depths
to the GE's broke the Need for Speed HUD).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lears

The fragment Z is the PSP's Z / 65536, and flat draws land exactly on an
integer Z. floor(z * 65535) put that Z - Z/65536 just above the boundary, so
float error (which differs with W) could drop it by one: Patlabor redraws a
HUD icon at the same depth with GEQUAL, and the second draw failed on
Vulkan. Floor Z + 0.01 instead, and store Z / 65535, as clears and the depth
clamp path do. Also fixes Heroes Phantasia #6485.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The copy for texturing from the current render target was cropped to the
UV bounds, but bilinear filtering at the edges reads one texel beyond them,
which then came from whatever the temp FBO last held. On Vulkan that put
magenta streaks into Need for Speed Shift's sun glow, and also hit Call of
Duty, Burnout Dominator (#12831) and Assassin's Creed Bloodlines (#15821).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… 12.0

1.4.0 never applied dynamic blend constants, so fixed-color blends lost
their constant factor on Vulkan (the Enemy panel in Tales of Phantasia
went dark, also Block Transfer effects). MoltenVK 1.4.2 requires macOS 12.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… to iOS 15

1.4.0 and older don't apply dynamic blend constants. The stock 1.4.2 build
needs iOS 15. Non-App Store builds keep their targets and dylib.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
They re-read the toolchain file without the cache, so they used the non-App
Store deployment target, which current Xcode no longer supports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It was only linked when the In-App Purchase capability was added by hand in
Xcode, which current Xcode no longer lists. There's no entitlement for it
on iOS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hrydgard hrydgard added this to the v1.21 milestone Oct 8, 2026
@hrydgard
hrydgard merged commit bd04d06 into master Oct 8, 2026
27 checks passed
@hrydgard
hrydgard deleted the hw-render-fixes branch October 8, 2026 14:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant