From 878c419a1fc66959cb9afb3a2b187b580b2e061e Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sat, 4 Jan 2025 20:09:59 -0500 Subject: [PATCH] Oversized streamlined --- code/font/vefontcache/draw.odin | 209 ++++++++++++------------- code/font/vefontcache/vefontcache.odin | 4 +- code/grime/profiler.odin | 2 +- code/sectr/app/settings_menu.odin | 16 +- code/sectr/engine/update.odin | 2 +- code/sectr/ui/core/layout.odin | 1 + scripts/build.ps1 | 4 +- 7 files changed, 117 insertions(+), 121 deletions(-) diff --git a/code/font/vefontcache/draw.odin b/code/font/vefontcache/draw.odin index a0e15b7..dccff18 100644 --- a/code/font/vefontcache/draw.odin +++ b/code/font/vefontcache/draw.odin @@ -85,10 +85,10 @@ Draw_List :: struct { Frame_Buffer_Pass :: enum u32 { None = 0, - Glyph = 1, // TODO(Ed): Rename this to Glyph_Mesh_To_Glyph_Buffer - Atlas = 2, // TODO(Ed): Rename this to Glyph_Buffer_To_Atlas - Target = 3, // TODO(Ed): Rename this to Target_From_Atlas - Target_Uncached = 4, // TODO(Ed): Rename this to Target_From_Glyph_Buffer + Glyph = 1, // Operations on glyph buffer render target + Atlas = 2, // Operations on atlas render target + Target = 3, // Operations on user's end-destination render target using atlas + Target_Uncached = 4, // Operations on user's end-destination render target using glyph buffer } Glyph_Batch_Cache :: struct { @@ -99,7 +99,6 @@ Glyph_Batch_Cache :: struct { Glyph_Draw_Buffer :: struct{ over_sample : Vec2, - batch : i32, // TODO(Ed): Review this. width : i32, height : i32, draw_padding : f32, @@ -333,6 +332,7 @@ generate_shape_draw_list :: #force_no_inline proc( draw_list : ^Draw_List, shape clear(oversized) clear(to_cache) clear(cached) + reset_batch( & glyph_buffer.batch_cache) for & glyph, index in glyph_pack { @@ -424,11 +424,6 @@ generate_shape_draw_list :: #force_no_inline proc( draw_list : ^Draw_List, shape ) } - reset_batch( & glyph_buffer.batch_cache) - // clear(oversized) - // clear(to_cache) - // clear(cached) - cursor_pos = target_position + shape.end_cursor_pos * target_scale return } @@ -456,8 +451,6 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List, colour := colour } - flush_glyph_buffer_draw_list(draw_list, & glyph_buffer.draw_list, & glyph_buffer.clear_draw_list, & glyph_buffer.allocated_x) - profile_begin("glyph buffer transform & draw quads compute") for id, index in cached { @@ -477,11 +470,10 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List, f32_allocated_x := cast(f32) glyph_buffer.allocated_x // Resolve how much space this glyph will allocate in the buffer - buffer_size := (glyph.bounds_size_scaled + glyph_buffer.draw_padding) * glyph.over_sample - + buffer_size := (glyph.bounds_size_scaled + glyph_buffer.draw_padding) * glyph_buffer.over_sample + glyph.over_sample // Allocate a glyph glyph render target region (FBO) - to_allocate_x := buffer_size.x + 2.0 // TODO - + to_allocate_x := buffer_size.x + // If allocation would exceed buffer's bounds the buffer must be flush before this glyph can be rendered. glyph.flush_glyph_buffer = i32(f32_allocated_x + to_allocate_x) >= i32(glyph_buffer_size.x) glyph.buffer_x = glyph.flush_glyph_buffer ? 0 : f32_allocated_x @@ -512,35 +504,97 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List, { glyph := & glyph_pack[id] + f32_allocated_x := cast(f32) glyph_buffer.allocated_x + // Resolve how much space this glyph will allocate in the buffer + buffer_size := (glyph.bounds_size_scaled + glyph_buffer.draw_padding) * glyph.over_sample + glyph.over_sample + + // Allocate a glyph glyph render target region (FBO) + to_allocate_x := buffer_size.x + glyph_buffer.allocated_x += i32(to_allocate_x) + + // If allocation would exceed buffer's bounds the buffer must be flush before this glyph can be rendered. + glyph.flush_glyph_buffer = i32(f32_allocated_x + to_allocate_x) >= i32(glyph_buffer_size.x) + // glyph.buffer_x = f32_allocated_x * f32( i32( glyph.flush_glyph_buffer ) ) + glyph.buffer_x = glyph.flush_glyph_buffer ? 0 : f32_allocated_x + // } + // for id, index in oversized + // { + // glyph := & glyph_pack[id] + + // Quad to for drawing atlas slot to target + draw_quad := & glyph.draw_quad + glyph_padding := vec2(glyph_buffer.draw_padding) - // Quad to draw during target pass, every - quad := & glyph.draw_quad - // Target position (draw_list's target image) - quad.dst_pos = glyph.position + (glyph.bounds_scaled.p0 - glyph_padding) * target_scale - quad.dst_scale = (glyph.bounds_size_scaled + glyph_padding) * target_scale - - // UV coordinates for sampling from glyph buffer - buffer_region_pos := Vec2{0, 0} // Where in the buffer we rendered - buffer_region_size := glyph.bounds_size_scaled * glyph.over_sample + glyph_padding //* font_scale - quad.src_pos = buffer_region_pos - quad.src_scale = buffer_region_size - to_target_space( & quad.src_pos, & quad.src_scale, glyph_buffer_size ) - + draw_quad.dst_pos = glyph.position + (glyph.bounds_scaled.p0 - glyph_padding) * target_scale + draw_quad.dst_scale = (glyph.bounds_size_scaled + glyph_padding) * target_scale + // The glyph buffer space transform for generate_glyph_pass_draw_list - transform := & glyph.draw_transform - transform.scale = font_scale * glyph.over_sample - transform.pos = -1 * glyph.bounds.p0 * transform.scale + vec2(atlas.glyph_padding) - to_glyph_buffer_space( & transform.pos, & transform.scale, glyph_buffer_size ) - // Oversized will use a cleared glyph_buffer every time. + draw_transform := & glyph.draw_transform + draw_transform.scale = font_scale * glyph.over_sample + draw_transform.pos = -1 * glyph.bounds.p0 * draw_transform.scale + vec2(atlas.glyph_padding) + draw_transform.pos.x += glyph.buffer_x + to_glyph_buffer_space( & draw_transform.pos, & draw_transform.scale, glyph_buffer_size ) - dummy := 0 - dummy += 1 + + draw_quad.src_pos = Vec2 { glyph.buffer_x, 0 } + draw_quad.src_scale = glyph.bounds_size_scaled * glyph.over_sample + glyph_padding + to_target_space( & draw_quad.src_pos, & draw_quad.src_scale, glyph_buffer_size ) } profile_end() - glyph_buffer.allocated_x = 0 + + profile_begin("generate oversized glyphs draw_list") + { + when ENABLE_DRAW_TYPE_VIS { + colour.r = 1.0 + colour.g = 1.0 + colour.b = 0.0 + } + for id, index in oversized { + error : Allocator_Error + glyph_pack[id].shape, error = parser_get_glyph_shape(entry.parser_info, glyph_pack[id].index) + assert(error == .None) + } + for id, index in oversized + { + glyph := & glyph_pack[id] + if glyph.flush_glyph_buffer do flush_glyph_buffer_draw_list(draw_list, + & glyph_buffer.draw_list, + & glyph_buffer.clear_draw_list, + & glyph_buffer.allocated_x + ) + + generate_glyph_pass_draw_list( draw_list, & glyph_buffer.shape_gen_scratch, + glyph_pack[id].shape, + entry.curve_quality, + glyph_pack[id].bounds, + glyph_pack[id].draw_transform.pos, + glyph_pack[id].draw_transform.scale + ) + + target_quad := & glyph_pack[id].draw_quad + + draw_to_target : Draw_Call + { + draw_to_target.pass = .Target_Uncached + draw_to_target.colour = colour + draw_to_target.start_index = u32(len(draw_list.indices)) + + blit_quad( draw_list, + target_quad.dst_pos, target_quad.dst_pos + target_quad.dst_scale, + target_quad.src_pos, target_quad.src_pos + target_quad.src_scale ) + + draw_to_target.end_index = u32(len(draw_list.indices)) + } + append( & draw_list.calls, draw_to_target ) + } + + if len(oversized) > 0 do flush_glyph_buffer_draw_list(draw_list, & glyph_buffer.draw_list, & glyph_buffer.clear_draw_list, & glyph_buffer.allocated_x) + for id, index in oversized do parser_free_shape(entry.parser_info, glyph_pack[id].shape) + } + profile_end() profile_begin("to_cache: caching to atlas") { @@ -588,6 +642,7 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List, src_size := (glyph.bounds_size_scaled + atlas.glyph_padding) * glyph_buffer.over_sample to_target_space( & src_position, & src_size, glyph_buffer_size ) + blit_to_atlas : Draw_Call { using blit_to_atlas @@ -615,7 +670,7 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List, ) } - flush_glyph_buffer_draw_list(draw_list, & glyph_buffer.draw_list, & glyph_buffer.clear_draw_list, & glyph_buffer.allocated_x) + if len(to_cache) > 0 do flush_glyph_buffer_draw_list(draw_list, & glyph_buffer.draw_list, & glyph_buffer.clear_draw_list, & glyph_buffer.allocated_x) for id, index in to_cache do parser_free_shape(entry.parser_info, glyph_pack[id].shape) } profile_end() @@ -658,87 +713,27 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List, } generate_cached_draw_list( draw_list, glyph_pack[:], cached, colour ) profile_end() - - // flush_glyph_buffer_draw_list(draw_list, & glyph_buffer.draw_list, & glyph_buffer.clear_draw_list, & glyph_buffer.allocated_x) - - profile_begin("generate oversized glyphs draw_list") - { - when ENABLE_DRAW_TYPE_VIS { - colour.r = 1.0 - colour.g = 1.0 - colour.b = 0.0 - } - for id, index in oversized { - error : Allocator_Error - glyph_pack[id].shape, error = parser_get_glyph_shape(entry.parser_info, glyph_pack[id].index) - assert(error == .None) - } - for id, index in oversized - { - // glyph_buffer.allocated_x += 1 - flush_glyph_buffer_draw_list(draw_list, & glyph_buffer.draw_list, & glyph_buffer.clear_draw_list, & glyph_buffer.allocated_x) - - generate_glyph_pass_draw_list( draw_list, & glyph_buffer.shape_gen_scratch, - glyph_pack[id].shape, - entry.curve_quality, - glyph_pack[id].bounds, - glyph_pack[id].draw_transform.pos, - glyph_pack[id].draw_transform.scale - ) - - target_quad := & glyph_pack[id].draw_quad - - calls : [2]Draw_Call - draw_to_target := & calls[0] - { - using draw_to_target - pass = .Target_Uncached - colour = colour - start_index = u32(len(draw_list.indices)) - - blit_quad( draw_list, - target_quad.dst_pos, target_quad.dst_pos + target_quad.dst_scale, - target_quad.src_pos, target_quad.src_pos + target_quad.src_scale ) - - end_index = u32(len(draw_list.indices)) - } - // clear_glyph_update := & calls[1] - // { - // // Clear glyph render target (FBO) - // clear_glyph_update.pass = .Glyph - // clear_glyph_update.start_index = 0 - // clear_glyph_update.end_index = 0 - // clear_glyph_update.clear_before_draw = true - // } - append( & draw_list.calls, calls[0] ) - append( & draw_list.calls, calls[1] ) - } - for id, index in oversized do parser_free_shape(entry.parser_info, glyph_pack[id].shape) - } - profile_end() } // Flush the content of the glyph_buffers draw lists to the main draw list flush_glyph_buffer_draw_list :: #force_inline proc( #no_alias draw_list, glyph_buffer_draw_list, glyph_buffer_clear_draw_list : ^Draw_List, allocated_x : ^i32 ) { profile(#procedure) + // if len(glyph_buffer_clear_draw_list.calls) == 0 || len(glyph_buffer_draw_list.calls) == 0 do return + // Flush Draw_Calls to draw list merge_draw_list( draw_list, glyph_buffer_clear_draw_list ) merge_draw_list( draw_list, glyph_buffer_draw_list) clear_draw_list( glyph_buffer_draw_list ) clear_draw_list( glyph_buffer_clear_draw_list ) - // Clear glyph render target (FBO) - // if (allocated_x ^) != 0 - // { - call := Draw_Call_Default - call.pass = .Glyph - call.start_index = 0 - call.end_index = 0 - call.clear_before_draw = true - append( & draw_list.calls, call ) - // (allocated_x ^) = 0 - // } + call := Draw_Call_Default + call.pass = .Glyph + call.start_index = 0 + call.end_index = 0 + call.clear_before_draw = true + append( & draw_list.calls, call ) + (allocated_x ^) = 0 } // ve_fontcache_clear_Draw_List diff --git a/code/font/vefontcache/vefontcache.odin b/code/font/vefontcache/vefontcache.odin index 7dc67d2..ade8018 100644 --- a/code/font/vefontcache/vefontcache.odin +++ b/code/font/vefontcache/vefontcache.odin @@ -10,7 +10,7 @@ import "base:runtime" // White: Cached Hit, Red: Cache Miss, Yellow: Oversized ENABLE_DRAW_TYPE_VIS :: true // See: mappings.odin for profiling hookup -DISABLE_PROFILING :: false +DISABLE_PROFILING :: true Font_ID :: distinct i32 Glyph :: distinct i32 @@ -500,7 +500,7 @@ draw_text :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size : f32, // TODO(Ed): Test this. // px_size_scalar :: 2 // px_size := px_size * px_size_scalar - // scale := scale / px_size_scalar + // scale := scale * (1 / px_size_scalar) entry := ctx.entries[ font ] font_scale := parser_scale( entry.parser_info, px_size ) diff --git a/code/grime/profiler.odin b/code/grime/profiler.odin index a924ffc..654578d 100644 --- a/code/grime/profiler.odin +++ b/code/grime/profiler.odin @@ -15,7 +15,7 @@ set_profiler_module_context :: #force_inline proc "contextless" ( ctx : ^SpallPr Module_Context = ctx } -DISABLE_PROFILING :: false +DISABLE_PROFILING :: true @(deferred_none = profile_end, disabled = DISABLE_PROFILING) profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { diff --git a/code/sectr/app/settings_menu.odin b/code/sectr/app/settings_menu.odin index 69365c5..0f99a22 100644 --- a/code/sectr/app/settings_menu.odin +++ b/code/sectr/app/settings_menu.odin @@ -243,9 +243,9 @@ ui_settings_menu_builder :: proc( captures : rawptr = nil ) -> ( should_raise : digits_only = true disallow_leading_zeros = false disallow_decimal = false - digit_min = 0.01 - digit_max = 9999 - max_length = 5 + digit_min = 0.001 + digit_max = 1.0 + max_length = 6 } ui_text_input_box( & min_zoom_inputbox, "settings_menu.cam_min_zoom.input_box", allocator = persistent_slab_allocator() ) { @@ -260,7 +260,7 @@ ui_settings_menu_builder :: proc( captures : rawptr = nil ) -> ( should_raise : { value, success := parse_f32(to_string(array_to_slice(input_str))) if success { - value = clamp(value, 0.001, 9999.0) + value = clamp(value, 0.0001, 1.0) config.cam_min_zoom = value } } @@ -294,9 +294,9 @@ ui_settings_menu_builder :: proc( captures : rawptr = nil ) -> ( should_raise : digits_only = true disallow_leading_zeros = false disallow_decimal = false - digit_min = 0.01 - digit_max = 9999 - max_length = 5 + digit_min = 1.0 + digit_max = 99 + max_length = 2 ui_text_input_box( & max_zoom_inputbox, "settings_menu.cam_max_zoom.input_box", allocator = persistent_slab_allocator() ) { using max_zoom_inputbox @@ -310,7 +310,7 @@ ui_settings_menu_builder :: proc( captures : rawptr = nil ) -> ( should_raise : { value, success := parse_f32(to_string(array_to_slice(input_str))) if success { - value = clamp(value, 0.001, 9999.0) + value = clamp(value, 0.001, 99.0) config.cam_max_zoom = value } } diff --git a/code/sectr/engine/update.odin b/code/sectr/engine/update.odin index c8072e9..990f4de 100644 --- a/code/sectr/engine/update.odin +++ b/code/sectr/engine/update.odin @@ -151,7 +151,7 @@ update :: proc( delta_time : f64 ) -> b32 // TODO(Ed): This should be per workspace view { Digial_Zoom_Snap_Levels := []f32{ - 0.025, // 0.4px (not practical for text, but allows extreme zoom out) + 0.0255, // 0.4px (not practical for text, but allows extreme zoom out) 0.03125, // 0.5px 0.0375, // 0.6px 0.04375, // 0.7px diff --git a/code/sectr/ui/core/layout.odin b/code/sectr/ui/core/layout.odin index 122ab7e..0d122be 100644 --- a/code/sectr/ui/core/layout.odin +++ b/code/sectr/ui/core/layout.odin @@ -74,6 +74,7 @@ UI_LayoutSide :: struct { UI_LayoutFlag :: enum u32 { // Will perform scissor pass on children to their parent's bounds (Specified in the parent) // Most boxes don't need a scissor pass so its opt-in. + // TODO(Ed): Implement this. Clip_Children_To_bounds, // Enforces the box will always remain in a specific position relative to the parent. diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 99726a2..ec895c5 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -201,10 +201,10 @@ push-location $path_root # $build_args += $flag_micro_architecture_native $build_args += $flag_use_separate_modules $build_args += $flag_thread_count + $CoreCount_Physical - $build_args += $flag_optimize_none + # $build_args += $flag_optimize_none # $build_args += $flag_optimize_minimal # $build_args += $flag_optimize_speed - # $build_args += $falg_optimize_aggressive + $build_args += $falg_optimize_aggressive $build_args += $flag_debug $build_args += $flag_pdb_name + $pdb $build_args += $flag_subsystem + 'windows'