Fix Vulkan texture exponent bias, depth-only pipeline stalls, and WaitMultiple polling overhead#368
Open
Ufoex wants to merge 3 commits into
Open
Fix Vulkan texture exponent bias, depth-only pipeline stalls, and WaitMultiple polling overhead#368Ufoex wants to merge 3 commits into
Ufoex wants to merge 3 commits into
Conversation
The Vulkan SPIR-V texture-fetch translator read fetch constant word 4 for both LOD biasing and the result exponent bias, but exponent bias lives in word 3 (matching the D3D12 DXBC translator, which already reads word 3 for this). Reusing word 4 applied the wrong bias value, producing blown-out/incorrect brightness on affected texture fetches on the Vulkan backend only. Adds a dedicated word 3 load for the exponent bias while leaving word 4's LOD/stacked-texture-filtering usage untouched.
Async pipeline compilation previously required a pixel shader (since the mechanism swaps in a fast placeholder pixel shader while the real one compiles on a background thread). Pipelines with no pixel shader at all (depth/shadow-only passes) were excluded from this check and always compiled synchronously on the render thread, regardless of the async_shader_compilation cvar. Depth/shadow-only pipeline permutations are created continuously during normal gameplay (not just at load), e.g. whenever the camera reveals previously-unseen shadow casters. Because there's nothing cheaper to substitute for a depth-only pipeline (no pixel shader to swap out), skip drawing with it for a few frames instead of blocking: queue the real pipeline on the background thread pool and mark it as a placeholder immediately, reusing the same "skip this draw, retry next frame" path already used for the pixel-shader placeholder-swap case. Measured on a real gameplay session: roughly half of all newly created pipeline permutations had no pixel shader, so this removes a frequent render-thread stall source tied to camera movement.
WaitMultiple (used to implement KeWaitForMultipleObjects-style waits across more than one handle) polled every handle's mutex via pthread_mutex_trylock on a fixed 1ms interval regardless of how long the wait had been idle. Any guest thread waiting on several kernel objects at once - e.g. AudioSystem's worker thread, which waits on up to 9 handles (8 client semaphores + a shutdown event) - paid this poll cost roughly 500 times/sec even when nothing was signaling. Profiling a real gameplay session (perf + Tracy) showed this self-time (WaitMultiple + pthread_mutex_trylock + clock_gettime) was one of the largest CPU consumers on the audio worker thread, ahead of most actual guest-code execution. The poll interval now backs off exponentially (1ms -> 2 -> 4 -> 8 -> 16ms cap) the longer a single WaitMultiple call goes without any handle becoming signaled, and resets on every new wait. Freshly started waits stay responsive at 1ms; only sustained idle waits back off. Semantics, return values, and timeout behavior are unchanged - only the sleep duration between polls differs. Measured effect on one affected thread (Audio Worker) in Lollipop: Chainsaw via Re-Cherry: CPU usage dropped from ~68% to ~21%, with no observed hangs or audio glitches across repeated test sessions.
|
i can attest to 1, its a bad issue for fh1 |
Member
|
Let's clean up the formatting errors |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three independent fixes found while debugging visual corruption and stuttering under the Vulkan backend, running Lollipop: Chainsaw via the Re-Cherry mod loader (Linux, NVIDIA proprietary driver):
spirv_translator_fetch.cpp- the SPIR-V texture-fetch translator read fetch constant word 4 for the result exponent bias instead of word 3 (D3D12's DXBC translator already reads word 3 for this). Caused blown-out brightness on affected texture fetches, Vulkan-only.vulkan/pipeline_cache.cpp- async pipeline compilation required a pixel shader, so depth/shadow-only pipelines (no pixel shader) always compiled synchronously on the render thread. These are created continuously during gameplay (not just at load) whenever the camera reveals new shadow casters, causing render-thread stalls. Extended the existing "skip this draw, retry next frame" placeholder mechanism to cover this case (there's nothing cheaper to substitute for a depth-only pipeline, so it just queues the real one on the background thread pool and skips drawing with it until ready).core/threading_posix.cpp-PosixConditionBase::WaitMultiple(backingKeWaitForMultipleObjects-style waits) polled every handle viapthread_mutex_trylockon a fixed 1ms interval regardless of wait duration. Any guest thread waiting on several kernel objects at once pays this cost continuously - measured viaperf+Tracy onAudioSystem's worker thread (waits on 9 handles), which dropped from ~68% to ~21% CPU after adding exponential backoff (1ms -> 16ms cap, resets per wait). Semantics/timeouts unchanged, only the poll interval.Test plan
perf record/perf reportbefore and after (WaitMultiple self-time 6.43% -> 2.73%,pthread_mutex_trylock5.13% -> 2.30%) andps -Tthread CPU (Audio Worker 68% -> 21%); no hangs or audio glitches observed