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:
Allen Webster 2016-05-29 15:28:29 -04:00
parent c56703cbc8
commit 93a1d3931f
3 changed files with 358 additions and 338 deletions

82
4ed.cpp
View File

@ -3631,51 +3631,53 @@ consume_input(Available_Input *available, i32 input_type){
App_Step_Sig(app_step){ App_Step_Sig(app_step){
Application_Step_Result app_result = *result; Application_Step_Result app_result = *result;
app_result.animating = 0; app_result.animating = 0;
App_Vars *vars = (App_Vars*)memory->vars_memory; App_Vars *vars = (App_Vars*)memory->vars_memory;
Models *models = &vars->models; Models *models = &vars->models;
target->partition = &models->mem.part; target->partition = &models->mem.part;
// NOTE(allen): OS clipboard event handling // NOTE(allen): OS clipboard event handling
String clipboard = input->clipboard;
if (clipboard.str){ if (clipboard.str){
String *dest = working_set_next_clipboard_string(&models->mem.general, &models->working_set, clipboard.size); 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); dest->size = eol_convert_in(dest->str, clipboard.str, clipboard.size);
} }
// NOTE(allen): check files are up to date // NOTE(allen): check files are up to date
{ {
File_Node *node, *used_nodes; File_Node *node, *used_nodes;
Editing_File *file; Editing_File *file;
u64 time_stamp; u64 time_stamp;
used_nodes = &models->working_set.used_sentinel; used_nodes = &models->working_set.used_sentinel;
for (dll_items(node, used_nodes)){ for (dll_items(node, used_nodes)){
file = (Editing_File*)node; file = (Editing_File*)node;
time_stamp = system->file_time_stamp(make_c_str(file->name.source_path)); time_stamp = system->file_time_stamp(make_c_str(file->name.source_path));
if (time_stamp > 0){ if (time_stamp > 0){
file->state.last_sys_write_time = time_stamp; file->state.last_sys_write_time = time_stamp;
} }
} }
} }
// NOTE(allen): reorganizing panels on screen // NOTE(allen): reorganizing panels on screen
{ {
i32 prev_width = models->layout.full_width; i32 prev_width = models->layout.full_width;
i32 prev_height = models->layout.full_height; i32 prev_height = models->layout.full_height;
i32 current_width = target->width; i32 current_width = target->width;
i32 current_height = target->height; i32 current_height = target->height;
Panel *panel, *used_panels; Panel *panel, *used_panels;
View *view; View *view;
models->layout.full_width = current_width; models->layout.full_width = current_width;
models->layout.full_height = current_height; models->layout.full_height = current_height;
if (prev_width != current_width || prev_height != current_height){ if (prev_width != current_width || prev_height != current_height){
layout_refit(&models->layout, prev_width, prev_height); layout_refit(&models->layout, prev_width, prev_height);
used_panels = &models->layout.used_sentinel; used_panels = &models->layout.used_sentinel;
for (dll_items(panel, used_panels)){ for (dll_items(panel, used_panels)){
view = panel->view; view = panel->view;
@ -3689,18 +3691,18 @@ App_Step_Sig(app_step){
// NOTE(allen): prepare input information // NOTE(allen): prepare input information
Key_Summary key_summary = {0}; Key_Summary key_summary = {0};
for (i32 i = 0; i < input->press_count; ++i){ for (i32 i = 0; i < input->keys.press_count; ++i){
key_summary.keys[key_summary.count++] = input->press[i]; key_summary.keys[key_summary.count++] = input->keys.press[i];
} }
for (i32 i = 0; i < input->hold_count; ++i){ for (i32 i = 0; i < input->keys.hold_count; ++i){
key_summary.keys[key_summary.count++] = input->hold[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 // NOTE(allen): detect mouse hover status
i32 mx = mouse->x; i32 mx = input->mouse.x;
i32 my = mouse->y; i32 my = input->mouse.y;
b32 mouse_in_edit_area = 0; b32 mouse_in_edit_area = 0;
b32 mouse_in_margin_area = 0; b32 mouse_in_margin_area = 0;
Panel *mouse_panel, *used_panels; Panel *mouse_panel, *used_panels;
@ -3787,7 +3789,7 @@ App_Step_Sig(app_step){
} }
// NOTE(allen): update child processes // NOTE(allen): update child processes
if (dt > 0){ if (input->dt > 0){
Temp_Memory temp = begin_temp_memory(&models->mem.part); Temp_Memory temp = begin_temp_memory(&models->mem.part);
u32 max = Kbytes(32); u32 max = Kbytes(32);
char *dest = push_array(&models->mem.part, char, max); 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); Temp_Memory param_stack_temp = begin_temp_memory(&models->mem.part);
cmd->part = partition_sub_part(&models->mem.part, 16 << 10); cmd->part = partition_sub_part(&models->mem.part, 16 << 10);
if (first_step){ if (input->first_step){
#if 0 #if 0
{ {
@ -3954,7 +3956,7 @@ App_Step_Sig(app_step){
} }
// NOTE(allen): process the command_coroutine if it is unfinished // 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. // NOTE(allen): Keyboard input to command coroutine.
if (models->command_coroutine != 0){ if (models->command_coroutine != 0){
@ -4029,7 +4031,7 @@ App_Step_Sig(app_step){
User_Input user_in; User_Input user_in;
user_in.type = UserInputMouse; user_in.type = UserInputMouse;
user_in.mouse = *mouse; user_in.mouse = input->mouse;
user_in.command = 0; user_in.command = 0;
user_in.abort = 0; user_in.abort = 0;
@ -4041,7 +4043,7 @@ App_Step_Sig(app_step){
consume_input(&available_input, Input_MouseMove); 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){ if (abort_flags & EventOnLeftButton){
user_in.abort = 1; 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){ if (abort_flags & EventOnRightButton){
user_in.abort = 1; 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){ if (abort_flags & EventOnWheel){
user_in.abort = 1; user_in.abort = 1;
} }
@ -4095,12 +4097,12 @@ App_Step_Sig(app_step){
// NOTE(allen): pass raw input to the panels // NOTE(allen): pass raw input to the panels
Input_Summary dead_input = {}; Input_Summary dead_input = {};
dead_input.mouse.x = mouse->x; dead_input.mouse.x = input->mouse.x;
dead_input.mouse.y = mouse->y; dead_input.mouse.y = input->mouse.y;
Input_Summary active_input = {}; Input_Summary active_input = {};
active_input.mouse.x = mouse->x; active_input.mouse.x = input->mouse.x;
active_input.mouse.y = mouse->y; active_input.mouse.y = input->mouse.y;
active_input.keys = get_key_data(&available_input); active_input.keys = get_key_data(&available_input);
@ -4110,7 +4112,7 @@ App_Step_Sig(app_step){
Panel *panel = 0, *used_panels = 0; Panel *panel = 0, *used_panels = 0;
View *view = 0, *active_view = 0; View *view = 0, *active_view = 0;
b32 active = 0; b32 active = 0;
Input_Summary input = {0}; Input_Summary summary = {0};
Input_Process_Result result = {0}; Input_Process_Result result = {0};
active_view = cmd->panel->view; active_view = cmd->panel->view;
@ -4118,8 +4120,8 @@ App_Step_Sig(app_step){
for (dll_items(panel, used_panels)){ for (dll_items(panel, used_panels)){
view = panel->view; view = panel->view;
active = (panel == cmd->panel); active = (panel == cmd->panel);
input = (active)?(active_input):(dead_input); summary = (active)?(active_input):(dead_input);
if (step_file_view(system, view, active_view, input)){ if (step_file_view(system, view, active_view, summary)){
app_result.animating = 1; app_result.animating = 1;
} }
} }
@ -4128,9 +4130,9 @@ App_Step_Sig(app_step){
view = panel->view; view = panel->view;
Assert(view->current_scroll); Assert(view->current_scroll);
active = (panel == cmd->panel); active = (panel == cmd->panel);
input = (active)?(active_input):(dead_input); summary = (active)?(active_input):(dead_input);
if (panel == mouse_panel && !mouse->out_of_window){ if (panel == mouse_panel && !input->mouse.out_of_window){
input.mouse = mouse_state; summary.mouse = mouse_state;
} }
@ -4138,7 +4140,7 @@ App_Step_Sig(app_step){
// TODO(allen): I feel like the scroll context should actually not // TODO(allen): I feel like the scroll context should actually not
// be allowed to change in here at all. // be allowed to change in here at all.
result = do_input_file_view(system, exchange, view, panel->inner, active, 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){ if (result.is_animating){
app_result.animating = 1; app_result.animating = 1;
} }
@ -4219,7 +4221,7 @@ App_Step_Sig(app_step){
update_command_data(vars, cmd); update_command_data(vars, cmd);
// NOTE(allen): initialize message // NOTE(allen): initialize message
if (first_step){ if (input->first_step){
String welcome = String welcome =
make_lit_string("Welcome to " VERSION "\n" make_lit_string("Welcome to " VERSION "\n"
"If you're new to 4coder there's no tutorial yet :(\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){ switch (vars->state){
case APP_STATE_EDIT: case APP_STATE_EDIT:
{ {
if (mouse->press_l && mouse_on_divider){ if (input->mouse.press_l && mouse_on_divider){
vars->state = APP_STATE_RESIZING; vars->state = APP_STATE_RESIZING;
Divider_And_ID div = layout_get_divider(&models->layout, mouse_divider_id); Divider_And_ID div = layout_get_divider(&models->layout, mouse_divider_id);
vars->resizing.divider = div.divider; vars->resizing.divider = div.divider;
@ -4323,7 +4325,7 @@ App_Step_Sig(app_step){
case APP_STATE_RESIZING: case APP_STATE_RESIZING:
{ {
if (mouse->l){ if (input->mouse.l){
Panel_Divider *divider = vars->resizing.divider; Panel_Divider *divider = vars->resizing.divider;
if (divider->v_divider){ if (divider->v_divider){
divider->pos = mx; divider->pos = mx;
@ -4347,7 +4349,7 @@ App_Step_Sig(app_step){
}break; }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); models->layout.active_panel = (i32)(mouse_panel - models->layout.panels);
} }

28
4ed.h
View File

@ -81,17 +81,19 @@ struct Plat_Settings{
typedef App_Read_Command_Line_Sig(App_Read_Command_Line); typedef App_Read_Command_Line_Sig(App_Read_Command_Line);
#define App_Init_Sig(name) void \ #define App_Init_Sig(name) void \
name(System_Functions *system, \ name(System_Functions *system, \
Render_Target *target, \ Render_Target *target, \
Application_Memory *memory, \ Application_Memory *memory, \
Exchange *exchange, \ Exchange *exchange, \
String clipboard, \ String clipboard, \
String current_directory, \ String current_directory, \
Custom_API api) Custom_API api)
typedef App_Init_Sig(App_Init); typedef App_Init_Sig(App_Init);
enum Application_Mouse_Cursor{ enum Application_Mouse_Cursor{
APP_MOUSE_CURSOR_DEFAULT, APP_MOUSE_CURSOR_DEFAULT,
APP_MOUSE_CURSOR_ARROW, APP_MOUSE_CURSOR_ARROW,
@ -110,19 +112,25 @@ struct Application_Step_Result{
b32 animating; 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 \ #define App_Step_Sig(name) void \
name(System_Functions *system, \ name(System_Functions *system, \
Key_Input_Data *input, \
Mouse_State *mouse, \
Render_Target *target, \ Render_Target *target, \
Application_Memory *memory, \ Application_Memory *memory, \
Exchange *exchange, \ Exchange *exchange, \
String clipboard, \ Application_Step_Input *input, \
f32 dt, b32 first_step, \
Application_Step_Result *result) Application_Step_Result *result)
typedef App_Step_Sig(App_Step); typedef App_Step_Sig(App_Step);
struct App_Functions{ struct App_Functions{
App_Read_Command_Line *read_command_line; App_Read_Command_Line *read_command_line;
App_Init *init; App_Init *init;

View File

@ -89,8 +89,6 @@ struct Win32_Input_Chunk_Persistent{
i32 mouse_x, mouse_y; i32 mouse_x, mouse_y;
b8 mouse_l, mouse_r; b8 mouse_l, mouse_r;
b8 keep_playing;
Control_Keys controls; Control_Keys controls;
b8 control_keys[MDFR_INDEX_COUNT]; b8 control_keys[MDFR_INDEX_COUNT];
}; };
@ -124,13 +122,11 @@ struct Win32_Vars{
DLL_Loaded app_dll; DLL_Loaded app_dll;
DLL_Loaded custom_dll; DLL_Loaded custom_dll;
#endif #endif
Plat_Settings settings; Plat_Settings settings;
Thread_Group groups[THREAD_GROUP_COUNT]; Thread_Group groups[THREAD_GROUP_COUNT];
CRITICAL_SECTION locks[LOCK_COUNT]; CRITICAL_SECTION locks[LOCK_COUNT];
CRITICAL_SECTION DEBUG_sysmem_lock;
Thread_Memory *thread_memory; Thread_Memory *thread_memory;
Win32_Coroutine coroutine_data[18]; Win32_Coroutine coroutine_data[18];
Win32_Coroutine *coroutine_free; Win32_Coroutine *coroutine_free;
@ -161,6 +157,7 @@ struct Win32_Vars{
#if FRED_INTERNAL #if FRED_INTERNAL
CRITICAL_SECTION DEBUG_sysmem_lock;
Sys_Bubble internal_bubble; Sys_Bubble internal_bubble;
#endif #endif
}; };
@ -169,6 +166,11 @@ globalvar Win32_Vars win32vars;
globalvar Application_Memory memory_vars; globalvar Application_Memory memory_vars;
globalvar Exchange exchange_vars; globalvar Exchange exchange_vars;
//
// Helpers
//
internal HANDLE internal HANDLE
Win32Handle(Plat_Handle h){ Win32Handle(Plat_Handle h){
HANDLE result; HANDLE result;
@ -198,6 +200,7 @@ Win32Ptr(void *h){
return(result); return(result);
} }
// //
// Memory (not exposed to application, but needed in system_shared.cpp) // Memory (not exposed to application, but needed in system_shared.cpp)
// //
@ -259,8 +262,269 @@ INTERNAL_system_debug_message(char *message){
} }
#endif #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 internal
@ -602,6 +866,7 @@ GET_4ED_PATH_SIG(system_get_4ed_path){
return(system_get_binary_path(&str)); return(system_get_binary_path(&str));
} }
// //
// Clipboard // Clipboard
// //
@ -646,263 +911,6 @@ Win32ReadClipboardContents(){
return(result); 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 // Command Line Exectuion
@ -1780,6 +1788,7 @@ WinMain(HINSTANCE hInstance,
} }
win32vars.custom_api.view_routine = (View_Routine_Function*)0; win32vars.custom_api.view_routine = (View_Routine_Function*)0;
#if 0 #if 0
if (win32vars.custom_api.view_routine == 0){ if (win32vars.custom_api.view_routine == 0){
win32vars.custom_api.view_routine = (View_Routine_Function*)view_routine; win32vars.custom_api.view_routine = (View_Routine_Function*)view_routine;
@ -1953,7 +1962,7 @@ WinMain(HINSTANCE hInstance,
system_free_memory(current_directory.str); system_free_memory(current_directory.str);
win32vars.input_chunk.pers.keep_playing = 1; b32 keep_playing = 1;
win32vars.first = 1; win32vars.first = 1;
timeBeginPeriod(1); timeBeginPeriod(1);
@ -1964,7 +1973,7 @@ WinMain(HINSTANCE hInstance,
u64 timer_start = Win32HighResolutionTime(); u64 timer_start = Win32HighResolutionTime();
system_acquire_lock(FRAME_LOCK); system_acquire_lock(FRAME_LOCK);
MSG msg; MSG msg;
for (;win32vars.input_chunk.pers.keep_playing;){ for (;keep_playing;){
// TODO(allen): Find a good way to wait on a pipe // TODO(allen): Find a good way to wait on a pipe
// without interfering with the reading process // without interfering with the reading process
// Looks like we can ReadFile with a size of zero // Looks like we can ReadFile with a size of zero
@ -1977,7 +1986,7 @@ WinMain(HINSTANCE hInstance,
for (;win32vars.got_useful_event == 0;){ for (;win32vars.got_useful_event == 0;){
if (GetMessage(&msg, 0, 0, 0)){ if (GetMessage(&msg, 0, 0, 0)){
if (msg.message == WM_QUIT){ if (msg.message == WM_QUIT){
win32vars.input_chunk.pers.keep_playing = 0; keep_playing = 0;
}else{ }else{
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
@ -1988,7 +1997,7 @@ WinMain(HINSTANCE hInstance,
while (PeekMessage(&msg, 0, 0, 0, 1)){ while (PeekMessage(&msg, 0, 0, 0, 1)){
if (msg.message == WM_QUIT){ if (msg.message == WM_QUIT){
win32vars.input_chunk.pers.keep_playing = 0; keep_playing = 0;
}else{ }else{
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
@ -2034,46 +2043,47 @@ WinMain(HINSTANCE hInstance,
} }
} }
Key_Input_Data input_data; Application_Step_Input input = {0};
Mouse_State mouse;
Application_Step_Result result;
input_data = input_chunk.trans.key_data; input.first_step = win32vars.first;
mouse.out_of_window = input_chunk.trans.out_of_window;
mouse.l = input_chunk.pers.mouse_l; // NOTE(allen): The expected dt given the frame limit in seconds.
mouse.press_l = input_chunk.trans.mouse_l_press; input.dt = frame_useconds / 1000000.f;
mouse.release_l = input_chunk.trans.mouse_l_release;
mouse.r = input_chunk.pers.mouse_r; input.keys = input_chunk.trans.key_data;
mouse.press_r = input_chunk.trans.mouse_r_press;
mouse.release_r = input_chunk.trans.mouse_r_release;
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; input.mouse.l = input_chunk.pers.mouse_l;
mouse.y = input_chunk.pers.mouse_y; 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.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT;
result.lctrl_lalt_is_altgr = win32vars.lctrl_lalt_is_altgr; result.lctrl_lalt_is_altgr = win32vars.lctrl_lalt_is_altgr;
result.trying_to_kill = input_chunk.trans.trying_to_kill; result.trying_to_kill = input_chunk.trans.trying_to_kill;
result.perform_kill = 0; 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, win32vars.app.step(&win32vars.system,
&input_data,
&mouse,
&win32vars.target, &win32vars.target,
&memory_vars, &memory_vars,
&exchange_vars, &exchange_vars,
win32vars.clipboard_contents, &input,
dt, win32vars.first,
&result); &result);
if (result.perform_kill){ if (result.perform_kill){
win32vars.input_chunk.pers.keep_playing = 0; keep_playing = 0;
} }
Win32SetCursorFromUpdate(result.mouse_cursor_type); Win32SetCursorFromUpdate(result.mouse_cursor_type);