Fixed input event buffer issues

Queue doesn't properly act as a ring buffer had to roll my own.
I want to make a allocated ring buffer as well...
This commit is contained in:
2024-06-23 03:04:38 -04:00
parent ce1d31f0d4
commit 55b80da8e5
17 changed files with 390 additions and 139 deletions

View File

@ -1,3 +0,0 @@
package sectr

View File

@ -112,14 +112,14 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
using input_events
error : AllocatorError
events, error = make( Queue(InputEvent), 4 * Kilo, persistent_allocator(), fixed_cap = true )
ensure(error == AllocatorError.None, "Failed to allocate input.events array")
// events, error = make( RingBuffer(InputEvent), 4 * Kilo, persistent_allocator(), fixed_cap = true )
// ensure(error == AllocatorError.None, "Failed to allocate input.events array")
key_events, error = make( Queue(InputKeyEvent), Kilo, persistent_allocator(), fixed_cap = true )
ensure(error == AllocatorError.None, "Failed to allocate key_events array")
// key_events, error = make( RingBuffer(InputKeyEvent), Kilo, persistent_allocator(), fixed_cap = true )
// ensure(error == AllocatorError.None, "Failed to allocate key_events array")
mouse_events, error = make( Queue(InputMouseEvent), 2 * Kilo, persistent_allocator(), fixed_cap = true )
ensure(error == AllocatorError.None, "Failed to allocate mouse_events array")
// mouse_events, error = make( RingBuffer(InputMouseEvent), 3 * Kilo, persistent_allocator(), fixed_cap = true )
// ensure(error == AllocatorError.None, "Failed to allocate mouse_events array")
codes_pressed, error = make( Array(rune), Kilo, persistent_slab_allocator() )
ensure(error == AllocatorError.None, "Failed to allocate codes_pressed array")
@ -422,9 +422,9 @@ hot_reload :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_
// input_reload()
{
using input_events
reload( & events, runtime.nil_allocator())
reload( & key_events, runtime.nil_allocator())
reload( & mouse_events, runtime.nil_allocator())
// reload( & events, runtime.nil_allocator())
// reload( & key_events, runtime.nil_allocator())
// reload( & mouse_events, runtime.nil_allocator())
codes_pressed.backing = persistent_slab_allocator()
staged_input_events.backing = persistent_slab_allocator()
}
@ -532,7 +532,7 @@ tick_frametime :: #force_inline proc( client_tick : ^time.Tick, host_delta_time_
// profile("Client tick timing processing")
config.engine_refresh_hz = uint(monitor_refresh_hz)
// config.engine_refresh_hz = uint(monitor_refresh_hz)
// config.engine_refresh_hz = 10
frametime_target_ms = 1.0 / f64(config.engine_refresh_hz) * S_To_MS
sub_ms_granularity_required := frametime_target_ms <= Frametime_High_Perf_Threshold_MS

View File

