transfered from codeberg

This commit is contained in:
2026-03-26 14:46:39 -05:00
parent 630f28bb7e
commit 5ed2173793
136 changed files with 14932 additions and 0 deletions

View File

@@ -0,0 +1,184 @@
#include "private_chunk_scheduler.h"
#include "chunk.h"
#include "chunk_mesh_builder.h"
#include "sunlight.h"
#include "terrain.h"
#include "world.h"
#include <dynamic_list.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
_chunk_job_struct _scheduler_job_queue[maximum_threads_allowed];
pthread_t _private_scheduler_worker_thread;
pthread_mutex_t _private_scheduler_job_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t _private_scheduler_job_condition = PTHREAD_COND_INITIALIZER;
bool _private_scheduler_is_currently_running = false;
// Static functions
static uint16_t _static_scheduler_job_head_index = 0;
static uint16_t _static_scheduler_job_tail_index = 0;
static bool _static_is_job_queue_empty(void);
static bool _static_is_job_queue_full(void);
static bool _static_pop_chunk_from_job_queue(_chunk_job_struct *output_job);
static void _static_step_chunk_state_machine_once(struct chunk_struct* chunk_to_process,
struct world_struct* world_context);
static bool _static_is_job_queue_empty(void)
{
return _static_scheduler_job_head_index == _static_scheduler_job_tail_index;
}
static bool _static_is_job_queue_full(void)
{
return ((_static_scheduler_job_tail_index + 1) %
maximum_threads_allowed) ==
_static_scheduler_job_head_index;
}
static bool _static_pop_chunk_from_job_queue(_chunk_job_struct *output_job)
{
pthread_mutex_lock(&_private_scheduler_job_mutex);
while (_static_is_job_queue_empty() && _private_scheduler_is_currently_running)
{
pthread_cond_wait(&_private_scheduler_job_condition,
&_private_scheduler_job_mutex);
}
if (!_private_scheduler_is_currently_running)
{
pthread_mutex_unlock(&_private_scheduler_job_mutex);
return false;
}
*output_job = _scheduler_job_queue[_static_scheduler_job_head_index];
_static_scheduler_job_head_index =
(uint16_t)(_static_scheduler_job_head_index + 1) %
maximum_threads_allowed;
pthread_mutex_unlock(&_private_scheduler_job_mutex);
return true;
}
static void _static_step_chunk_state_machine_once(struct chunk_struct* chunk_to_process,
struct world_struct* world)
{
puts("scheduler run");
int expected = state_needs_data;
if (atomic_compare_exchange_strong(&chunk_to_process->build_state,
&expected,
state_getting_data)
||
atomic_compare_exchange_strong(&chunk_to_process->build_state,
&(int){state_needs_terrain},
state_getting_terrain))
{
puts("getting data run");
generate_terrain(chunk_to_process,
&chunk_to_process->position);
atomic_store(&chunk_to_process->build_state,
state_needs_lighting);
_private_push_chunk_to_job_queue(chunk_to_process);
}
expected = state_needs_lighting;
if (atomic_compare_exchange_strong(&chunk_to_process->build_state,
&expected,
state_getting_lighting))
{
puts("getting lighting run");
//apply_sunlight(world_context, current_chunk);
atomic_store(&chunk_to_process->build_state, state_needs_mesh);
_private_push_chunk_to_job_queue(chunk_to_process);
}
expected = state_needs_mesh;
if (atomic_compare_exchange_strong(&chunk_to_process->build_state,
&expected,
state_getting_mesh))
{
puts("getting mesh run");
build_chunk_mesh(chunk_to_process, world);
atomic_store(&chunk_to_process->build_state, state_need_upload_to_gpu);
_private_push_chunk_to_job_queue(chunk_to_process);
}
expected = state_need_upload_to_gpu;
if (atomic_compare_exchange_strong(&chunk_to_process->build_state,
&expected,
state_chunk_pending_upload))
{
uint32_t index_awaiting_draw =
atomic_load(&world->count_chunks_awaiting_draw);
printf("test");
sem_wait(&world->semaphore_free_slots_in_awaiting_draw);
printf("test");
world->chunks_awaiting_draw[index_awaiting_draw] = chunk_to_process;
atomic_fetch_add_explicit(&world->count_chunks_awaiting_draw,
1,
memory_order_acq_rel);
atomic_fetch_sub_explicit(&chunk_to_process->reference_counter,
1,
memory_order_acquire);
}
}
bool _private_push_chunk_to_job_queue(struct chunk_struct *chunk)
{
bool push_was_successful = false;
pthread_mutex_lock(&_private_scheduler_job_mutex);
if (!_static_is_job_queue_full())
{
_scheduler_job_queue[_static_scheduler_job_tail_index].chunk = chunk;
_static_scheduler_job_tail_index =
(uint16_t)(_static_scheduler_job_tail_index + 1) %
maximum_threads_allowed;
pthread_cond_signal(&_private_scheduler_job_condition);
push_was_successful = true;
}
pthread_mutex_unlock(&_private_scheduler_job_mutex);
return push_was_successful;
}
void* _private_chunk_worker_thread_main_loop(void* argument)
{
struct world_struct *world_context = (struct world_struct*)argument;
while (true)
{
_chunk_job_struct current_active_job;
if (!_static_pop_chunk_from_job_queue(&current_active_job))
{
break;
}
struct chunk_struct *current_chunk = current_active_job.chunk;
if (current_chunk == NULL)
{
continue;
}
if (atomic_load(&current_chunk->marked_for_unload))
{
continue;
}
_static_step_chunk_state_machine_once(current_chunk, world_context);
}
return NULL;
}

