misc changes

* draw_text_string_pos_extent_zoomed can now oversample text futher (if desired)
* render_ui_via_box_tree has a rudimentary render pass layering optimization

Add support for the slab allocator to accept arbitrary alignments (odin's map container needs it)
Messing around with 64-byte alignment as the default for the allocator...
This commit is contained in:
Edward R. Gonzalez 2024-06-25 19:13:41 -04:00
parent 268ba29ec6
commit 1533a14a1b
13 changed files with 94 additions and 51 deletions

View File

@ -181,12 +181,12 @@ array_append_at_slice :: proc( using self : ^Array( $ Type ), items : []Type, id
return AllocatorError.None
}
array_back :: proc( self : Array($Type) ) -> Type {
array_back :: #force_inline proc "contextless" ( self : Array($Type) ) -> Type {
value := self.data[self.num - 1]
return value
}
array_push_back :: proc( using self : Array( $ Type)) -> b32 {
array_push_back :: #force_inline proc "contextless" ( using self : Array( $ Type)) -> b32 {
if num == capacity {
return false
}

View File

@ -3,16 +3,16 @@ package grime
import "base:runtime"
reload_array :: proc( self : ^[dynamic]$Type, allocator : Allocator ) {
raw := transmute(runtime.Raw_Dynamic_Array) self
raw := transmute( ^runtime.Raw_Dynamic_Array) self
raw.allocator = allocator
}
reload_queue :: proc( self : ^Queue($Type), allocator : Allocator ) {
raw_array := transmute(runtime.Raw_Dynamic_Array) self.data
raw_array := transmute( ^runtime.Raw_Dynamic_Array) self.data
raw_array.allocator = allocator
}
reload_map :: proc( self : ^map [$KeyType] $EntryType, allocator : Allocator ) {
raw := transmute(runtime.Raw_Map) self
raw := transmute( ^runtime.Raw_Map) self
raw.allocator = allocator
}

View File

@ -87,6 +87,11 @@ memory_aign_forward :: #force_inline proc( address, alignment : uintptr) -> uint
return aligned_address
}
// align_up :: proc(address: uintptr, alignment: uintptr) -> uintptr {
// return (address + alignment - 1) & ~(alignment - 1)
// }
//endregion Memory Math
swap :: #force_inline proc( a, b : ^ $Type ) -> ( ^ Type, ^ Type ) { return b, a }

View File

@ -353,11 +353,12 @@ pool_validate_ownership :: proc( using self : Pool, block : [] byte ) -> b32
{
misalignment := (block_address - start) % uintptr(block_size)
if misalignment != 0 {
ensure(false, "pool_validate_ownership: This data is within this pool's buckets, however its not aligned to the start of a block")
log(str_fmt("Block address: %p Misalignment: %p closest: %p",
transmute(rawptr)block_address,
transmute(rawptr)misalignment,
rawptr(block_address - misalignment)))
// TODO(Ed): We cannot use thsi to validate that the data is within the pool bucket as we can provide the user different alignments
// ensure(false, "pool_validate_ownership: This data is within this pool's buckets, however its not aligned to the start of a block")
// log(str_fmt("Block address: %p Misalignment: %p closest: %p",
// transmute(rawptr)block_address,
// transmute(rawptr)misalignment,
// rawptr(block_address - misalignment)))
}
within_bucket = true

View File

@ -17,13 +17,13 @@ set_profiler_module_context :: #force_inline proc "contextless" ( ctx : ^SpallPr
@(deferred_none = profile_end)
profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) {
spall._buffer_begin( & Module_Context.ctx, & Module_Context.buffer, name, "", loc )
// spall._buffer_begin( & Module_Context.ctx, & Module_Context.buffer, name, "", loc )
}
profile_begin :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) {
spall._buffer_begin( & Module_Context.ctx, & Module_Context.buffer, name, "", loc )
// spall._buffer_begin( & Module_Context.ctx, & Module_Context.buffer, name, "", loc )
}
profile_end :: #force_inline proc "contextless" () {
spall._buffer_end( & Module_Context.ctx, & Module_Context.buffer)
// spall._buffer_end( & Module_Context.ctx, & Module_Context.buffer)
}

View File

