fixes for: Atlas-Region B clear-region on caching glyph, batching, & tuning default values for performance
Need to fix the debug vis for the library
This commit is contained in:
parent
08a8b4b823
commit
c114624eee
@ -69,7 +69,7 @@ atlas_glyph_lru_code :: #force_inline proc "contextless" ( font : Font_ID, px_si
|
||||
@(optimization_mode="favor_size")
|
||||
atlas_region_bbox :: #force_inline proc( region : Atlas_Region, local_idx : i32 ) -> (position, size: Vec2)
|
||||
{
|
||||
size = vec2(region.slot_size.x)
|
||||
size = vec2(region.slot_size)
|
||||
|
||||
position.x = cast(f32) (( local_idx % region.capacity.x ) * region.slot_size.x)
|
||||
position.y = cast(f32) (( local_idx / region.capacity.x ) * region.slot_size.y)
|
||||
|
@ -281,11 +281,9 @@ generate_shapes_draw_list :: #force_inline proc ( ctx : ^Context, font : Font_ID
|
||||
* Dealing with shaping (essentially minimizing having to ever deal with it in a hot path if possible)
|
||||
* Dealing with atlas regioning (the expensive region resolution & parser calls are done on the shape pass)
|
||||
|
||||
|
||||
Pipleine order:
|
||||
* Resolve atlas lru codes and track shape indexes
|
||||
* Resolve the glyph's position offset from the target position
|
||||
* Resolve glyph bounds and scale
|
||||
* Resolve atlas region the glyph is associated with
|
||||
* Segregate the glyphs into three slices: oversized, to_cache, cached.
|
||||
* If oversized is not necessary for your use case and your hitting a bottleneck, remove it in a derivative procedure.
|
||||
* You have to to be drawing a px font size > ~140 px for it to trigger.
|
||||
@ -389,8 +387,10 @@ generate_shape_draw_list :: proc( draw_list : ^Draw_List, shape : Shaped_Text,
|
||||
{
|
||||
pack := cached
|
||||
|
||||
found_take_slow_path : b8
|
||||
success : bool
|
||||
|
||||
// Determine if we hit the limit for this batch.
|
||||
if glyph_buffer.batch_cache.num >= glyph_buffer.batch_cache.cap do break Prepare_For_Batch
|
||||
if glyph.atlas_index == - 1
|
||||
{
|
||||
// Check to see if we reached capacity for the atlas
|
||||
@ -398,8 +398,9 @@ generate_shape_draw_list :: proc( draw_list : ^Draw_List, shape : Shaped_Text,
|
||||
{
|
||||
// We will evict LRU. We must predict which LRU will get evicted, and if it's something we've seen then we need to take slowpath and flush batch.
|
||||
next_evict_glyph := lru_get_next_evicted( region.state )
|
||||
found_take_slow_path, success := glyph_buffer.batch_cache.table[next_evict_glyph]
|
||||
found_take_slow_path, success = glyph_buffer.batch_cache.table[next_evict_glyph]
|
||||
assert(success != false)
|
||||
// TODO(Ed): This might not be needed with the new pipeline/batching
|
||||
if (found_take_slow_path) {
|
||||
break Prepare_For_Batch
|
||||
}
|
||||
@ -407,12 +408,17 @@ generate_shape_draw_list :: proc( draw_list : ^Draw_List, shape : Shaped_Text,
|
||||
// profile_begin("glyph needs caching")
|
||||
glyph.atlas_index = atlas_reserve_slot(region, atlas_key)
|
||||
pack = to_cache
|
||||
profile_end()
|
||||
// profile_end()
|
||||
}
|
||||
// profile("append cached")
|
||||
glyph.region_pos, glyph.region_size = atlas_region_bbox(region ^, glyph.atlas_index)
|
||||
mark_glyph_seen(& glyph_buffer.batch_cache, atlas_key)
|
||||
append_sub_pack(pack, cast(i32) index)
|
||||
// TODO(Ed): This might not be needed with the new pipeline/batching
|
||||
// if (found_take_slow_path) {
|
||||
// break Prepare_For_Batch
|
||||
// }
|
||||
if glyph_buffer.batch_cache.num >= glyph_buffer.batch_cache.cap do break Prepare_For_Batch
|
||||
continue
|
||||
}
|
||||
|
||||
@ -513,14 +519,14 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List,
|
||||
glyph := & glyph_pack[id]
|
||||
bounds := shape.bounds[id]
|
||||
bounds_scaled := mul(bounds, font_scale)
|
||||
glyph_scale := ceil(size(bounds_scaled) + glyph_buffer.draw_padding)
|
||||
glyph_scale := size(bounds_scaled) + glyph_buffer.draw_padding
|
||||
|
||||
f32_allocated_x := cast(f32) glyph_buffer.allocated_x
|
||||
|
||||
// Resolve how much space this glyph will allocate in the buffer
|
||||
buffer_size := glyph_scale * glyph_buffer.over_sample
|
||||
// Allocate a glyph glyph render target region (FBO)
|
||||
to_allocate_x := buffer_size.x + 2.0
|
||||
to_allocate_x := buffer_size.x + 4.0
|
||||
|
||||
// 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)
|
||||
@ -593,9 +599,9 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List,
|
||||
profile_begin("gen oversized glyphs draw_list")
|
||||
when ENABLE_OVERSIZED_GLYPHS do if len(oversized) > 0
|
||||
{
|
||||
// colour.r = max(colour.a, enable_debug_vis_type)
|
||||
// colour.g = max(colour.g, enable_debug_vis_type)
|
||||
// colour.b = colour.b * f32(cast(i32) ! b32(cast(i32) enable_debug_vis_type))
|
||||
colour.r = max(colour.r, 1.0 * enable_debug_vis_type)
|
||||
colour.g = max(colour.g, 1.0 * enable_debug_vis_type)
|
||||
colour.b = colour.b * cast(f32) cast(i32) ! b32( cast(i32) enable_debug_vis_type)
|
||||
for pack_id, index in oversized {
|
||||
error : Allocator_Error
|
||||
glyph_pack[pack_id].shape, error = parser_get_glyph_shape(entry.parser_info, shape.glyph[pack_id])
|
||||
@ -738,18 +744,18 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List,
|
||||
for id, index in to_cache do parser_free_shape(entry.parser_info, glyph_pack[id].shape)
|
||||
|
||||
profile_begin("gen_cached_draw_list: to_cache")
|
||||
colour.r = max(colour.r, 1.0 * enable_debug_vis_type)
|
||||
colour.g = max(colour.g, 1.0 * enable_debug_vis_type)
|
||||
colour.b = max(colour.b, 1.0 * enable_debug_vis_type)
|
||||
// colour.r = max(colour.r, 1.0 * enable_debug_vis_type)
|
||||
// colour.g = colour.g * cast(f32) cast(i32) ! cast(b32) cast(i32) enable_debug_vis_type
|
||||
// colour.b = colour.b * cast(f32) cast(i32) ! cast(b32) cast(i32) enable_debug_vis_type
|
||||
generate_blit_from_atlas_draw_list( draw_list, glyph_pack[:], to_cache, colour )
|
||||
profile_end()
|
||||
}
|
||||
profile_end()
|
||||
|
||||
profile_begin("gen_cached_draw_list: cached")
|
||||
colour.r = max(colour.r, 0.80 * enable_debug_vis_type)
|
||||
colour.g = max(colour.g, 0.25 * enable_debug_vis_type)
|
||||
colour.b = max(colour.b, 0.25 * enable_debug_vis_type)
|
||||
// colour.r = max(colour.r, 0.4 * enable_debug_vis_type)
|
||||
// colour.g = max(colour.g, 0.4 * enable_debug_vis_type)
|
||||
// colour.b = max(colour.b, 0.4 * enable_debug_vis_type)
|
||||
generate_blit_from_atlas_draw_list( draw_list, glyph_pack[:], cached, colour )
|
||||
profile_end()
|
||||
}
|
||||
|
@ -14,7 +14,10 @@ Shape_Key :: u32
|
||||
its position should be used for rendering.
|
||||
|
||||
For this library's case it also involes keeping any content
|
||||
that does not have to be resolved once again in the later stage of processing.
|
||||
that does not have to be resolved once again in the later stage of processing:
|
||||
* Resolve atlas lru codes
|
||||
* Resolve glyph bounds and scale
|
||||
* Resolve atlas region the glyph is associated with.
|
||||
|
||||
Ideally the user should resolve this shape once and cache/store it on their side.
|
||||
They have the best ability to avoid costly lookups to streamline
|
||||
@ -22,8 +25,8 @@ Shape_Key :: u32
|
||||
|
||||
For ease of use the cache does a relatively good job and only adds a
|
||||
few hundred nano-seconds to resolve a shape's lookup from its source specification.
|
||||
If your doing something heavy though (where there is thousands, or tens-of thousands)
|
||||
your not going to be satisfied with keeping that in the iteration).
|
||||
If your doing something very heavy though (tens-of thousands +) your not
|
||||
going to be satisfied with keeping that in the iteration).
|
||||
*/
|
||||
Shaped_Text :: struct #packed {
|
||||
glyph : [dynamic]Glyph,
|
||||
@ -31,11 +34,6 @@ Shaped_Text :: struct #packed {
|
||||
atlas_lru_code : [dynamic]Atlas_Key,
|
||||
region_kind : [dynamic]Atlas_Region_Kind,
|
||||
bounds : [dynamic]Range2,
|
||||
// TODO(Ed): Profile if its worth not doing compute for these per frame.
|
||||
// bounds_scaled : [dynamic]Range2,
|
||||
// bounds_size : [dynamic]Vec2,
|
||||
// bounds_size_Scaled : [dynamic]Vec2,
|
||||
atlas_bbox : [dynamic]Transform,
|
||||
end_cursor_pos : Vec2,
|
||||
size : Vec2,
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
/*
|
||||
A port of (https://github.com/hypernewbie/VEFontCache) to Odin.
|
||||
|
||||
See: https://github.com/Ed94/VEFontCache-Odin
|
||||
*/
|
||||
package vetext
|
||||
@ -8,7 +6,7 @@ package vetext
|
||||
import "base:runtime"
|
||||
|
||||
// See: mappings.odin for profiling hookup
|
||||
DISABLE_PROFILING :: false
|
||||
DISABLE_PROFILING :: true
|
||||
ENABLE_OVERSIZED_GLYPHS :: true
|
||||
|
||||
Font_ID :: distinct i16
|
||||
@ -139,8 +137,8 @@ Init_Glyph_Draw_Params_Default :: Init_Glyph_Draw_Params {
|
||||
over_sample = 4,
|
||||
draw_padding = Init_Atlas_Params_Default.glyph_padding,
|
||||
shape_gen_scratch_reserve = 512,
|
||||
buffer_glyph_limit = 4,
|
||||
batch_glyph_limit = 32,
|
||||
buffer_glyph_limit = 16,
|
||||
batch_glyph_limit = 256,
|
||||
}
|
||||
|
||||
Init_Shaper_Params :: struct {
|
||||
@ -223,8 +221,8 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType, // N
|
||||
|
||||
atlas_size := Vec2i { 4096, 2048 } * i32(atlas.size_multiplier)
|
||||
slot_region_a := Vec2i { 32, 32 } * i32(atlas.size_multiplier)
|
||||
slot_region_c := Vec2i { 64, 64 } * i32(atlas.size_multiplier)
|
||||
slot_region_b := Vec2i { 32, 64 } * i32(atlas.size_multiplier)
|
||||
slot_region_c := Vec2i { 64, 64 } * i32(atlas.size_multiplier)
|
||||
slot_region_d := Vec2i { 128, 128 } * i32(atlas.size_multiplier)
|
||||
|
||||
init_atlas_region :: proc( region : ^Atlas_Region, atlas_size, slot_size : Vec2i, factor : Vec2i )
|
||||
@ -303,9 +301,6 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType, // N
|
||||
glyph_buffer.size.y = atlas.region_d.slot_size.y * i32(glyph_buffer.over_sample.y)
|
||||
glyph_buffer.draw_padding = cast(f32) glyph_draw_params.draw_padding
|
||||
|
||||
buffer_limit := glyph_draw_params.buffer_glyph_limit
|
||||
batch_limit := glyph_draw_params.batch_glyph_limit
|
||||
|
||||
glyph_buffer.draw_list.vertices, error = make( [dynamic]Vertex, len = 0, cap = 8 * Kilobyte )
|
||||
assert( error == .None, "VEFontCache.init : Failed to allocate vertices array for glyph_buffer.draw_list" )
|
||||
|
||||
@ -787,11 +782,11 @@ draw_text_layer :: #force_inline proc( ctx : ^Context, layer : []Text_Layer_Elem
|
||||
assert( ctx != nil )
|
||||
assert( len(layer) > 0 )
|
||||
|
||||
shapes := make( []Shaped_Text, len(layer) )
|
||||
for elem in layer
|
||||
{
|
||||
assert( elem.font >= 0 && int(elem.font) < len(ctx.entries) )
|
||||
|
||||
shapes := make( []Shaped_Text, len(layer) )
|
||||
for elem, id in layer
|
||||
{
|
||||
entry := ctx.entries[ elem.font ]
|
||||
@ -823,25 +818,25 @@ draw_text_layer :: #force_inline proc( ctx : ^Context, layer : []Text_Layer_Elem
|
||||
)
|
||||
shapes[id] = shape
|
||||
}
|
||||
}
|
||||
|
||||
for elem, id in layer {
|
||||
entry := ctx.entries[ elem.font ]
|
||||
for elem, id in layer {
|
||||
entry := ctx.entries[ elem.font ]
|
||||
|
||||
ctx.cursor_pos = {}
|
||||
ctx.cursor_pos = {}
|
||||
|
||||
colour := ctx.colour
|
||||
colour.a = 1.0 + ctx.alpha_sharpen
|
||||
colour := ctx.colour
|
||||
colour.a = 1.0 + ctx.alpha_sharpen
|
||||
|
||||
adjusted_position := get_snapped_position( ctx^, elem.position )
|
||||
adjusted_position := get_snapped_position( ctx^, elem.position )
|
||||
|
||||
// font_scale := parser_scale( entry.parser_info, elem.px_size )
|
||||
// font_scale := parser_scale( entry.parser_info, elem.px_size )
|
||||
|
||||
target_px_size := elem.px_size * ctx.px_scalar
|
||||
target_scale := elem.scale * (1 / ctx.px_scalar)
|
||||
target_font_scale := parser_scale( entry.parser_info, target_px_size )
|
||||
target_px_size := elem.px_size * ctx.px_scalar
|
||||
target_scale := elem.scale * (1 / ctx.px_scalar)
|
||||
target_font_scale := parser_scale( entry.parser_info, target_px_size )
|
||||
|
||||
generate_shapes_draw_list(ctx, elem.font, elem.colour, entry, target_px_size, target_font_scale, adjusted_position, target_scale, shapes )
|
||||
}
|
||||
generate_shapes_draw_list(ctx, elem.font, elem.colour, entry, target_px_size, target_font_scale, adjusted_position, target_scale, shapes )
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 ) {
|
||||
|
@ -119,6 +119,10 @@ font_load :: proc(path_file : string,
|
||||
return fid
|
||||
}
|
||||
|
||||
font_provider_set_draw_type_visualization :: #force_inline proc( should_enable : b32 ) {
|
||||
ve.set_draw_type_visualization( & get_state().font_provider_ctx.ve_ctx, should_enable )
|
||||
}
|
||||
|
||||
font_provider_set_alpha_sharpen :: #force_inline proc( scalar : f32 ) {
|
||||
ve.set_alpha_scalar( & get_state().font_provider_ctx.ve_ctx, scalar )
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ font_provider_setup_sokol_gfx_objects :: proc( ctx : ^VE_RenderData, ve_ctx : ve
|
||||
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) * 1 * Mega,
|
||||
size = size_of(u32) * 3 * Mega,
|
||||
usage = BufferUsage.STREAM,
|
||||
type = BufferType.INDEXBUFFER,
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user