View File

@@ -0,0 +1,25 @@
#ifndef private_chunk_scheduler_h
#define private_chunk_scheduler_h
#include <pthread.h>
#include <stdbool.h>
struct chunk_struct;
typedef struct _chunk_job_struct
{
struct chunk_struct *chunk;
} _chunk_job_struct;
#define maximum_threads_allowed 256
extern pthread_t _private_scheduler_worker_thread;
extern pthread_mutex_t _private_scheduler_job_mutex;
extern pthread_cond_t _private_scheduler_job_condition;
extern bool _private_scheduler_is_currently_running;
bool _private_push_chunk_to_job_queue(struct chunk_struct* chunk);
void* _private_chunk_worker_thread_main_loop(void* argument);
#endif

View File

@@ -0,0 +1,33 @@
#include "chunk_scheduler.h"
#include "_internal/private_chunk_scheduler.h"
#include "chunk.h"
void start_chunk_scheduler(struct world_struct* world)
{
_private_scheduler_is_currently_running = true;
pthread_create(&_private_scheduler_worker_thread,
NULL,
_private_chunk_worker_thread_main_loop,
world);
}
void stop_chunk_scheduler(void)
{
pthread_mutex_lock(&_private_scheduler_job_mutex);
_private_scheduler_is_currently_running = false;
pthread_cond_signal(&_private_scheduler_job_condition);
pthread_mutex_unlock(&_private_scheduler_job_mutex);
pthread_join(_private_scheduler_worker_thread, NULL);
}
void schedule_chunk_job(struct chunk_struct *chunk)
{
int expected = state_new;
if (atomic_compare_exchange_strong(&chunk->build_state,
&expected,
state_needs_data))
{
_private_push_chunk_to_job_queue(chunk);
}
}

View File

@@ -0,0 +1,25 @@
#ifndef chunk_scheduler_h
#define chunk_scheduler_h
struct chunk_struct;
struct world_struct;
/**
* Initializes the threading primitives and launches the background worker
* thread responsible for processing the chunk mesh generation queue.
*/
void start_chunk_scheduler(struct world_struct* world);
/**
* Signals the worker thread to terminate, waits for it to finish its
* current task, and cleans up the thread handle.
*/
void stop_chunk_scheduler(void);
/**
* Places a chunk into the asynchronous build queue if it is not already
* being processed or waiting in the queue.
*/
void schedule_chunk_job(struct chunk_struct *chunk);
#endif