mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-18 01:52:22 -07:00
continue coalescing df frame
This commit is contained in:
@@ -4,21 +4,29 @@
|
||||
internal void
|
||||
main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **arguments, U64 arguments_count)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
ThreadNameF("[main thread]");
|
||||
|
||||
//- rjf: set up telemetry
|
||||
#if PROFILE_TELEMETRY
|
||||
local_persist U8 tm_data[MB(64)];
|
||||
tmLoadLibrary(TM_RELEASE);
|
||||
tmSetMaxThreadCount(256);
|
||||
tmInitialize(sizeof(tm_data), (char *)tm_data);
|
||||
#endif
|
||||
ThreadNameF("[main thread]");
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
//- rjf: parse command line
|
||||
String8List command_line_argument_strings = os_string_list_from_argcv(scratch.arena, (int)arguments_count, arguments);
|
||||
CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings);
|
||||
|
||||
//- rjf: begin captures
|
||||
B32 capture = cmd_line_has_flag(&cmdline, str8_lit("capture"));
|
||||
if(capture)
|
||||
{
|
||||
ProfBeginCapture(arguments[0]);
|
||||
}
|
||||
|
||||
//- rjf: initialize all included layers
|
||||
#if defined(TASK_SYSTEM_H) && !defined(TS_INIT_MANUAL)
|
||||
ts_init();
|
||||
#endif
|
||||
@@ -74,7 +82,11 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum
|
||||
#if defined(DBG_FRONTEND_CORE_H) && !defined(DF_INIT_MANUAL)
|
||||
df_init(update_and_render, d_state_delta_history());
|
||||
#endif
|
||||
|
||||
//- rjf: call into entry point
|
||||
entry_point(&cmdline);
|
||||
|
||||
//- rjf: end captures
|
||||
if(capture)
|
||||
{
|
||||
ProfEndCapture();
|
||||
|
||||
@@ -5845,8 +5845,9 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, D_CmdList *cmds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui_end_build();
|
||||
}
|
||||
ui_end_build();
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: ensure hover eval is in-bounds
|
||||
@@ -7958,23 +7959,252 @@ df_init(OS_WindowRepaintFunctionType *window_repaint_entry_point, D_StateDeltaHi
|
||||
}
|
||||
|
||||
internal void
|
||||
df_begin_frame(Arena *arena, D_CmdList *cmds)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal void
|
||||
df_frame(D_CmdList *cmds, F32 dt)
|
||||
df_frame(OS_Handle repaint_window_handle)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: mark user-facing thread tick
|
||||
//
|
||||
ProfTick(0);
|
||||
txt_user_clock_tick();
|
||||
dasm_user_clock_tick();
|
||||
geo_user_clock_tick();
|
||||
tex_user_clock_tick();
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: get events from the OS
|
||||
//
|
||||
OS_EventList events = {0};
|
||||
if(os_handle_match(repaint_window_handle, os_handle_zero()))
|
||||
{
|
||||
events = os_get_events(scratch.arena, df_state->num_frames_requested == 0);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: pick target hz
|
||||
//
|
||||
// TODO(rjf): maximize target, given all windows and their monitors
|
||||
F32 target_hz = os_get_gfx_info()->default_refresh_rate;
|
||||
if(df_state->frame_time_us_history_idx > 32)
|
||||
{
|
||||
// rjf: calculate average frame time out of the last N
|
||||
U64 num_frames_in_history = Min(ArrayCount(df_state->frame_time_us_history), df_state->frame_time_us_history_idx);
|
||||
U64 frame_time_history_sum_us = 0;
|
||||
for(U64 idx = 0; idx < num_frames_in_history; idx += 1)
|
||||
{
|
||||
frame_time_history_sum_us += df_state->frame_time_us_history[idx];
|
||||
}
|
||||
U64 frame_time_history_avg_us = frame_time_history_sum_us/num_frames_in_history;
|
||||
|
||||
// rjf: pick among a number of sensible targets to snap to, given how well
|
||||
// we've been performing
|
||||
F32 possible_alternate_hz_targets[] = {target_hz, 60.f, 120.f, 144.f, 240.f};
|
||||
F32 best_target_hz = target_hz;
|
||||
S64 best_target_hz_frame_time_us_diff = max_S64;
|
||||
for(U64 idx = 0; idx < ArrayCount(possible_alternate_hz_targets); idx += 1)
|
||||
{
|
||||
F32 candidate = possible_alternate_hz_targets[idx];
|
||||
if(candidate <= target_hz)
|
||||
{
|
||||
U64 candidate_frame_time_us = 1000000/(U64)candidate;
|
||||
S64 frame_time_us_diff = (S64)frame_time_history_avg_us - (S64)candidate_frame_time_us;
|
||||
if(abs_s64(frame_time_us_diff) < best_target_hz_frame_time_us_diff)
|
||||
{
|
||||
best_target_hz = candidate;
|
||||
best_target_hz_frame_time_us_diff = frame_time_us_diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
target_hz = best_target_hz;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: target Hz -> delta time
|
||||
//
|
||||
F32 dt = 1.f/target_hz;
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: begin measuring actual per-frame work
|
||||
//
|
||||
U64 begin_time_us = os_now_microseconds();
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: bind change
|
||||
//
|
||||
if(!df_state->confirm_active && df_state->bind_change_active)
|
||||
{
|
||||
if(os_key_press(&events, os_handle_zero(), 0, OS_Key_Esc))
|
||||
{
|
||||
df_request_frame();
|
||||
df_state->bind_change_active = 0;
|
||||
}
|
||||
if(os_key_press(&events, os_handle_zero(), 0, OS_Key_Delete))
|
||||
{
|
||||
df_request_frame();
|
||||
df_unbind_spec(df_state->bind_change_cmd_spec, df_state->bind_change_binding);
|
||||
df_state->bind_change_active = 0;
|
||||
d_cmd(d_cfg_src_write_cmd_kind_table[D_CfgSrc_User]);
|
||||
}
|
||||
for(OS_Event *event = events.first, *next = 0; event != 0; event = next)
|
||||
{
|
||||
if(event->kind == OS_EventKind_Press &&
|
||||
event->key != OS_Key_Esc &&
|
||||
event->key != OS_Key_Return &&
|
||||
event->key != OS_Key_Backspace &&
|
||||
event->key != OS_Key_Delete &&
|
||||
event->key != OS_Key_LeftMouseButton &&
|
||||
event->key != OS_Key_RightMouseButton &&
|
||||
event->key != OS_Key_MiddleMouseButton &&
|
||||
event->key != OS_Key_Ctrl &&
|
||||
event->key != OS_Key_Alt &&
|
||||
event->key != OS_Key_Shift)
|
||||
{
|
||||
df_state->bind_change_active = 0;
|
||||
DF_Binding binding = zero_struct;
|
||||
{
|
||||
binding.key = event->key;
|
||||
binding.flags = event->flags;
|
||||
}
|
||||
df_unbind_spec(df_state->bind_change_cmd_spec, df_state->bind_change_binding);
|
||||
df_bind_spec(df_state->bind_change_cmd_spec, binding);
|
||||
U32 codepoint = os_codepoint_from_event_flags_and_key(event->flags, event->key);
|
||||
os_text(&events, os_handle_zero(), codepoint);
|
||||
os_eat_event(&events, event);
|
||||
d_cmd(d_cfg_src_write_cmd_kind_table[D_CfgSrc_User]);
|
||||
df_request_frame();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: consume events
|
||||
//
|
||||
{
|
||||
for(OS_Event *event = events.first, *next = 0;
|
||||
event != 0;
|
||||
event = next)
|
||||
{
|
||||
next = event->next;
|
||||
DF_Window *window = df_window_from_os_handle(event->window);
|
||||
D_CmdParams params = window ? df_cmd_params_from_window(window) : df_cmd_params_from_gfx();
|
||||
B32 take = 0;
|
||||
|
||||
//- rjf: try window close
|
||||
if(!take && event->kind == OS_EventKind_WindowClose && window != 0)
|
||||
{
|
||||
take = 1;
|
||||
d_cmd(D_CmdKind_CloseWindow, .window = df_handle_from_window(window));
|
||||
}
|
||||
|
||||
//- rjf: try menu bar operations
|
||||
{
|
||||
if(!take && event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0)
|
||||
{
|
||||
take = 1;
|
||||
df_request_frame();
|
||||
window->menu_bar_focused_on_press = window->menu_bar_focused;
|
||||
window->menu_bar_key_held = 1;
|
||||
window->menu_bar_focus_press_started = 1;
|
||||
}
|
||||
if(!take && event->kind == OS_EventKind_Release && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0)
|
||||
{
|
||||
take = 1;
|
||||
df_request_frame();
|
||||
window->menu_bar_key_held = 0;
|
||||
}
|
||||
if(window->menu_bar_focused && event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0)
|
||||
{
|
||||
take = 1;
|
||||
df_request_frame();
|
||||
window->menu_bar_focused = 0;
|
||||
}
|
||||
else if(window->menu_bar_focus_press_started && !window->menu_bar_focused && event->kind == OS_EventKind_Release && event->flags == 0 && event->key == OS_Key_Alt && event->is_repeat == 0)
|
||||
{
|
||||
take = 1;
|
||||
df_request_frame();
|
||||
window->menu_bar_focused = !window->menu_bar_focused_on_press;
|
||||
window->menu_bar_focus_press_started = 0;
|
||||
}
|
||||
else if(event->kind == OS_EventKind_Press && event->key == OS_Key_Esc && window->menu_bar_focused && !ui_any_ctx_menu_is_open())
|
||||
{
|
||||
take = 1;
|
||||
df_request_frame();
|
||||
window->menu_bar_focused = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: try hotkey presses
|
||||
if(!take && event->kind == OS_EventKind_Press)
|
||||
{
|
||||
DF_Binding binding = {event->key, event->flags};
|
||||
D_CmdSpecList spec_candidates = df_cmd_spec_list_from_binding(scratch.arena, binding);
|
||||
if(spec_candidates.first != 0 && !d_cmd_spec_is_nil(spec_candidates.first->spec))
|
||||
{
|
||||
D_CmdSpec *run_spec = d_cmd_spec_from_kind(D_CmdKind_RunCommand);
|
||||
D_CmdSpec *spec = spec_candidates.first->spec;
|
||||
if(run_spec != spec)
|
||||
{
|
||||
params.cmd_spec = spec;
|
||||
}
|
||||
U32 hit_char = os_codepoint_from_event_flags_and_key(event->flags, event->key);
|
||||
take = 1;
|
||||
d_push_cmd(run_spec, ¶ms);
|
||||
if(event->flags & OS_EventFlag_Alt)
|
||||
{
|
||||
window->menu_bar_focus_press_started = 0;
|
||||
}
|
||||
}
|
||||
else if(OS_Key_F1 <= event->key && event->key <= OS_Key_F19)
|
||||
{
|
||||
window->menu_bar_focus_press_started = 0;
|
||||
}
|
||||
df_request_frame();
|
||||
}
|
||||
|
||||
//- rjf: try text events
|
||||
if(!take && event->kind == OS_EventKind_Text)
|
||||
{
|
||||
String32 insertion32 = str32(&event->character, 1);
|
||||
String8 insertion8 = str8_from_32(scratch.arena, insertion32);
|
||||
D_CmdSpec *spec = d_cmd_spec_from_kind(D_CmdKind_InsertText);
|
||||
params.string = insertion8;
|
||||
d_push_cmd(spec, ¶ms);
|
||||
df_request_frame();
|
||||
take = 1;
|
||||
if(event->flags & OS_EventFlag_Alt)
|
||||
{
|
||||
window->menu_bar_focus_press_started = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: do fall-through
|
||||
if(!take)
|
||||
{
|
||||
take = 1;
|
||||
params.os_event = event;
|
||||
d_push_cmd(d_cmd_spec_from_kind(D_CmdKind_OSEvent), ¶ms);
|
||||
}
|
||||
|
||||
//- rjf: take
|
||||
if(take)
|
||||
{
|
||||
os_eat_event(&events, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: gather root-level commands
|
||||
//
|
||||
D_CmdList cmds = d_gather_root_cmds(scratch.arena);
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: tick debug engine
|
||||
//
|
||||
d_tick(scratch.arena, di_scope, cmds, dt);
|
||||
d_tick(scratch.arena, di_scope, &cmds, dt);
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: apply new rich hover info
|
||||
@@ -8077,25 +8307,68 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
default:{}break;
|
||||
|
||||
//- rjf: meta
|
||||
case DF_MsgKind_Null:{}break;
|
||||
case DF_MsgKind_Exit:{}break;
|
||||
case DF_MsgKind_RunCommand:{}break;
|
||||
case DF_MsgKind_ToggleDevMenu:{}break;
|
||||
case DF_MsgKind_Exit:
|
||||
{
|
||||
// TODO(rjf): current implementation is wrong - will lose multiple windows!!!
|
||||
}break;
|
||||
case DF_MsgKind_RunCommand:
|
||||
{
|
||||
// TODO(rjf): need to somehow pass the command kind down...
|
||||
}break;
|
||||
case DF_MsgKind_ToggleDevMenu:
|
||||
{
|
||||
// TODO(rjf)
|
||||
}break;
|
||||
|
||||
//- rjf: config reading/writing
|
||||
case DF_MsgKind_ApplyUserData:{}break;
|
||||
case DF_MsgKind_ApplyProjectData:{}break;
|
||||
case DF_MsgKind_WriteUserData:{}break;
|
||||
case DF_MsgKind_WriteProjectData:{}break;
|
||||
case DF_MsgKind_ApplyUserData:
|
||||
case DF_MsgKind_ApplyProjectData:
|
||||
{
|
||||
// TODO(rjf)
|
||||
}break;
|
||||
case DF_MsgKind_WriteUserData:
|
||||
case DF_MsgKind_WriteProjectData:
|
||||
{
|
||||
// TODO(rjf)
|
||||
}break;
|
||||
|
||||
//- rjf: windows
|
||||
case DF_MsgKind_OpenWindow:{}break;
|
||||
case DF_MsgKind_CloseWindow:{}break;
|
||||
case DF_MsgKind_ToggleFullscreen:{}break;
|
||||
case DF_MsgKind_OpenWindow:
|
||||
{
|
||||
DF_Window *originating_window = df_window_from_handle(regs->window);
|
||||
if(originating_window == 0)
|
||||
{
|
||||
originating_window = df_state->first_window;
|
||||
}
|
||||
DF_Window *new_ws = df_window_open(v2f32(1280, 720), os_handle_zero(), D_CfgSrc_User);
|
||||
if(originating_window != 0)
|
||||
{
|
||||
MemoryCopy(new_ws->setting_vals, originating_window->setting_vals, sizeof(DF_SettingVal)*DF_SettingCode_COUNT);
|
||||
}
|
||||
}break;
|
||||
case DF_MsgKind_CloseWindow:
|
||||
{
|
||||
// TODO(rjf): coordinate with Exit msg
|
||||
}break;
|
||||
case DF_MsgKind_ToggleFullscreen:
|
||||
{
|
||||
DF_Window *window = df_window_from_handle(regs->window);
|
||||
if(window != 0)
|
||||
{
|
||||
os_window_set_fullscreen(window->os, !os_window_is_fullscreen(window->os));
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: confirmation
|
||||
case DF_MsgKind_ConfirmAccept:{}break;
|
||||
case DF_MsgKind_ConfirmCancel:{}break;
|
||||
case DF_MsgKind_ConfirmAccept:
|
||||
{
|
||||
// TODO(rjf): confirm cmds -> msgs
|
||||
}break;
|
||||
case DF_MsgKind_ConfirmCancel:
|
||||
{
|
||||
df_state->confirm_active = 0;
|
||||
df_state->confirm_key = ui_key_zero();
|
||||
}break;
|
||||
|
||||
//- rjf: queries
|
||||
case DF_MsgKind_CompleteQuery:{}break;
|
||||
@@ -8186,7 +8459,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
B32 panel_reset_done = 0;
|
||||
{
|
||||
B32 cfg_write_done[D_CfgSrc_COUNT] = {0};
|
||||
for(D_CmdNode *cmd_node = cmds->first;
|
||||
for(D_CmdNode *cmd_node = cmds.first;
|
||||
cmd_node != 0;
|
||||
cmd_node = cmd_node->next)
|
||||
{
|
||||
@@ -8215,7 +8488,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
{
|
||||
D_CmdParams p = *params;
|
||||
p.view_spec = view_spec;
|
||||
d_cmd_list_push(scratch.arena, cmds, &p, d_cmd_spec_from_kind(D_CmdKind_OpenTab));
|
||||
d_cmd_list_push(scratch.arena, &cmds, &p, d_cmd_spec_from_kind(D_CmdKind_OpenTab));
|
||||
}
|
||||
}break;
|
||||
|
||||
@@ -8380,7 +8653,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
case D_CmdKind_SelectUnwind:
|
||||
thread_locator:;
|
||||
{
|
||||
d_cmd_list_push(scratch.arena, cmds, params, d_cmd_spec_from_kind(D_CmdKind_FindThread));
|
||||
d_cmd_list_push(scratch.arena, &cmds, params, d_cmd_spec_from_kind(D_CmdKind_FindThread));
|
||||
}break;
|
||||
|
||||
//- rjf: loading/applying stateful config changes
|
||||
@@ -8983,11 +9256,11 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
D_CmdParams blank_params = df_cmd_params_from_window(ws);
|
||||
if(monitor_dim.x < 1920)
|
||||
{
|
||||
d_cmd_list_push(scratch.arena, cmds, &blank_params, d_cmd_spec_from_kind(D_CmdKind_ResetToCompactPanels));
|
||||
d_cmd_list_push(scratch.arena, &cmds, &blank_params, d_cmd_spec_from_kind(D_CmdKind_ResetToCompactPanels));
|
||||
}
|
||||
else
|
||||
{
|
||||
d_cmd_list_push(scratch.arena, cmds, &blank_params, d_cmd_spec_from_kind(D_CmdKind_ResetToDefaultPanels));
|
||||
d_cmd_list_push(scratch.arena, &cmds, &blank_params, d_cmd_spec_from_kind(D_CmdKind_ResetToDefaultPanels));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9064,13 +9337,13 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
{
|
||||
D_CmdParams p = *params;
|
||||
p.string = df_push_search_string(scratch.arena);
|
||||
d_cmd_list_push(scratch.arena, cmds, &p, d_cmd_spec_from_kind(D_CmdKind_FindTextForward));
|
||||
d_cmd_list_push(scratch.arena, &cmds, &p, d_cmd_spec_from_kind(D_CmdKind_FindTextForward));
|
||||
}break;
|
||||
case D_CmdKind_FindPrev:
|
||||
{
|
||||
D_CmdParams p = *params;
|
||||
p.string = df_push_search_string(scratch.arena);
|
||||
d_cmd_list_push(scratch.arena, cmds, &p, d_cmd_spec_from_kind(D_CmdKind_FindTextBackward));
|
||||
d_cmd_list_push(scratch.arena, &cmds, &p, d_cmd_spec_from_kind(D_CmdKind_FindTextBackward));
|
||||
}break;
|
||||
|
||||
//- rjf: font sizes
|
||||
@@ -9215,7 +9488,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
move_tab_panel != new_panel->prev && move_tab_panel != new_panel->next)
|
||||
{
|
||||
D_CmdParams p = df_cmd_params_from_panel(ws, move_tab_panel);
|
||||
d_cmd_list_push(scratch.arena, cmds, &p, d_cmd_spec_from_kind(D_CmdKind_ClosePanel));
|
||||
d_cmd_list_push(scratch.arena, &cmds, &p, d_cmd_spec_from_kind(D_CmdKind_ClosePanel));
|
||||
}
|
||||
}
|
||||
}break;
|
||||
@@ -9265,7 +9538,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
{
|
||||
D_CmdParams p = df_cmd_params_from_window(ws);
|
||||
p.panel = df_handle_from_panel(panel);
|
||||
d_cmd_list_push(scratch.arena, cmds, &p, d_cmd_spec_from_kind(D_CmdKind_FocusPanel));
|
||||
d_cmd_list_push(scratch.arena, &cmds, &p, d_cmd_spec_from_kind(D_CmdKind_FocusPanel));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -9323,7 +9596,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
}
|
||||
D_CmdParams p = df_cmd_params_from_window(ws);
|
||||
p.panel = df_handle_from_panel(dst_panel);
|
||||
d_cmd_list_push(scratch.arena, cmds, &p, d_cmd_spec_from_kind(D_CmdKind_FocusPanel));
|
||||
d_cmd_list_push(scratch.arena, &cmds, &p, d_cmd_spec_from_kind(D_CmdKind_FocusPanel));
|
||||
}
|
||||
}break;
|
||||
|
||||
@@ -9475,7 +9748,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
p.dest_panel = df_handle_from_panel(panel);
|
||||
p.view = df_handle_from_view(view);
|
||||
p.prev_view = df_handle_from_view(prev_view);
|
||||
d_cmd_list_push(scratch.arena, cmds, &p, d_cmd_spec_from_kind(D_CmdKind_MoveTab));
|
||||
d_cmd_list_push(scratch.arena, &cmds, &p, d_cmd_spec_from_kind(D_CmdKind_MoveTab));
|
||||
}
|
||||
}break;
|
||||
case D_CmdKind_OpenTab:
|
||||
@@ -9543,7 +9816,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
if(src_panel_is_empty && src_panel != ws->root_panel)
|
||||
{
|
||||
D_CmdParams p = df_cmd_params_from_panel(ws, src_panel);
|
||||
d_cmd_list_push(scratch.arena, cmds, &p, d_cmd_spec_from_kind(D_CmdKind_ClosePanel));
|
||||
d_cmd_list_push(scratch.arena, &cmds, &p, d_cmd_spec_from_kind(D_CmdKind_ClosePanel));
|
||||
}
|
||||
}
|
||||
}break;
|
||||
@@ -9569,7 +9842,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
D_CmdParams p = *params;
|
||||
p.window = df_handle_from_window(ws);
|
||||
p.panel = df_handle_from_panel(ws->focused_panel);
|
||||
d_cmd_list_push(scratch.arena, cmds, &p, d_cmd_spec_from_kind(D_CmdKind_PendingFile));
|
||||
d_cmd_list_push(scratch.arena, &cmds, &p, d_cmd_spec_from_kind(D_CmdKind_PendingFile));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -10066,7 +10339,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
params.vaddr = rip_vaddr;
|
||||
params.unwind_index = unwind_index;
|
||||
params.inline_depth = inline_depth;
|
||||
d_cmd_list_push(scratch.arena, cmds, ¶ms, d_cmd_spec_from_kind(D_CmdKind_FindCodeLocation));
|
||||
d_cmd_list_push(scratch.arena, &cmds, ¶ms, d_cmd_spec_from_kind(D_CmdKind_FindCodeLocation));
|
||||
}
|
||||
|
||||
// rjf: snap to resolved address w/o line info
|
||||
@@ -10078,7 +10351,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
params.vaddr = rip_vaddr;
|
||||
params.unwind_index = unwind_index;
|
||||
params.inline_depth = inline_depth;
|
||||
d_cmd_list_push(scratch.arena, cmds, ¶ms, d_cmd_spec_from_kind(D_CmdKind_FindCodeLocation));
|
||||
d_cmd_list_push(scratch.arena, &cmds, ¶ms, d_cmd_spec_from_kind(D_CmdKind_FindCodeLocation));
|
||||
}
|
||||
|
||||
// rjf: retry on stopped, pending debug info
|
||||
@@ -10097,7 +10370,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
params.entity = d_handle_from_entity(selected_thread);
|
||||
params.unwind_index = d_base_regs()->unwind_count;
|
||||
params.inline_depth = d_base_regs()->inline_depth;
|
||||
d_cmd_list_push(scratch.arena, cmds, ¶ms, d_cmd_spec_from_kind(D_CmdKind_FindThread));
|
||||
d_cmd_list_push(scratch.arena, &cmds, ¶ms, d_cmd_spec_from_kind(D_CmdKind_FindThread));
|
||||
}break;
|
||||
|
||||
//- rjf: name finding
|
||||
@@ -10245,7 +10518,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
}
|
||||
}
|
||||
}
|
||||
d_cmd_list_push(scratch.arena, cmds, &p, d_cmd_spec_from_kind(D_CmdKind_FindCodeLocation));
|
||||
d_cmd_list_push(scratch.arena, &cmds, &p, d_cmd_spec_from_kind(D_CmdKind_FindCodeLocation));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10256,7 +10529,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
D_CmdParams p = *params;
|
||||
p.file_path = path;
|
||||
p.text_point = txt_pt(1, 1);
|
||||
d_cmd_list_push(scratch.arena, cmds, &p, d_cmd_spec_from_kind(D_CmdKind_FindCodeLocation));
|
||||
d_cmd_list_push(scratch.arena, &cmds, &p, d_cmd_spec_from_kind(D_CmdKind_FindCodeLocation));
|
||||
}
|
||||
}
|
||||
}break;
|
||||
@@ -10270,7 +10543,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
default: break;
|
||||
case D_EntityKind_Target:
|
||||
{
|
||||
d_cmd_list_push(scratch.arena, cmds, params, d_cmd_spec_from_kind(D_CmdKind_EditTarget));
|
||||
d_cmd_list_push(scratch.arena, &cmds, params, d_cmd_spec_from_kind(D_CmdKind_EditTarget));
|
||||
}break;
|
||||
}
|
||||
}break;
|
||||
@@ -10281,7 +10554,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
D_Entity *entity = d_entity_from_handle(params->entity);
|
||||
if(!d_entity_is_nil(entity) && entity->kind == D_EntityKind_Target)
|
||||
{
|
||||
d_cmd_list_push(scratch.arena, cmds, params, d_cmd_spec_from_kind(D_CmdKind_Target));
|
||||
d_cmd_list_push(scratch.arena, &cmds, params, d_cmd_spec_from_kind(D_CmdKind_Target));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -10322,7 +10595,7 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
{
|
||||
D_CmdParams params = df_cmd_params_from_panel(ws, panel);
|
||||
params.entity = d_handle_from_entity(entity);
|
||||
d_cmd_list_push(scratch.arena, cmds, ¶ms, d_cmd_spec_from_kind(D_CmdKind_EditTarget));
|
||||
d_cmd_list_push(scratch.arena, &cmds, ¶ms, d_cmd_spec_from_kind(D_CmdKind_EditTarget));
|
||||
}break;
|
||||
}
|
||||
}break;
|
||||
@@ -10563,8 +10836,8 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
dst_panel->selected_tab_view = df_handle_from_view(dst_view);
|
||||
D_CmdParams params = df_cmd_params_from_view(ws, dst_panel, dst_view);
|
||||
params.text_point = point;
|
||||
d_cmd_list_push(scratch.arena, cmds, ¶ms, d_cmd_spec_from_kind(D_CmdKind_GoToLine));
|
||||
d_cmd_list_push(scratch.arena, cmds, ¶ms, d_cmd_spec_from_kind(cursor_snap_kind));
|
||||
d_cmd_list_push(scratch.arena, &cmds, ¶ms, d_cmd_spec_from_kind(D_CmdKind_GoToLine));
|
||||
d_cmd_list_push(scratch.arena, &cmds, ¶ms, d_cmd_spec_from_kind(cursor_snap_kind));
|
||||
panel_used_for_src_code = dst_panel;
|
||||
}
|
||||
}
|
||||
@@ -10610,8 +10883,8 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
D_CmdParams params = df_cmd_params_from_view(ws, dst_panel, dst_view);
|
||||
params.entity = d_handle_from_entity(process);
|
||||
params.vaddr = vaddr;
|
||||
d_cmd_list_push(scratch.arena, cmds, ¶ms, d_cmd_spec_from_kind(D_CmdKind_GoToAddress));
|
||||
d_cmd_list_push(scratch.arena, cmds, ¶ms, d_cmd_spec_from_kind(cursor_snap_kind));
|
||||
d_cmd_list_push(scratch.arena, &cmds, ¶ms, d_cmd_spec_from_kind(D_CmdKind_GoToAddress));
|
||||
d_cmd_list_push(scratch.arena, &cmds, ¶ms, d_cmd_spec_from_kind(cursor_snap_kind));
|
||||
}
|
||||
}
|
||||
}break;
|
||||
@@ -10737,13 +11010,13 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
B32 window_is_focused = os_window_is_focused(w->os);
|
||||
if(window_is_focused)
|
||||
{
|
||||
last_focused_window = df_handle_from_window(w);
|
||||
df_state->last_focused_window = df_handle_from_window(w);
|
||||
}
|
||||
d_push_regs();
|
||||
d_regs()->window = df_handle_from_window(w);
|
||||
df_window_update_and_render(scratch.arena, w, cmds);
|
||||
df_window_update_and_render(scratch.arena, w, &cmds);
|
||||
D_Regs *window_regs = d_pop_regs();
|
||||
if(df_window_from_handle(last_focused_window) == w)
|
||||
if(df_window_from_handle(df_state->last_focused_window) == w)
|
||||
{
|
||||
MemoryCopyStruct(d_regs(), window_regs);
|
||||
}
|
||||
@@ -10807,6 +11080,34 @@ df_frame(D_CmdList *cmds, F32 dt)
|
||||
r_end_frame();
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: show windows after first frame
|
||||
//
|
||||
if(os_handle_match(repaint_window_handle, os_handle_zero()))
|
||||
{
|
||||
D_HandleList windows_to_show = {0};
|
||||
for(DF_Window *w = df_state->first_window; w != 0; w = w->next)
|
||||
{
|
||||
if(w->frames_alive == 1)
|
||||
{
|
||||
d_handle_list_push(scratch.arena, &windows_to_show, df_handle_from_window(w));
|
||||
}
|
||||
}
|
||||
for(D_HandleNode *n = windows_to_show.first; n != 0; n = n->next)
|
||||
{
|
||||
DF_Window *window = df_window_from_handle(n->handle);
|
||||
os_window_first_paint(window->os);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: determine frame time, record into history
|
||||
//
|
||||
U64 end_time_us = os_now_microseconds();
|
||||
U64 frame_time_us = end_time_us-begin_time_us;
|
||||
df_state->frame_time_us_history[df_state->frame_time_us_history_idx%ArrayCount(df_state->frame_time_us_history)] = frame_time_us;
|
||||
df_state->frame_time_us_history_idx += 1;
|
||||
|
||||
di_scope_close(di_scope);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
@@ -666,6 +666,7 @@ struct DF_State
|
||||
DF_Window *free_window;
|
||||
U64 window_count;
|
||||
B32 last_window_queued_save;
|
||||
D_Handle last_focused_window;
|
||||
|
||||
// rjf: view state
|
||||
DF_View *first_view;
|
||||
@@ -697,6 +698,10 @@ struct DF_State
|
||||
|
||||
// rjf: icon texture
|
||||
R_Handle icon_texture;
|
||||
|
||||
// rjf: frame time history
|
||||
U64 frame_time_us_history[64];
|
||||
U64 frame_time_us_history_idx;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -963,6 +968,6 @@ __VA_ARGS__\
|
||||
//~ rjf: Main Layer Top-Level Calls
|
||||
|
||||
internal void df_init(OS_WindowRepaintFunctionType *window_repaint_entry_point, D_StateDeltaHistory *hist);
|
||||
internal void df_frame(D_CmdList *cmds, F32 dt);
|
||||
internal void df_frame(OS_Handle repaint_window_handle);
|
||||
|
||||
#endif // DBG_FRONTEND_CORE_H
|
||||
|
||||
@@ -1,317 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Frontend Entry Points
|
||||
|
||||
internal void
|
||||
update_and_render(OS_Handle repaint_window_handle, void *user_data)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: begin logging
|
||||
//
|
||||
if(main_thread_log == 0)
|
||||
{
|
||||
main_thread_log = log_alloc();
|
||||
String8 user_program_data_path = os_get_process_info()->user_program_data_path;
|
||||
String8 user_data_folder = push_str8f(scratch.arena, "%S/raddbg/logs", user_program_data_path);
|
||||
main_thread_log_path = push_str8f(d_state->arena, "%S/ui_thread.raddbg_log", user_data_folder);
|
||||
os_make_directory(user_data_folder);
|
||||
os_write_data_to_file_path(main_thread_log_path, str8_zero());
|
||||
}
|
||||
log_select(main_thread_log);
|
||||
log_scope_begin();
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: mark user-facing thread tick
|
||||
//
|
||||
ProfTick(0);
|
||||
txt_user_clock_tick();
|
||||
dasm_user_clock_tick();
|
||||
geo_user_clock_tick();
|
||||
tex_user_clock_tick();
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: get events from the OS
|
||||
//
|
||||
OS_EventList events = {0};
|
||||
if(os_handle_match(repaint_window_handle, os_handle_zero()))
|
||||
{
|
||||
events = os_get_events(scratch.arena, df_state->num_frames_requested == 0);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: pick target hz
|
||||
//
|
||||
// TODO(rjf): maximize target, given all windows and their monitors
|
||||
F32 target_hz = os_get_gfx_info()->default_refresh_rate;
|
||||
if(frame_time_us_history_idx > 32)
|
||||
{
|
||||
// rjf: calculate average frame time out of the last N
|
||||
U64 num_frames_in_history = Min(ArrayCount(frame_time_us_history), frame_time_us_history_idx);
|
||||
U64 frame_time_history_sum_us = 0;
|
||||
for(U64 idx = 0; idx < num_frames_in_history; idx += 1)
|
||||
{
|
||||
frame_time_history_sum_us += frame_time_us_history[idx];
|
||||
}
|
||||
U64 frame_time_history_avg_us = frame_time_history_sum_us/num_frames_in_history;
|
||||
|
||||
// rjf: pick among a number of sensible targets to snap to, given how well
|
||||
// we've been performing
|
||||
F32 possible_alternate_hz_targets[] = {target_hz, 60.f, 120.f, 144.f, 240.f};
|
||||
F32 best_target_hz = target_hz;
|
||||
S64 best_target_hz_frame_time_us_diff = max_S64;
|
||||
for(U64 idx = 0; idx < ArrayCount(possible_alternate_hz_targets); idx += 1)
|
||||
{
|
||||
F32 candidate = possible_alternate_hz_targets[idx];
|
||||
if(candidate <= target_hz)
|
||||
{
|
||||
U64 candidate_frame_time_us = 1000000/(U64)candidate;
|
||||
S64 frame_time_us_diff = (S64)frame_time_history_avg_us - (S64)candidate_frame_time_us;
|
||||
if(abs_s64(frame_time_us_diff) < best_target_hz_frame_time_us_diff)
|
||||
{
|
||||
best_target_hz = candidate;
|
||||
best_target_hz_frame_time_us_diff = frame_time_us_diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
target_hz = best_target_hz;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: target Hz -> delta time
|
||||
//
|
||||
F32 dt = 1.f/target_hz;
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: begin measuring actual per-frame work
|
||||
//
|
||||
U64 begin_time_us = os_now_microseconds();
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: bind change
|
||||
//
|
||||
if(!df_state->confirm_active && df_state->bind_change_active)
|
||||
{
|
||||
if(os_key_press(&events, os_handle_zero(), 0, OS_Key_Esc))
|
||||
{
|
||||
df_request_frame();
|
||||
df_state->bind_change_active = 0;
|
||||
}
|
||||
if(os_key_press(&events, os_handle_zero(), 0, OS_Key_Delete))
|
||||
{
|
||||
df_request_frame();
|
||||
df_unbind_spec(df_state->bind_change_cmd_spec, df_state->bind_change_binding);
|
||||
df_state->bind_change_active = 0;
|
||||
d_cmd(d_cfg_src_write_cmd_kind_table[D_CfgSrc_User]);
|
||||
}
|
||||
for(OS_Event *event = events.first, *next = 0; event != 0; event = next)
|
||||
{
|
||||
if(event->kind == OS_EventKind_Press &&
|
||||
event->key != OS_Key_Esc &&
|
||||
event->key != OS_Key_Return &&
|
||||
event->key != OS_Key_Backspace &&
|
||||
event->key != OS_Key_Delete &&
|
||||
event->key != OS_Key_LeftMouseButton &&
|
||||
event->key != OS_Key_RightMouseButton &&
|
||||
event->key != OS_Key_MiddleMouseButton &&
|
||||
event->key != OS_Key_Ctrl &&
|
||||
event->key != OS_Key_Alt &&
|
||||
event->key != OS_Key_Shift)
|
||||
{
|
||||
df_state->bind_change_active = 0;
|
||||
DF_Binding binding = zero_struct;
|
||||
{
|
||||
binding.key = event->key;
|
||||
binding.flags = event->flags;
|
||||
}
|
||||
df_unbind_spec(df_state->bind_change_cmd_spec, df_state->bind_change_binding);
|
||||
df_bind_spec(df_state->bind_change_cmd_spec, binding);
|
||||
U32 codepoint = os_codepoint_from_event_flags_and_key(event->flags, event->key);
|
||||
os_text(&events, os_handle_zero(), codepoint);
|
||||
os_eat_event(&events, event);
|
||||
d_cmd(d_cfg_src_write_cmd_kind_table[D_CfgSrc_User]);
|
||||
df_request_frame();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: consume events
|
||||
//
|
||||
{
|
||||
for(OS_Event *event = events.first, *next = 0;
|
||||
event != 0;
|
||||
event = next)
|
||||
{
|
||||
next = event->next;
|
||||
DF_Window *window = df_window_from_os_handle(event->window);
|
||||
D_CmdParams params = window ? df_cmd_params_from_window(window) : df_cmd_params_from_gfx();
|
||||
B32 take = 0;
|
||||
|
||||
//- rjf: try window close
|
||||
if(!take && event->kind == OS_EventKind_WindowClose && window != 0)
|
||||
{
|
||||
take = 1;
|
||||
d_cmd(D_CmdKind_CloseWindow, .window = df_handle_from_window(window));
|
||||
}
|
||||
|
||||
//- rjf: try menu bar operations
|
||||
{
|
||||
if(!take && event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0)
|
||||
{
|
||||
take = 1;
|
||||
df_request_frame();
|
||||
window->menu_bar_focused_on_press = window->menu_bar_focused;
|
||||
window->menu_bar_key_held = 1;
|
||||
window->menu_bar_focus_press_started = 1;
|
||||
}
|
||||
if(!take && event->kind == OS_EventKind_Release && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0)
|
||||
{
|
||||
take = 1;
|
||||
df_request_frame();
|
||||
window->menu_bar_key_held = 0;
|
||||
}
|
||||
if(window->menu_bar_focused && event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->flags == 0 && event->is_repeat == 0)
|
||||
{
|
||||
take = 1;
|
||||
df_request_frame();
|
||||
window->menu_bar_focused = 0;
|
||||
}
|
||||
else if(window->menu_bar_focus_press_started && !window->menu_bar_focused && event->kind == OS_EventKind_Release && event->flags == 0 && event->key == OS_Key_Alt && event->is_repeat == 0)
|
||||
{
|
||||
take = 1;
|
||||
df_request_frame();
|
||||
window->menu_bar_focused = !window->menu_bar_focused_on_press;
|
||||
window->menu_bar_focus_press_started = 0;
|
||||
}
|
||||
else if(event->kind == OS_EventKind_Press && event->key == OS_Key_Esc && window->menu_bar_focused && !ui_any_ctx_menu_is_open())
|
||||
{
|
||||
take = 1;
|
||||
df_request_frame();
|
||||
window->menu_bar_focused = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: try hotkey presses
|
||||
if(!take && event->kind == OS_EventKind_Press)
|
||||
{
|
||||
DF_Binding binding = {event->key, event->flags};
|
||||
D_CmdSpecList spec_candidates = df_cmd_spec_list_from_binding(scratch.arena, binding);
|
||||
if(spec_candidates.first != 0 && !d_cmd_spec_is_nil(spec_candidates.first->spec))
|
||||
{
|
||||
D_CmdSpec *run_spec = d_cmd_spec_from_kind(D_CmdKind_RunCommand);
|
||||
D_CmdSpec *spec = spec_candidates.first->spec;
|
||||
if(run_spec != spec)
|
||||
{
|
||||
params.cmd_spec = spec;
|
||||
}
|
||||
U32 hit_char = os_codepoint_from_event_flags_and_key(event->flags, event->key);
|
||||
take = 1;
|
||||
d_push_cmd(run_spec, ¶ms);
|
||||
if(event->flags & OS_EventFlag_Alt)
|
||||
{
|
||||
window->menu_bar_focus_press_started = 0;
|
||||
}
|
||||
}
|
||||
else if(OS_Key_F1 <= event->key && event->key <= OS_Key_F19)
|
||||
{
|
||||
window->menu_bar_focus_press_started = 0;
|
||||
}
|
||||
df_request_frame();
|
||||
}
|
||||
|
||||
//- rjf: try text events
|
||||
if(!take && event->kind == OS_EventKind_Text)
|
||||
{
|
||||
String32 insertion32 = str32(&event->character, 1);
|
||||
String8 insertion8 = str8_from_32(scratch.arena, insertion32);
|
||||
D_CmdSpec *spec = d_cmd_spec_from_kind(D_CmdKind_InsertText);
|
||||
params.string = insertion8;
|
||||
d_push_cmd(spec, ¶ms);
|
||||
df_request_frame();
|
||||
take = 1;
|
||||
if(event->flags & OS_EventFlag_Alt)
|
||||
{
|
||||
window->menu_bar_focus_press_started = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: do fall-through
|
||||
if(!take)
|
||||
{
|
||||
take = 1;
|
||||
params.os_event = event;
|
||||
d_push_cmd(d_cmd_spec_from_kind(D_CmdKind_OSEvent), ¶ms);
|
||||
}
|
||||
|
||||
//- rjf: take
|
||||
if(take)
|
||||
{
|
||||
os_eat_event(&events, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: gather root-level commands
|
||||
//
|
||||
D_CmdList cmds = d_gather_root_cmds(scratch.arena);
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: do frontend frame
|
||||
//
|
||||
df_frame(&cmds, dt);
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: show windows after first frame
|
||||
//
|
||||
if(os_handle_match(repaint_window_handle, os_handle_zero()))
|
||||
{
|
||||
D_HandleList windows_to_show = {0};
|
||||
for(DF_Window *w = df_state->first_window; w != 0; w = w->next)
|
||||
{
|
||||
if(w->frames_alive == 1)
|
||||
{
|
||||
d_handle_list_push(scratch.arena, &windows_to_show, df_handle_from_window(w));
|
||||
}
|
||||
}
|
||||
for(D_HandleNode *n = windows_to_show.first; n != 0; n = n->next)
|
||||
{
|
||||
DF_Window *window = df_window_from_handle(n->handle);
|
||||
os_window_first_paint(window->os);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: determine frame time, record into history
|
||||
//
|
||||
U64 end_time_us = os_now_microseconds();
|
||||
U64 frame_time_us = end_time_us-begin_time_us;
|
||||
frame_time_us_history[frame_time_us_history_idx%ArrayCount(frame_time_us_history)] = frame_time_us;
|
||||
frame_time_us_history_idx += 1;
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: end logging
|
||||
//
|
||||
{
|
||||
LogScopeResult log = log_scope_end(scratch.arena);
|
||||
os_append_data_to_file_path(main_thread_log_path, log.strings[LogMsgKind_Info]);
|
||||
if(log.strings[LogMsgKind_UserError].size != 0)
|
||||
{
|
||||
d_error(log.strings[LogMsgKind_UserError]);
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
internal CTRL_WAKEUP_FUNCTION_DEF(wakeup_hook_ctrl)
|
||||
{
|
||||
os_send_wakeup_event();
|
||||
}
|
||||
@@ -1,534 +0,0 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Frontend/UI Pass Tasks
|
||||
//
|
||||
// [ ] empty user file causing failure to launch
|
||||
//
|
||||
// [ ] engine/frontend commands situation
|
||||
// - currently, there is an interesting bifurcation of commands in the
|
||||
// frontend; you can either push a command *at a root level*, or push a
|
||||
// command to a locally-accessible list if you want that command to run
|
||||
// on the same frame (root level commands are deferred by a frame, since
|
||||
// the engine must see them first).
|
||||
// - things would be simpler if there was only a single "push command"
|
||||
// mechanism, and codepaths only ever saw these commands at most once.
|
||||
// this would require an alternate strategy of the initial "gather" of
|
||||
// commands, and instead it would just be a global queue, or something...
|
||||
// it is a little weird since commands are not just consumed in order...
|
||||
// - this will clean up the various different ways that codepaths
|
||||
// parameterize commands.
|
||||
// [ ] frontend entities vs. engine entities
|
||||
// - currently, the engine has entities like "watch", and the frontend
|
||||
// has entities like "windows", "panels", and "views".
|
||||
// - because "watch" entities ideally have a hierarchical relationship
|
||||
// with windows, panels, and views (enabling things like drag/drop
|
||||
// from watch window -> tab, or tab -> watch window, trivially), it
|
||||
// would be much better if all entities could collapse into engine
|
||||
// entities.
|
||||
// - now, the frontend requires various specialized resources for things
|
||||
// like windows, so what I am thinking is that the engine just controls
|
||||
// all of the stateful windows/panel/view/watch mechanisms, and then
|
||||
// the frontend pure-functionally queries stuff like os/r handles
|
||||
// on-demand, and then prunes them, immediate-mode cache style.
|
||||
// [ ] command params -> d_regs
|
||||
// - currently there are two almost-identical concepts relating to commands:
|
||||
// the parameters struct, and D_Regs. D_Regs is a registers struct which
|
||||
// is used to manage a stack of contextual information in various debugger
|
||||
// codepaths. it is used so that codepaths can register information they
|
||||
// know about, without passing it down to everyone explicitly - but those
|
||||
// later codepaths can still pass that information along. e.g. a window
|
||||
// calls into a watch window, watch window calls into visualizer, visualizer
|
||||
// pushes command, which needs to pass which window it occurred on along.
|
||||
// - i think D_Regs needs to expand a bit in order to encompass all of the
|
||||
// things that the command parameters were being used for, but at that point
|
||||
// commands can just be a spec * regs, and then the push-command API can
|
||||
// just have ways of overriding regs values explicitly, when the codepath
|
||||
// needs to be opinionated about which things are affected by which commands
|
||||
//
|
||||
// [ ] transient view timeout releasing
|
||||
//
|
||||
// [ ] save view column pcts; generalize to being a first-class thing in
|
||||
// DF_View, e.g. by just having a string -> f32 store
|
||||
// [ ] decay arrays to pointers in pointer/value comparison
|
||||
// [ ] EVAL LOOKUP RULES -> currently going 0 -> rdis_count, but we need
|
||||
// to prioritize the primary rdi
|
||||
//
|
||||
// [ ] file overrides -> always pick most specific one! found with conflicting
|
||||
// overrides, e.g. C:/devel/ -> D:/devel/, but also C:/devel/foo ->
|
||||
// C:/devel/bar, etc.
|
||||
//
|
||||
// [ ] auto-scroll output window
|
||||
// [ ] theme lister -> fonts & font sizes
|
||||
// [ ] "Browse..." buttons should adopt a more relevant starting search path,
|
||||
// if possible
|
||||
// [ ] visualize all breakpoints everywhere - source view should show up in
|
||||
// disasm, disasm should show up in source view, function should show up in
|
||||
// both, etc.
|
||||
// [ ] ** Function breakpoints should show up in the source listing. Without
|
||||
// them being visible, it is confusing when you run and you stop there,
|
||||
// because you're like "wait why did it stop" and then you later remember
|
||||
// that's because there was a function breakpoint there.
|
||||
//
|
||||
// [ ] font lister
|
||||
// [ ] per-panel font size overrides
|
||||
//
|
||||
// [ ] For the Scheduler window, it would be nice if you could dim or
|
||||
// folderize threads that are not your threads - eg., if a thread doesn't
|
||||
// have any resolved stack pointers in your executable code, then you can
|
||||
// ignore it when you are focusing on your own code. I don't know what the
|
||||
// best way to detect this is, other than by walking the call stack... one
|
||||
// way might be to just have a way to separate threads you've named from
|
||||
// threads you haven't? Or, there could even be a debugger-specific API
|
||||
// that you use to tag them. Just some way that would make it easier to
|
||||
// focus on your own threads.
|
||||
//
|
||||
// [ ] "concept key stack"; basically, any point in UI builder path has a stack
|
||||
// of active "concept keys", which can be used to e.g. build context menus
|
||||
// automatically (could just be a per-box attachment; right-click any
|
||||
// point, search up the tree and see the concept keys)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup)
|
||||
//
|
||||
// [ ] Setting the code_font/main_font values to a font name doesn't work.
|
||||
// Should probably make note that you have to set it to a path to a TTF,
|
||||
// since that's not normally how Windows fonts work.
|
||||
//
|
||||
// [ ] "root" concept in hash store, which buckets keys & allows usage code to
|
||||
// jettison a collection of keys in retained mode fashion
|
||||
//
|
||||
// [ ] Jeff Notes
|
||||
// [ ] sort locals by appearance in source code (or maybe just debug info)
|
||||
// [ ] sum view rule
|
||||
// [ ] plot view rule
|
||||
// [ ] histogram view rule
|
||||
// [ ] max view rule
|
||||
// [ ] min view rule
|
||||
//
|
||||
// [ ] filesystem drag/drop support
|
||||
// [ ] double-click vs. single-click for folder navigation, see if we can infer
|
||||
// [ ] use backslashes on windows by default, forward slashes elsewhere
|
||||
//
|
||||
// [ ] investigate /DEBUG:FASTLINK - can we somehow alert that we do not
|
||||
// support it?
|
||||
//
|
||||
// [ ] ** Converter performance & heuristics for asynchronously doing it early
|
||||
//
|
||||
// [ ] visualize conversion failures
|
||||
//
|
||||
// [ ] I was a little confused about what a profile file was. I understood
|
||||
// what the user file was, but the profile file sounded like it should
|
||||
// perhaps be per-project, yet it sounded like it was meant to be somewhat
|
||||
// global? I don't have any feedback here because it probably will make
|
||||
// sense once I use the debugger more, but I just thought I'd make a note
|
||||
// to say that I was confused about it after reading the manual, so
|
||||
// perhaps you could elaborate a little more on it in there.
|
||||
// [ ] It wasn't clear to me how you save a user or project file. I can see
|
||||
// how to load them, but not how you save them. Obviously I can just copy
|
||||
// the files myself in the shell, but it seemed weird that there was no
|
||||
// "save" option in the menus.
|
||||
//
|
||||
// [ ] Right-clicking on a thread in the Scheduler window pops up a context
|
||||
// menu, but you can't actually see it because the tooltip for the thread
|
||||
// draws on top of it, so you can't see the menu.
|
||||
//
|
||||
// [ ] In a "hover watch" (where you hover over a variable and it shows a pop-
|
||||
// up watch window), if you expand an item near the bottom of the listing,
|
||||
// it will be clipped to the bottom of the listing instead of showing the
|
||||
// actual items (ie., it doesn't resize the listing based on what's
|
||||
// actually visible)
|
||||
//
|
||||
// [ ] ** One very nice feature of RemedyBG that I use all the time is the
|
||||
// ability to put "$err, hr" into the watch window, which will just show
|
||||
// the value of GetLastError() as a string. This is super useful for
|
||||
// debugging, so you don't have to litter your own code with it.
|
||||
//
|
||||
// [ ] Tooltip Coverage:
|
||||
// [ ] lock icon
|
||||
// [ ] "rotation arrow" icon next to executables
|
||||
//
|
||||
// [ ] For theme editing, when you hove the mouse over a theme color entry and
|
||||
// it highlights that entry, it might help to temporarily change that
|
||||
// color to white (or the inverse of the background color, or whatever) so
|
||||
// that the user can see what things on the screen use that theme color.
|
||||
//
|
||||
// [ ] I had to go into the user file to change the font. That should probably
|
||||
// be in the theme window?
|
||||
//
|
||||
// [ ] It'd be nice to have a "goto byte" option for source views, for jumping
|
||||
// to error messages that are byte-based instead of line-based.
|
||||
//
|
||||
// [ ] @feature debug info overrides (both path-based AND module-based)
|
||||
//
|
||||
// [ ] C++ virtual inheritance member visualization in watch window
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, Low Priority Tasks (UI Opinions, Less-Serious Jank, Preferences, Cleanup)
|
||||
//
|
||||
// [ ] The hex format for color values in the config file was a real
|
||||
// mindbender. It's prefixed with "0x", so I was assuming it was either
|
||||
// Windows Big Endian (0xAARRGGBB) or Mac Little Endian (0xAABBGGRR). To
|
||||
// my surprise, it was neither - it was actually web format (RRGGBBAA),
|
||||
// which I was not expecting because that is normally written with a
|
||||
// number sign (#AARRGGBB) not an 0x.
|
||||
//
|
||||
// [ ] Clicking on either side of a scroll bar is idiosyncratic. Normally,
|
||||
// that is "page up" / "page down", but here it is "smooth scroll upward"
|
||||
// / "smooth scroll downward" for some reason?
|
||||
//
|
||||
// [ ] can it ignore stepping into _RTC_CheckStackVars generated functions?
|
||||
// [ ] mouse back button should make view to go back after I double clicked
|
||||
// on function to open it
|
||||
// [ ] Alt+8 to switch to disassembly would be nice (regardless on which
|
||||
// panel was previous, don't want to use ctrl+, multiple times)
|
||||
// Alt+8 for disasm and Alt+6 for memory view are shortcuts I often use
|
||||
// in VS
|
||||
// [ ] default font size is too small for me - not only source code, but
|
||||
// menus/tab/watch names (which don't resize). Maybe you could query
|
||||
// Windows for initial font size?
|
||||
// [ ] icon fonts glyphs sometimes disappear for specific font size, but they
|
||||
// reappear if you go +1 higher or -1 lower. Mostly red triangle in watch
|
||||
// values for "unknown identifier". But also yellow arrow in call stack
|
||||
// disappears if font size gets too large.
|
||||
// [ ] undo close tab would be nice. If not for everything, then at least
|
||||
// just for source files
|
||||
// [ ] Jump table thunks, on code w/o /INCREMENTAL:NO
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, Feature Tasks (Not really "low priority" but less urgent than fixes)
|
||||
//
|
||||
// [ ] @eval_upgrade
|
||||
// [ ] new eval system; support strings, many address spaces, many debug
|
||||
// infos, wide/async transforms (e.g. diff(blob1, blob2))
|
||||
//
|
||||
// [ ] Fancy View Rules
|
||||
// [ ] table column boundaries should be checked against *AFTER* table
|
||||
// contents, not before
|
||||
// [ ] `array:(x, y)` - multidimensional array
|
||||
//
|
||||
// [ ] search-in-all-files
|
||||
//
|
||||
// [ ] Memory View
|
||||
// [ ] memory view mutation controls
|
||||
// [ ] memory view user-made annotations
|
||||
//
|
||||
// [ ] undo/redo
|
||||
// [ ] proper "go back" + "go forward" history navigations
|
||||
//
|
||||
// [ ] globally disable/configure default view rule-like things (string
|
||||
// viz for u8s in particular)
|
||||
//
|
||||
// [ ] @feature processor/data breakpoints
|
||||
// [ ] @feature automatically snap to search matches when searching source files
|
||||
// [ ] automatically start search query with selected text
|
||||
// [ ] @feature entity views: filtering & reordering
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cold, Clean-up Tasks That Probably Only Ryan Notices
|
||||
// (E.G. Because They Are Code-Related Or Because Nobody Cares)
|
||||
//
|
||||
// [ ] @bug view-snapping in scroll-lists, accounting for mapping between
|
||||
// visual positions & logical positions (variably sized rows in watch,
|
||||
// table headers, etc.)
|
||||
// [ ] @cleanup straighten out index/number space & types & terminology for
|
||||
// scroll lists
|
||||
// [ ] @cleanup central worker thread pool - eliminate per-layer thread pools
|
||||
// [ ] @cleanup eliminate explicit font parameters in the various ui paths (e.g.
|
||||
// code slice params)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cold, Unsorted Notes (Deferred Until Existing Lists Mostly Exhausted)
|
||||
//
|
||||
// [ ] @feature types -> auto view rules (don't statefully fill view rules
|
||||
// given types, just query if no other view rule is present, & autofill
|
||||
// when editing)
|
||||
// [ ] @feature eval system -> somehow evaluate breakpoint hit counts? "meta"
|
||||
// variables?
|
||||
//
|
||||
// [ ] @feature disasm view improvement features
|
||||
// [ ] visualize jump destinations in disasm
|
||||
//
|
||||
// [ ] @feature eval ui improvement features
|
||||
// [ ] serializing eval view maps
|
||||
// [ ] view rule editors in hover-eval
|
||||
// [ ] view rule hook coverage
|
||||
// [ ] `each:(expr addition)` - apply some additional expression to all
|
||||
// elements in an array/linked list would be useful to look at only a
|
||||
// subset of an array of complex structs
|
||||
// [ ] `slider:(min max)` view rule
|
||||
// [ ] `v2f32` view rule
|
||||
// [ ] `v3` view rule
|
||||
// [ ] `quat` view rule
|
||||
// [ ] `matrix` view rule
|
||||
// [ ] `audio` waveform view rule
|
||||
// [ ] smart scopes - expression operators for "grab me the first type X"
|
||||
// [ ] "pinning" watch expressions, to attach it to a particular ctrl_ctx
|
||||
//
|
||||
// [ ] @feature header file for target -> debugger communication; printf, log,
|
||||
// etc.
|
||||
// [ ] @feature just-in-time debugging
|
||||
// [ ] @feature step-out-of-loop
|
||||
//
|
||||
//-[ ] long-term future notes from martins
|
||||
// [ ] core dump saving/loading
|
||||
// [ ] parallel call stacks view
|
||||
// [ ] parallel watch view
|
||||
// [ ] mixed native/interpreted/jit debugging
|
||||
// - it seems python has a top-level linked list of interpreter states,
|
||||
// which should allow the debugger to map native callstacks to python
|
||||
// code
|
||||
//
|
||||
// [ ] fancy string runs can include "weakness" information for text truncation
|
||||
// ... can prioritize certain parts of strings to be truncated before
|
||||
// others. would be good for e.g. the middle of a path
|
||||
// [ ] font cache eviction (both for font tags, closing fp handles, and
|
||||
// rasterizations)
|
||||
// [ ] frontend speedup opportunities
|
||||
// [ ] tables in UI -> currently building per-row, could probably cut down on
|
||||
// # of boxes and # of draws by doing per-column in some cases?
|
||||
// [ ] font cache layer -> can probably cache (string*font*size) -> (run) too
|
||||
// (not just rasterization)... would save a *lot*, there is a ton of work
|
||||
// just in looking up & stitching stuff repeatedly
|
||||
// [ ] convert UI layout pass to not be naive recursive version
|
||||
// [ ] (big change) parallelize window ui build codepaths per-panel
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Recently Completed Task Log
|
||||
//
|
||||
// [x] UI_NavActions, OS_Event -> UI_Event (single event stream)
|
||||
// [x] better discoverability for view rules - have better help hover tooltip,
|
||||
// info on arguments, and better autocomplete lister
|
||||
// [x] source view -> floating margin/line-nums
|
||||
// [x] watch window reordering
|
||||
// [x] standard way to filter
|
||||
// [x] autocomplete lister should respect position in edited expression,
|
||||
// tabbing through should autocomplete but not exit, etc.
|
||||
// [x] pipe failure-to-launch errors back to frontend
|
||||
// [x] bit more padding on the tabs
|
||||
// [x] unified top-level cursor/typing/lister helper
|
||||
// [x] collapse text cells & command lister & etc. into same codepath (?)
|
||||
// [x] page-up & page-down correct handling in keyboard nav
|
||||
// [x] interleaved src/dasm view
|
||||
// [x] in watch window when I enter some new expression and then click mouse
|
||||
// away from cell, then it should behave the same as if I pressed enter.
|
||||
// Currently it does the same as if I have pressed esc and I have lost my
|
||||
// expression
|
||||
// [x] pressing random keyboard keys in source code advances text cursor like
|
||||
// you were inputting text, very strange.
|
||||
// [x] It's confusing that ENTER is the way you expand and collapse things in
|
||||
// the watch window, but then also how you edit them if they are not
|
||||
// expandable? It seems like this should be consistent (one way to edit,
|
||||
// one way to expand/collapse, that are distinct)
|
||||
// [x] Dragging a window tab (like Locals or Registers or whatnot) and
|
||||
// canceling with ESC should revert the window tab to where it was.
|
||||
// Currently, it leaves the window tab reordered if you dragged over its
|
||||
// window and shuffled its position.
|
||||
// [x] ** I couldn't figure out how to really view threads in the debugger.
|
||||
// The only place I found a thread list was in "The Scheduler", but it
|
||||
// only lists threads by ID, which is hard to use. I can hover over them
|
||||
// to get the stack, which helps, but it would be much nicer if the top
|
||||
// function was displayed in the window by default next to the thread.
|
||||
// [x] ** It would be nice if thread listings displayed the name of the
|
||||
// thread, instead of just the ID.
|
||||
// [x] TLS eval -> in-process-memory EXE info
|
||||
// [x] unwinding -> in-process-memory EXE info
|
||||
// [x] new fuzzy searching layer
|
||||
// [x] robustify dbgi layer to renames (cache should not be based only on
|
||||
// path - must invalidate naturally when new filetime occurs)
|
||||
// [x] rdi file regeneration too strict
|
||||
// [x] raddbg jai.exe my_file.jai -- foobar -> raddbg consumes `--` incorrectly
|
||||
// [x] mouse-driven way to complete file/folder selection, or more generally
|
||||
// query completion
|
||||
// [x] it would be nice to have "show in explorer" for right click on source
|
||||
// file tab (opens explorer & selects the file)
|
||||
// [x] asan stepping breakage
|
||||
// [x] what's up with decimal number coloring where every group of 3 are in
|
||||
// different color? can I turn it off? And why sometimes digits in number
|
||||
// start with brighter color, but sometimes with darker - shouldn't it
|
||||
// always have the same color ordering?
|
||||
// [x] fix tabs-on-bottom positioning
|
||||
// [x] colors: consistent tooltip styles (colors, font flags, etc.)
|
||||
// [x] colors: scroll bars
|
||||
// [x] colors: watch window navigation visuals
|
||||
// [x] floating source view margin background/placement
|
||||
// [x] "interaction root", or "group" ui_key, or something; used for menu bar interactions
|
||||
// [x] theme colors -> more explicit about e.g. opaque backgrounds vs. floating
|
||||
// & scrollbars etc.
|
||||
// [x] Pressing the left mouse button on the menu bar and dragging does not
|
||||
// move through the menus as expected - instead, it opens the one you
|
||||
// clicked down on, then does nothing until you release, at which point it
|
||||
// opens the menu you released on.
|
||||
// [x] Similarly, pressing the left mouse button on a menu and dragging to an
|
||||
// item, then releasing, does not trigger that item as expected. Instead,
|
||||
// it is a nop, and it waits for you to click again on the item.
|
||||
// [x] Using the word "symbol" in "Code (Symbol)" seems like a bad idea, since
|
||||
// you're referring to non-identifier characters, but in a debugger
|
||||
// "symbol" usually means something defined in the debug information.
|
||||
// [x] I couldn't figure out how to affect the "dim" color in constants that
|
||||
// have alternating bright/dim letters to show sections of a number. Is
|
||||
// this in the theme colors somewhere?
|
||||
//
|
||||
// [x] ** Scrollbars are barely visible for me, for some reason. I could not
|
||||
// find anything in the theme that would fill them with a solid, bright
|
||||
// color. Instead they are just a thin outline and the same color as the
|
||||
// scroll bar background.
|
||||
//
|
||||
// [x] Many of the UI elements, like the menus, would like better if they had
|
||||
// a little bit of margin. Having the text right next to the edges, and
|
||||
// with no line spacing, makes it harder to read things quickly.
|
||||
// [x] colors: memory view
|
||||
// [x] Hitting ESC during a color picker drag should abort the color picking
|
||||
// and revert to the previous color. Currently, it just accepts the last
|
||||
// drag result as the new color.
|
||||
// [x] It was not clear to me why a small "tab picker" appeared when I got to
|
||||
// a certain number of tabs. It seemed to appear even if the tabs were
|
||||
// quite large, and there was no need to a drop-down menu to pick them. It
|
||||
// feels like either it should always be there, or it should only show up
|
||||
// if at least one tab gets small enough to have its name cut off?
|
||||
// [x] I found the "context menu" convention to be confusing. For example, if
|
||||
// I left-click on a tab, it selects the tab. If I right-click on a tab,
|
||||
// it opens the context menu. However, if I left-click on a module, it
|
||||
// opens the context window. It seems like maybe menus should be right,
|
||||
// and left should do the default action, more consistently?
|
||||
//
|
||||
// [x] double click on procedure in procedures tab to jump to source
|
||||
// [x] highlighted text & ctrl+f -> auto-fill search query
|
||||
// [x] double-click any part of frame in callstack view -> snap to function
|
||||
// [x] Menus take too long to show up. I would prefer it if they were instant.
|
||||
// The animation doesn't really provide any useful cues, since I know
|
||||
// where the menu came from.
|
||||
// [x] user settings (ui & functionality - generally need a story for it)
|
||||
// [x] hover animations
|
||||
// [x] press animations
|
||||
// [x] focus animations
|
||||
// [x] tooltip animations
|
||||
// [x] context menu animations
|
||||
// [x] scrolling animations
|
||||
// [x] background blur
|
||||
// [x] tab width
|
||||
// [x] ** In the call stack, I would like to be able to click quickly and move
|
||||
// around the stack. Right now, you can do that with the first and third
|
||||
// column, but the second column drops down a context menu. Since right
|
||||
// click is already for context menus, can it not just be that double-
|
||||
// clicking any column jumps to that stack frame?
|
||||
//
|
||||
// [x] ** I find it really hard to read the code with the heavyweight lines
|
||||
// running through it for breakpoints and stepping and things. Is there a
|
||||
// way to turn the lines off? AFAICT they are based on thread and
|
||||
// breakpoint color, so you can't really control the line drawing? I might
|
||||
// be fine with them, but they would have to be much more light (like
|
||||
// alpha 0.1 or something)
|
||||
// [x] zooming behaves very strangely - sometimes it zooms source code,
|
||||
// sometimes both source code and menu/tab/watch font size, sometimes
|
||||
// just menu/tab/watch font size not source size.
|
||||
// [x] colors: fill out rest of theme presets for new theme setup
|
||||
// [x] I LOVE ALT-W to add watch under cursor, but I would prefer to have it
|
||||
// add what's under the MOUSE cursor instead of the keyboard cursor. Can
|
||||
// we get a command for that so I can bind ALT-W to that instead?
|
||||
// [x] editing multiple bindings for commands
|
||||
// [x] inline breakpoint hit_count
|
||||
// [x] to count hit counts, resolve all bps to addresses, check addresses
|
||||
// against stopper thread's
|
||||
//
|
||||
// [x] PDB files distributed with the build are not found by DbgHelp!!!
|
||||
// [x] Jai compiler debugging crash
|
||||
//
|
||||
//- 2024/8/29
|
||||
//
|
||||
// [x] fix HRESULTs
|
||||
// [x] fix escape char literals
|
||||
// [x] eval: indexing into string literals
|
||||
// [x] fix incorrectly consuming keyboard inputs, preventing fallback-to-filtering, when
|
||||
// selecting null selection in watch views
|
||||
// [x] ui_next_event(...), built-in focus filtering, no need to manually check
|
||||
// if(ui_is_focus_active())
|
||||
// [x] Theme window should include font scaling. I was able to find the
|
||||
// command for increasing the font scale, but I imagine most people
|
||||
// wouldn't think to look there.
|
||||
// [x] n-row table selection, in watch window & other UIs, multi-selection
|
||||
// ctrl+C
|
||||
// [x] target/breakpoint/watch-pin reordering
|
||||
// [x] move breakpoints to being a global thing, not nested to particular files
|
||||
// [x] EVAL SPACES - each rdi gets an rdi space, rdi space is passed to
|
||||
// memory reads & so on, used to resolve to value space; REPLACES "mode"
|
||||
// [x] fix selecting hover eval, then hover eval disappearing, causing
|
||||
// busted focus, until a new hover eval is opened
|
||||
// [x] `text[:lang]` - interpret memory as text, in lang `lang`
|
||||
// [x] `disasm:arch` - interpret memory as machine code for isa `arch`
|
||||
// [x] `memory` - view memory in usual memory hex-editor view
|
||||
// NOTE(rjf): When the visualization system is solid, layers like dasm, txti,
|
||||
// and so on can be dispensed with, as things like the source view, disasm
|
||||
// view, or memory view will simply be specializations of the general purpose
|
||||
// viz system.
|
||||
// [x] view rule hook for standalone visualization ui, granted its own
|
||||
// tab
|
||||
// [x] collapse frontend visualization systems - source view, disasm view,
|
||||
// callstack, modules, scheduler, should *all* be flavors of watch view
|
||||
// [x] globally disable/configure bp/ip lines in source view
|
||||
// [x] @cleanup naming pass over eval visualization part of the frontend,
|
||||
// "blocks" vs. "canvas" vs. "expansion" - etc.
|
||||
// [x] @cleanup collapse DF_CfgNodes into just being MD trees, find another way
|
||||
// to encode config source - don't need it at every node
|
||||
// [x] @cleanup in the frontend, we are starting to have to pass down "DF_Window"
|
||||
// everywhere, because of per-window parameters (e.g. font rendering settings).
|
||||
// this is really better solved by implicit thread-local parameters, similar to
|
||||
// interaction registers, so that one window can "pick" all of the implicit
|
||||
// parameters, and then 99% of the UI code does not have to care.
|
||||
// [x] @cleanup simplification pass over eval visualization pipeline & types,
|
||||
// including view rule hooks
|
||||
|
||||
#ifndef RADDBG_H
|
||||
#define RADDBG_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Execution Types
|
||||
|
||||
typedef enum ExecMode
|
||||
{
|
||||
ExecMode_Normal,
|
||||
ExecMode_IPCSender,
|
||||
ExecMode_Converter,
|
||||
ExecMode_Help,
|
||||
}
|
||||
ExecMode;
|
||||
|
||||
typedef struct IPCInfo IPCInfo;
|
||||
struct IPCInfo
|
||||
{
|
||||
U64 msg_size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
//- rjf: IPC resources
|
||||
#define IPC_SHARED_MEMORY_BUFFER_SIZE MB(4)
|
||||
StaticAssert(IPC_SHARED_MEMORY_BUFFER_SIZE > sizeof(IPCInfo), ipc_buffer_size_requirement);
|
||||
global OS_Handle ipc_signal_semaphore = {0};
|
||||
global OS_Handle ipc_lock_semaphore = {0};
|
||||
global U8 *ipc_shared_memory_base = 0;
|
||||
global U8 ipc_s2m_ring_buffer[MB(4)] = {0};
|
||||
global U64 ipc_s2m_ring_write_pos = 0;
|
||||
global U64 ipc_s2m_ring_read_pos = 0;
|
||||
global OS_Handle ipc_s2m_ring_mutex = {0};
|
||||
global OS_Handle ipc_s2m_ring_cv = {0};
|
||||
|
||||
//- rjf: last focused window
|
||||
global D_Handle last_focused_window = {0};
|
||||
|
||||
//- rjf: frame time history
|
||||
global U64 frame_time_us_history[64] = {0};
|
||||
global U64 frame_time_us_history_idx = 0;
|
||||
|
||||
//- rjf: main thread log
|
||||
global Log *main_thread_log = 0;
|
||||
global String8 main_thread_log_path = {0};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Frontend Entry Points
|
||||
|
||||
internal void update_and_render(OS_Handle repaint_window_handle, void *user_data);
|
||||
|
||||
#endif // RADDBG_H
|
||||
+562
-2
@@ -1,6 +1,484 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Frontend/UI Pass Tasks
|
||||
//
|
||||
// [ ] empty user file causing failure to launch
|
||||
//
|
||||
// [ ] engine/frontend commands situation
|
||||
// - currently, there is an interesting bifurcation of commands in the
|
||||
// frontend; you can either push a command *at a root level*, or push a
|
||||
// command to a locally-accessible list if you want that command to run
|
||||
// on the same frame (root level commands are deferred by a frame, since
|
||||
// the engine must see them first).
|
||||
// - things would be simpler if there was only a single "push command"
|
||||
// mechanism, and codepaths only ever saw these commands at most once.
|
||||
// this would require an alternate strategy of the initial "gather" of
|
||||
// commands, and instead it would just be a global queue, or something...
|
||||
// it is a little weird since commands are not just consumed in order...
|
||||
// - this will clean up the various different ways that codepaths
|
||||
// parameterize commands.
|
||||
// [ ] frontend entities vs. engine entities
|
||||
// - currently, the engine has entities like "watch", and the frontend
|
||||
// has entities like "windows", "panels", and "views".
|
||||
// - because "watch" entities ideally have a hierarchical relationship
|
||||
// with windows, panels, and views (enabling things like drag/drop
|
||||
// from watch window -> tab, or tab -> watch window, trivially), it
|
||||
// would be much better if all entities could collapse into engine
|
||||
// entities.
|
||||
// - now, the frontend requires various specialized resources for things
|
||||
// like windows, so what I am thinking is that the engine just controls
|
||||
// all of the stateful windows/panel/view/watch mechanisms, and then
|
||||
// the frontend pure-functionally queries stuff like os/r handles
|
||||
// on-demand, and then prunes them, immediate-mode cache style.
|
||||
// [ ] command params -> d_regs
|
||||
// - currently there are two almost-identical concepts relating to commands:
|
||||
// the parameters struct, and D_Regs. D_Regs is a registers struct which
|
||||
// is used to manage a stack of contextual information in various debugger
|
||||
// codepaths. it is used so that codepaths can register information they
|
||||
// know about, without passing it down to everyone explicitly - but those
|
||||
// later codepaths can still pass that information along. e.g. a window
|
||||
// calls into a watch window, watch window calls into visualizer, visualizer
|
||||
// pushes command, which needs to pass which window it occurred on along.
|
||||
// - i think D_Regs needs to expand a bit in order to encompass all of the
|
||||
// things that the command parameters were being used for, but at that point
|
||||
// commands can just be a spec * regs, and then the push-command API can
|
||||
// just have ways of overriding regs values explicitly, when the codepath
|
||||
// needs to be opinionated about which things are affected by which commands
|
||||
//
|
||||
// [ ] transient view timeout releasing
|
||||
//
|
||||
// [ ] save view column pcts; generalize to being a first-class thing in
|
||||
// DF_View, e.g. by just having a string -> f32 store
|
||||
// [ ] decay arrays to pointers in pointer/value comparison
|
||||
// [ ] EVAL LOOKUP RULES -> currently going 0 -> rdis_count, but we need
|
||||
// to prioritize the primary rdi
|
||||
//
|
||||
// [ ] file overrides -> always pick most specific one! found with conflicting
|
||||
// overrides, e.g. C:/devel/ -> D:/devel/, but also C:/devel/foo ->
|
||||
// C:/devel/bar, etc.
|
||||
//
|
||||
// [ ] auto-scroll output window
|
||||
// [ ] theme lister -> fonts & font sizes
|
||||
// [ ] "Browse..." buttons should adopt a more relevant starting search path,
|
||||
// if possible
|
||||
// [ ] visualize all breakpoints everywhere - source view should show up in
|
||||
// disasm, disasm should show up in source view, function should show up in
|
||||
// both, etc.
|
||||
// [ ] ** Function breakpoints should show up in the source listing. Without
|
||||
// them being visible, it is confusing when you run and you stop there,
|
||||
// because you're like "wait why did it stop" and then you later remember
|
||||
// that's because there was a function breakpoint there.
|
||||
//
|
||||
// [ ] font lister
|
||||
// [ ] per-panel font size overrides
|
||||
//
|
||||
// [ ] For the Scheduler window, it would be nice if you could dim or
|
||||
// folderize threads that are not your threads - eg., if a thread doesn't
|
||||
// have any resolved stack pointers in your executable code, then you can
|
||||
// ignore it when you are focusing on your own code. I don't know what the
|
||||
// best way to detect this is, other than by walking the call stack... one
|
||||
// way might be to just have a way to separate threads you've named from
|
||||
// threads you haven't? Or, there could even be a debugger-specific API
|
||||
// that you use to tag them. Just some way that would make it easier to
|
||||
// focus on your own threads.
|
||||
//
|
||||
// [ ] "concept key stack"; basically, any point in UI builder path has a stack
|
||||
// of active "concept keys", which can be used to e.g. build context menus
|
||||
// automatically (could just be a per-box attachment; right-click any
|
||||
// point, search up the tree and see the concept keys)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup)
|
||||
//
|
||||
// [ ] Setting the code_font/main_font values to a font name doesn't work.
|
||||
// Should probably make note that you have to set it to a path to a TTF,
|
||||
// since that's not normally how Windows fonts work.
|
||||
//
|
||||
// [ ] "root" concept in hash store, which buckets keys & allows usage code to
|
||||
// jettison a collection of keys in retained mode fashion
|
||||
//
|
||||
// [ ] Jeff Notes
|
||||
// [ ] sort locals by appearance in source code (or maybe just debug info)
|
||||
// [ ] sum view rule
|
||||
// [ ] plot view rule
|
||||
// [ ] histogram view rule
|
||||
// [ ] max view rule
|
||||
// [ ] min view rule
|
||||
//
|
||||
// [ ] filesystem drag/drop support
|
||||
// [ ] double-click vs. single-click for folder navigation, see if we can infer
|
||||
// [ ] use backslashes on windows by default, forward slashes elsewhere
|
||||
//
|
||||
// [ ] investigate /DEBUG:FASTLINK - can we somehow alert that we do not
|
||||
// support it?
|
||||
//
|
||||
// [ ] ** Converter performance & heuristics for asynchronously doing it early
|
||||
//
|
||||
// [ ] visualize conversion failures
|
||||
//
|
||||
// [ ] I was a little confused about what a profile file was. I understood
|
||||
// what the user file was, but the profile file sounded like it should
|
||||
// perhaps be per-project, yet it sounded like it was meant to be somewhat
|
||||
// global? I don't have any feedback here because it probably will make
|
||||
// sense once I use the debugger more, but I just thought I'd make a note
|
||||
// to say that I was confused about it after reading the manual, so
|
||||
// perhaps you could elaborate a little more on it in there.
|
||||
// [ ] It wasn't clear to me how you save a user or project file. I can see
|
||||
// how to load them, but not how you save them. Obviously I can just copy
|
||||
// the files myself in the shell, but it seemed weird that there was no
|
||||
// "save" option in the menus.
|
||||
//
|
||||
// [ ] Right-clicking on a thread in the Scheduler window pops up a context
|
||||
// menu, but you can't actually see it because the tooltip for the thread
|
||||
// draws on top of it, so you can't see the menu.
|
||||
//
|
||||
// [ ] In a "hover watch" (where you hover over a variable and it shows a pop-
|
||||
// up watch window), if you expand an item near the bottom of the listing,
|
||||
// it will be clipped to the bottom of the listing instead of showing the
|
||||
// actual items (ie., it doesn't resize the listing based on what's
|
||||
// actually visible)
|
||||
//
|
||||
// [ ] ** One very nice feature of RemedyBG that I use all the time is the
|
||||
// ability to put "$err, hr" into the watch window, which will just show
|
||||
// the value of GetLastError() as a string. This is super useful for
|
||||
// debugging, so you don't have to litter your own code with it.
|
||||
//
|
||||
// [ ] Tooltip Coverage:
|
||||
// [ ] lock icon
|
||||
// [ ] "rotation arrow" icon next to executables
|
||||
//
|
||||
// [ ] For theme editing, when you hove the mouse over a theme color entry and
|
||||
// it highlights that entry, it might help to temporarily change that
|
||||
// color to white (or the inverse of the background color, or whatever) so
|
||||
// that the user can see what things on the screen use that theme color.
|
||||
//
|
||||
// [ ] I had to go into the user file to change the font. That should probably
|
||||
// be in the theme window?
|
||||
//
|
||||
// [ ] It'd be nice to have a "goto byte" option for source views, for jumping
|
||||
// to error messages that are byte-based instead of line-based.
|
||||
//
|
||||
// [ ] @feature debug info overrides (both path-based AND module-based)
|
||||
//
|
||||
// [ ] C++ virtual inheritance member visualization in watch window
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, Low Priority Tasks (UI Opinions, Less-Serious Jank, Preferences, Cleanup)
|
||||
//
|
||||
// [ ] The hex format for color values in the config file was a real
|
||||
// mindbender. It's prefixed with "0x", so I was assuming it was either
|
||||
// Windows Big Endian (0xAARRGGBB) or Mac Little Endian (0xAABBGGRR). To
|
||||
// my surprise, it was neither - it was actually web format (RRGGBBAA),
|
||||
// which I was not expecting because that is normally written with a
|
||||
// number sign (#AARRGGBB) not an 0x.
|
||||
//
|
||||
// [ ] Clicking on either side of a scroll bar is idiosyncratic. Normally,
|
||||
// that is "page up" / "page down", but here it is "smooth scroll upward"
|
||||
// / "smooth scroll downward" for some reason?
|
||||
//
|
||||
// [ ] can it ignore stepping into _RTC_CheckStackVars generated functions?
|
||||
// [ ] mouse back button should make view to go back after I double clicked
|
||||
// on function to open it
|
||||
// [ ] Alt+8 to switch to disassembly would be nice (regardless on which
|
||||
// panel was previous, don't want to use ctrl+, multiple times)
|
||||
// Alt+8 for disasm and Alt+6 for memory view are shortcuts I often use
|
||||
// in VS
|
||||
// [ ] default font size is too small for me - not only source code, but
|
||||
// menus/tab/watch names (which don't resize). Maybe you could query
|
||||
// Windows for initial font size?
|
||||
// [ ] icon fonts glyphs sometimes disappear for specific font size, but they
|
||||
// reappear if you go +1 higher or -1 lower. Mostly red triangle in watch
|
||||
// values for "unknown identifier". But also yellow arrow in call stack
|
||||
// disappears if font size gets too large.
|
||||
// [ ] undo close tab would be nice. If not for everything, then at least
|
||||
// just for source files
|
||||
// [ ] Jump table thunks, on code w/o /INCREMENTAL:NO
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hot, Feature Tasks (Not really "low priority" but less urgent than fixes)
|
||||
//
|
||||
// [ ] @eval_upgrade
|
||||
// [ ] new eval system; support strings, many address spaces, many debug
|
||||
// infos, wide/async transforms (e.g. diff(blob1, blob2))
|
||||
//
|
||||
// [ ] Fancy View Rules
|
||||
// [ ] table column boundaries should be checked against *AFTER* table
|
||||
// contents, not before
|
||||
// [ ] `array:(x, y)` - multidimensional array
|
||||
//
|
||||
// [ ] search-in-all-files
|
||||
//
|
||||
// [ ] Memory View
|
||||
// [ ] memory view mutation controls
|
||||
// [ ] memory view user-made annotations
|
||||
//
|
||||
// [ ] undo/redo
|
||||
// [ ] proper "go back" + "go forward" history navigations
|
||||
//
|
||||
// [ ] globally disable/configure default view rule-like things (string
|
||||
// viz for u8s in particular)
|
||||
//
|
||||
// [ ] @feature processor/data breakpoints
|
||||
// [ ] @feature automatically snap to search matches when searching source files
|
||||
// [ ] automatically start search query with selected text
|
||||
// [ ] @feature entity views: filtering & reordering
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cold, Clean-up Tasks That Probably Only Ryan Notices
|
||||
// (E.G. Because They Are Code-Related Or Because Nobody Cares)
|
||||
//
|
||||
// [ ] @bug view-snapping in scroll-lists, accounting for mapping between
|
||||
// visual positions & logical positions (variably sized rows in watch,
|
||||
// table headers, etc.)
|
||||
// [ ] @cleanup straighten out index/number space & types & terminology for
|
||||
// scroll lists
|
||||
// [ ] @cleanup central worker thread pool - eliminate per-layer thread pools
|
||||
// [ ] @cleanup eliminate explicit font parameters in the various ui paths (e.g.
|
||||
// code slice params)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cold, Unsorted Notes (Deferred Until Existing Lists Mostly Exhausted)
|
||||
//
|
||||
// [ ] @feature types -> auto view rules (don't statefully fill view rules
|
||||
// given types, just query if no other view rule is present, & autofill
|
||||
// when editing)
|
||||
// [ ] @feature eval system -> somehow evaluate breakpoint hit counts? "meta"
|
||||
// variables?
|
||||
//
|
||||
// [ ] @feature disasm view improvement features
|
||||
// [ ] visualize jump destinations in disasm
|
||||
//
|
||||
// [ ] @feature eval ui improvement features
|
||||
// [ ] serializing eval view maps
|
||||
// [ ] view rule editors in hover-eval
|
||||
// [ ] view rule hook coverage
|
||||
// [ ] `each:(expr addition)` - apply some additional expression to all
|
||||
// elements in an array/linked list would be useful to look at only a
|
||||
// subset of an array of complex structs
|
||||
// [ ] `slider:(min max)` view rule
|
||||
// [ ] `v2f32` view rule
|
||||
// [ ] `v3` view rule
|
||||
// [ ] `quat` view rule
|
||||
// [ ] `matrix` view rule
|
||||
// [ ] `audio` waveform view rule
|
||||
// [ ] smart scopes - expression operators for "grab me the first type X"
|
||||
// [ ] "pinning" watch expressions, to attach it to a particular ctrl_ctx
|
||||
//
|
||||
// [ ] @feature header file for target -> debugger communication; printf, log,
|
||||
// etc.
|
||||
// [ ] @feature just-in-time debugging
|
||||
// [ ] @feature step-out-of-loop
|
||||
//
|
||||
//-[ ] long-term future notes from martins
|
||||
// [ ] core dump saving/loading
|
||||
// [ ] parallel call stacks view
|
||||
// [ ] parallel watch view
|
||||
// [ ] mixed native/interpreted/jit debugging
|
||||
// - it seems python has a top-level linked list of interpreter states,
|
||||
// which should allow the debugger to map native callstacks to python
|
||||
// code
|
||||
//
|
||||
// [ ] fancy string runs can include "weakness" information for text truncation
|
||||
// ... can prioritize certain parts of strings to be truncated before
|
||||
// others. would be good for e.g. the middle of a path
|
||||
// [ ] font cache eviction (both for font tags, closing fp handles, and
|
||||
// rasterizations)
|
||||
// [ ] frontend speedup opportunities
|
||||
// [ ] tables in UI -> currently building per-row, could probably cut down on
|
||||
// # of boxes and # of draws by doing per-column in some cases?
|
||||
// [ ] font cache layer -> can probably cache (string*font*size) -> (run) too
|
||||
// (not just rasterization)... would save a *lot*, there is a ton of work
|
||||
// just in looking up & stitching stuff repeatedly
|
||||
// [ ] convert UI layout pass to not be naive recursive version
|
||||
// [ ] (big change) parallelize window ui build codepaths per-panel
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Recently Completed Task Log
|
||||
//
|
||||
// [x] UI_NavActions, OS_Event -> UI_Event (single event stream)
|
||||
// [x] better discoverability for view rules - have better help hover tooltip,
|
||||
// info on arguments, and better autocomplete lister
|
||||
// [x] source view -> floating margin/line-nums
|
||||
// [x] watch window reordering
|
||||
// [x] standard way to filter
|
||||
// [x] autocomplete lister should respect position in edited expression,
|
||||
// tabbing through should autocomplete but not exit, etc.
|
||||
// [x] pipe failure-to-launch errors back to frontend
|
||||
// [x] bit more padding on the tabs
|
||||
// [x] unified top-level cursor/typing/lister helper
|
||||
// [x] collapse text cells & command lister & etc. into same codepath (?)
|
||||
// [x] page-up & page-down correct handling in keyboard nav
|
||||
// [x] interleaved src/dasm view
|
||||
// [x] in watch window when I enter some new expression and then click mouse
|
||||
// away from cell, then it should behave the same as if I pressed enter.
|
||||
// Currently it does the same as if I have pressed esc and I have lost my
|
||||
// expression
|
||||
// [x] pressing random keyboard keys in source code advances text cursor like
|
||||
// you were inputting text, very strange.
|
||||
// [x] It's confusing that ENTER is the way you expand and collapse things in
|
||||
// the watch window, but then also how you edit them if they are not
|
||||
// expandable? It seems like this should be consistent (one way to edit,
|
||||
// one way to expand/collapse, that are distinct)
|
||||
// [x] Dragging a window tab (like Locals or Registers or whatnot) and
|
||||
// canceling with ESC should revert the window tab to where it was.
|
||||
// Currently, it leaves the window tab reordered if you dragged over its
|
||||
// window and shuffled its position.
|
||||
// [x] ** I couldn't figure out how to really view threads in the debugger.
|
||||
// The only place I found a thread list was in "The Scheduler", but it
|
||||
// only lists threads by ID, which is hard to use. I can hover over them
|
||||
// to get the stack, which helps, but it would be much nicer if the top
|
||||
// function was displayed in the window by default next to the thread.
|
||||
// [x] ** It would be nice if thread listings displayed the name of the
|
||||
// thread, instead of just the ID.
|
||||
// [x] TLS eval -> in-process-memory EXE info
|
||||
// [x] unwinding -> in-process-memory EXE info
|
||||
// [x] new fuzzy searching layer
|
||||
// [x] robustify dbgi layer to renames (cache should not be based only on
|
||||
// path - must invalidate naturally when new filetime occurs)
|
||||
// [x] rdi file regeneration too strict
|
||||
// [x] raddbg jai.exe my_file.jai -- foobar -> raddbg consumes `--` incorrectly
|
||||
// [x] mouse-driven way to complete file/folder selection, or more generally
|
||||
// query completion
|
||||
// [x] it would be nice to have "show in explorer" for right click on source
|
||||
// file tab (opens explorer & selects the file)
|
||||
// [x] asan stepping breakage
|
||||
// [x] what's up with decimal number coloring where every group of 3 are in
|
||||
// different color? can I turn it off? And why sometimes digits in number
|
||||
// start with brighter color, but sometimes with darker - shouldn't it
|
||||
// always have the same color ordering?
|
||||
// [x] fix tabs-on-bottom positioning
|
||||
// [x] colors: consistent tooltip styles (colors, font flags, etc.)
|
||||
// [x] colors: scroll bars
|
||||
// [x] colors: watch window navigation visuals
|
||||
// [x] floating source view margin background/placement
|
||||
// [x] "interaction root", or "group" ui_key, or something; used for menu bar interactions
|
||||
// [x] theme colors -> more explicit about e.g. opaque backgrounds vs. floating
|
||||
// & scrollbars etc.
|
||||
// [x] Pressing the left mouse button on the menu bar and dragging does not
|
||||
// move through the menus as expected - instead, it opens the one you
|
||||
// clicked down on, then does nothing until you release, at which point it
|
||||
// opens the menu you released on.
|
||||
// [x] Similarly, pressing the left mouse button on a menu and dragging to an
|
||||
// item, then releasing, does not trigger that item as expected. Instead,
|
||||
// it is a nop, and it waits for you to click again on the item.
|
||||
// [x] Using the word "symbol" in "Code (Symbol)" seems like a bad idea, since
|
||||
// you're referring to non-identifier characters, but in a debugger
|
||||
// "symbol" usually means something defined in the debug information.
|
||||
// [x] I couldn't figure out how to affect the "dim" color in constants that
|
||||
// have alternating bright/dim letters to show sections of a number. Is
|
||||
// this in the theme colors somewhere?
|
||||
//
|
||||
// [x] ** Scrollbars are barely visible for me, for some reason. I could not
|
||||
// find anything in the theme that would fill them with a solid, bright
|
||||
// color. Instead they are just a thin outline and the same color as the
|
||||
// scroll bar background.
|
||||
//
|
||||
// [x] Many of the UI elements, like the menus, would like better if they had
|
||||
// a little bit of margin. Having the text right next to the edges, and
|
||||
// with no line spacing, makes it harder to read things quickly.
|
||||
// [x] colors: memory view
|
||||
// [x] Hitting ESC during a color picker drag should abort the color picking
|
||||
// and revert to the previous color. Currently, it just accepts the last
|
||||
// drag result as the new color.
|
||||
// [x] It was not clear to me why a small "tab picker" appeared when I got to
|
||||
// a certain number of tabs. It seemed to appear even if the tabs were
|
||||
// quite large, and there was no need to a drop-down menu to pick them. It
|
||||
// feels like either it should always be there, or it should only show up
|
||||
// if at least one tab gets small enough to have its name cut off?
|
||||
// [x] I found the "context menu" convention to be confusing. For example, if
|
||||
// I left-click on a tab, it selects the tab. If I right-click on a tab,
|
||||
// it opens the context menu. However, if I left-click on a module, it
|
||||
// opens the context window. It seems like maybe menus should be right,
|
||||
// and left should do the default action, more consistently?
|
||||
//
|
||||
// [x] double click on procedure in procedures tab to jump to source
|
||||
// [x] highlighted text & ctrl+f -> auto-fill search query
|
||||
// [x] double-click any part of frame in callstack view -> snap to function
|
||||
// [x] Menus take too long to show up. I would prefer it if they were instant.
|
||||
// The animation doesn't really provide any useful cues, since I know
|
||||
// where the menu came from.
|
||||
// [x] user settings (ui & functionality - generally need a story for it)
|
||||
// [x] hover animations
|
||||
// [x] press animations
|
||||
// [x] focus animations
|
||||
// [x] tooltip animations
|
||||
// [x] context menu animations
|
||||
// [x] scrolling animations
|
||||
// [x] background blur
|
||||
// [x] tab width
|
||||
// [x] ** In the call stack, I would like to be able to click quickly and move
|
||||
// around the stack. Right now, you can do that with the first and third
|
||||
// column, but the second column drops down a context menu. Since right
|
||||
// click is already for context menus, can it not just be that double-
|
||||
// clicking any column jumps to that stack frame?
|
||||
//
|
||||
// [x] ** I find it really hard to read the code with the heavyweight lines
|
||||
// running through it for breakpoints and stepping and things. Is there a
|
||||
// way to turn the lines off? AFAICT they are based on thread and
|
||||
// breakpoint color, so you can't really control the line drawing? I might
|
||||
// be fine with them, but they would have to be much more light (like
|
||||
// alpha 0.1 or something)
|
||||
// [x] zooming behaves very strangely - sometimes it zooms source code,
|
||||
// sometimes both source code and menu/tab/watch font size, sometimes
|
||||
// just menu/tab/watch font size not source size.
|
||||
// [x] colors: fill out rest of theme presets for new theme setup
|
||||
// [x] I LOVE ALT-W to add watch under cursor, but I would prefer to have it
|
||||
// add what's under the MOUSE cursor instead of the keyboard cursor. Can
|
||||
// we get a command for that so I can bind ALT-W to that instead?
|
||||
// [x] editing multiple bindings for commands
|
||||
// [x] inline breakpoint hit_count
|
||||
// [x] to count hit counts, resolve all bps to addresses, check addresses
|
||||
// against stopper thread's
|
||||
//
|
||||
// [x] PDB files distributed with the build are not found by DbgHelp!!!
|
||||
// [x] Jai compiler debugging crash
|
||||
//
|
||||
//- 2024/8/29
|
||||
//
|
||||
// [x] fix HRESULTs
|
||||
// [x] fix escape char literals
|
||||
// [x] eval: indexing into string literals
|
||||
// [x] fix incorrectly consuming keyboard inputs, preventing fallback-to-filtering, when
|
||||
// selecting null selection in watch views
|
||||
// [x] ui_next_event(...), built-in focus filtering, no need to manually check
|
||||
// if(ui_is_focus_active())
|
||||
// [x] Theme window should include font scaling. I was able to find the
|
||||
// command for increasing the font scale, but I imagine most people
|
||||
// wouldn't think to look there.
|
||||
// [x] n-row table selection, in watch window & other UIs, multi-selection
|
||||
// ctrl+C
|
||||
// [x] target/breakpoint/watch-pin reordering
|
||||
// [x] move breakpoints to being a global thing, not nested to particular files
|
||||
// [x] EVAL SPACES - each rdi gets an rdi space, rdi space is passed to
|
||||
// memory reads & so on, used to resolve to value space; REPLACES "mode"
|
||||
// [x] fix selecting hover eval, then hover eval disappearing, causing
|
||||
// busted focus, until a new hover eval is opened
|
||||
// [x] `text[:lang]` - interpret memory as text, in lang `lang`
|
||||
// [x] `disasm:arch` - interpret memory as machine code for isa `arch`
|
||||
// [x] `memory` - view memory in usual memory hex-editor view
|
||||
// NOTE(rjf): When the visualization system is solid, layers like dasm, txti,
|
||||
// and so on can be dispensed with, as things like the source view, disasm
|
||||
// view, or memory view will simply be specializations of the general purpose
|
||||
// viz system.
|
||||
// [x] view rule hook for standalone visualization ui, granted its own
|
||||
// tab
|
||||
// [x] collapse frontend visualization systems - source view, disasm view,
|
||||
// callstack, modules, scheduler, should *all* be flavors of watch view
|
||||
// [x] globally disable/configure bp/ip lines in source view
|
||||
// [x] @cleanup naming pass over eval visualization part of the frontend,
|
||||
// "blocks" vs. "canvas" vs. "expansion" - etc.
|
||||
// [x] @cleanup collapse DF_CfgNodes into just being MD trees, find another way
|
||||
// to encode config source - don't need it at every node
|
||||
// [x] @cleanup in the frontend, we are starting to have to pass down "DF_Window"
|
||||
// everywhere, because of per-window parameters (e.g. font rendering settings).
|
||||
// this is really better solved by implicit thread-local parameters, similar to
|
||||
// interaction registers, so that one window can "pick" all of the implicit
|
||||
// parameters, and then 99% of the UI code does not have to care.
|
||||
// [x] @cleanup simplification pass over eval visualization pipeline & types,
|
||||
// including view rule hooks
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Build Options
|
||||
|
||||
@@ -65,7 +543,6 @@
|
||||
#include "ui/ui_inc.h"
|
||||
#include "dbg_engine/dbg_engine_inc.h"
|
||||
#include "dbg_frontend/dbg_frontend_inc.h"
|
||||
#include "raddbg.h"
|
||||
|
||||
//- rjf: [c]
|
||||
#include "base/base_inc.c"
|
||||
@@ -105,7 +582,43 @@
|
||||
#include "ui/ui_inc.c"
|
||||
#include "dbg_engine/dbg_engine_inc.c"
|
||||
#include "dbg_frontend/dbg_frontend_inc.c"
|
||||
#include "raddbg.c"
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Execution Types
|
||||
|
||||
typedef enum ExecMode
|
||||
{
|
||||
ExecMode_Normal,
|
||||
ExecMode_IPCSender,
|
||||
ExecMode_Converter,
|
||||
ExecMode_Help,
|
||||
}
|
||||
ExecMode;
|
||||
|
||||
typedef struct IPCInfo IPCInfo;
|
||||
struct IPCInfo
|
||||
{
|
||||
U64 msg_size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
//- rjf: IPC resources
|
||||
#define IPC_SHARED_MEMORY_BUFFER_SIZE MB(4)
|
||||
StaticAssert(IPC_SHARED_MEMORY_BUFFER_SIZE > sizeof(IPCInfo), ipc_buffer_size_requirement);
|
||||
global OS_Handle ipc_signal_semaphore = {0};
|
||||
global OS_Handle ipc_lock_semaphore = {0};
|
||||
global U8 *ipc_shared_memory_base = 0;
|
||||
global U8 ipc_s2m_ring_buffer[MB(4)] = {0};
|
||||
global U64 ipc_s2m_ring_write_pos = 0;
|
||||
global U64 ipc_s2m_ring_read_pos = 0;
|
||||
global OS_Handle ipc_s2m_ring_mutex = {0};
|
||||
global OS_Handle ipc_s2m_ring_cv = {0};
|
||||
|
||||
//- rjf: main thread log
|
||||
global Log *main_thread_log = 0;
|
||||
global String8 main_thread_log_path = {0};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: IPC Signaler Thread
|
||||
@@ -143,6 +656,53 @@ ipc_signaler_thread__entry_point(void *p)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Frame Entry Point
|
||||
|
||||
internal void
|
||||
update_and_render(OS_Handle repaint_window_handle, void *user_data)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
//- rjf: begin logging
|
||||
if(main_thread_log == 0)
|
||||
{
|
||||
main_thread_log = log_alloc();
|
||||
String8 user_program_data_path = os_get_process_info()->user_program_data_path;
|
||||
String8 user_data_folder = push_str8f(scratch.arena, "%S/raddbg/logs", user_program_data_path);
|
||||
main_thread_log_path = push_str8f(d_state->arena, "%S/ui_thread.raddbg_log", user_data_folder);
|
||||
os_make_directory(user_data_folder);
|
||||
os_write_data_to_file_path(main_thread_log_path, str8_zero());
|
||||
}
|
||||
log_select(main_thread_log);
|
||||
log_scope_begin();
|
||||
|
||||
//- rjf: do frontend frame
|
||||
df_frame(repaint_window_handle);
|
||||
|
||||
//- rjf: end logging
|
||||
{
|
||||
LogScopeResult log = log_scope_end(scratch.arena);
|
||||
os_append_data_to_file_path(main_thread_log_path, log.strings[LogMsgKind_Info]);
|
||||
if(log.strings[LogMsgKind_UserError].size != 0)
|
||||
{
|
||||
d_error(log.strings[LogMsgKind_UserError]);
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Ctrl -> Main Thread Wakeup Hook
|
||||
|
||||
internal CTRL_WAKEUP_FUNCTION_DEF(wakeup_hook_ctrl)
|
||||
{
|
||||
os_send_wakeup_event();
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Entry Point
|
||||
|
||||
|
||||
Reference in New Issue
Block a user