call resource callbacks in job

This commit is contained in:
jacob 2025-07-01 01:03:06 -05:00
parent fea0346982
commit 892daa5ed2
16 changed files with 177 additions and 100 deletions

BIN
res/sprite/tim.ase (Stored with Git LFS)

Binary file not shown.

View File

@ -236,13 +236,13 @@ void app_entry_point(struct string args_str)
i32 worker_count; i32 worker_count;
{ {
/* FIXME: Switch this on to utilize all cores. Only decreasing worker count for testing purposes. */ /* FIXME: Switch this on to utilize all cores. Only decreasing worker count for testing purposes. */
#if !PROFILING && !RTC || 1 #if !PROFILING && !RTC
i32 min_worker_count = min_i32(NUM_APP_DEDICATED_WORKERS + 2, JOB_MIN_WORKERS);
i32 max_worker_count = JOB_MAX_WORKERS; i32 max_worker_count = JOB_MAX_WORKERS;
i32 min_worker_count = clamp_i32(NUM_APP_DEDICATED_WORKERS + 2, JOB_MIN_WORKERS, max_worker_count);
i32 target_worker_count = (i32)sys_num_logical_processors() * 0.75; i32 target_worker_count = (i32)sys_num_logical_processors() * 0.75;
worker_count = clamp_i32(target_worker_count, min_worker_count, max_worker_count); worker_count = clamp_i32(target_worker_count, min_worker_count, max_worker_count);
#else #else
worker_count = 8; worker_count = 5;
#endif #endif
} }

View File

