Skip to content

[WRAPPER] Fix SDL Vulkan bridge2 passing wrong fnc2 (regression from c7bc29329)#3578

Merged
ptitSeb merged 2 commits intoptitSeb:mainfrom
runlevel5:fix-vulkan-sdl-bridge2
Feb 27, 2026
Merged

[WRAPPER] Fix SDL Vulkan bridge2 passing wrong fnc2 (regression from c7bc29329)#3578
ptitSeb merged 2 commits intoptitSeb:mainfrom
runlevel5:fix-vulkan-sdl-bridge2

Conversation

@runlevel5
Copy link
Copy Markdown
Contributor

Summary

This fixes a regression introduced in commit c7bc293 ("[WRAPPER] Add/Fix SDL_Vulkan_GetVkGetInstanceProcAddr wrapped function from SDL2/SDL3 to use bridge2") that breaks Vulkan in any SDL2/SDL3 game using SDL_Vulkan_GetVkGetInstanceProcAddr.

The Bug

In both wrappedsdl2.c (line 843) and wrappedsdl3.c (line 56), AddCheckBridge2() is called with my->SDL_Vulkan_GetVkGetInstanceProcAddr as the fnc2 parameter. This is the SDL function that returns the native vkGetInstanceProcAddr pointer — not the pointer itself.

When my_vkGetInstanceProcAddr in wrappedvulkan.c later calls getBridgeFnc2(R_RIP) to retrieve the native proc address resolver, it gets SDL_Vulkan_GetVkGetInstanceProcAddr instead of the actual vkGetInstanceProcAddr. So when the wrapper does getprocaddr(instance, name), it actually calls SDL_Vulkan_GetVkGetInstanceProcAddr(instance, name), which ignores both arguments and just returns the vkGetInstanceProcAddr pointer again.

This pointer then gets wrapped as if it were the resolved Vulkan function (e.g. vkEnumerateInstanceVersion). When the game calls through the bridge thinking it's calling vkEnumerateInstanceVersion(&version), it actually calls vkGetInstanceProcAddr(&version) — interpreting a stack pointer as a VkInstance handle. This triggers the Vulkan loader's "Invalid instance [VUID-vkGetInstanceProcAddr-instance-parameter]" validation error followed by SIGSEGV/SIGABRT.

The Fix

Pass (void*)emu->context->vkprocaddress instead, which already holds the actual native vkGetInstanceProcAddr function pointer (set on the preceding lines via SDL_Vulkan_GetVkGetInstanceProcAddr()). Same fix applied to both SDL2 and SDL3 wrappers.

Testing

I tested this on PPC64LE (POWER9) with SuperTuxKart 1.5. Before the fix, the game crashes immediately on Vulkan init with validation errors and SIGABRT. After the fix, Vulkan initializes correctly — detects AMD Radeon RX 6600 XT via RADV NAVI23 (Vulkan 1.4.328), creates command loader threads, and the game runs without crash.

This bug affects all architectures, not just PPC64LE — any box64 user running an SDL2/SDL3 Vulkan game will hit this crash.

Commit c7bc293 introduced a regression in both wrappedsdl2.c and
wrappedsdl3.c where AddCheckBridge2() was called with
my->SDL_Vulkan_GetVkGetInstanceProcAddr as the fnc2 parameter. This is
the SDL function that *returns* the native vkGetInstanceProcAddr pointer,
not the pointer itself.

When my_vkGetInstanceProcAddr (wrappedvulkan.c) later calls
getBridgeFnc2(R_RIP) to retrieve the native proc address resolver, it
gets SDL_Vulkan_GetVkGetInstanceProcAddr instead. Calling
getprocaddr(instance, name) then invokes
SDL_Vulkan_GetVkGetInstanceProcAddr(instance, name), which ignores both
arguments and returns the vkGetInstanceProcAddr pointer. This pointer
gets wrapped as if it were the resolved function (e.g.
vkEnumerateInstanceVersion), so calling the bridge actually calls
vkGetInstanceProcAddr with wrong arguments, causing Vulkan loader
validation errors and a crash (SIGSEGV/SIGABRT).

Fix: pass (void*)emu->context->vkprocaddress instead, which already
holds the actual native vkGetInstanceProcAddr pointer (set on line 840
in SDL2 and line 51 in SDL3).

Tested with SuperTuxKart on PPC64LE — Vulkan initializes correctly
(RADV NAVI23, Vulkan 1.4.328) and the game runs without crash.
@ptitSeb
Copy link
Copy Markdown
Owner

ptitSeb commented Feb 27, 2026

Ah indeed, nice debugging.

But I have an issue with the fix. It should use the result of the SDL call, no matter the previous state of emu->context->vkprocaddress

something like:

    void* procaddr= my->SDL_Vulkan_GetVkGetInstanceProcAddr();
    if(!emu->context->vkprocaddress)
        emu->context->vkprocaddress = (vkprocaddess_t)procaddr;

    if(emu->context->vkprocaddress)
        return (void*)AddCheckBridge2(my_lib->w.bridge, pFEpp, my_vkGetInstanceProcAddr, (void*)procaddr, 0, "vkGetInstanceProcAddr");

@runlevel5
Copy link
Copy Markdown
Contributor Author

Good point — updated. Now always calls SDL_Vulkan_GetVkGetInstanceProcAddr() and stores the result in a local procaddr, which is passed directly as fnc2. The emu->context->vkprocaddress cache is only populated if it wasn't already set.

@ptitSeb
Copy link
Copy Markdown
Owner

ptitSeb commented Feb 27, 2026

Ok thanks.

(note: all those (void*) transtyping are useless, it's already void*)

@runlevel5
Copy link
Copy Markdown
Contributor Author

(note: all those (void*) transtyping are useless, it's already void*)

Let me clean up

… as fnc2

As suggested by ptitSeb: the bridge2 fnc2 parameter should use the
result of the current SDL call, not the potentially stale cached
vkprocaddress from a previous invocation. Store the SDL call result
in a local variable and pass that directly to AddCheckBridge2().
@runlevel5 runlevel5 force-pushed the fix-vulkan-sdl-bridge2 branch from 49f6d6e to 42ff462 Compare February 27, 2026 16:37
@runlevel5
Copy link
Copy Markdown
Contributor Author

Removed the redundant (void*) cast on the procaddr assignment — it's already void* from the SDL call. Kept the one on the AddCheckBridge2 return since that's a uintptr_t to void* conversion. Force-pushed.

@ptitSeb
Copy link
Copy Markdown
Owner

ptitSeb commented Feb 27, 2026

LGTM, Thanks!

@ptitSeb ptitSeb merged commit 2ef63f2 into ptitSeb:main Feb 27, 2026
27 checks passed
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.

2 participants