Set, count down and clear vk_dlaa.c's setting_presents with atomics, as vk_dlaa_frame and vk_dlaa_resized_take can run on two threads.

setting_presents says how many more presents a new scene size counts as the result of a settings change (the resize
hold of vk_backend.c frame_hold). vk_dlaa_frame sets and counts it down, and vk_dlaa_resized_take tests and clears it
at the same present. With the replay on the submitting threads the frame's bookkeeping, vk_dlaa_frame among it, can run
on another thread than the presenting one (another thread's replay, or the next submission once the bookkeeping goes in
replay order), so a plain test-then-clear beside a plain decrement could take the hold twice or miss it. Now the take is
two exchanges, which give the outcome of the old two statements, and the count-down is a compare-and-swap that stops at
0, so it never goes below a clear made meanwhile.

Not reproduced before the change. Checks that passed: pass_cc_check of vk_dlaa.c with no new -Wall -Wextra warnings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
chrg6
2026-11-13 18:59:10 -05:00
parent ddc0247b25
commit 01cb13dc31

View File

@@ -3244,15 +3244,16 @@ static void preset_check(void) {
// intact (Ultra Performance and DLAA). Measured by capturing every present over six mode changes, 2026-11-10: bad
// frames 3 and 5 presents after the change, with every other setting the same. evaluate notes a scene of another size;
// vk_dlaa_frame counts the presents since a setting last changed, so a game that draws two sizes in turn holds nothing.
static int setting_presents; // vk_dlaa_frame: presents left in which that counts as a mode change
// setting_presents: presents left in which that counts as a mode change. vk_dlaa_frame sets and counts it down on the
// thread that runs the frame's bookkeeping, vk_dlaa_resized_take clears it on the presenting thread: atomics.
static int setting_presents;
#define SETTING_PRESENTS 60
// vk_backend.c frame_hold, each present after vk_dlaa_frame: 1 once when the scene took a new size after a setting
// changed. The previous picture then stays on screen over the frames described above.
int vk_dlaa_resized_take(void) {
if (!__atomic_exchange_n(&size_changed, 0, __ATOMIC_ACQ_REL) || !setting_presents) return 0;
setting_presents = 0;
return 1;
if (!__atomic_exchange_n(&size_changed, 0, __ATOMIC_ACQ_REL)) return 0;
return __atomic_exchange_n(&setting_presents, 0, __ATOMIC_ACQ_REL) != 0;
}
// What DLSS holds while nothing uses it (NX2NAVI_DLSS_IDLE_FREE 1 or 2, the default 1). With the upscaler switched off
@@ -3423,8 +3424,13 @@ void vk_dlaa_frame(void) {
static int cfg_known;
unsigned v = cfg_version();
D.presents++;
if (cfg_known && v != cfg_seen) setting_presents = SETTING_PRESENTS;
else if (setting_presents) setting_presents--;
if (cfg_known && v != cfg_seen) {
__atomic_store_n(&setting_presents, SETTING_PRESENTS, __ATOMIC_RELAXED);
} else { // down to 0, not past it: vk_dlaa_resized_take may clear it meanwhile
int s = __atomic_load_n(&setting_presents, __ATOMIC_RELAXED);
while (s > 0 &&
!__atomic_compare_exchange_n(&setting_presents, &s, s - 1, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) {}
}
cfg_seen = v, cfg_known = 1;
vk_dlaa_swap_img = NULL, vk_dlaa_swap_view = VK_NULL_HANDLE;
D.pre = D.comp = 0, D.comp_game = VK_NULL_HANDLE; // the frame before was recorded up to its present