@ -76,7 +76,7 @@ void *arena_push_bytes_no_zero(struct arena *arena, u64 size, u64 align)
u64 new_pos = aligned_start_pos + size; u64 new_pos = aligned_start_pos + size;
if (new_pos > arena->committed) { if (new_pos > arena->committed) {
__profscope(_arena_push_bytes_COMMIT); __profscope(Arena commit);
/* Commit new block(s) */ /* Commit new block(s) */
u64 blocks_needed = (new_pos - arena->committed + ARENA_BLOCK_SIZE - 1) / ARENA_BLOCK_SIZE; u64 blocks_needed = (new_pos - arena->committed + ARENA_BLOCK_SIZE - 1) / ARENA_BLOCK_SIZE;
u64 commit_bytes = blocks_needed * ARENA_BLOCK_SIZE; u64 commit_bytes = blocks_needed * ARENA_BLOCK_SIZE;

View File

@ -732,7 +732,7 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct stri
} }
{ {
__profscope(assemble_image); __profscope(Build image from cels);
/* Assemble image from cels */ /* Assemble image from cels */
for (struct cel *cel = cel_head; cel; cel = cel->next) { for (struct cel *cel = cel_head; cel; cel = cel->next) {

View File

@ -653,7 +653,7 @@ struct host_event_list host_update_begin(struct arena *arena, struct host *host)
i64 now_ns = sys_time_ns(); i64 now_ns = sys_time_ns();
{ {
__profscope(host_update_read_packets); __profscope(Read host packets);
struct string read_buff = ZI; struct string read_buff = ZI;
read_buff.len = PACKET_DATA_MAX_LEN; read_buff.len = PACKET_DATA_MAX_LEN;
read_buff.text = arena_push_array_no_zero(scratch.arena, u8, read_buff.len); read_buff.text = arena_push_array_no_zero(scratch.arena, u8, read_buff.len);
@ -829,7 +829,7 @@ struct host_event_list host_update_begin(struct arena *arena, struct host *host)
/* Update channels */ /* Update channels */
{ {
__profscope(host_update_channels); __profscope(Update host channels);
for (u64 i = 0; i < host->num_channels_reserved; ++i) { for (u64 i = 0; i < host->num_channels_reserved; ++i) {
struct host_channel *channel = &host->channels[i]; struct host_channel *channel = &host->channels[i];
if (channel->valid) { if (channel->valid) {
@ -903,7 +903,7 @@ void host_update_end(struct host *host)
/* Process cmds into sendable packets */ /* Process cmds into sendable packets */
/* TODO: Unreliable packets don't need to be allocated into unreliable packet queue, should just send them and forget */ /* TODO: Unreliable packets don't need to be allocated into unreliable packet queue, should just send them and forget */
{ {
__profscope(host_update_process_cmds); __profscope(Process host cmds);
for (struct host_cmd *cmd = host->first_cmd; cmd; cmd = cmd->next) { for (struct host_cmd *cmd = host->first_cmd; cmd; cmd = cmd->next) {
enum host_cmd_kind kind = cmd->kind; enum host_cmd_kind kind = cmd->kind;
struct host_channel_id channel_id = cmd->channel_id; struct host_channel_id channel_id = cmd->channel_id;
@ -1018,7 +1018,7 @@ void host_update_end(struct host *host)
/* Send packets */ /* Send packets */
/* TODO: Aggregate small packets */ /* TODO: Aggregate small packets */
{ {
__profscope(host_update_send_packets); __profscope(Send host packets);
for (u64 i = 0; i < host->num_channels_reserved; ++i) { for (u64 i = 0; i < host->num_channels_reserved; ++i) {
struct sock *sock = host->sock; struct sock *sock = host->sock;
struct host_channel *channel = &host->channels[i]; struct host_channel *channel = &host->channels[i];

View File

@ -236,17 +236,27 @@ INTERNAL struct job_handle job_dispatch_ex(struct job_desc desc)
/* Queue job */ /* Queue job */
if (job_queue) { if (job_queue) {
__profscope(Queue); __profscope(Queue job);
struct sys_lock lock = sys_mutex_lock_e(G.queued_jobs_mutex); struct sys_lock lock = sys_mutex_lock_e(G.queued_jobs_mutex);
{ {
/* Push to queue */ /* Push to queue */
{ {
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
if (job_queue->last) { if (job_queue->last) {
job_queue->last->next = job; job_queue->last->next = job;
} else { } else {
job_queue->first = job; job_queue->first = job;
} }
job->prev = job_queue->last;
job_queue->last = job; job_queue->last = job;
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
} }
++G.queue_submit_gen; ++G.queue_submit_gen;
/* Signal workers */ /* Signal workers */
@ -272,8 +282,12 @@ INTERNAL struct job_handle job_dispatch_ex(struct job_desc desc)
while (!stop) { while (!stop) {
/* Remove job from queue */ /* Remove job from queue */
if (job_queue && job_id == (job_count - 1)) { if (job_queue && job_id == (job_count - 1)) {
__profscope(Dequeue job);
struct sys_lock queue_lock = sys_mutex_lock_e(G.queued_jobs_mutex); struct sys_lock queue_lock = sys_mutex_lock_e(G.queued_jobs_mutex);
{ {
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
struct worker_job *prev = job->prev; struct worker_job *prev = job->prev;
struct worker_job *next = job->next; struct worker_job *next = job->next;
if (prev) { if (prev) {
@ -286,11 +300,15 @@ INTERNAL struct job_handle job_dispatch_ex(struct job_desc desc)
} else { } else {
job_queue->last = prev; job_queue->last = prev;
} }
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
} }
sys_mutex_unlock(&queue_lock); sys_mutex_unlock(&queue_lock);
} }
/* Run */ /* Run */
{ {
__profscope(Run job);
data.id = job_id; data.id = job_id;
job_func(data); job_func(data);
} }
@ -313,8 +331,12 @@ INTERNAL struct job_handle job_dispatch_ex(struct job_desc desc)
} }
} }
if (should_release) { if (should_release) {
__profscope(Release job);
struct sys_lock fj_lock = sys_mutex_lock_e(G.free_jobs_mutex); struct sys_lock fj_lock = sys_mutex_lock_e(G.free_jobs_mutex);
{ {
if (job->queue && (job->queue->first == job || job->queue->last == job)) {
DEBUGBREAK;
}
job->next_free = G.first_free_job; job->next_free = G.first_free_job;
G.first_free_job = job; G.first_free_job = job;
} }
@ -326,7 +348,7 @@ INTERNAL struct job_handle job_dispatch_ex(struct job_desc desc)
/* Wait for job completion */ /* Wait for job completion */
if (wait && !is_done) { if (wait && !is_done) {
__profscope(Wait for job); __profscope(Wait for job);
struct sys_lock lock = sys_mutex_lock_s(job->mutex); struct sys_lock lock = sys_mutex_lock_e(job->mutex);
is_done = atomic_u64_eval(&job->gen) != handle.gen; is_done = atomic_u64_eval(&job->gen) != handle.gen;
while (!is_done) { while (!is_done) {
sys_condition_variable_wait(job->gen_cv, &lock); sys_condition_variable_wait(job->gen_cv, &lock);
@ -411,6 +433,9 @@ void job_wait(struct job_handle handle)
__profscope(Dequeue job); __profscope(Dequeue job);
struct sys_lock queue_lock = sys_mutex_lock_e(G.queued_jobs_mutex); struct sys_lock queue_lock = sys_mutex_lock_e(G.queued_jobs_mutex);
{ {
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
struct worker_job *prev = job->prev; struct worker_job *prev = job->prev;
struct worker_job *next = job->next; struct worker_job *next = job->next;
if (prev) { if (prev) {
@ -423,6 +448,9 @@ void job_wait(struct job_handle handle)
} else { } else {
job_queue->last = prev; job_queue->last = prev;
} }
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
} }
sys_mutex_unlock(&queue_lock); sys_mutex_unlock(&queue_lock);
} }
@ -451,6 +479,9 @@ void job_wait(struct job_handle handle)
__profscope(Release job); __profscope(Release job);
struct sys_lock fj_lock = sys_mutex_lock_e(G.free_jobs_mutex); struct sys_lock fj_lock = sys_mutex_lock_e(G.free_jobs_mutex);
{ {
if (job->queue && (job->queue->first == job || job->queue->last == job)) {
DEBUGBREAK;
}
job->next_free = G.first_free_job; job->next_free = G.first_free_job;
G.first_free_job = job; G.first_free_job = job;
} }
@ -462,7 +493,7 @@ void job_wait(struct job_handle handle)
/* Wait for job completion */ /* Wait for job completion */
if (!is_done) { if (!is_done) {
__profscope(Wait for job); __profscope(Wait for job);
struct sys_lock lock = sys_mutex_lock_s(job->mutex); struct sys_lock lock = sys_mutex_lock_e(job->mutex);
is_done = atomic_u64_eval(&job->gen) != handle.gen; is_done = atomic_u64_eval(&job->gen) != handle.gen;
while (!is_done) { while (!is_done) {
sys_condition_variable_wait(job->gen_cv, &lock); sys_condition_variable_wait(job->gen_cv, &lock);
@ -485,7 +516,7 @@ INTERNAL SYS_THREAD_DEF(worker_thread_entry_point, thread_arg)
struct worker_ctx *ctx = thread_local_var_eval(&tl_worker_ctx); struct worker_ctx *ctx = thread_local_var_eval(&tl_worker_ctx);
ctx->worker_id = worker_id; ctx->worker_id = worker_id;
struct worker_job_queues *queues[] = { &G.pinned_queues[worker_id], &G.global_queue }; struct worker_job_queue *queues[] = { &G.pinned_queues[worker_id], &G.global_queue };
u64 seen_queue_submit_gen = 0; u64 seen_queue_submit_gen = 0;
struct sys_lock queue_lock = sys_mutex_lock_s(G.queued_jobs_mutex); struct sys_lock queue_lock = sys_mutex_lock_s(G.queued_jobs_mutex);
@ -503,7 +534,7 @@ INTERNAL SYS_THREAD_DEF(worker_thread_entry_point, thread_arg)
queue_lock = sys_mutex_lock_s(G.queued_jobs_mutex); queue_lock = sys_mutex_lock_s(G.queued_jobs_mutex);
{ {
seen_queue_submit_gen = G.queue_submit_gen; seen_queue_submit_gen = G.queue_submit_gen;
for (i32 queue_index = 0; queue_index < ARRAY_COUNT(queues); ++queue_index) { for (i32 queue_index = 0; queue_index < (i32)ARRAY_COUNT(queues); ++queue_index) {
struct worker_job_queue *queue = queues[queue_index]; struct worker_job_queue *queue = queues[queue_index];
struct worker_job *tmp = queue->first; struct worker_job *tmp = queue->first;
while (!job && tmp) { while (!job && tmp) {
@ -511,8 +542,6 @@ INTERNAL SYS_THREAD_DEF(worker_thread_entry_point, thread_arg)
{ {
i32 tmp_id = tmp->num_dispatched; i32 tmp_id = tmp->num_dispatched;
i32 tmp_count = tmp->count; i32 tmp_count = tmp->count;
i32 tmp_pinned_worker = tmp->pinned_worker_id;
b32 tmp_is_pinned_to_worker = tmp_pinned_worker == worker_id;
if (tmp_id < tmp_count) { if (tmp_id < tmp_count) {
/* Pick job */ /* Pick job */
++tmp->num_workers; ++tmp->num_workers;
@ -537,6 +566,9 @@ INTERNAL SYS_THREAD_DEF(worker_thread_entry_point, thread_arg)
__profscope(Dequeue job); __profscope(Dequeue job);
queue_lock = sys_mutex_lock_e(G.queued_jobs_mutex); queue_lock = sys_mutex_lock_e(G.queued_jobs_mutex);
{ {
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
struct worker_job *prev = job->prev; struct worker_job *prev = job->prev;
struct worker_job *next = job->next; struct worker_job *next = job->next;
if (prev) { if (prev) {
@ -549,6 +581,9 @@ INTERNAL SYS_THREAD_DEF(worker_thread_entry_point, thread_arg)
} else { } else {
job_queue->last = prev; job_queue->last = prev;
} }
if (job->prev == job || job->next == job) {
DEBUGBREAKABLE;
}
} }
sys_mutex_unlock(&queue_lock); sys_mutex_unlock(&queue_lock);
} }

View File

@ -291,7 +291,7 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
/* Update & read mixes */ /* Update & read mixes */
mixes = arena_push_array_no_zero(scratch.arena, struct mix *, G.track_playing_count); mixes = arena_push_array_no_zero(scratch.arena, struct mix *, G.track_playing_count);
for (struct track *track = G.track_first_playing; track; track = track->next) { for (struct track *track = G.track_first_playing; track; track = track->next) {
__profscope(prepare_track); __profscope(Prepare track);
struct mix *mix = &track->mix; struct mix *mix = &track->mix;
mix->desc = track->desc; mix->desc = track->desc;
mixes[mixes_count++] = mix; mixes[mixes_count++] = mix;
@ -301,7 +301,7 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
} }
for (u64 mix_index = 0; mix_index < mixes_count; ++mix_index) { for (u64 mix_index = 0; mix_index < mixes_count; ++mix_index) {
__profscope(mix_track); __profscope(Mix track);
struct mix *mix = mixes[mix_index]; struct mix *mix = mixes[mix_index];
if (mix->source->pcm.count <= 0) { if (mix->source->pcm.count <= 0) {
@ -354,7 +354,7 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
/* Transform 16 bit source -> 32 bit stereo at output duration */ /* Transform 16 bit source -> 32 bit stereo at output duration */
{ {
__profscope(resample); __profscope(Resample);
f32 *out_samples = mix_pcm.samples; f32 *out_samples = mix_pcm.samples;
u64 out_frames_count = mix_pcm.count / 2; u64 out_frames_count = mix_pcm.count / 2;
@ -408,7 +408,7 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
* ========================== */ * ========================== */
if (desc.flags & MIXER_FLAG_SPATIALIZE) { if (desc.flags & MIXER_FLAG_SPATIALIZE) {
__profscope(spatialize); __profscope(Spatialize);
/* Algorithm constants */ /* Algorithm constants */
const f32 rolloff_height = 1.2f; const f32 rolloff_height = 1.2f;
@ -469,7 +469,7 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
} }
{ {
__profscope(update_track_effect_data); __profscope(Update track effect data);
struct sys_lock lock = sys_mutex_lock_e(G.mutex); struct sys_lock lock = sys_mutex_lock_e(G.mutex);
for (u64 i = 0; i < mixes_count; ++i) { for (u64 i = 0; i < mixes_count; ++i) {
struct mix *mix = mixes[i]; struct mix *mix = mixes[i];

View File

@ -1254,7 +1254,7 @@ void phys_step(struct phys_step_ctx *ctx, f32 timestep)
f32 remaining_dt = timestep; f32 remaining_dt = timestep;
while (remaining_dt > 0) { while (remaining_dt > 0) {
__profscope(step_part); __profscope(Step part);
++phys_iteration; ++phys_iteration;
struct arena_temp scratch = scratch_begin_no_conflict(); struct arena_temp scratch = scratch_begin_no_conflict();
@ -1282,7 +1282,7 @@ void phys_step(struct phys_step_ctx *ctx, f32 timestep)
f32 substep_dt = step_dt / SIM_PHYSICS_SUBSTEPS; f32 substep_dt = step_dt / SIM_PHYSICS_SUBSTEPS;
for (u32 i = 0; i < SIM_PHYSICS_SUBSTEPS; ++i) { for (u32 i = 0; i < SIM_PHYSICS_SUBSTEPS; ++i) {
__profscope(substep); __profscope(Substep);
/* Warm start */ /* Warm start */
#if SIM_PHYSICS_ENABLE_WARM_STARTING #if SIM_PHYSICS_ENABLE_WARM_STARTING

View File

@ -9,9 +9,12 @@
/* Include tracy client */ /* Include tracy client */
#define TRACY_ENABLE #define TRACY_ENABLE
#define TRACY_MANUAL_LIFETIME #if 0
#define TRACY_DELAYED_INIT /* Enable manual lifetime */
#if 1 # define TRACY_MANUAL_LIFETIME
# define TRACY_DELAYED_INIT
#endif
#if 0
/* Disable system tracing (very slow) */ /* Disable system tracing (very slow) */
# define TRACY_NO_CALLSTACK # define TRACY_NO_CALLSTACK
# define TRACY_NO_SYSTEM_TRACING # define TRACY_NO_SYSTEM_TRACING
@ -19,7 +22,7 @@
#include STRINGIZE(TRACY_INCLUDE_PATH) #include STRINGIZE(TRACY_INCLUDE_PATH)
#define PROFILING_CAPTURE_FRAME_IMAGE 0 #define PROFILING_CAPTURE_FRAME_IMAGE 0
#define PROFILING_LOCKS 0 #define PROFILING_LOCKS 1
#define PROFILING_D3D 1 #define PROFILING_D3D 1
#define PROFILING_CMD_WSTR L"tracy-profiler.exe -a 127.0.0.1" #define PROFILING_CMD_WSTR L"tracy-profiler.exe -a 127.0.0.1"

View File

@ -4,6 +4,7 @@
#include "tar.h" #include "tar.h"
#include "incbin.h" #include "incbin.h"
#include "util.h" #include "util.h"
#include "job.h"
/* ========================== * /* ========================== *
* Global data * Global data
@ -218,6 +219,20 @@ INTERNAL SYS_THREAD_DEF(resource_watch_monitor_thread_entry_point, _)
#define WATCH_DISPATCHER_DELAY_SECONDS 0.050 #define WATCH_DISPATCHER_DELAY_SECONDS 0.050
#define WATCH_DISPATCHER_DEDUP_DICT_BINS 128 #define WATCH_DISPATCHER_DEDUP_DICT_BINS 128
struct resource_watch_callback_job_sig {
struct string name;
resource_watch_callback **callbacks;
};
INTERNAL JOB_DEF(resource_watch_callback_job, job)
{
__prof;
struct resource_watch_callback_job_sig *sig = job.sig;
struct string name = sig->name;
resource_watch_callback *callback = sig->callbacks[job.id];
callback(name);
}
INTERNAL SYS_THREAD_DEF(resource_watch_dispatcher_thread_entry_point, _) INTERNAL SYS_THREAD_DEF(resource_watch_dispatcher_thread_entry_point, _)
{ {
(UNUSED)_; (UNUSED)_;
@ -227,8 +242,10 @@ INTERNAL SYS_THREAD_DEF(resource_watch_dispatcher_thread_entry_point, _)
while (!atomic_i32_eval(&G.watch_shutdown)) { while (!atomic_i32_eval(&G.watch_shutdown)) {
sys_condition_variable_wait(G.watch_dispatcher_cv, &watch_dispatcher_lock); sys_condition_variable_wait(G.watch_dispatcher_cv, &watch_dispatcher_lock);
if (!atomic_i32_eval(&G.watch_shutdown) && G.watch_dispatcher_info_arena->pos > 0) { if (!atomic_i32_eval(&G.watch_shutdown) && G.watch_dispatcher_info_arena->pos > 0) {
__profscope(Dispatch resource watch callbacks);
/* Unlock and sleep a bit so duplicate events pile up */ /* Unlock and sleep a bit so duplicate events pile up */
{ {
__profscope(Delay);
sys_mutex_unlock(&watch_dispatcher_lock); sys_mutex_unlock(&watch_dispatcher_lock);
sys_sleep(WATCH_DISPATCHER_DELAY_SECONDS); sys_sleep(WATCH_DISPATCHER_DELAY_SECONDS);
watch_dispatcher_lock = sys_mutex_lock_e(G.watch_dispatcher_mutex); watch_dispatcher_lock = sys_mutex_lock_e(G.watch_dispatcher_mutex);
@ -241,12 +258,25 @@ INTERNAL SYS_THREAD_DEF(resource_watch_dispatcher_thread_entry_point, _)
MEMZERO_STRUCT(&G.watch_dispatcher_info_list); MEMZERO_STRUCT(&G.watch_dispatcher_info_list);
arena_reset(G.watch_dispatcher_info_arena); arena_reset(G.watch_dispatcher_info_arena);
/* Build callbacks array */
u64 num_callbacks = 0;
resource_watch_callback **callbacks = NULL;
struct sys_lock callbacks_lock = sys_mutex_lock_s(G.watch_callbacks_mutex);
{
num_callbacks = G.num_watch_callbacks;
callbacks = arena_push_array_no_zero(temp.arena, resource_watch_callback *, num_callbacks);
for (u64 i = 0; i < num_callbacks; ++i) {
callbacks[i] = G.watch_callbacks[i];
}
}
sys_mutex_unlock(&callbacks_lock);
/* Unlock and run callbacks */ /* Unlock and run callbacks */
sys_mutex_unlock(&watch_dispatcher_lock); sys_mutex_unlock(&watch_dispatcher_lock);
{ {
__profscope(run_resource_watch_callbacks);
struct dict *dedup_dict = dict_init(temp.arena, WATCH_DISPATCHER_DEDUP_DICT_BINS); struct dict *dedup_dict = dict_init(temp.arena, WATCH_DISPATCHER_DEDUP_DICT_BINS);
for (struct sys_watch_info *info = watch_info_list.first; info; info = info->next) { for (struct sys_watch_info *info = watch_info_list.first; info; info = info->next) {
__profscope(Dispatch);
/* Do not run callbacks for the same file more than once */ /* Do not run callbacks for the same file more than once */
b32 skip = false; b32 skip = false;
u64 hash = hash_fnv64(HASH_FNV64_BASIS, info->name); u64 hash = hash_fnv64(HASH_FNV64_BASIS, info->name);
@ -256,12 +286,10 @@ INTERNAL SYS_THREAD_DEF(resource_watch_dispatcher_thread_entry_point, _)
dict_set(temp.arena, dedup_dict, hash, 1); dict_set(temp.arena, dedup_dict, hash, 1);
} }
if (!skip) { if (!skip) {
struct sys_lock callbacks_lock = sys_mutex_lock_s(G.watch_callbacks_mutex); struct resource_watch_callback_job_sig sig = ZI;
for (u64 i = 0; i < G.num_watch_callbacks; ++i) { sig.name = info->name;
resource_watch_callback *callback = G.watch_callbacks[i]; sig.callbacks = callbacks;
callback(info->name); job_dispatch_wait(num_callbacks, resource_watch_callback_job, &sig);
}
sys_mutex_unlock(&callbacks_lock);
} }
} }
} }

View File

@ -649,7 +649,7 @@ struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_client *client, str
/* Blend entities */ /* Blend entities */
{ {
__profscope(snapshot_lerp_entities); __profscope(Lerp snapshot entities);
u64 num_entities = min_u64(ss0->num_ents_reserved, ss1->num_ents_reserved); u64 num_entities = min_u64(ss0->num_ents_reserved, ss1->num_ents_reserved);
for (u64 i = 0; i < num_entities; ++i) { for (u64 i = 0; i < num_entities; ++i) {
struct sim_ent *e = &ss->ents[i]; struct sim_ent *e = &ss->ents[i];

View File

@ -153,11 +153,10 @@ GLOBAL struct {
/* Evictor thread */ /* Evictor thread */
struct atomic_i32 evictor_cycle; struct atomic_i32 evictor_cycle;
b32 evictor_shutdown; b32 evictor_scheduler_shutdown;
struct sys_mutex *evictor_mutex; struct sys_mutex *evictor_scheduler_mutex;
struct sys_condition_variable *evictor_cv; struct sys_condition_variable *evictor_scheduler_shutdown_cv;
struct sys_thread *evictor_scheduler_thread;
struct sys_thread *evictor_thread;
} G = ZI, DEBUG_ALIAS(G, G_sprite); } G = ZI, DEBUG_ALIAS(G, G_sprite);
/* ========================== * /* ========================== *
@ -204,7 +203,7 @@ INTERNAL struct image_rgba generate_purple_black_image(struct arena *arena, u32
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sprite_shutdown); INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sprite_shutdown);
INTERNAL JOB_DEF(sprite_load_job, arg); INTERNAL JOB_DEF(sprite_load_job, arg);
INTERNAL SYS_THREAD_DEF(sprite_evictor_thread_entry_point, arg); INTERNAL SYS_THREAD_DEF(sprite_evictor_scheduler_thread_entry_point, arg);
#if RESOURCE_RELOADING #if RESOURCE_RELOADING
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, info); INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, info);
@ -256,10 +255,10 @@ struct sprite_startup_receipt sprite_startup(struct gp_startup_receipt *gp_sr,
G.scopes_arena = arena_alloc(GIGABYTE(64)); G.scopes_arena = arena_alloc(GIGABYTE(64));
G.evictor_mutex = sys_mutex_alloc(); G.evictor_scheduler_mutex = sys_mutex_alloc();
G.evictor_cv = sys_condition_variable_alloc(); G.evictor_scheduler_shutdown_cv = sys_condition_variable_alloc();
G.evictor_thread = sys_thread_alloc(sprite_evictor_thread_entry_point, NULL, LIT("[P2] Sprite evictor")); G.evictor_scheduler_thread = sys_thread_alloc(sprite_evictor_scheduler_thread_entry_point, NULL, LIT("[P2] Sprite evictor scheduler"));
app_register_exit_callback(&sprite_shutdown); app_register_exit_callback(&sprite_shutdown);
resource_register_watch_callback(&sprite_resource_watch_callback); resource_register_watch_callback(&sprite_resource_watch_callback);
@ -272,12 +271,12 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sprite_shutdown)
__prof; __prof;
/* Signal evictor shutdown */ /* Signal evictor shutdown */
{ {
struct sys_lock lock = sys_mutex_lock_e(G.evictor_mutex); struct sys_lock lock = sys_mutex_lock_e(G.evictor_scheduler_mutex);
G.evictor_shutdown = true; G.evictor_scheduler_shutdown = true;
sys_condition_variable_broadcast(G.evictor_cv); sys_condition_variable_broadcast(G.evictor_scheduler_shutdown_cv);
sys_mutex_unlock(&lock); sys_mutex_unlock(&lock);
} }
sys_thread_wait_release(G.evictor_thread); sys_thread_wait_release(G.evictor_scheduler_thread);
} }
/* ========================== * /* ========================== *
@ -430,7 +429,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
/* Init frames */ /* Init frames */
{ {
__profscope(init_frames); __profscope(Init frames);
sheet.image_size = ase.image_size; sheet.image_size = ase.image_size;
sheet.frame_size = ase.frame_size; sheet.frame_size = ase.frame_size;
sheet.frames = arena_push_array(arena, struct sprite_sheet_frame, ase.num_frames); sheet.frames = arena_push_array(arena, struct sprite_sheet_frame, ase.num_frames);
@ -452,7 +451,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
/* Init spans */ /* Init spans */
sheet.spans_count = ase.num_spans; sheet.spans_count = ase.num_spans;
if (ase.num_spans > 0) { if (ase.num_spans > 0) {
__profscope(init_spans); __profscope(Init spans);
sheet.spans = arena_push_array(arena, struct sprite_sheet_span, sheet.spans_count); sheet.spans = arena_push_array(arena, struct sprite_sheet_span, sheet.spans_count);
sheet.spans_dict = dict_init(arena, (u64)(ase.num_spans * SHEET_SPAN_LOOKUP_TABLE_BIN_RATIO)); sheet.spans_dict = dict_init(arena, (u64)(ase.num_spans * SHEET_SPAN_LOOKUP_TABLE_BIN_RATIO));
u64 index = 0; u64 index = 0;
@ -470,7 +469,7 @@ INTERNAL struct sprite_sheet init_sheet_from_ase_result(struct arena *arena, str
/* Init slices */ /* Init slices */
if (ase.num_slice_keys > 0) { if (ase.num_slice_keys > 0) {
__profscope(init_slices); __profscope(Init slices);
struct arena_temp scratch = scratch_begin(arena); struct arena_temp scratch = scratch_begin(arena);
struct temp_ase_slice_key_node { struct temp_ase_slice_key_node {
@ -1209,7 +1208,7 @@ INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(sprite_resource_watch_callback, name)
#endif #endif
/* ========================== * /* ========================== *
* Evictor thread * Evictor job
* ========================== */ * ========================== */
struct evict_node { struct evict_node {
@ -1230,34 +1229,21 @@ INTERNAL SORT_COMPARE_FUNC_DEF(evict_sort, arg_a, arg_b, udata)
return (b_cycle > a_cycle) - (a_cycle > b_cycle); return (b_cycle > a_cycle) - (a_cycle > b_cycle);
} }
/* NOTE: INTERNAL JOB_DEF(sprite_evictor_job, _)
* A cache node is safe from eviction as long as:
* - Its bin mutex is locked
* - Any references are held to the node (its refcount > 0)
*
* An attempt to evict a cache node will occur when:
* - Its refcount = 0 and
* - The cache is over its memory budget and the node's last reference is longer ago than the grace period
* - Resource reloading is enabled and the node is out of date due to a change to its original resource file
*/
INTERNAL SYS_THREAD_DEF(sprite_evictor_thread_entry_point, arg)
{ {
(UNUSED)arg; (UNUSED)_;
__prof;
struct sys_lock evictor_lock = sys_mutex_lock_e(G.evictor_mutex); struct arena_temp scratch = scratch_begin_no_conflict();
while (!G.evictor_shutdown) { {
struct arena_temp scratch = scratch_begin_no_conflict();
u64 evict_array_count = 0; u64 evict_array_count = 0;
struct evict_node *evict_array = arena_push_dry(scratch.arena, struct evict_node); struct evict_node *evict_array = arena_push_dry(scratch.arena, struct evict_node);
{
if (!G.evictor_shutdown) {
i32 cur_cycle = atomic_i32_eval(&G.evictor_cycle); i32 cur_cycle = atomic_i32_eval(&G.evictor_cycle);
/* Scan for evictable nodes */ /* Scan for evictable nodes */
b32 cache_over_budget_threshold = atomic_u64_eval(&G.cache.memory_usage) > CACHE_MEMORY_BUDGET_THRESHOLD; b32 cache_over_budget_threshold = atomic_u64_eval(&G.cache.memory_usage) > CACHE_MEMORY_BUDGET_THRESHOLD;
if (cache_over_budget_threshold || RESOURCE_RELOADING) { if (cache_over_budget_threshold || RESOURCE_RELOADING) {
__profscope(eviction_scan); __profscope(Evictor scan);
for (u64 i = 0; i < CACHE_BINS_COUNT; ++i) { for (u64 i = 0; i < CACHE_BINS_COUNT; ++i) {
struct cache_bin *bin = &G.cache.bins[i]; struct cache_bin *bin = &G.cache.bins[i];
struct sys_lock bin_lock = sys_mutex_lock_s(bin->mutex); struct sys_lock bin_lock = sys_mutex_lock_s(bin->mutex);
@ -1298,14 +1284,14 @@ INTERNAL SYS_THREAD_DEF(sprite_evictor_thread_entry_point, arg)
/* Sort evict nodes */ /* Sort evict nodes */
{ {
__profscope(eviction_sort); __profscope(Evictor sort);
merge_sort(evict_array, evict_array_count, sizeof(*evict_array), evict_sort, NULL); merge_sort(evict_array, evict_array_count, sizeof(*evict_array), evict_sort, NULL);
} }
/* Remove evictable nodes from cache until under budget */ /* Remove evictable nodes from cache until under budget */
struct evict_node *first_evicted = NULL; struct evict_node *first_evicted = NULL;
{ {
__profscope(eviction_cache_removal); __profscope(Evictor cache removal);
b32 stop_evicting = false; b32 stop_evicting = false;
for (u64 i = 0; i < evict_array_count && !stop_evicting; ++i) { for (u64 i = 0; i < evict_array_count && !stop_evicting; ++i) {
struct evict_node *en = &evict_array[i]; struct evict_node *en = &evict_array[i];
@ -1351,7 +1337,7 @@ INTERNAL SYS_THREAD_DEF(sprite_evictor_thread_entry_point, arg)
if (first_evicted) { if (first_evicted) {
/* Release evicted node memory */ /* Release evicted node memory */
{ {
__profscope(eviction_memory_release); __profscope(Evictor memory release);
for (struct evict_node *en = first_evicted; en; en = en->next_evicted) { for (struct evict_node *en = first_evicted; en; en = en->next_evicted) {
struct cache_entry *n = en->cache_entry; struct cache_entry *n = en->cache_entry;
if (n->kind == CACHE_ENTRY_KIND_TEXTURE && n->texture->valid) { if (n->kind == CACHE_ENTRY_KIND_TEXTURE && n->texture->valid) {
@ -1363,7 +1349,7 @@ INTERNAL SYS_THREAD_DEF(sprite_evictor_thread_entry_point, arg)
/* Add evicted nodes to free list */ /* Add evicted nodes to free list */
{ {
__profscope(eviction_free_list_append); __profscope(Evictor free list append);
struct sys_lock pool_lock = sys_mutex_lock_e(G.cache.entry_pool_mutex); struct sys_lock pool_lock = sys_mutex_lock_e(G.cache.entry_pool_mutex);
for (struct evict_node *en = first_evicted; en; en = en->next_evicted) { for (struct evict_node *en = first_evicted; en; en = en->next_evicted) {
struct cache_entry *n = en->cache_entry; struct cache_entry *n = en->cache_entry;
@ -1376,9 +1362,28 @@ INTERNAL SYS_THREAD_DEF(sprite_evictor_thread_entry_point, arg)
} }
atomic_i32_eval_add(&G.evictor_cycle, 1); atomic_i32_eval_add(&G.evictor_cycle, 1);
scratch_end(scratch); scratch_end(scratch);
}
/* Wait */ }
sys_condition_variable_wait_time(G.evictor_cv, &evictor_lock, SECONDS_FROM_NS(EVICTOR_CYCLE_INTERVAL_NS));
/* NOTE:
* A cache node is safe from eviction as long as:
* - Its bin mutex is locked
* - Any references are held to the node (its refcount > 0)
*
* An attempt to evict a cache node will occur when:
* - Its refcount = 0 and
* - The cache is over its memory budget and the node's last reference is longer ago than the grace period
* - Resource reloading is enabled and the node is out of date due to a change to its original resource file
*/
INTERNAL SYS_THREAD_DEF(sprite_evictor_scheduler_thread_entry_point, arg)
{
(UNUSED)arg;
struct sys_lock evictor_lock = sys_mutex_lock_e(G.evictor_scheduler_mutex);
while (!G.evictor_scheduler_shutdown) {
job_dispatch_wait(1, sprite_evictor_job, NULL);
sys_condition_variable_wait_time(G.evictor_scheduler_shutdown_cv, &evictor_lock, SECONDS_FROM_NS(EVICTOR_CYCLE_INTERVAL_NS));
} }
sys_mutex_unlock(&evictor_lock); sys_mutex_unlock(&evictor_lock);
} }

View File

@ -282,6 +282,7 @@ struct sys_watch_info {
struct sys_watch_info_list { struct sys_watch_info_list {
struct sys_watch_info *first; struct sys_watch_info *first;
struct sys_watch_info *last; struct sys_watch_info *last;
u64 count;
}; };
struct sys_watch *sys_watch_alloc(struct string path); struct sys_watch *sys_watch_alloc(struct string path);

View File

@ -418,7 +418,7 @@ struct sys_file sys_file_open_read_wait(struct string path)
HANDLE handle; HANDLE handle;
while ((handle = CreateFileW(path_wstr, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) { while ((handle = CreateFileW(path_wstr, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
if (GetLastError() == ERROR_SHARING_VIOLATION) { if (GetLastError() == ERROR_SHARING_VIOLATION) {
__profscope(file_share_conflict_delay); __profscope(File share conflict delay);
Sleep(delay_ms); Sleep(delay_ms);
if (delay_ms < 1024) { if (delay_ms < 1024) {
delay_ms *= 2; delay_ms *= 2;
@ -800,11 +800,11 @@ struct sys_watch_info_list sys_watch_wait(struct arena *arena, struct sys_watch
if (list.last) { if (list.last) {
list.last->next = info; list.last->next = info;
info->prev = list.last; info->prev = list.last;
list.last = info;
} else { } else {
list.first = info; list.first = info;
list.last = info;
} }
list.last = info;
++list.count;
struct string16 name16 = ZI; struct string16 name16 = ZI;
name16.text = res->FileName; name16.text = res->FileName;
@ -856,6 +856,7 @@ struct sys_watch_info_list sys_watch_wait(struct arena *arena, struct sys_watch
} }
} }
} else if (wait_res == WAIT_OBJECT_0 + 1) { } else if (wait_res == WAIT_OBJECT_0 + 1) {
ResetEvent(w32_watch->wake_handle);
done = true; done = true;
} else { } else {
ASSERT(false); ASSERT(false);
@ -886,6 +887,7 @@ struct sys_watch_info_list sys_watch_info_copy(struct arena *arena, struct sys_w
dst_list.first = dst; dst_list.first = dst;
dst_list.last = dst; dst_list.last = dst;
} }
dst_list.count = src_list.count;
} }
return dst_list; return dst_list;
} }
@ -1634,6 +1636,7 @@ void sys_mutex_release(struct sys_mutex *mutex)
struct sys_lock sys_mutex_lock_e(struct sys_mutex *mutex) struct sys_lock sys_mutex_lock_e(struct sys_mutex *mutex)
{ {
__prof;
struct win32_mutex *m = (struct win32_mutex *)mutex; struct win32_mutex *m = (struct win32_mutex *)mutex;
__proflock_before_exclusive_lock(m->profiling_ctx); __proflock_before_exclusive_lock(m->profiling_ctx);
AcquireSRWLockExclusive((SRWLOCK *)&m->srwlock); AcquireSRWLockExclusive((SRWLOCK *)&m->srwlock);
@ -1650,6 +1653,7 @@ struct sys_lock sys_mutex_lock_e(struct sys_mutex *mutex)
struct sys_lock sys_mutex_lock_s(struct sys_mutex *mutex) struct sys_lock sys_mutex_lock_s(struct sys_mutex *mutex)
{ {
__prof;
struct win32_mutex *m = (struct win32_mutex *)mutex; struct win32_mutex *m = (struct win32_mutex *)mutex;
__proflock_before_shared_lock(m->profiling_ctx); __proflock_before_shared_lock(m->profiling_ctx);
AcquireSRWLockShared((SRWLOCK *)&m->srwlock); AcquireSRWLockShared((SRWLOCK *)&m->srwlock);
@ -1664,6 +1668,7 @@ struct sys_lock sys_mutex_lock_s(struct sys_mutex *mutex)
void sys_mutex_unlock(struct sys_lock *lock) void sys_mutex_unlock(struct sys_lock *lock)
{ {
__prof;
struct win32_mutex *m = (struct win32_mutex *)lock->mutex; struct win32_mutex *m = (struct win32_mutex *)lock->mutex;
#if RTC #if RTC
atomic_i64_eval_add(&m->count, -1); atomic_i64_eval_add(&m->count, -1);
@ -1743,6 +1748,7 @@ void sys_condition_variable_release(struct sys_condition_variable *sys_cv)
void sys_condition_variable_wait(struct sys_condition_variable *sys_cv, struct sys_lock *lock) void sys_condition_variable_wait(struct sys_condition_variable *sys_cv, struct sys_lock *lock)
{ {
__prof;
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv; struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
struct win32_mutex *m = (struct win32_mutex *)lock->mutex; struct win32_mutex *m = (struct win32_mutex *)lock->mutex;
b32 exclusive = lock->exclusive; b32 exclusive = lock->exclusive;
@ -1780,6 +1786,7 @@ void sys_condition_variable_wait(struct sys_condition_variable *sys_cv, struct s
void sys_condition_variable_wait_time(struct sys_condition_variable *sys_cv, struct sys_lock *lock, f64 seconds) void sys_condition_variable_wait_time(struct sys_condition_variable *sys_cv, struct sys_lock *lock, f64 seconds)
{ {
__prof;
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv; struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
struct win32_mutex *m = (struct win32_mutex *)lock->mutex; struct win32_mutex *m = (struct win32_mutex *)lock->mutex;
b32 exclusive = lock->exclusive; b32 exclusive = lock->exclusive;
@ -1818,6 +1825,7 @@ void sys_condition_variable_wait_time(struct sys_condition_variable *sys_cv, str
void sys_condition_variable_signal(struct sys_condition_variable *sys_cv, u32 count) void sys_condition_variable_signal(struct sys_condition_variable *sys_cv, u32 count)
{ {
__prof;
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv; struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
/* Windows will wake all waiters if many single-wakes occur anyway, so we /* Windows will wake all waiters if many single-wakes occur anyway, so we
* might as well wake all ourselves. * might as well wake all ourselves.
@ -1833,6 +1841,7 @@ void sys_condition_variable_signal(struct sys_condition_variable *sys_cv, u32 co
void sys_condition_variable_broadcast(struct sys_condition_variable *sys_cv) void sys_condition_variable_broadcast(struct sys_condition_variable *sys_cv)
{ {
__prof;
struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv; struct win32_condition_variable *cv = (struct win32_condition_variable *)sys_cv;
WakeAllConditionVariable(&cv->condition_variable); WakeAllConditionVariable(&cv->condition_variable);
} }
@ -2232,7 +2241,7 @@ INTERNAL void win32_precise_sleep_timer(f64 seconds, HANDLE timer)
i64 max_ticks = (i64)scheduler_period_ms * 9500; i64 max_ticks = (i64)scheduler_period_ms * 9500;
while (true) { while (true) {
__profscope(win32_sleep_part); __profscope(Sleep part);
/* Break sleep up into parts that are lower than scheduler period */ /* Break sleep up into parts that are lower than scheduler period */
f64 remaining_seconds = (f64)(target_qpc - qpc.QuadPart) / (f64)qpc_per_second; f64 remaining_seconds = (f64)(target_qpc - qpc.QuadPart) / (f64)qpc_per_second;
i64 sleep_ticks = (i64)((remaining_seconds - tolerance) * 10000000); i64 sleep_ticks = (i64)((remaining_seconds - tolerance) * 10000000);
@ -2248,7 +2257,7 @@ INTERNAL void win32_precise_sleep_timer(f64 seconds, HANDLE timer)
/* Spin for any remaining time */ /* Spin for any remaining time */
{ {
__profscope(sleep_spin); __profscope(Sleep spin);
while (qpc.QuadPart < target_qpc) { while (qpc.QuadPart < target_qpc) {
YieldProcessor(); YieldProcessor();
QueryPerformanceCounter(&qpc); QueryPerformanceCounter(&qpc);
@ -2276,18 +2285,14 @@ INTERNAL void win32_precise_sleep_legacy(f64 seconds)
f64 sleep_ms = (seconds * 1000) - tolerance; f64 sleep_ms = (seconds * 1000) - tolerance;
i32 sleep_slices = (i32)(sleep_ms / scheduler_period_ms); i32 sleep_slices = (i32)(sleep_ms / scheduler_period_ms);
if (sleep_slices > 0) { if (sleep_slices > 0) {
__profscope(win32_sleep); __profscope(Legacy sleep part);
Sleep((DWORD)sleep_slices * scheduler_period_ms); Sleep((DWORD)sleep_slices * scheduler_period_ms);
} }
QueryPerformanceCounter(&qpc);
{
__profscope(win32_qpc);
QueryPerformanceCounter(&qpc);
}
/* Spin for any remaining time */ /* Spin for any remaining time */
{ {
__profscope(sleep_spin); __profscope(Legacy sleep spin);
while (qpc.QuadPart < target_qpc) { while (qpc.QuadPart < target_qpc) {
YieldProcessor(); YieldProcessor();
QueryPerformanceCounter(&qpc); QueryPerformanceCounter(&qpc);

View File

@ -63,7 +63,7 @@ volatile void *_thread_local_var_eval(struct thread_local_var_meta *meta)
{ {
u64 id_plus_one = atomic_u64_eval(&meta->id_plus_one); u64 id_plus_one = atomic_u64_eval(&meta->id_plus_one);
if (id_plus_one == 0) { if (id_plus_one == 0) {
__profscope(_thread_local_var_eval__REGISTER); __profscope(Register thread local var);
metas_lock(); metas_lock();
{ {
id_plus_one = atomic_u64_eval(&meta->id_plus_one); /* Reevaluate now that we've locked */ id_plus_one = atomic_u64_eval(&meta->id_plus_one); /* Reevaluate now that we've locked */
@ -89,7 +89,7 @@ volatile void *_thread_local_var_eval(struct thread_local_var_meta *meta)
/* Allocate var for thread if unallocated */ /* Allocate var for thread if unallocated */
if (!data) { if (!data) {
__profscope(_thread_local_var_eval__ALLOC); __profscope(Alloc thread local var);
/* Allocate */ /* Allocate */
arena_align(t->arena, meta->align); arena_align(t->arena, meta->align);
data = arena_push_array_no_zero(t->arena, u8, meta->size); data = arena_push_array_no_zero(t->arena, u8, meta->size);

View File

@ -1162,7 +1162,7 @@ INTERNAL void user_update(void)
{ {
/* Copy valid entities */ /* Copy valid entities */
{ {
__profscope(copy_sprites_for_sorting); __profscope(Build ents list for sorting);
for (u64 ent_index = 0; ent_index < G.ss_blended->num_ents_reserved; ++ent_index) { for (u64 ent_index = 0; ent_index < G.ss_blended->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &G.ss_blended->ents[ent_index]; struct sim_ent *ent = &G.ss_blended->ents[ent_index];
if (sim_ent_is_valid_and_active(ent)) { if (sim_ent_is_valid_and_active(ent)) {
@ -1173,7 +1173,7 @@ INTERNAL void user_update(void)
} }
/* Sort */ /* Sort */
{ {
__profscope(sort_sprites); __profscope(Sort ents);
merge_sort(sorted, sorted_count, sizeof(*sorted), ent_draw_order_cmp, NULL); merge_sort(sorted, sorted_count, sizeof(*sorted), ent_draw_order_cmp, NULL);
} }
} }
@ -1183,7 +1183,7 @@ INTERNAL void user_update(void)
* ========================== */ * ========================== */
{ {
__profscope(draw_entities); __profscope(Draw entities);
for (u64 sorted_index = 0; sorted_index < sorted_count; ++sorted_index) { for (u64 sorted_index = 0; sorted_index < sorted_count; ++sorted_index) {
struct sim_ent *ent = sorted[sorted_index]; struct sim_ent *ent = sorted[sorted_index];
if (!sim_ent_is_valid_and_active(ent)) continue; if (!sim_ent_is_valid_and_active(ent)) continue;
@ -1709,7 +1709,7 @@ INTERNAL void user_update(void)
/* Draw crosshair or show cursor */ /* Draw crosshair or show cursor */
if (!G.debug_camera) { if (!G.debug_camera) {
__profscope(draw_crosshair); __profscope(Draw crosshair);
struct v2 crosshair_pos = G.user_cursor; struct v2 crosshair_pos = G.user_cursor;
struct sprite_tag crosshair_tag = sprite_tag_from_path(LIT("sprite/crosshair.ase")); struct sprite_tag crosshair_tag = sprite_tag_from_path(LIT("sprite/crosshair.ase"));
@ -1726,7 +1726,7 @@ INTERNAL void user_update(void)
sys_window_cursor_hide(G.window); sys_window_cursor_hide(G.window);
sys_window_cursor_enable_clip(G.window, cursor_clip); sys_window_cursor_enable_clip(G.window, cursor_clip);
} else { } else {
__profscope(update_window_cursor); __profscope(Update windows cursor);
sys_window_cursor_disable_clip(G.window); sys_window_cursor_disable_clip(G.window);
sys_window_cursor_show(G.window); sys_window_cursor_show(G.window);
} }
@ -2055,7 +2055,7 @@ INTERNAL void user_update(void)
* ========================== */ * ========================== */
{ {
__profscope(render); __profscope(Render);
struct rect user_viewport = RECT_FROM_V2(V2(0, 0), G.user_size); struct rect user_viewport = RECT_FROM_V2(V2(0, 0), G.user_size);
struct v2i32 user_resolution = v2_round_to_int(user_viewport.size); struct v2i32 user_resolution = v2_round_to_int(user_viewport.size);