@ -129,19 +129,24 @@ slab_alloc :: proc( self : Slab,
loc := #caller_location
) -> ( data : []byte, alloc_error : AllocatorError )
{
// profile(#procedure)
pool : Pool
id : u32 = 0
for ; id < self.pools.idx; id += 1 {
pool = self.pools.items[id]
if pool.block_size >= size && pool.alignment >= alignment {
adjusted_alignment := clamp(alignment, pool.alignment, alignment)
aligned_size := size + (adjusted_alignment - 1)
if pool.block_size >= aligned_size {
break
}
}
verify( id < self.pools.idx, "There is not a size class in the slab's policy to satisfy the requested allocation", location = loc )
verify( pool.header != nil, "Requested alloc not supported by the slab allocator", location = loc )
adjusted_alignment := clamp(alignment, pool.alignment, alignment)
block : []byte
slab_validate_pools( self )
block, alloc_error = pool_grab(pool)
@ -153,7 +158,11 @@ slab_alloc :: proc( self : Slab,
}
// log( str_fmt_tmp("%v: Retrieved block: %p %d", self.dbg_name, raw_data(block), len(block) ))
data = byte_slice(raw_data(block), size)
// Align the block
block_start := uintptr(raw_data(block))
aligned_start := memory_aign_forward(block_start, uintptr(adjusted_alignment))
data = byte_slice(transmute(rawptr) aligned_start, size)
if zero_memory {
slice.zero(data)
}

View File

@ -39,14 +39,15 @@ Module_String_Cache : ^StringCache
str_cache_init :: proc( table_allocator, slabs_allocator : Allocator ) -> (cache : StringCache)
{
alignment := uint(mem.DEFAULT_ALIGNMENT)
// alignment := uint(mem.DEFAULT_ALIGNMENT)
alignment := uint(64)
policy : SlabPolicy
policy_ptr := & policy
push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 8, alignment })
push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 16, alignment })
push( policy_ptr, SlabSizeClass { 128 * Kilobyte, 32, alignment })
push( policy_ptr, SlabSizeClass { 128 * Kilobyte, 64, alignment })
// push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 8, alignment })
// push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 16, alignment })
// push( policy_ptr, SlabSizeClass { 128 * Kilobyte, 32, alignment })
push( policy_ptr, SlabSizeClass { 640 * Kilobyte, 64, alignment })
push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 128, alignment })
push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 256, alignment })
push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 512, alignment })

View File

@ -154,11 +154,14 @@ AppConfig :: struct {
engine_refresh_hz : uint,
timing_fps_moving_avg_alpha : f32,
ui_resize_border_width : f32,
color_theme : AppColorTheme,
font_size_canvas_scalar : f32,
}
AppWindow :: struct {

View File

@ -68,7 +68,8 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
// Setup Persistent Slabs & String Cache
{
alignment := uint(mem.DEFAULT_ALIGNMENT)
// alignment := uint(mem.DEFAULT_ALIGNMENT)
alignment := uint(64) // Doing the cache line
policy_ptr := & default_slab_policy
push( policy_ptr, SlabSizeClass { 128 * Kilobyte, 1 * Kilobyte, alignment })
@ -150,6 +151,8 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
ui_resize_border_width = 5
color_theme = App_Thm_Dusk
font_size_canvas_scalar = 2.0
}
Desired_OS_Scheduler_MS :: 1
@ -325,8 +328,8 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
ui_startup( & workspace.ui, cache_allocator = persistent_slab_allocator() )
}
debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum (197).txt", allocator = persistent_slab_allocator())
// debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum (1022).txt", allocator = persistent_slab_allocator())
// debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum (197).txt", allocator = persistent_slab_allocator())
debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum (1022).txt", allocator = persistent_slab_allocator())
alloc_error : AllocatorError; success : bool
debug.lorem_content, success = os.read_entire_file( debug.path_lorem, persistent_slab_allocator() )

View File

