switched app.step over to a big input struct so that the signature does not have to change if I want to pass in more parameters in the future
This commit is contained in:
parent
c56703cbc8
commit
93a1d3931f
60
4ed.cpp
60
4ed.cpp
|
@ -3637,6 +3637,8 @@ App_Step_Sig(app_step){
|
|||
target->partition = &models->mem.part;
|
||||
|
||||
// NOTE(allen): OS clipboard event handling
|
||||
String clipboard = input->clipboard;
|
||||
|
||||
if (clipboard.str){
|
||||
String *dest = working_set_next_clipboard_string(&models->mem.general, &models->working_set, clipboard.size);
|
||||
dest->size = eol_convert_in(dest->str, clipboard.str, clipboard.size);
|
||||
|
@ -3689,18 +3691,18 @@ App_Step_Sig(app_step){
|
|||
|
||||
// NOTE(allen): prepare input information
|
||||
Key_Summary key_summary = {0};
|
||||
for (i32 i = 0; i < input->press_count; ++i){
|
||||
key_summary.keys[key_summary.count++] = input->press[i];
|
||||
for (i32 i = 0; i < input->keys.press_count; ++i){
|
||||
key_summary.keys[key_summary.count++] = input->keys.press[i];
|
||||
}
|
||||
for (i32 i = 0; i < input->hold_count; ++i){
|
||||
key_summary.keys[key_summary.count++] = input->hold[i];
|
||||
for (i32 i = 0; i < input->keys.hold_count; ++i){
|
||||
key_summary.keys[key_summary.count++] = input->keys.hold[i];
|
||||
}
|
||||
|
||||
mouse->wheel = -mouse->wheel;
|
||||
input->mouse.wheel = -input->mouse.wheel;
|
||||
|
||||
// NOTE(allen): detect mouse hover status
|
||||
i32 mx = mouse->x;
|
||||
i32 my = mouse->y;
|
||||
i32 mx = input->mouse.x;
|
||||
i32 my = input->mouse.y;
|
||||
b32 mouse_in_edit_area = 0;
|
||||
b32 mouse_in_margin_area = 0;
|
||||
Panel *mouse_panel, *used_panels;
|
||||
|
@ -3787,7 +3789,7 @@ App_Step_Sig(app_step){
|
|||
}
|
||||
|
||||
// NOTE(allen): update child processes
|
||||
if (dt > 0){
|
||||
if (input->dt > 0){
|
||||
Temp_Memory temp = begin_temp_memory(&models->mem.part);
|
||||
u32 max = Kbytes(32);
|
||||
char *dest = push_array(&models->mem.part, char, max);
|
||||
|
@ -3830,7 +3832,7 @@ App_Step_Sig(app_step){
|
|||
Temp_Memory param_stack_temp = begin_temp_memory(&models->mem.part);
|
||||
cmd->part = partition_sub_part(&models->mem.part, 16 << 10);
|
||||
|
||||
if (first_step){
|
||||
if (input->first_step){
|
||||
|
||||
#if 0
|
||||
{
|
||||
|
@ -3954,7 +3956,7 @@ App_Step_Sig(app_step){
|
|||
}
|
||||
|
||||
// NOTE(allen): process the command_coroutine if it is unfinished
|
||||
Available_Input available_input = init_available_input(&key_summary, mouse);
|
||||
Available_Input available_input = init_available_input(&key_summary, &input->mouse);
|
||||
|
||||
// NOTE(allen): Keyboard input to command coroutine.
|
||||
if (models->command_coroutine != 0){
|
||||
|
@ -4029,7 +4031,7 @@ App_Step_Sig(app_step){
|
|||
|
||||
User_Input user_in;
|
||||
user_in.type = UserInputMouse;
|
||||
user_in.mouse = *mouse;
|
||||
user_in.mouse = input->mouse;
|
||||
user_in.command = 0;
|
||||
user_in.abort = 0;
|
||||
|
||||
|
@ -4041,7 +4043,7 @@ App_Step_Sig(app_step){
|
|||
consume_input(&available_input, Input_MouseMove);
|
||||
}
|
||||
|
||||
if (mouse->press_l || mouse->release_l || mouse->l){
|
||||
if (input->mouse.press_l || input->mouse.release_l || input->mouse.l){
|
||||
if (abort_flags & EventOnLeftButton){
|
||||
user_in.abort = 1;
|
||||
}
|
||||
|
@ -4051,7 +4053,7 @@ App_Step_Sig(app_step){
|
|||
}
|
||||
}
|
||||
|
||||
if (mouse->press_r || mouse->release_r || mouse->r){
|
||||
if (input->mouse.press_r || input->mouse.release_r || input->mouse.r){
|
||||
if (abort_flags & EventOnRightButton){
|
||||
user_in.abort = 1;
|
||||
}
|
||||
|
@ -4061,7 +4063,7 @@ App_Step_Sig(app_step){
|
|||
}
|
||||
}
|
||||
|
||||
if (mouse->wheel != 0){
|
||||
if (input->mouse.wheel != 0){
|
||||
if (abort_flags & EventOnWheel){
|
||||
user_in.abort = 1;
|
||||
}
|
||||
|
@ -4095,12 +4097,12 @@ App_Step_Sig(app_step){
|
|||
// NOTE(allen): pass raw input to the panels
|
||||
|
||||
Input_Summary dead_input = {};
|
||||
dead_input.mouse.x = mouse->x;
|
||||
dead_input.mouse.y = mouse->y;
|
||||
dead_input.mouse.x = input->mouse.x;
|
||||
dead_input.mouse.y = input->mouse.y;
|
||||
|
||||
Input_Summary active_input = {};
|
||||
active_input.mouse.x = mouse->x;
|
||||
active_input.mouse.y = mouse->y;
|
||||
active_input.mouse.x = input->mouse.x;
|
||||
active_input.mouse.y = input->mouse.y;
|
||||
|
||||
active_input.keys = get_key_data(&available_input);
|
||||
|
||||
|
@ -4110,7 +4112,7 @@ App_Step_Sig(app_step){
|
|||
Panel *panel = 0, *used_panels = 0;
|
||||
View *view = 0, *active_view = 0;
|
||||
b32 active = 0;
|
||||
Input_Summary input = {0};
|
||||
Input_Summary summary = {0};
|
||||
Input_Process_Result result = {0};
|
||||
|
||||
active_view = cmd->panel->view;
|
||||
|
@ -4118,8 +4120,8 @@ App_Step_Sig(app_step){
|
|||
for (dll_items(panel, used_panels)){
|
||||
view = panel->view;
|
||||
active = (panel == cmd->panel);
|
||||
input = (active)?(active_input):(dead_input);
|
||||
if (step_file_view(system, view, active_view, input)){
|
||||
summary = (active)?(active_input):(dead_input);
|
||||
if (step_file_view(system, view, active_view, summary)){
|
||||
app_result.animating = 1;
|
||||
}
|
||||
}
|
||||
|
@ -4128,9 +4130,9 @@ App_Step_Sig(app_step){
|
|||
view = panel->view;
|
||||
Assert(view->current_scroll);
|
||||
active = (panel == cmd->panel);
|
||||
input = (active)?(active_input):(dead_input);
|
||||
if (panel == mouse_panel && !mouse->out_of_window){
|
||||
input.mouse = mouse_state;
|
||||
summary = (active)?(active_input):(dead_input);
|
||||
if (panel == mouse_panel && !input->mouse.out_of_window){
|
||||
summary.mouse = mouse_state;
|
||||
}
|
||||
|
||||
|
||||
|
@ -4138,7 +4140,7 @@ App_Step_Sig(app_step){
|
|||
// TODO(allen): I feel like the scroll context should actually not
|
||||
// be allowed to change in here at all.
|
||||
result = do_input_file_view(system, exchange, view, panel->inner, active,
|
||||
&input, *vars, view->scroll_region);
|
||||
&summary, *vars, view->scroll_region);
|
||||
if (result.is_animating){
|
||||
app_result.animating = 1;
|
||||
}
|
||||
|
@ -4219,7 +4221,7 @@ App_Step_Sig(app_step){
|
|||
update_command_data(vars, cmd);
|
||||
|
||||
// NOTE(allen): initialize message
|
||||
if (first_step){
|
||||
if (input->first_step){
|
||||
String welcome =
|
||||
make_lit_string("Welcome to " VERSION "\n"
|
||||
"If you're new to 4coder there's no tutorial yet :(\n"
|
||||
|
@ -4256,7 +4258,7 @@ App_Step_Sig(app_step){
|
|||
switch (vars->state){
|
||||
case APP_STATE_EDIT:
|
||||
{
|
||||
if (mouse->press_l && mouse_on_divider){
|
||||
if (input->mouse.press_l && mouse_on_divider){
|
||||
vars->state = APP_STATE_RESIZING;
|
||||
Divider_And_ID div = layout_get_divider(&models->layout, mouse_divider_id);
|
||||
vars->resizing.divider = div.divider;
|
||||
|
@ -4323,7 +4325,7 @@ App_Step_Sig(app_step){
|
|||
|
||||
case APP_STATE_RESIZING:
|
||||
{
|
||||
if (mouse->l){
|
||||
if (input->mouse.l){
|
||||
Panel_Divider *divider = vars->resizing.divider;
|
||||
if (divider->v_divider){
|
||||
divider->pos = mx;
|
||||
|
@ -4347,7 +4349,7 @@ App_Step_Sig(app_step){
|
|||
}break;
|
||||
}
|
||||
|
||||
if (mouse_in_edit_area && mouse_panel != 0 && mouse->press_l){
|
||||
if (mouse_in_edit_area && mouse_panel != 0 && input->mouse.press_l){
|
||||
models->layout.active_panel = (i32)(mouse_panel - models->layout.panels);
|
||||
}
|
||||
|
||||
|
|
16
4ed.h
16
4ed.h
|
@ -81,6 +81,7 @@ struct Plat_Settings{
|
|||
|
||||
typedef App_Read_Command_Line_Sig(App_Read_Command_Line);
|
||||
|
||||
|
||||
#define App_Init_Sig(name) void \
|
||||
name(System_Functions *system, \
|
||||
Render_Target *target, \
|
||||
|
@ -92,6 +93,7 @@ name(System_Functions *system, \
|
|||
|
||||
typedef App_Init_Sig(App_Init);
|
||||
|
||||
|
||||
enum Application_Mouse_Cursor{
|
||||
APP_MOUSE_CURSOR_DEFAULT,
|
||||
APP_MOUSE_CURSOR_ARROW,
|
||||
|
@ -110,19 +112,25 @@ struct Application_Step_Result{
|
|||
b32 animating;
|
||||
};
|
||||
|
||||
struct Application_Step_Input{
|
||||
b32 first_step;
|
||||
f32 dt;
|
||||
Key_Input_Data keys;
|
||||
Mouse_State mouse;
|
||||
String clipboard;
|
||||
};
|
||||
|
||||
#define App_Step_Sig(name) void \
|
||||
name(System_Functions *system, \
|
||||
Key_Input_Data *input, \
|
||||
Mouse_State *mouse, \
|
||||
Render_Target *target, \
|
||||
Application_Memory *memory, \
|
||||
Exchange *exchange, \
|
||||
String clipboard, \
|
||||
f32 dt, b32 first_step, \
|
||||
Application_Step_Input *input, \
|
||||
Application_Step_Result *result)
|
||||
|
||||
typedef App_Step_Sig(App_Step);
|
||||
|
||||
|
||||
struct App_Functions{
|
||||
App_Read_Command_Line *read_command_line;
|
||||
App_Init *init;
|
||||
|
|
586
win32_4ed.cpp
586
win32_4ed.cpp
|
@ -89,8 +89,6 @@ struct Win32_Input_Chunk_Persistent{
|
|||
i32 mouse_x, mouse_y;
|
||||
b8 mouse_l, mouse_r;
|
||||
|
||||
b8 keep_playing;
|
||||
|
||||
Control_Keys controls;
|
||||
b8 control_keys[MDFR_INDEX_COUNT];
|
||||
};
|
||||
|
@ -124,13 +122,11 @@ struct Win32_Vars{
|
|||
DLL_Loaded app_dll;
|
||||
DLL_Loaded custom_dll;
|
||||
#endif
|
||||
|
||||
Plat_Settings settings;
|
||||
|
||||
|
||||
Thread_Group groups[THREAD_GROUP_COUNT];
|
||||
CRITICAL_SECTION locks[LOCK_COUNT];
|
||||
CRITICAL_SECTION DEBUG_sysmem_lock;
|
||||
Thread_Memory *thread_memory;
|
||||
Win32_Coroutine coroutine_data[18];
|
||||
Win32_Coroutine *coroutine_free;
|
||||
|
@ -161,6 +157,7 @@ struct Win32_Vars{
|
|||
|
||||
|
||||
#if FRED_INTERNAL
|
||||
CRITICAL_SECTION DEBUG_sysmem_lock;
|
||||
Sys_Bubble internal_bubble;
|
||||
#endif
|
||||
};
|
||||
|
@ -169,6 +166,11 @@ globalvar Win32_Vars win32vars;
|
|||
globalvar Application_Memory memory_vars;
|
||||
globalvar Exchange exchange_vars;
|
||||
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
internal HANDLE
|
||||
Win32Handle(Plat_Handle h){
|
||||
HANDLE result;
|
||||
|
@ -198,6 +200,7 @@ Win32Ptr(void *h){
|
|||
return(result);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Memory (not exposed to application, but needed in system_shared.cpp)
|
||||
//
|
||||
|
@ -259,8 +262,269 @@ INTERNAL_system_debug_message(char *message){
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// File
|
||||
// Multithreading
|
||||
//
|
||||
|
||||
internal
|
||||
Sys_Acquire_Lock_Sig(system_acquire_lock){
|
||||
EnterCriticalSection(&win32vars.locks[id]);
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Release_Lock_Sig(system_release_lock){
|
||||
LeaveCriticalSection(&win32vars.locks[id]);
|
||||
}
|
||||
|
||||
internal DWORD
|
||||
JobThreadProc(LPVOID lpParameter){
|
||||
Thread_Context *thread = (Thread_Context*)lpParameter;
|
||||
Work_Queue *queue = thread->queue;
|
||||
|
||||
for (;;){
|
||||
u32 read_index = queue->read_position;
|
||||
u32 write_index = queue->write_position;
|
||||
|
||||
if (read_index != write_index){
|
||||
u32 next_read_index = (read_index + 1) % JOB_ID_WRAP;
|
||||
u32 safe_read_index =
|
||||
InterlockedCompareExchange(&queue->read_position,
|
||||
next_read_index, read_index);
|
||||
|
||||
if (safe_read_index == read_index){
|
||||
Full_Job_Data *full_job = queue->jobs + (safe_read_index % QUEUE_WRAP);
|
||||
// NOTE(allen): This is interlocked so that it plays nice
|
||||
// with the cancel job routine, which may try to cancel this job
|
||||
// at the same time that we try to run it
|
||||
|
||||
i32 safe_running_thread =
|
||||
InterlockedCompareExchange(&full_job->running_thread,
|
||||
thread->id, THREAD_NOT_ASSIGNED);
|
||||
|
||||
if (safe_running_thread == THREAD_NOT_ASSIGNED){
|
||||
thread->job_id = full_job->id;
|
||||
thread->running = 1;
|
||||
Thread_Memory *thread_memory = 0;
|
||||
|
||||
// TODO(allen): remove memory_request
|
||||
if (full_job->job.memory_request != 0){
|
||||
thread_memory = win32vars.thread_memory + thread->id - 1;
|
||||
if (thread_memory->size < full_job->job.memory_request){
|
||||
if (thread_memory->data){
|
||||
Win32FreeMemory(thread_memory->data);
|
||||
}
|
||||
i32 new_size = LargeRoundUp(full_job->job.memory_request, Kbytes(4));
|
||||
thread_memory->data = Win32GetMemory(new_size);
|
||||
thread_memory->size = new_size;
|
||||
}
|
||||
}
|
||||
full_job->job.callback(&win32vars.system, thread, thread_memory,
|
||||
&exchange_vars.thread, full_job->job.data);
|
||||
PostMessage(win32vars.window_handle, WM_4coder_ANIMATE, 0, 0);
|
||||
full_job->running_thread = 0;
|
||||
thread->running = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
WaitForSingleObject(Win32Handle(queue->semaphore), INFINITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Post_Job_Sig(system_post_job){
|
||||
Work_Queue *queue = exchange_vars.thread.queues + group_id;
|
||||
|
||||
Assert((queue->write_position + 1) % QUEUE_WRAP != queue->read_position % QUEUE_WRAP);
|
||||
|
||||
b32 success = 0;
|
||||
u32 result = 0;
|
||||
while (!success){
|
||||
u32 write_index = queue->write_position;
|
||||
u32 next_write_index = (write_index + 1) % JOB_ID_WRAP;
|
||||
u32 safe_write_index =
|
||||
InterlockedCompareExchange(&queue->write_position,
|
||||
next_write_index, write_index);
|
||||
if (safe_write_index == write_index){
|
||||
result = write_index;
|
||||
write_index = write_index % QUEUE_WRAP;
|
||||
queue->jobs[write_index].job = job;
|
||||
queue->jobs[write_index].running_thread = THREAD_NOT_ASSIGNED;
|
||||
queue->jobs[write_index].id = result;
|
||||
success = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseSemaphore(Win32Handle(queue->semaphore), 1, 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO(allen): I would like to get rid of job canceling
|
||||
// but I still don't know what exactly I would do without it.
|
||||
internal
|
||||
Sys_Cancel_Job_Sig(system_cancel_job){
|
||||
Work_Queue *queue = exchange_vars.thread.queues + group_id;
|
||||
Thread_Group *group = win32vars.groups + group_id;
|
||||
|
||||
u32 job_index;
|
||||
u32 thread_id;
|
||||
Full_Job_Data *full_job;
|
||||
Thread_Context *thread;
|
||||
|
||||
job_index = job_id % QUEUE_WRAP;
|
||||
full_job = queue->jobs + job_index;
|
||||
|
||||
Assert(full_job->id == job_id);
|
||||
thread_id =
|
||||
InterlockedCompareExchange(&full_job->running_thread,
|
||||
0, THREAD_NOT_ASSIGNED);
|
||||
|
||||
if (thread_id != THREAD_NOT_ASSIGNED){
|
||||
system_acquire_lock(CANCEL_LOCK0 + thread_id - 1);
|
||||
thread = group->threads + thread_id - 1;
|
||||
TerminateThread(thread->handle, 0);
|
||||
u32 creation_flag = 0;
|
||||
thread->handle = CreateThread(0, 0, JobThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id);
|
||||
system_release_lock(CANCEL_LOCK0 + thread_id - 1);
|
||||
thread->running = 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
system_grow_thread_memory(Thread_Memory *memory){
|
||||
void *old_data;
|
||||
i32 old_size, new_size;
|
||||
|
||||
system_acquire_lock(CANCEL_LOCK0 + memory->id - 1);
|
||||
old_data = memory->data;
|
||||
old_size = memory->size;
|
||||
new_size = LargeRoundUp(memory->size*2, Kbytes(4));
|
||||
memory->data = system_get_memory(new_size);
|
||||
memory->size = new_size;
|
||||
if (old_data){
|
||||
memcpy(memory->data, old_data, old_size);
|
||||
system_free_memory(old_data);
|
||||
}
|
||||
system_release_lock(CANCEL_LOCK0 + memory->id - 1);
|
||||
}
|
||||
|
||||
#if FRED_INTERNAL
|
||||
internal void
|
||||
INTERNAL_get_thread_states(Thread_Group_ID id, bool8 *running, i32 *pending){
|
||||
Work_Queue *queue = exchange_vars.thread.queues + id;
|
||||
u32 write = queue->write_position;
|
||||
u32 read = queue->read_position;
|
||||
if (write < read) write += JOB_ID_WRAP;
|
||||
*pending = (i32)(write - read);
|
||||
|
||||
Thread_Group *group = win32vars.groups + id;
|
||||
for (i32 i = 0; i < group->count; ++i){
|
||||
running[i] = (group->threads[i].running != 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// Coroutines
|
||||
//
|
||||
|
||||
internal Win32_Coroutine*
|
||||
Win32AllocCoroutine(){
|
||||
Win32_Coroutine *result = win32vars.coroutine_free;
|
||||
Assert(result != 0);
|
||||
win32vars.coroutine_free = result->next;
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
Win32FreeCoroutine(Win32_Coroutine *data){
|
||||
data->next = win32vars.coroutine_free;
|
||||
win32vars.coroutine_free = data;
|
||||
}
|
||||
|
||||
internal void
|
||||
Win32CoroutineMain(void *arg_){
|
||||
Win32_Coroutine *c = (Win32_Coroutine*)arg_;
|
||||
c->coroutine.func(&c->coroutine);
|
||||
c->done = 1;
|
||||
Win32FreeCoroutine(c);
|
||||
SwitchToFiber(c->coroutine.yield_handle);
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Create_Coroutine_Sig(system_create_coroutine){
|
||||
Win32_Coroutine *c;
|
||||
Coroutine *coroutine;
|
||||
void *fiber;
|
||||
|
||||
c = Win32AllocCoroutine();
|
||||
c->done = 0;
|
||||
|
||||
coroutine = &c->coroutine;
|
||||
|
||||
fiber = CreateFiber(0, Win32CoroutineMain, coroutine);
|
||||
|
||||
coroutine->plat_handle = Win32Handle(fiber);
|
||||
coroutine->func = func;
|
||||
|
||||
return(coroutine);
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Launch_Coroutine_Sig(system_launch_coroutine){
|
||||
Win32_Coroutine *c = (Win32_Coroutine*)coroutine;
|
||||
void *fiber;
|
||||
|
||||
fiber = Win32Handle(coroutine->plat_handle);
|
||||
coroutine->yield_handle = GetCurrentFiber();
|
||||
coroutine->in = in;
|
||||
coroutine->out = out;
|
||||
|
||||
SwitchToFiber(fiber);
|
||||
|
||||
if (c->done){
|
||||
DeleteFiber(fiber);
|
||||
Win32FreeCoroutine(c);
|
||||
coroutine = 0;
|
||||
}
|
||||
|
||||
return(coroutine);
|
||||
}
|
||||
|
||||
Sys_Resume_Coroutine_Sig(system_resume_coroutine){
|
||||
Win32_Coroutine *c = (Win32_Coroutine*)coroutine;
|
||||
void *fiber;
|
||||
|
||||
Assert(c->done == 0);
|
||||
|
||||
coroutine->yield_handle = GetCurrentFiber();
|
||||
coroutine->in = in;
|
||||
coroutine->out = out;
|
||||
|
||||
fiber = Win32Ptr(coroutine->plat_handle);
|
||||
|
||||
SwitchToFiber(fiber);
|
||||
|
||||
if (c->done){
|
||||
DeleteFiber(fiber);
|
||||
Win32FreeCoroutine(c);
|
||||
coroutine = 0;
|
||||
}
|
||||
|
||||
return(coroutine);
|
||||
}
|
||||
|
||||
Sys_Yield_Coroutine_Sig(system_yield_coroutine){
|
||||
SwitchToFiber(coroutine->yield_handle);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Files
|
||||
//
|
||||
|
||||
internal
|
||||
|
@ -602,6 +866,7 @@ GET_4ED_PATH_SIG(system_get_4ed_path){
|
|||
return(system_get_binary_path(&str));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Clipboard
|
||||
//
|
||||
|
@ -646,263 +911,6 @@ Win32ReadClipboardContents(){
|
|||
return(result);
|
||||
}
|
||||
|
||||
//
|
||||
// Multithreading
|
||||
//
|
||||
|
||||
internal
|
||||
Sys_Acquire_Lock_Sig(system_acquire_lock){
|
||||
EnterCriticalSection(&win32vars.locks[id]);
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Release_Lock_Sig(system_release_lock){
|
||||
LeaveCriticalSection(&win32vars.locks[id]);
|
||||
}
|
||||
|
||||
internal DWORD
|
||||
JobThreadProc(LPVOID lpParameter){
|
||||
Thread_Context *thread = (Thread_Context*)lpParameter;
|
||||
Work_Queue *queue = thread->queue;
|
||||
|
||||
for (;;){
|
||||
u32 read_index = queue->read_position;
|
||||
u32 write_index = queue->write_position;
|
||||
|
||||
if (read_index != write_index){
|
||||
u32 next_read_index = (read_index + 1) % JOB_ID_WRAP;
|
||||
u32 safe_read_index =
|
||||
InterlockedCompareExchange(&queue->read_position,
|
||||
next_read_index, read_index);
|
||||
|
||||
if (safe_read_index == read_index){
|
||||
Full_Job_Data *full_job = queue->jobs + (safe_read_index % QUEUE_WRAP);
|
||||
// NOTE(allen): This is interlocked so that it plays nice
|
||||
// with the cancel job routine, which may try to cancel this job
|
||||
// at the same time that we try to run it
|
||||
|
||||
i32 safe_running_thread =
|
||||
InterlockedCompareExchange(&full_job->running_thread,
|
||||
thread->id, THREAD_NOT_ASSIGNED);
|
||||
|
||||
if (safe_running_thread == THREAD_NOT_ASSIGNED){
|
||||
thread->job_id = full_job->id;
|
||||
thread->running = 1;
|
||||
Thread_Memory *thread_memory = 0;
|
||||
|
||||
// TODO(allen): remove memory_request
|
||||
if (full_job->job.memory_request != 0){
|
||||
thread_memory = win32vars.thread_memory + thread->id - 1;
|
||||
if (thread_memory->size < full_job->job.memory_request){
|
||||
if (thread_memory->data){
|
||||
Win32FreeMemory(thread_memory->data);
|
||||
}
|
||||
i32 new_size = LargeRoundUp(full_job->job.memory_request, Kbytes(4));
|
||||
thread_memory->data = Win32GetMemory(new_size);
|
||||
thread_memory->size = new_size;
|
||||
}
|
||||
}
|
||||
full_job->job.callback(&win32vars.system, thread, thread_memory,
|
||||
&exchange_vars.thread, full_job->job.data);
|
||||
PostMessage(win32vars.window_handle, WM_4coder_ANIMATE, 0, 0);
|
||||
full_job->running_thread = 0;
|
||||
thread->running = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
WaitForSingleObject(Win32Handle(queue->semaphore), INFINITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Post_Job_Sig(system_post_job){
|
||||
Work_Queue *queue = exchange_vars.thread.queues + group_id;
|
||||
|
||||
Assert((queue->write_position + 1) % QUEUE_WRAP != queue->read_position % QUEUE_WRAP);
|
||||
|
||||
b32 success = 0;
|
||||
u32 result = 0;
|
||||
while (!success){
|
||||
u32 write_index = queue->write_position;
|
||||
u32 next_write_index = (write_index + 1) % JOB_ID_WRAP;
|
||||
u32 safe_write_index =
|
||||
InterlockedCompareExchange(&queue->write_position,
|
||||
next_write_index, write_index);
|
||||
if (safe_write_index == write_index){
|
||||
result = write_index;
|
||||
write_index = write_index % QUEUE_WRAP;
|
||||
queue->jobs[write_index].job = job;
|
||||
queue->jobs[write_index].running_thread = THREAD_NOT_ASSIGNED;
|
||||
queue->jobs[write_index].id = result;
|
||||
success = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseSemaphore(Win32Handle(queue->semaphore), 1, 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO(allen): I would like to get rid of job canceling
|
||||
// but I still don't know what exactly I would do without it.
|
||||
internal
|
||||
Sys_Cancel_Job_Sig(system_cancel_job){
|
||||
Work_Queue *queue = exchange_vars.thread.queues + group_id;
|
||||
Thread_Group *group = win32vars.groups + group_id;
|
||||
|
||||
u32 job_index;
|
||||
u32 thread_id;
|
||||
Full_Job_Data *full_job;
|
||||
Thread_Context *thread;
|
||||
|
||||
job_index = job_id % QUEUE_WRAP;
|
||||
full_job = queue->jobs + job_index;
|
||||
|
||||
Assert(full_job->id == job_id);
|
||||
thread_id =
|
||||
InterlockedCompareExchange(&full_job->running_thread,
|
||||
0, THREAD_NOT_ASSIGNED);
|
||||
|
||||
if (thread_id != THREAD_NOT_ASSIGNED){
|
||||
system_acquire_lock(CANCEL_LOCK0 + thread_id - 1);
|
||||
thread = group->threads + thread_id - 1;
|
||||
TerminateThread(thread->handle, 0);
|
||||
u32 creation_flag = 0;
|
||||
thread->handle = CreateThread(0, 0, JobThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id);
|
||||
system_release_lock(CANCEL_LOCK0 + thread_id - 1);
|
||||
thread->running = 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
system_grow_thread_memory(Thread_Memory *memory){
|
||||
void *old_data;
|
||||
i32 old_size, new_size;
|
||||
|
||||
system_acquire_lock(CANCEL_LOCK0 + memory->id - 1);
|
||||
old_data = memory->data;
|
||||
old_size = memory->size;
|
||||
new_size = LargeRoundUp(memory->size*2, Kbytes(4));
|
||||
memory->data = system_get_memory(new_size);
|
||||
memory->size = new_size;
|
||||
if (old_data){
|
||||
memcpy(memory->data, old_data, old_size);
|
||||
system_free_memory(old_data);
|
||||
}
|
||||
system_release_lock(CANCEL_LOCK0 + memory->id - 1);
|
||||
}
|
||||
|
||||
#if FRED_INTERNAL
|
||||
internal void
|
||||
INTERNAL_get_thread_states(Thread_Group_ID id, bool8 *running, i32 *pending){
|
||||
Work_Queue *queue = exchange_vars.thread.queues + id;
|
||||
u32 write = queue->write_position;
|
||||
u32 read = queue->read_position;
|
||||
if (write < read) write += JOB_ID_WRAP;
|
||||
*pending = (i32)(write - read);
|
||||
|
||||
Thread_Group *group = win32vars.groups + id;
|
||||
for (i32 i = 0; i < group->count; ++i){
|
||||
running[i] = (group->threads[i].running != 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Coroutine
|
||||
//
|
||||
|
||||
internal Win32_Coroutine*
|
||||
Win32AllocCoroutine(){
|
||||
Win32_Coroutine *result = win32vars.coroutine_free;
|
||||
Assert(result != 0);
|
||||
win32vars.coroutine_free = result->next;
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal void
|
||||
Win32FreeCoroutine(Win32_Coroutine *data){
|
||||
data->next = win32vars.coroutine_free;
|
||||
win32vars.coroutine_free = data;
|
||||
}
|
||||
|
||||
internal void
|
||||
Win32CoroutineMain(void *arg_){
|
||||
Win32_Coroutine *c = (Win32_Coroutine*)arg_;
|
||||
c->coroutine.func(&c->coroutine);
|
||||
c->done = 1;
|
||||
Win32FreeCoroutine(c);
|
||||
SwitchToFiber(c->coroutine.yield_handle);
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Create_Coroutine_Sig(system_create_coroutine){
|
||||
Win32_Coroutine *c;
|
||||
Coroutine *coroutine;
|
||||
void *fiber;
|
||||
|
||||
c = Win32AllocCoroutine();
|
||||
c->done = 0;
|
||||
|
||||
coroutine = &c->coroutine;
|
||||
|
||||
fiber = CreateFiber(0, Win32CoroutineMain, coroutine);
|
||||
|
||||
coroutine->plat_handle = Win32Handle(fiber);
|
||||
coroutine->func = func;
|
||||
|
||||
return(coroutine);
|
||||
}
|
||||
|
||||
internal
|
||||
Sys_Launch_Coroutine_Sig(system_launch_coroutine){
|
||||
Win32_Coroutine *c = (Win32_Coroutine*)coroutine;
|
||||
void *fiber;
|
||||
|
||||
fiber = Win32Handle(coroutine->plat_handle);
|
||||
coroutine->yield_handle = GetCurrentFiber();
|
||||
coroutine->in = in;
|
||||
coroutine->out = out;
|
||||
|
||||
SwitchToFiber(fiber);
|
||||
|
||||
if (c->done){
|
||||
DeleteFiber(fiber);
|
||||
Win32FreeCoroutine(c);
|
||||
coroutine = 0;
|
||||
}
|
||||
|
||||
return(coroutine);
|
||||
}
|
||||
|
||||
Sys_Resume_Coroutine_Sig(system_resume_coroutine){
|
||||
Win32_Coroutine *c = (Win32_Coroutine*)coroutine;
|
||||
void *fiber;
|
||||
|
||||
Assert(c->done == 0);
|
||||
|
||||
coroutine->yield_handle = GetCurrentFiber();
|
||||
coroutine->in = in;
|
||||
coroutine->out = out;
|
||||
|
||||
fiber = Win32Ptr(coroutine->plat_handle);
|
||||
|
||||
SwitchToFiber(fiber);
|
||||
|
||||
if (c->done){
|
||||
DeleteFiber(fiber);
|
||||
Win32FreeCoroutine(c);
|
||||
coroutine = 0;
|
||||
}
|
||||
|
||||
return(coroutine);
|
||||
}
|
||||
|
||||
Sys_Yield_Coroutine_Sig(system_yield_coroutine){
|
||||
SwitchToFiber(coroutine->yield_handle);
|
||||
}
|
||||
|
||||
//
|
||||
// Command Line Exectuion
|
||||
|
@ -1780,6 +1788,7 @@ WinMain(HINSTANCE hInstance,
|
|||
}
|
||||
|
||||
win32vars.custom_api.view_routine = (View_Routine_Function*)0;
|
||||
|
||||
#if 0
|
||||
if (win32vars.custom_api.view_routine == 0){
|
||||
win32vars.custom_api.view_routine = (View_Routine_Function*)view_routine;
|
||||
|
@ -1953,7 +1962,7 @@ WinMain(HINSTANCE hInstance,
|
|||
|
||||
system_free_memory(current_directory.str);
|
||||
|
||||
win32vars.input_chunk.pers.keep_playing = 1;
|
||||
b32 keep_playing = 1;
|
||||
win32vars.first = 1;
|
||||
timeBeginPeriod(1);
|
||||
|
||||
|
@ -1964,7 +1973,7 @@ WinMain(HINSTANCE hInstance,
|
|||
u64 timer_start = Win32HighResolutionTime();
|
||||
system_acquire_lock(FRAME_LOCK);
|
||||
MSG msg;
|
||||
for (;win32vars.input_chunk.pers.keep_playing;){
|
||||
for (;keep_playing;){
|
||||
// TODO(allen): Find a good way to wait on a pipe
|
||||
// without interfering with the reading process
|
||||
// Looks like we can ReadFile with a size of zero
|
||||
|
@ -1977,7 +1986,7 @@ WinMain(HINSTANCE hInstance,
|
|||
for (;win32vars.got_useful_event == 0;){
|
||||
if (GetMessage(&msg, 0, 0, 0)){
|
||||
if (msg.message == WM_QUIT){
|
||||
win32vars.input_chunk.pers.keep_playing = 0;
|
||||
keep_playing = 0;
|
||||
}else{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
|
@ -1988,7 +1997,7 @@ WinMain(HINSTANCE hInstance,
|
|||
|
||||
while (PeekMessage(&msg, 0, 0, 0, 1)){
|
||||
if (msg.message == WM_QUIT){
|
||||
win32vars.input_chunk.pers.keep_playing = 0;
|
||||
keep_playing = 0;
|
||||
}else{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
|
@ -2034,46 +2043,47 @@ WinMain(HINSTANCE hInstance,
|
|||
}
|
||||
}
|
||||
|
||||
Key_Input_Data input_data;
|
||||
Mouse_State mouse;
|
||||
Application_Step_Result result;
|
||||
Application_Step_Input input = {0};
|
||||
|
||||
input_data = input_chunk.trans.key_data;
|
||||
mouse.out_of_window = input_chunk.trans.out_of_window;
|
||||
input.first_step = win32vars.first;
|
||||
|
||||
mouse.l = input_chunk.pers.mouse_l;
|
||||
mouse.press_l = input_chunk.trans.mouse_l_press;
|
||||
mouse.release_l = input_chunk.trans.mouse_l_release;
|
||||
// NOTE(allen): The expected dt given the frame limit in seconds.
|
||||
input.dt = frame_useconds / 1000000.f;
|
||||
|
||||
mouse.r = input_chunk.pers.mouse_r;
|
||||
mouse.press_r = input_chunk.trans.mouse_r_press;
|
||||
mouse.release_r = input_chunk.trans.mouse_r_release;
|
||||
input.keys = input_chunk.trans.key_data;
|
||||
|
||||
mouse.wheel = input_chunk.trans.mouse_wheel;
|
||||
input.mouse.out_of_window = input_chunk.trans.out_of_window;
|
||||
|
||||
mouse.x = input_chunk.pers.mouse_x;
|
||||
mouse.y = input_chunk.pers.mouse_y;
|
||||
input.mouse.l = input_chunk.pers.mouse_l;
|
||||
input.mouse.press_l = input_chunk.trans.mouse_l_press;
|
||||
input.mouse.release_l = input_chunk.trans.mouse_l_release;
|
||||
|
||||
input.mouse.r = input_chunk.pers.mouse_r;
|
||||
input.mouse.press_r = input_chunk.trans.mouse_r_press;
|
||||
input.mouse.release_r = input_chunk.trans.mouse_r_release;
|
||||
|
||||
input.mouse.wheel = input_chunk.trans.mouse_wheel;
|
||||
input.mouse.x = input_chunk.pers.mouse_x;
|
||||
input.mouse.y = input_chunk.pers.mouse_y;
|
||||
|
||||
input.clipboard = win32vars.clipboard_contents;
|
||||
|
||||
|
||||
Application_Step_Result result = {(Application_Mouse_Cursor)0};
|
||||
result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT;
|
||||
result.lctrl_lalt_is_altgr = win32vars.lctrl_lalt_is_altgr;
|
||||
result.trying_to_kill = input_chunk.trans.trying_to_kill;
|
||||
result.perform_kill = 0;
|
||||
|
||||
// NOTE(allen): The expected dt given the frame limit in seconds.
|
||||
f32 dt = frame_useconds / 1000000.f;
|
||||
|
||||
win32vars.app.step(&win32vars.system,
|
||||
&input_data,
|
||||
&mouse,
|
||||
&win32vars.target,
|
||||
&memory_vars,
|
||||
&exchange_vars,
|
||||
win32vars.clipboard_contents,
|
||||
dt, win32vars.first,
|
||||
&input,
|
||||
&result);
|
||||
|
||||
if (result.perform_kill){
|
||||
win32vars.input_chunk.pers.keep_playing = 0;
|
||||
keep_playing = 0;
|
||||
}
|
||||
|
||||
Win32SetCursorFromUpdate(result.mouse_cursor_type);
|
||||
|
|
Loading…
Reference in New Issue