mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Count the draws skipped for a pending pipeline with atomics, as the replay adds to the count on one thread while the present takes it on another.
pending_draws (vk_exec_draw.c) counts the draws a frame left out because their shader or pipeline was still building; vk_backend.c frame_hold takes it at the present to hold such a frame back. The comment said both happen on the replay thread, which is true only with the replay on its own thread. With the replay on the submitting threads, draw_skipped adds on the thread holding the submission lock (and its parallel chunks) while vk_exec_pending_draws_take reads and clears it on the presenting thread, so a plain ++ and a read-then-clear could lose a count: a frame missing draws shown instead of held, or the next frame held for nothing. The add, the take (an exchange) and the read that skips a link wait are atomics now. Not reproduced before the change. Checks that passed: pass_cc_check of vk_exec_draw.c with no new -Wall -Wextra warnings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4388,18 +4388,15 @@ static void draw_stats_tick(void) {
|
||||
|
||||
// The draws skipped since the last present because their shader or pipeline was still building: the picture of that
|
||||
// frame lacks them (a light, a wall, a whole lighting pass). vk_backend.c frame_hold reads it at the present and keeps
|
||||
// the previous picture on screen instead. Written and read on the replay thread.
|
||||
// the previous picture on screen instead. The replay and its parallel chunks add to it; the present takes it, on the
|
||||
// presenting thread, which with the replay on the submitting threads need not be the one replaying: atomics.
|
||||
static uint32_t pending_draws;
|
||||
uint32_t vk_exec_pending_draws_take(void) {
|
||||
uint32_t n = pending_draws;
|
||||
pending_draws = 0;
|
||||
return n;
|
||||
}
|
||||
uint32_t vk_exec_pending_draws_take(void) { return __atomic_exchange_n(&pending_draws, 0, __ATOMIC_RELAXED); }
|
||||
|
||||
static int draw_skipped(const VkExec *ex, int mesh, int why) {
|
||||
DRS.skipped[mesh][why]++;
|
||||
if (vk_dump_armed) vk_dump_draw_skipped(ex, mesh, why);
|
||||
if (why == SK_SHADER_PENDING || why == SK_PIPE_PENDING) pending_draws++;
|
||||
if (why == SK_SHADER_PENDING || why == SK_PIPE_PENDING) __atomic_add_fetch(&pending_draws, 1, __ATOMIC_RELAXED);
|
||||
if (why == SK_PIPE_PENDING) perf_count(PERF_CNT_PIPE_SKIP); // skipped draws only: a lookup that then waited is none
|
||||
if (!(DRS.first[mesh] >> why & 1)) {
|
||||
DRS.first[mesh] |= 1u << why;
|
||||
@@ -4583,7 +4580,7 @@ static int prepare_draw_ex(VkExec *ex, int prim, int32_t count, int restart, int
|
||||
budget = link_budget();
|
||||
// A frame that has left a draw out already is not shown, or is shown without that draw (pending_draws,
|
||||
// vk_backend.c frame_hold): a wait for another pipeline would only make it later.
|
||||
wait_ms = pending_draws ? 0 : (uint32_t)(*budget / 1000000);
|
||||
wait_ms = __atomic_load_n(&pending_draws, __ATOMIC_RELAXED) ? 0 : (uint32_t)(*budget / 1000000);
|
||||
if (wait_ms > LINK_DRAW_MS) wait_ms = LINK_DRAW_MS;
|
||||
linking = wait_ms != 0;
|
||||
if (!wait_ms) budget = NULL;
|
||||
|
||||
Reference in New Issue
Block a user