@ -73,7 +73,8 @@ sokol_app_log_callback :: proc "c" (
message_or_null: cstring,
line_nr: u32,
filename_or_null: cstring,
user_data: rawptr) {
user_data: rawptr)
{
context = get_state().sokol_context
odin_level : LogLevel

View File

@ -80,13 +80,13 @@ render :: proc()
profile(#procedure)
state := get_state(); using state // TODO(Ed): Prefer passing static context to through the callstack
clear_pass := gfx.Pass { action = render_data.pass_actions.bg_clear_black, swapchain = sokol_glue.swapchain() }
clear_pass.action.colors[0].clear_value = transmute(gfx.Color) normalize_rgba8( config.color_theme.bg )
// TODO(Ed): Eventually we want to only update when state is dirty/user has done an action
gfx.begin_pass(gfx.Pass { action = render_data.pass_actions.bg_clear_black, swapchain = sokol_glue.swapchain() })
gfx.begin_pass(clear_pass)
gfx.end_pass();
// render_mode_3d()
render_mode_2d_workspace()
render_mode_screenspace()
@ -133,25 +133,35 @@ render_mode_screenspace :: proc()
cam := & project.workspace.cam
win_extent := state.app_window.extent
ve.configure_snap( & font_provider_data.ve_font_cache, u32(state.app_window.extent.x * 2.0), u32(state.app_window.extent.y * 2.0) )
render_screen_ui()
screen_extent := app_window.extent
screen_size := app_window.extent * 2
screen_ratio := screen_size.x * ( 1.0 / screen_size.y )
gp.begin( i32(screen_size.x), i32(screen_size.y) )
gp.viewport(0, 0, i32(screen_size.x), i32(screen_size.y))
gp.project( -screen_extent.x, screen_extent.x, screen_extent.y, -screen_extent.y )
ve.configure_snap( & font_provider_data.ve_font_cache, u32(state.app_window.extent.x * 2.0), u32(state.app_window.extent.y * 2.0) )
gp_set_color(Color_Screen_Center_Dot)
draw_filled_circle(0, 0, 2, 24)
render_screen_ui()
gfx.begin_pass( gfx.Pass { action = render_data.pass_actions.empty_action, swapchain = sokol_glue.swapchain() })
gp.flush()
gp.end()
gfx.end_pass()
Render_Reference_Dots:
{
gp.begin( i32(screen_size.x), i32(screen_size.y) )
gp.viewport(0, 0, i32(screen_size.x), i32(screen_size.y))
gp.project( -screen_extent.x, screen_extent.x, screen_extent.y, -screen_extent.y )
gp_set_color(Color_Screen_Center_Dot)
draw_filled_circle(0, 0, 2, 24)
Mouse_Position:
{
mouse_pos := input.mouse.pos
gp_set_color({ 180, 180, 180, 20})
draw_filled_circle( mouse_pos.x, mouse_pos.y, 4, 24 )
}
gfx.begin_pass( gfx.Pass { action = render_data.pass_actions.empty_action, swapchain = sokol_glue.swapchain() })
gp.flush()
gp.end()
gfx.end_pass()
}
debug_draw_text :: proc( content : string, pos : Vec2, size : f32, color := Color_White, font : FontID = Font_Default )
@ -183,8 +193,8 @@ render_mode_screenspace :: proc()
cam := & project.workspace.cam
screen_corners := screen_get_corners()
position := screen_corners.top_right
position.x -= app_window.extent.x * 0.5
position := screen_corners.top_left
position.x = 0
position.y -= debug.draw_debug_text_y
content := str_fmt_buffer( draw_text_scratch[:], format, ..args )
@ -201,18 +211,33 @@ render_mode_screenspace :: proc()
fps_msg_pos := screen_get_corners().top_right - { fps_msg_width, 0 } - { 5, 5 }
debug_draw_text( fps_msg, fps_msg_pos, 38.0, color = Color_Red )
// debug_text( "Screen Width : %v", rl.GetScreenWidth () )
// debug_text( "Screen Height: %v", rl.GetScreenHeight() )
// debug_text( "frametime_target_ms : %f ms", frametime_target_ms )
debug_text( "Screen Width : %v", screen_size.x )
debug_text( "Screen Height: %v", screen_size.y )
debug_text( "frametime_target_ms : %f ms", frametime_target_ms )
debug_text( "frametime : %0.3f ms", frametime_delta32() )
// debug_text( "frametime_last_elapsed_ms : %f ms", frametime_elapsed_ms )
debug_text( "frametime_last_elapsed_ms : %f ms", frametime_elapsed_ms )
if replay.mode == ReplayMode.Record {
debug_text( "Recording Input")
}
if replay.mode == ReplayMode.Playback {
debug_text( "Replaying Input")
}
// debug_text("Zoom Target: %v", project.workspace.zoom_target)
debug_text("Zoom Target: %v", project.workspace.zoom_target)
if true
{
using input_events
id := 0
iter_obj := iterator( & mouse_events ); iter := & iter_obj
for event := next( iter ); event != nil; event = next( iter )
{
if id >= 4 do break
id += 1
debug_text("Mouse Event: %v", event )
}
}
if debug.mouse_vis {
debug_text("Mouse scroll: %v", input.mouse.scroll )

View File

@ -1,60 +0,0 @@
/*
The default arena allocator Odin provides does fragmented resizes even for the last most allocated block getting resized.
This is an alternative to alleviates that.
TODO(Ed): Implement? Maybe we should trash this I' haven't seen a need to step away from using odin's
*/
package sectr
import "core:mem"
// Initialize a sub-section of our virtual memory as a sub-arena
sub_arena_init :: proc( address : ^byte, size : int ) -> ( ^ Arena) {
Arena :: mem.Arena
arena_size :: size_of( Arena)
sub_arena := cast( ^ Arena ) address
mem_slice := slice_ptr( ptr_offset( address, arena_size), size )
arena_init( sub_arena, mem_slice )
return sub_arena
}
ArenaFixedHeader :: struct {
data : []byte,
offset : uint,
peak_used : uint,
}
ArenaFixed :: struct {
using header : ^ArenaFixedHeader,
}
arena_fixed_init :: proc( backing : []byte ) -> (arena : ArenaFixed) {
header_size := size_of(ArenaFixedHeader)
verify(len(backing) >= (header_size + Kilobyte), "Attempted to init an arena with less than kilobyte of memory...")
arena.header = cast(^ArenaFixedHeader) raw_data(backing)
using arena.header
data_ptr := cast([^]byte) (cast( [^]ArenaFixedHeader) arena.header)[ 1:]
data = slice_ptr( data_ptr, len(backing) - header_size )
offset = 0
peak_used = 0
return
}
arena_fixed_allocator_proc :: proc(
allocator_data : rawptr,
mode : AllocatorMode,
size : int,
alignment : int,
old_memory : rawptr,
old_size : int,
location := #caller_location
) -> ([]byte, AllocatorError)
{
return nil, .Out_Of_Memory
}

View File

@ -30,8 +30,8 @@ import "base:runtime"
import c "core:c/libc"
import "core:container/queue"
Queue :: queue.Queue
// import "core:container/queue"
// Queue :: queue.Queue
// import "core:dynlib"
@ -188,12 +188,26 @@ import "codebase:grime"
hmap_zpl_reload :: grime.hmap_zpl_reload
hmap_zpl_set :: grime.hmap_zpl_set
make_queue :: grime.make_queue
// make_queue :: grime.make_queue
next_queue_iterator :: grime.next_queue_iterator
// next_queue_iterator :: grime.next_queue_iterator
Pool :: grime.Pool
RingBufferFixed :: grime.RingBufferFixed
RingBufferFixedIterator :: grime.RingBufferFixedIterator
ringbuf_fixed_clear :: grime.ringbuf_fixed_clear
ringbuf_fixed_is_full :: grime.ringbuf_fixed_is_full
ringbuf_fixed_is_empty :: grime.ringbuf_fixed_is_empty
ringbuf_fixed_peak_back :: grime.ringbuf_fixed_peak_back
ringbuf_fixed_push :: grime.ringbuf_fixed_push
ringbuf_fixed_push_slice :: grime.ringbuf_fixed_push_slice
ringbuf_fixed_pop :: grime.ringbuf_fixed_pop
iterator_ringbuf_fixed :: grime.iterator_ringbuf_fixed
next_ringbuf_fixed_iterator :: grime.next_ringbuf_fixed_iterator
Slab :: grime.Slab
SlabPolicy :: grime.SlabPolicy
SlabSizeClass :: grime.SlabSizeClass
@ -368,14 +382,15 @@ is_power_of_two :: proc {
}
iterator :: proc {
grime.iterator_queue,
// grime.iterator_queue,
grime.iterator_ringbuf_fixed,
}
make :: proc {
array_init,
hmap_chained_init,
hmap_zpl_init,
make_queue,
// make_queue,
// Usual
make_slice,
@ -396,16 +411,17 @@ mov_avg_exp :: proc {
}
next :: proc {
next_queue_iterator,
// next_queue_iterator,
next_ringbuf_fixed_iterator,
}
peek_back :: proc {
queue.peek_back,
ringbuf_fixed_peak_back,
}
peek_front :: proc {
queue.peek_front,
}
// peek_front :: proc {
// queue.peek_front,
// }
pixels_to_cm :: proc {
f32_pixels_to_cm,
@ -444,8 +460,11 @@ pressed :: proc {
}
push :: proc {
queue.push_back,
grime.push_back_slice_queue,
ringbuf_fixed_push,
ringbuf_fixed_push_slice,
// queue.push_back,
// grime.push_back_slice_queue,
stack_push,
stack_allocator_push,
@ -476,10 +495,6 @@ reload :: proc {
grime.reload_map,
}
space_left :: proc {
queue.space,
}
scope :: proc {
ui_layout_scope_via_layout,
ui_layout_scope_via_combo,

View File

@ -53,9 +53,9 @@ InputMouseEvent :: struct {
}
InputEvents :: struct {
events : Queue(InputEvent),
key_events : Queue(InputKeyEvent),
mouse_events : Queue(InputMouseEvent),
events : RingBufferFixed(InputEvent, 640),
key_events : RingBufferFixed(InputKeyEvent, 128),
mouse_events : RingBufferFixed(InputMouseEvent, 512),
codes_pressed : Array(rune),
}
@ -138,6 +138,8 @@ pull_staged_input_events :: proc( input : ^InputState, input_events : ^InputEve
scroll = event.mouse.scroll,
modifiers = event.modifiers,
})
// logf("Detected scroll: %v", event.mouse.scroll)
case .Mouse_Move:
push( & mouse_events, InputMouseEvent {
frame_id = event.frame_id,
@ -200,8 +202,8 @@ poll_input_events :: proc( input, prev_input : ^InputState, input_events : Input
@static prev_frame : u64 = 0
last_frame : u64 = 0
if events.len > 0 {
last_frame = peek_back( & events).frame_id
if events.num > 0 {
last_frame = peek_back( events).frame_id
}
// No new events, don't update
@ -209,18 +211,19 @@ poll_input_events :: proc( input, prev_input : ^InputState, input_events : Input
Iterate_Key_Events:
{
iter_obj := iterator( key_events ); iter := & iter_obj
iter_obj := iterator( & key_events ); iter := & iter_obj
for event := next( iter ); event != nil; event = next( iter )
{
// logf("last_frame (iter): %v", last_frame)
// logf("frame (iter): %v", event.frame_id )
if last_frame > event.frame_id {
break
}
// logf("last_frame (iter): %v", last_frame)
// logf("frame (iter): %v", event.frame_id )
key := & input.keyboard.keys[event.key]
prev_key := prev_input.keyboard.keys[event.key]
// logf("key event: %v", event)
first_transition := key.half_transitions == 0
#partial switch event.type {
@ -237,7 +240,7 @@ poll_input_events :: proc( input, prev_input : ^InputState, input_events : Input
Iterate_Mouse_Events:
{
iter_obj := iterator( mouse_events ); iter := & iter_obj
iter_obj := iterator( & mouse_events ); iter := & iter_obj
for event := next( iter ); event != nil; event = next( iter )
{
if last_frame > event.frame_id {
@ -252,6 +255,8 @@ poll_input_events :: proc( input, prev_input : ^InputState, input_events : Input
btn.ended_down = ended_down
}
// logf("mouse event: %v", event)
#partial switch event.type {
case .Mouse_Pressed:
btn := & input.mouse.btns[event.btn]
@ -264,7 +269,7 @@ poll_input_events :: proc( input, prev_input : ^InputState, input_events : Input
process_digital_btn( btn, prev_btn, false )
case .Mouse_Scroll:
input.mouse.scroll += event.scroll.x
input.mouse.scroll += event.scroll
case .Mouse_Move:
case .Mouse_Enter: