- Replaced the old ImGui tab-based layout with a cleaner switch-driven structure.
- The settings dialog now runs in full-screen mode with the app’s settings background image.
- Fixed an issue caused by buttons being too small in certain languages.
The HLE dispatching bridge is now a stateless lambda that the compiler generates per-export via a NTTP,
with the ARM calling convention layout computed at compile-time time so all register and
stack argument reads are resolved at compile time with no runtime dispatch.
Also replace std::function with a plain function pointer for ImportFn to
avoid possible heap-allocation and indirection.
Before: two functions, runtime dispatch, indirect call through captured fn ptr.
Example: `_sceKernelCancelEventFlag(SceUID event_id, SceUInt pattern, SceUInt32 *num_wait_thread)`
```
; std::_Function_handler::_M_invoke -- unwraps the std::function heap object
_ZNSt17_Function_handlerI...bridge<int,(int,uint,uint*)>...M_invoke...:
pushq %rax
movq (%rdi), %rdx ; load captured state from heap
movq (%rdx), %rdi
movq 8(%rdx), %rax ; load captured export_fn ptr
leaq 16(%rdx), %rcx ; load captured args_layout ptr
callq _Z4call<int,(int,uint,uint*)>...
retq
; call<> -- dispatches each arg through a runtime switch on arg.location
_Z4call<int,(int,uint,uint*)>...:
movl (%rdx), %eax
cmpl $1, %eax ; arg[0]: gpr or stack?
je .stack_path_0
testl %eax, %eax
jne .done_0
movq 8(%r14), %rsi
callq read_reg
movl 16(%r14), %eax
cmpl $1, %eax ; arg[1]: gpr or stack?
je .stack_path_1
testl %eax, %eax
jne .done_1
movq 24(%r14), %rsi
callq read_reg
movl 32(%r14), %eax
cmpl $1, %eax ; arg[2]: gpr or stack?
je .stack_path_2
testl %eax, %eax
jne .done_2
movq 40(%r14), %rsi
callq read_reg
callq *%r10 ; indirect call through captured fn ptr
jmp write_return_value
```
After: single function with register indices hardcoded (generated at compile-time), direct call.
```
; make_bridge<&export__sceKernelCancelEventFlag>(...).__invoke
_ZZ11make_bridge<&export__sceKernelCancelEventFlag>...NUl...8__invoke...:
xorl %esi, %esi
callq read_reg ; r0 -> SceUID (index 0, hardcoded)
movl $1, %esi
callq read_reg ; r1 -> SceUInt (index 1, hardcoded)
movl $2, %esi
callq read_reg ; r2 -> Ptr<SceUInt32> (index 2, hardcoded)
callq eventflag_cancel ; direct call, resolved at compile time
jmp write_return_value
```
- Small refactor for blocking double click on button.
- Fix hide info bar when option is disable.
- Fix input is now also blocked on controller while the gate animation is playing.
The previous fix (a93e009a) changed the inner do-while loop into a
while-at-top loop, checking exit conditions before the first
execution. But those conditions (res, hit_breakpoint, etc.) only
make sense after execution — checking them first caused the loop
to break immediately without executing any guest code (0 fps).
Restore do-while semantics: always execute at least once, then
check the loop condition under the mutex. The to_do read at the
top of each iteration (step vs run decision) and the exit
condition at the bottom are both protected by the mutex.
Also fix suspend() to hold the mutex before modifying to_do,
matching what resume() and exit_delete() already do.
* kernel/thread: Fix wrong SVC number passed to call_svc
cpu->svc_called (a bool, always 1) was passed instead of cpu->svc
(the actual SVC number). This meant debugger trampoline SVCs (0x53
and 0x54) could never be recognized, since the svc parameter was
always 1. The normal import path was unaffected because it reads
the NID from memory at pc+4, not from the SVC number.
Found by @imWatchful
* cpu/dynarmic: Fix stop() to actually halt JIT execution
stop() only set an exit_request flag that was never checked by
anything. This meant suspend() and exit_delete() could not
interrupt guest execution — the JIT kept running until it
happened to hit an SVC or exception. For tight guest loops
without SVCs, this could hang.
Replace with jit->HaltExecution() which is the Dynarmic API
for cross-thread execution interruption. Remove the unused
exit_request field.
* kernel/thread: Fix data race on to_do field
The inner execution loop in run_loop() reads and writes to_do
without holding the mutex, while exit_delete() and suspend()
modify it from other threads. This is a data race.
Restructure the inner loop so that every access to to_do is
under the mutex. The lock is acquired briefly to snapshot or
modify to_do, then released before guest execution. The lock
is held when the loop breaks out, matching the original post-loop
lock state.
- Allow Disable and change volume of it during this first step.
- Change default volume to 65 % accorded to real hw.
- No restart emu anymore after finish this first step.
- Avoid dereferencing the address of `si_addr` after converting it to `uint64 *`.
- Prohibit to use initialization expressions when using `LOG_XXX_IF`.
- Handle null exception pointer in terminate handler.
* renderer/vulkan: Drain VK wait thread queue in sceGxmFinish
renderer::finish() only waited for the renderer command thread (via Nop),
but the VK wait thread that writes notification values after GPU fences
complete runs asynchronously. This caused a race where sceGxmFinish
returned before all notifications were written, allowing late writes to
overwrite values the game expected to be final (e.g. display callback
resets to 0), resulting in deadlocks during scene transitions.
* renderer/vulkan: Address review comments for VK wait thread drain
- Push a dummy CallbackRequest before wait_empty to ensure the last
request on the queue has been fully processed, not just dequeued
- Use static_cast instead of reinterpret_cast
- If after 'emplace_back()' the new 'size()' is greater than old 'capacity()' a reallocation takes place, in which case all references to the elements are invalidated.
While investigating #2733, I noticed that Vita3K would render an
_ancient_ frame from a previous scene transition (with a red hue)
whenever a new scene transition occurred.
This happens because `surface_cache` includes a stale texture from the
previous transition. By adding a `dirty` flag to the cache entries by
trapping writes to texture memory we can skip the `surface_cache` for
stale textures and pass through to `texture_cache` instead.
Also, set `can_mprotect_mapped_memory` if using double buffering.
Fixes#2733.