transfered from codeberg
This commit is contained in:
@@ -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(¤t_active_job))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
struct chunk_struct *current_chunk = current_active_job.chunk;
|
||||
if (current_chunk == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (atomic_load(¤t_chunk->marked_for_unload))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_static_step_chunk_state_machine_once(current_chunk, world_context);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user