@ -182,16 +182,17 @@ render_mode_screenspace :: proc()
screen_corners := screen_get_corners()
position := screen_corners.top_left
position.x += 2
position.y -= debug.draw_debug_text_y
content := str_fmt( format, ..args )
text_size := measure_text_size( content, default_font, 14.0, 0.0 )
debug_draw_text( content, position, 14.0 )
debug.draw_debug_text_y += text_size.y + 4
debug.draw_debug_text_y += text_size.y + 3
}
profile("debug_text_vis")
fps_size : f32 = 16.0
fps_size : f32 = 14.0
fps_msg := str_fmt( "FPS: %0.2f", fps_avg)
fps_msg_size := measure_text_size( fps_msg, default_font, fps_size, 0.0 )
fps_msg_pos := screen_get_corners().top_right - { fps_msg_size.x, fps_msg_size.y }
@ -218,7 +219,7 @@ render_mode_screenspace :: proc()
iter_obj := iterator( & mouse_events ); iter := & iter_obj
for event := next( iter ); event != nil; event = next( iter )
{
if id >= 4 do break
if id >= 2 do break
id += 1
debug_text("Mouse Event: %v", event )
@ -227,10 +228,10 @@ render_mode_screenspace :: proc()
if debug.mouse_vis {
debug_text("Mouse scroll: %v", input.mouse.scroll )
debug_text("Mouse Delta : %v", input.mouse.delta )
debug_text("Mouse Position (Render) : %v", input.mouse.raw_pos )
debug_text("Mouse Position (Screen) : %v", input.mouse.pos )
debug_text("Mouse Position (Workspace View): %v", screen_to_ws_view_pos(input.mouse.pos) )
debug_text("Mouse Delta : %0.2f", input.mouse.delta )
debug_text("Mouse Position (Render) : %0.2f", input.mouse.raw_pos )
debug_text("Mouse Position (Screen) : %0.2f", input.mouse.pos )
debug_text("Mouse Position (Workspace View): %0.2f", screen_to_ws_view_pos(input.mouse.pos) )
}
if true
@ -269,6 +270,15 @@ render_mode_screenspace :: proc()
}
}
if true {
state.config.font_size_canvas_scalar = 1.0
zoom_adjust_size := 16 * state.project.workspace.cam.zoom
over_sample := zoom_adjust_size < 12 ? 1.0 : f32(state.config.font_size_canvas_scalar)
debug_text("font_size_canvas_scalar: %v", config.font_size_canvas_scalar)
ve_id, resolved_size := font_provider_resolve_draw_id( default_font, zoom_adjust_size * over_sample )
debug_text("font_size resolved: %v px", resolved_size)
}
render_text_layer()
}
@ -492,10 +502,18 @@ render_ui_via_box_tree :: proc( root : ^UI_Box, cam : ^Camera = nil )
cam_zoom_ratio := cam != nil ? 1.0 / cam.zoom : 1.0
circle_radius := cam != nil ? cam_zoom_ratio * 3 : 3
text_enqueued : b32 = false
shape_enqueued : b32 = false
previous_layer : i32 = 0
for box := root.first; box != nil; box = ui_box_tranverse_next_depth_based( box )
{
text_enqueued : b32 = false
shape_enqueued : b32 = false
if box.ancestors != previous_layer {
if shape_enqueued do render_flush_gp()
if text_enqueued do render_text_layer()
shape_enqueued = false
text_enqueued = false
}
border_width := box.layout.border_width
computed := box.computed
@ -509,7 +527,7 @@ render_ui_via_box_tree :: proc( root : ^UI_Box, cam : ^Camera = nil )
GP_Render:
{
// profile("draw_shapes")
profile("draw_shapes")
if style.bg_color.a != 0
{
draw_rect( bounds, style.bg_color )
@ -555,9 +573,11 @@ render_ui_via_box_tree :: proc( root : ^UI_Box, cam : ^Camera = nil )
text_enqueued = true
}
if shape_enqueued do render_flush_gp()
if text_enqueued do render_text_layer()
previous_layer = box.ancestors
}
if shape_enqueued do render_flush_gp()
if text_enqueued do render_text_layer()
}
render_ui_via_box_list :: proc( render_list : []UI_RenderBoxInfo, cam : ^Camera = nil )
@ -693,7 +713,7 @@ draw_text_string_pos_norm :: proc( content : string, id : FontID, size : f32, po
// Draw text using a string and extent-based screen coordinates
draw_text_string_pos_extent :: proc( content : string, id : FontID, size : f32, pos : Vec2, color := Color_White )
{
// profile(#procedure)
profile(#procedure)
state := get_state(); using state
screen_size := app_window.extent * 2
render_pos := screen_to_render_pos(pos)
@ -703,9 +723,9 @@ draw_text_string_pos_extent :: proc( content : string, id : FontID, size : f32,
draw_text_string_pos_extent_zoomed :: proc( content : string, id : FontID, size : f32, pos : Vec2, cam : Camera, color := Color_White )
{
profile(#procedure)
state := get_state(); using state
// profile(#procedure)
cam_offset := Vec2 {
cam.position.x,
cam.position.y,
@ -719,10 +739,10 @@ draw_text_string_pos_extent_zoomed :: proc( content : string, id : FontID, size
render_pos := ws_view_to_render_pos(pos)
normalized_pos := render_pos * screen_scale
// Oversample font-size for any render under a camera
over_sample : f32 = 2.0
zoom_adjust_size := size * cam.zoom
// Over-sample font-size for any render under a camera
over_sample : f32 = zoom_adjust_size < 12 ? 1.0 : f32(state.config.font_size_canvas_scalar)
zoom_adjust_size *= over_sample
ve_id, resolved_size := font_provider_resolve_draw_id( id, zoom_adjust_size )
@ -737,7 +757,7 @@ draw_text_string_pos_extent_zoomed :: proc( content : string, id : FontID, size
text_scale.y = clamp( text_scale.y, 0, screen_size.y )
}
// Downsample back
// Down-sample back
text_scale /= over_sample
color_norm := normalize_rgba8(color)
@ -749,6 +769,7 @@ draw_text_string_pos_extent_zoomed :: proc( content : string, id : FontID, size
render_flush_gp :: #force_inline proc()
{
profile(#procedure)
gfx.begin_pass( gfx.Pass { action = get_state().render_data.pass_actions.empty_action, swapchain = sokol_glue.swapchain() })
gp.flush()
gfx.end_pass()

View File

@ -165,10 +165,10 @@ update :: proc( delta_time : f64 ) -> b32
}
config.cam_max_zoom = 10
config.cam_min_zoom = 0.10
config.cam_min_zoom = 0.05
config.cam_zoom_sensitivity_digital = 0.05
config.cam_zoom_sensitivity_smooth = 2.0
config.cam_zoom_mode = .Digital
config.cam_zoom_mode = .Smooth
switch config.cam_zoom_mode
{
case .Smooth:
@ -247,9 +247,9 @@ update :: proc( delta_time : f64 ) -> b32
config.ui_resize_border_width = 2.5
// test_hover_n_click()
// test_draggable()
test_text_box()
// test_text_box()
// test_parenting( & default_layout, & frame_style_default )
// test_whitespace_ast( & default_layout, & frame_style_default )
test_whitespace_ast( & default_layout, & frame_style_default )
}
//endregion Workspace Imgui Tick

View File

@ -8,7 +8,7 @@ import sokol_glue "thirdparty:sokol/glue"
Font_Provider_Use_Freetype :: false
Font_Largest_Px_Size :: 110
Font_Largest_Px_Size :: 172
Font_Size_Interval :: 2
Font_Default :: FontID { 0, "" }
@ -119,14 +119,14 @@ font_provider_startup :: proc()
screen_shader = sokol_gfx.make_shader(ve_draw_text_shader_desc(backend) )
draw_list_vbuf = sokol_gfx.make_buffer( BufferDesciption {
size = size_of([4]f32) * Kilo * 512,
size = size_of([4]f32) * Kilo * 1024,
usage = BufferUsage.STREAM,
type = BufferType.VERTEXBUFFER,
})
verify( sokol_gfx.query_buffer_state( draw_list_vbuf) < ResourceState.FAILED, "Failed to make draw_list_vbuf" )
draw_list_ibuf = sokol_gfx.make_buffer( BufferDesciption {
size = size_of(u32) * Kilo * 256,
size = size_of(u32) * Kilo * 512,
usage = BufferUsage.STREAM,
type = BufferType.INDEXBUFFER,
})
@ -563,7 +563,7 @@ font_load :: proc(path_file : string,
def.path_file = path_file
def.default_size = default_size
for font_size : i32 = Font_Size_Interval; font_size <= Font_Largest_Px_Size; font_size += Font_Size_Interval
for font_size : i32 = clamp( Font_Size_Interval, 10, Font_Size_Interval ); font_size <= Font_Largest_Px_Size; font_size += Font_Size_Interval
{
// logf("Loading at size %v", font_size)
id := (font_size / Font_Size_Interval) + (font_size % Font_Size_Interval)
@ -585,7 +585,7 @@ font_provider_resolve_draw_id :: proc( id : FontID, size := Font_Use_Default_Siz
def := hmap_chained_get( font_provider_data.font_cache, id.key )
size := size == 0.0 ? f32(def.default_size) : size
even_size := math.round(size * (1.0 / f32(Font_Size_Interval))) * f32(Font_Size_Interval)
resolved_size = clamp( i32( even_size), 14, Font_Largest_Px_Size )
resolved_size = clamp( i32( even_size), 12, Font_Largest_Px_Size )
id := (resolved_size / Font_Size_Interval) + (resolved_size % Font_Size_Interval)
ve_id = def.size_table[ id - 1 ]

View File

@ -118,7 +118,7 @@ ui_prev_cached_box :: #force_inline proc( box : ^UI_Box ) -> ^UI_Box { return hm
// TODO(Ed): Rename to ui_box_tranverse_view_next
// Traveral pritorizes immeidate children
ui_box_tranverse_next_depth_based :: proc "contextless" ( box : ^ UI_Box, bypass_intersection_test := false ) -> (^ UI_Box)
ui_box_tranverse_next_depth_based :: #force_inline proc "contextless" ( box : ^ UI_Box, bypass_intersection_test := false ) -> (^ UI_Box)
{
using state := get_state()
// If current has children, do them first