Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 33 additions & 4 deletions runtime/nvn/vulkan/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,20 @@ static void *worker(void *a) {
return NULL;
}

static bool job_run_one(void) {
pthread_mutex_lock(&jobs_lock);
Job *j = jobs_head;
if (j) {
jobs_head = j->next;
if (!jobs_head) jobs_tail = NULL;
}
pthread_mutex_unlock(&jobs_lock);
if (!j) return false;
j->fn(j->arg);
free(j);
return true;
}

// Shaders and pipelines compile where they are first needed, the draw waiting for them (a short stutter the first time
// an effect appears), unless the "Asynchronous shaders" setting is on: then they compile on other threads and draws
// that need them are skipped meanwhile. That loses what the game draws only once: the save file's screenshot (a
Expand Down Expand Up @@ -7660,7 +7674,7 @@ static bool one_shot_target(void) {
// stalls on them - where a first boot linked 236 pipelines in one 109 ms frame. A stage library still to compile
// (5-50 ms) always goes to a worker. SAVAGEWIND_PIPE_LINK_MS=0: every build on a worker, as before.
static void build_pipeline(void *arg);
static bool link_now(Pipe *pp) {
static bool link_now(Pipe *pp, bool must_happen) {
static int64_t budget = -1;
if (budget < 0) budget = (getenv("SAVAGEWIND_PIPE_LINK_MS") ? atoi(getenv("SAVAGEWIND_PIPE_LINK_MS")) : 3) * 1000000ll;
const Prog *pr = pp->k.prog;
Expand All @@ -7672,18 +7686,32 @@ static bool link_now(Pipe *pp) {
static uint64_t frame, spent;
uint64_t now = renderer_present_count();
if (now != frame) { frame = now; spent = 0; }
if (spent >= (uint64_t)budget) return false;
if (!must_happen && spent >= (uint64_t)budget) return false;
uint64_t t0 = SDL_GetTicksNS();
build_pipeline(pp);
spent += SDL_GetTicksNS() - t0;
stat_links_now++;
return true;
}

#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
#define exec_relax() __builtin_ia32_pause()
#elif defined(__aarch64__) || defined(_M_ARM64)
#define exec_relax() __asm__ volatile("yield")
#else
#define exec_relax() ((void)0)
#endif

static void wait_built(_Atomic int *state) { // (0 building: until built or failed, 5 s at most)
if (atomic_load(state) != 0 || sync_shaders()) return;
uint64_t t0 = SDL_GetTicksNS();
while (atomic_load(state) == 0 && SDL_GetTicksNS() - t0 < 5000000000ull) SDL_Delay(1);
while (atomic_load(state) == 0 && SDL_GetTicksNS() - t0 < 5000000000ull) {
if (!job_run_one()) {
for (int i = 0; i < 200 && atomic_load(state) == 0; i++) exec_relax();
if (atomic_load(state) != 0) break;
SDL_Delay(1);
}
}
stat_build_waits++;
perfcount_add(PC_BUILD_WAITS, 1);
perfcount_add(PC_BUILD_WAIT_NS, SDL_GetTicksNS() - t0);
Expand Down Expand Up @@ -8099,9 +8127,10 @@ static void draw_(CmdRec *r, bool indexed) {
pipe_tab[pslot].key = ph;
pipe_tab[pslot].pipe = pp;
pipe_n++;
bool must = one_shot_target() || draw_must_happen();
VkPipeline ready = sync_shaders() ? VK_NULL_HANDLE : warm_ready(pr->vi, pr->fi, &k.s);
if (ready) { pp->pipe = ready; atomic_store(&pp->state, 1); atomic_fetch_add(&stat_warm, 1); }
else if (sync_shaders() || !link_now(pp)) run_job(build_pipeline, pp); // (asynchronous: a link alone is done here)
else if (sync_shaders() || !link_now(pp, must)) run_job(build_pipeline, pp); // (asynchronous: a link alone is done here)
}
pipe_memo.k = k;
pipe_memo.pp = pp;
Expand Down
Loading