WIP - VEFontCache: Working on streamlining to_cache codepath

This commit is contained in:
Edward R. Gonzalez 2025-01-04 15:55:33 -05:00
parent 83b7098ce9
commit 5b59942c1a
4 changed files with 348 additions and 237 deletions

View File

@ -55,7 +55,7 @@ atlas_decide_region :: #force_inline proc "contextless" (atlas : Atlas, glyph_bu
{
profile(#procedure)
glyph_padding_dbl := atlas.glyph_padding * 2
padded_bounds := bounds_size_scaled + glyph_padding_dbl
padded_bounds := bounds_size_scaled + glyph_padding_dbl
for kind in 1 ..= 4 do if padded_bounds.x <= f32( atlas.regions[kind].width) && padded_bounds.y <= f32(atlas.regions[kind].height) {
return cast(Atlas_Region_Kind) kind

View File

@ -28,7 +28,9 @@ Glyph_Draw_Quad :: struct {
src_scale : Vec2,
}
Glyph_Pack_Entry :: struct #packed {
// This is used by generate_shape_draw_list & batch_generate_glyphs_draw_list
// to track relevant glyph data in soa format for pipelined processing
Glyph_Pack_Entry :: struct {
position : Vec2,
index : Glyph,
@ -40,8 +42,6 @@ Glyph_Pack_Entry :: struct #packed {
region_pos : Vec2,
region_size : Vec2,
shape : Parser_Glyph_Shape,
bounds : Range2,
bounds_scaled : Range2,
bounds_size : Vec2,
@ -49,11 +49,14 @@ Glyph_Pack_Entry :: struct #packed {
over_sample : Vec2,
scale : Vec2,
shape : Parser_Glyph_Shape,
draw_transform : Transform,
draw_quad : Glyph_Draw_Quad,
draw_atlas_quad : Glyph_Draw_Quad,
draw_quad_clear : Glyph_Draw_Quad,
draw_quad : Glyph_Draw_Quad,
draw_atlas_quad : Glyph_Draw_Quad,
draw_quad_clear : Glyph_Draw_Quad,
buffer_x : f32,
flush_glyph_buffer : b8,
}
Draw_Call :: struct {
@ -80,7 +83,6 @@ Draw_List :: struct {
calls : [dynamic]Draw_Call,
}
// TODO(Ed): This was a rough translation of the raw values the orignal was using, need to give better names...
Frame_Buffer_Pass :: enum u32 {
None = 0,
Glyph = 1,
@ -97,16 +99,15 @@ Glyph_Batch_Cache :: struct {
Glyph_Draw_Buffer :: struct{
over_sample : Vec2,
batch : i32,
batch : i32, // TODO(Ed): Review this.
width : i32,
height : i32,
draw_padding : f32,
batch_x : i32,
allocated_x : i32, // Space used (horizontally) within the glyph buffer
clear_draw_list : Draw_List,
draw_list : Draw_List,
// TODO(Ed): Get this working properly again.
batch_cache : Glyph_Batch_Cache,
shape_gen_scratch : [dynamic]Vertex,
@ -264,26 +265,27 @@ cache_glyph_to_atlas :: #force_no_inline proc (
glyph_buffer_size : Vec2,
over_sample : Vec2,
glyph_padding : f32,
buf_transform : Transform,
draw_transform : Transform,
region_pos : Vec2,
region_size : Vec2,
curve_quality : f32,
flush_glyph_buffer : b8,
glyph_buffer_x : f32,
)
{
profile(#procedure)
batch_x := cast(f32) glyph_buf_Batch_x ^
buffer_padding_scaled := glyph_padding * over_sample
buffer_bounds_scale := (bounds_size_scaled) * over_sample
f32_allocated_x := cast(f32) glyph_buf_Batch_x ^
// Allocate a glyph glyph render target region (FBO)
buffer_x_allocation := buffer_bounds_scale.x + buffer_padding_scaled.x + 2.0
// Resolve how much space this glyph will allocate in the buffer
buffer_size := (bounds_size_scaled + glyph_padding) * over_sample
// If we exceed the region availbe to draw on the buffer, flush the calls to reset the buffer
if i32(batch_x + buffer_x_allocation) >= i32(glyph_buffer_size.x) {
flush_glyph_buffer_draw_list( draw_list, glyph_buf_draw_list, glyph_buf_clear_list, glyph_buf_Batch_x )
batch_x = cast(f32) glyph_buf_Batch_x ^
}
// If allocation would exceed buffer's bounds the buffer must be flush before this glyph can be rendered.
// flush_glyph_buffer := i32(f32_allocated_x + to_allocate_x) >= i32(glyph_buffer_size.x)
// glyph_buffer_x := flush_glyph_buffer ? 0 : f32_allocated_x
if flush_glyph_buffer do flush_glyph_buffer_draw_list( draw_list, glyph_buf_draw_list, glyph_buf_clear_list, glyph_buf_Batch_x )
region_pos := region_pos
dst_glyph_position := region_pos
@ -292,8 +294,8 @@ cache_glyph_to_atlas :: #force_no_inline proc (
to_glyph_buffer_space( & dst_glyph_position, & dst_glyph_size, atlas_size )
to_glyph_buffer_space( & region_pos, & dst_size, atlas_size )
src_position := Vec2 { batch_x, 0 }
src_size := (buffer_bounds_scale + buffer_padding_scaled)
src_position := Vec2 { glyph_buffer_x, 0 }
src_size := buffer_size
to_target_space( & src_position, & src_size, glyph_buffer_size )
clear_target_region : Draw_Call
@ -327,14 +329,18 @@ cache_glyph_to_atlas :: #force_no_inline proc (
append( & glyph_buf_clear_list.calls, clear_target_region )
append( & glyph_buf_draw_list.calls, blit_to_atlas )
// Allocate a glyph glyph render target region (FBO)
to_allocate_x := buffer_size.x + 2.0
// The glyph buffer space transform for generate_glyph_pass_draw_list
glyph_transform := buf_transform
glyph_transform.pos.x += batch_x
(glyph_buf_Batch_x ^) += i32(buffer_x_allocation)
to_glyph_buffer_space( & glyph_transform.pos, & glyph_transform.scale, glyph_buffer_size )
draw_transform := draw_transform
draw_transform.pos.x += glyph_buffer_x
to_glyph_buffer_space( & draw_transform.pos, & draw_transform.scale, glyph_buffer_size )
(glyph_buf_Batch_x ^) += i32(to_allocate_x)
// Render glyph to glyph render target (FBO)
generate_glyph_pass_draw_list( draw_list, temp_path, glyph_shape, curve_quality, bounds, glyph_transform.scale, glyph_transform.pos )
generate_glyph_pass_draw_list( draw_list, temp_path, glyph_shape, curve_quality, bounds, draw_transform.scale, draw_transform.pos )
}
generate_shape_draw_list :: #force_no_inline proc( draw_list : ^Draw_List, shape : Shaped_Text,
@ -543,7 +549,9 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List,
colour := colour
}
profile_begin("transform & quad compute")
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
{
// Quad to for drawing atlas slot to target
@ -559,24 +567,60 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List,
{
glyph := & glyph_pack[id]
// Quad to for drawing atlas slot to target
quad := & glyph.draw_quad
quad.dst_pos = glyph.position + (glyph.bounds_scaled.p0) * target_scale
quad.dst_scale = (glyph.scale) * target_scale
quad.src_scale = (glyph.scale)
quad.src_pos = (glyph.region_pos)
to_target_space( & quad.src_pos, & quad.src_scale, atlas_size )
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
// Allocate a glyph glyph render target region (FBO)
to_allocate_x := buffer_size.x + 2.0 // TODO
// 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
// The glyph buffer space transform for generate_glyph_pass_draw_list
transform := & glyph.draw_transform
transform.scale = font_scale * glyph_buffer.over_sample
transform.pos = -1 * (glyph.bounds.p0) * transform.scale + atlas.glyph_padding
// Unlike with oversized, this cannot be finished here as its final value is dependent on glyph_buffer.batch_x allocation
draw_transform := & glyph.draw_transform
draw_transform.scale = font_scale * glyph_buffer.over_sample
draw_transform.pos = -1 * (glyph.bounds.p0) * draw_transform.scale + atlas.glyph_padding
// draw_transform.pos += glyph.buffer_x
// to_glyph_buffer_space( & draw_transform.pos, & draw_transform.scale, glyph_buffer_size )
// Allocate the space
glyph_buffer.allocated_x += i32(to_allocate_x)
// Quad to for drawing atlas slot to target (used in generate_cached_draw_list)
draw_quad := & glyph.draw_quad
// Destination (draw_list's target image)
draw_quad.dst_pos = glyph.position + (glyph.bounds_scaled.p0) * target_scale
draw_quad.dst_scale = (glyph.scale) * target_scale
// UV Coordinates for sampling the atlas
draw_quad.src_scale = (glyph.scale)
draw_quad.src_pos = (glyph.region_pos)
to_target_space( & draw_quad.src_pos, & draw_quad.src_scale, atlas_size )
}
for id, index in oversized
{
glyph := & glyph_pack[id]
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 )
// The glyph buffer space transform for generate_glyph_pass_draw_list
transform := & glyph.draw_transform
transform.scale = font_scale * glyph.over_sample
@ -584,21 +628,115 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List,
to_glyph_buffer_space( & transform.pos, & transform.scale, glyph_buffer_size )
// Oversized will use a cleared glyph_buffer every time.
glyph_padding := vec2(glyph_buffer.draw_padding)
// Quad to draw during target pass, every
quad := & glyph.draw_quad
quad.dst_pos = glyph.position + (glyph.bounds_scaled.p0 - glyph_padding) * target_scale //- ({0, 0.5}) * target_scale
quad.dst_scale = (glyph.bounds_size_scaled + glyph_padding) * target_scale
quad.src_pos = {}
quad.src_scale = glyph.bounds_size_scaled * glyph.over_sample - glyph_padding
to_target_space( & quad.src_pos, & quad.src_scale, glyph_buffer_size )
dummy := 0
dummy += 1
}
profile_end()
glyph_buffer.allocated_x = 0
profile_begin("to_cache: caching to atlas")
{
for id, index in to_cache {
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 to_cache
{
profile("glyph")
glyph := & glyph_pack[id]
cache_glyph_to_atlas(
draw_list,
& glyph_buffer.draw_list,
& glyph_buffer.clear_draw_list,
& glyph_buffer.allocated_x,
& glyph_buffer.shape_gen_scratch,
glyph.shape,
glyph.bounds_scaled,
glyph.bounds_size_scaled,
atlas_size,
glyph_buffer_size,
glyph.over_sample,
glyph_buffer.draw_padding,
glyph.draw_transform,
glyph.region_pos,
glyph.region_size,
entry.curve_quality,
glyph.flush_glyph_buffer,
glyph.buffer_x
)
// 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
// )
// dst_region_pos := glyph.region_pos
// dst_region_size := glyph.region_size
// to_glyph_buffer_space( & dst_region_pos, & dst_region_size, atlas_size )
// clear_target_region : Draw_Call
// {
// using clear_target_region
// pass = .Atlas
// region = .Ignore
// start_index = cast(u32) len(glyph_buffer.clear_draw_list.indices)
// blit_quad( & glyph_buffer.clear_draw_list,
// dst_region_pos, dst_region_pos + dst_region_size,
// { 1.0, 1.0 }, { 1.0, 1.0 } )
// // { 0.0, 0.0 }, { 0.0, 0.0 } )
// end_index = cast(u32) len(glyph_buffer.clear_draw_list.indices)
// }
// dst_glyph_pos := glyph.region_pos
// dst_glyph_size := (glyph.bounds_size_scaled) + atlas.glyph_padding
// to_glyph_buffer_space( & dst_glyph_pos, & dst_glyph_size, atlas_size )
// src_position := Vec2 { glyph.glyph_buffer_x, 0 }
// 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
// pass = .Atlas
// region = .None
// start_index = cast(u32) len(glyph_buffer.draw_list.indices)
// blit_quad( & glyph_buffer.draw_list,
// dst_glyph_pos, dst_glyph_pos + dst_glyph_size,
// src_position, src_position + src_size )
// end_index = cast(u32) len(glyph_buffer.draw_list.indices)
// }
// append( & glyph_buffer.clear_draw_list.calls, clear_target_region )
// append( & glyph_buffer.draw_list.calls, blit_to_atlas )
// // Render glyph to glyph render target (FBO)
// generate_glyph_pass_draw_list( draw_list, & glyph_buffer.shape_gen_scratch,
// glyph.shape,
// entry.curve_quality,
// glyph.bounds,
// glyph.draw_transform.pos,
// glyph.draw_transform.scale
// )
}
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()
generate_cached_draw_list :: #force_inline proc (draw_list : ^Draw_List, glyph_pack : #soa[]Glyph_Pack_Entry, sub_pack : []i32, colour : Colour )
{
profile(#procedure)
@ -620,49 +758,14 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List,
}
}
profile_begin("to_cache: caching to atlas")
for id, index in to_cache {
error : Allocator_Error
glyph_pack[id].shape, error = parser_get_glyph_shape(entry.parser_info, glyph_pack[id].index)
assert(error == .None)
profile_begin("generate_cached_draw_list: to_cache")
when ENABLE_DRAW_TYPE_VIS {
colour.r = 0.80
colour.g = 0.25
colour.b = 0.25
}
for id, index in to_cache
{
profile("glyph")
when ENABLE_DRAW_TYPE_VIS {
colour.r = 0.80
colour.g = 0.25
colour.b = 0.25
}
glyph := glyph_pack[id]
cache_glyph_to_atlas(
draw_list,
& glyph_buffer.draw_list,
& glyph_buffer.clear_draw_list,
& glyph_buffer.batch_x,
& glyph_buffer.shape_gen_scratch,
glyph.shape,
glyph.bounds_scaled,
glyph.bounds_size_scaled,
atlas_size,
glyph_buffer_size,
glyph.over_sample,
atlas.glyph_padding,
glyph.draw_transform,
glyph.region_pos,
glyph.region_size,
entry.curve_quality,
)
}
flush_glyph_buffer_draw_list(draw_list, & glyph_buffer.draw_list, & glyph_buffer.clear_draw_list, & glyph_buffer.batch_x)
for id, index in to_cache do parser_free_shape(entry.parser_info, glyph_pack[id].shape)
profile_end()
generate_cached_draw_list( draw_list, glyph_pack[:], to_cache, colour )
profile_end()
profile_begin("generate_cached_draw_list: to_cache")
when ENABLE_DRAW_TYPE_VIS {
@ -673,64 +776,66 @@ 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.batch_x)
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")
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
{
flush_glyph_buffer_draw_list(draw_list, & glyph_buffer.draw_list, & glyph_buffer.clear_draw_list, & glyph_buffer.batch_x)
generate_glyph_pass_draw_list( draw_list, & glyph_buffer.shape_gen_scratch,
glyph_pack[id].shape,
entry.curve_quality,
glyph_pack[id].bounds_scaled,
glyph_pack[id].draw_transform.scale,
glyph_pack[id].draw_transform.pos
)
when ENABLE_DRAW_TYPE_VIS {
colour.r = 1.0
colour.g = 1.0
colour.b = 0.0
}
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))
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)
}
clear_glyph_update := & calls[1]
for id, index in oversized
{
// 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
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.scale,
glyph_pack[id].draw_transform.pos
)
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] )
}
append( & draw_list.calls, ..calls[:] )
for id, index in oversized do parser_free_shape(entry.parser_info, glyph_pack[id].shape)
}
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, glyph_buffer_batch_x : ^i32 )
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)
// Flush Draw_Calls to draw list
@ -740,7 +845,7 @@ flush_glyph_buffer_draw_list :: #force_inline proc( #no_alias draw_list, glyph_b
clear_draw_list( glyph_buffer_clear_draw_list )
// Clear glyph render target (FBO)
if (glyph_buffer_batch_x ^) != 0
if (allocated_x ^) != 0
{
call := Draw_Call_Default
call.pass = .Glyph
@ -748,7 +853,7 @@ flush_glyph_buffer_draw_list :: #force_inline proc( #no_alias draw_list, glyph_b
call.end_index = 0
call.clear_before_draw = true
append( & draw_list.calls, call )
(glyph_buffer_batch_x ^) = 0
(allocated_x ^) = 0
}
}

View File

@ -117,16 +117,16 @@ Init_Glyph_Draw_Params :: struct {
over_sample : Vec2,
draw_padding : u32,
shape_gen_scratch_reserve : u32,
buffer_batch : u32,
buffer_batch_glyph_limit : u32, // How many glyphs can at maximimum be proccessed at once by batch_generate_glyphs_draw_list
buffer_glyph_limit : u32, // How many region.D glyphs can be drawn to the glyph render target buffer at once (worst case scenario)
batch_glyph_limit : u32, // How many glyphs can at maximimum be proccessed at once by batch_generate_glyphs_draw_list
}
Init_Glyph_Draw_Params_Default :: Init_Glyph_Draw_Params {
over_sample = Vec2 { 4, 4 },
draw_padding = Init_Atlas_Params_Default.glyph_padding,
shape_gen_scratch_reserve = 10 * 1024,
buffer_batch = 4,
buffer_batch_glyph_limit = 512,
buffer_glyph_limit = 4,
batch_glyph_limit = 512,
}
Init_Shaper_Params :: struct {
@ -166,147 +166,146 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType,
)
{
assert( ctx != nil, "Must provide a valid context" )
using ctx
ctx.backing = allocator
context.allocator = ctx.backing
ctx.colour = { 1, 1, 1, 1 }
shaper_ctx := & ctx.shaper_ctx
shaper_ctx.adv_snap_small_font_threshold = f32(shaper_params.adv_snap_small_font_threshold)
shaper_ctx.snap_glyph_position = shaper_params.snap_glyph_position
if default_curve_quality == 0 {
default_curve_quality = 3
}
ctx.default_curve_quality = default_curve_quality
ctx.default_curve_quality = default_curve_quality == 0 ? 3 : i32(default_curve_quality)
error : Allocator_Error
entries, error = make( [dynamic]Entry, len = 0, cap = entires_reserve )
ctx.entries, error = make( [dynamic]Entry, len = 0, cap = entires_reserve )
assert(error == .None, "VEFontCache.init : Failed to allocate entries")
draw_list.vertices, error = make( [dynamic]Vertex, len = 0, cap = 8 * Kilobyte )
ctx.draw_list.vertices, error = make( [dynamic]Vertex, len = 0, cap = 8 * Kilobyte )
assert(error == .None, "VEFontCache.init : Failed to allocate draw_list.vertices")
draw_list.indices, error = make( [dynamic]u32, len = 0, cap = 16 * Kilobyte )
ctx.draw_list.indices, error = make( [dynamic]u32, len = 0, cap = 16 * Kilobyte )
assert(error == .None, "VEFontCache.init : Failed to allocate draw_list.indices")
draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = 1024 )
ctx.draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = Kilobyte )
assert(error == .None, "VEFontCache.init : Failed to allocate draw_list.calls")
init_atlas_region :: proc( region : ^Atlas_Region, params : Init_Atlas_Params, region_params : Init_Atlas_Region_Params, factor : Vec2i, expected_cap : i32 )
atlas := & ctx.atlas
Atlas_Setup:
{
using region
init_atlas_region :: proc( region : ^Atlas_Region, params : Init_Atlas_Params, region_params : Init_Atlas_Region_Params, factor : Vec2i, expected_cap : i32 )
{
region.next_idx = 0;
region.width = i32(region_params.width)
region.height = i32(region_params.height)
region.size = {
i32(params.width) / factor.x,
i32(params.height) / factor.y,
}
region.capacity = {
region.size.x / i32(region.width),
region.size.y / i32(region.height),
}
assert( region.capacity.x * region.capacity.y == expected_cap )
next_idx = 0;
width = i32(region_params.width)
height = i32(region_params.height)
size = {
i32(params.width) / factor.x,
i32(params.height) / factor.y,
error : Allocator_Error
lru_init( & region.state, region.capacity.x * region.capacity.y )
}
capacity = {
size.x / i32(width),
size.y / i32(height),
init_atlas_region( & atlas.region_a, atlas_params, atlas_params.region_a, { 4, 2}, 1024 )
init_atlas_region( & atlas.region_b, atlas_params, atlas_params.region_b, { 4, 2}, 512 )
init_atlas_region( & atlas.region_c, atlas_params, atlas_params.region_c, { 4, 1}, 512 )
init_atlas_region( & atlas.region_d, atlas_params, atlas_params.region_d, { 2, 1}, 256 )
atlas.width = i32(atlas_params.width)
atlas.height = i32(atlas_params.height)
atlas.glyph_padding = f32(atlas_params.glyph_padding)
atlas.glyph_over_scalar = atlas_params.glyph_over_scalar
atlas.region_a.offset = {0, 0}
atlas.region_b.offset.x = 0
atlas.region_b.offset.y = atlas.region_a.size.y
atlas.region_c.offset.x = atlas.region_a.size.x
atlas.region_c.offset.y = 0
atlas.region_d.offset.x = atlas.width / 2
atlas.region_d.offset.y = 0
atlas.regions = {
nil,
& atlas.region_a,
& atlas.region_b,
& atlas.region_c,
& atlas.region_d,
}
assert( capacity.x * capacity.y == expected_cap )
error : Allocator_Error
lru_init( & state, capacity.x * capacity.y )
}
init_atlas_region( & atlas.region_a, atlas_params, atlas_params.region_a, { 4, 2}, 1024 )
init_atlas_region( & atlas.region_b, atlas_params, atlas_params.region_b, { 4, 2}, 512 )
init_atlas_region( & atlas.region_c, atlas_params, atlas_params.region_c, { 4, 1}, 512 )
init_atlas_region( & atlas.region_d, atlas_params, atlas_params.region_d, { 2, 1}, 256 )
atlas.width = i32(atlas_params.width)
atlas.height = i32(atlas_params.height)
atlas.glyph_padding = f32(atlas_params.glyph_padding)
atlas.glyph_over_scalar = atlas_params.glyph_over_scalar
atlas.region_a.offset = {0, 0}
atlas.region_b.offset.x = 0
atlas.region_b.offset.y = atlas.region_a.size.y
atlas.region_c.offset.x = atlas.region_a.size.x
atlas.region_c.offset.y = 0
atlas.region_d.offset.x = atlas.width / 2
atlas.region_d.offset.y = 0
atlas.regions = {
nil,
& atlas.region_a,
& atlas.region_b,
& atlas.region_c,
& atlas.region_d,
}
lru_init( & shape_cache.state, i32(shape_cache_params.capacity) )
Shape_Cache_Setup:
{
shape_cache := & ctx.shape_cache
lru_init( & shape_cache.state, i32(shape_cache_params.capacity) )
shape_cache.storage, error = make( [dynamic]Shaped_Text, shape_cache_params.capacity )
assert(error == .None, "VEFontCache.init : Failed to allocate shape_cache.storage")
shape_cache.storage, error = make( [dynamic]Shaped_Text, shape_cache_params.capacity )
assert(error == .None, "VEFontCache.init : Failed to allocate shape_cache.storage")
for idx : u32 = 0; idx < shape_cache_params.capacity; idx += 1 {
stroage_entry := & shape_cache.storage[idx]
using stroage_entry
glyphs, error = make( [dynamic]Glyph, len = 0, cap = shape_cache_params.reserve_length )
assert( error == .None, "VEFontCache.init : Failed to allocate glyphs array for shape cache storage" )
for idx : u32 = 0; idx < shape_cache_params.capacity; idx += 1 {
stroage_entry := & shape_cache.storage[idx]
positions, error = make( [dynamic]Vec2, len = 0, cap = shape_cache_params.reserve_length )
assert( error == .None, "VEFontCache.init : Failed to allocate positions array for shape cache storage" )
stroage_entry.glyphs, error = make( [dynamic]Glyph, len = 0, cap = shape_cache_params.reserve_length )
assert( error == .None, "VEFontCache.init : Failed to allocate glyphs array for shape cache storage" )
draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
assert( error == .None, "VEFontCache.init : Failed to allocate calls for draw_list" )
draw_list.indices, error = make( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 6 )
assert( error == .None, "VEFontCache.init : Failed to allocate indices array for draw_list" )
draw_list.vertices, error = make( [dynamic]Vertex, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 4 )
assert( error == .None, "VEFontCache.init : Failed to allocate vertices array for draw_list" )
stroage_entry.positions, error = make( [dynamic]Vec2, len = 0, cap = shape_cache_params.reserve_length )
assert( error == .None, "VEFontCache.init : Failed to allocate positions array for shape cache storage" )
}
}
Glyph_Buffer_Setup:
{
using glyph_buffer
over_sample = glyph_draw_params.over_sample
batch = cast(i32) glyph_draw_params.buffer_batch
width = atlas.region_d.width * i32(over_sample.x) * batch
height = atlas.region_d.height * i32(over_sample.y) //* (batch / 2)
draw_padding = cast(f32) glyph_draw_params.draw_padding
glyph_buffer := & ctx.glyph_buffer
draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
assert( error == .None, "VEFontCache.init : Failed to allocate calls for draw_list" )
// using glyph_buffer
glyph_buffer.over_sample = glyph_draw_params.over_sample
glyph_buffer.width = atlas.region_d.width * i32(glyph_buffer.over_sample.x) * i32(glyph_draw_params.buffer_glyph_limit)
glyph_buffer.height = atlas.region_d.height * i32(glyph_buffer.over_sample.y)
glyph_buffer.draw_padding = cast(f32) glyph_draw_params.draw_padding
draw_list.indices, error = make( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 6 )
assert( error == .None, "VEFontCache.init : Failed to allocate indices array for draw_list" )
buffer_limit := glyph_draw_params.buffer_glyph_limit
batch_limit := glyph_draw_params.batch_glyph_limit
draw_list.vertices, error = make( [dynamic]Vertex, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 4 )
assert( error == .None, "VEFontCache.init : Failed to allocate vertices array for draw_list" )
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" )
clear_draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
assert( error == .None, "VEFontCache.init : Failed to allocate calls for calls for clear_draw_list" )
glyph_buffer.draw_list.indices, error = make( [dynamic]u32, len = 0, cap = 16 * Kilobyte )
assert( error == .None, "VEFontCache.init : Failed to allocate indices for glyph_buffer.draw_list" )
clear_draw_list.indices, error = make( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 4 )
assert( error == .None, "VEFontCache.init : Failed to allocate calls for indices array for clear_draw_list" )
glyph_buffer.draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = Kilobyte )
assert( error == .None, "VEFontCache.init : Failed to allocate calls for glyph_buffer.draw_list" )
clear_draw_list.vertices, error = make( [dynamic]Vertex, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 4 )
glyph_buffer.clear_draw_list.vertices, error = make( [dynamic]Vertex, len = 0, cap = 2 * Kilobyte )
assert( error == .None, "VEFontCache.init : Failed to allocate vertices array for clear_draw_list" )
shape_gen_scratch, error = make( [dynamic]Vertex, len = 0, cap = glyph_draw_params.buffer_batch_glyph_limit )
glyph_buffer.clear_draw_list.indices, error = make( [dynamic]u32, len = 0, cap = 4 * Kilobyte )
assert( error == .None, "VEFontCache.init : Failed to allocate calls for indices array for clear_draw_list" )
glyph_buffer.clear_draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = Kilobyte )
assert( error == .None, "VEFontCache.init : Failed to allocate calls for calls for clear_draw_list" )
glyph_buffer.shape_gen_scratch, error = make( [dynamic]Vertex, len = 0, cap = 4 * Kilobyte )
assert(error == .None, "VEFontCache.init : Failed to allocate shape_gen_scratch")
batch_cache.cap = i32(glyph_draw_params.buffer_batch_glyph_limit)
batch_cache := & glyph_buffer.batch_cache
batch_cache.cap = i32(glyph_draw_params.batch_glyph_limit)
batch_cache.num = 0
batch_cache.table, error = make( map[u32]b8, uint(glyph_draw_params.shape_gen_scratch_reserve) )
assert(error == .None, "VEFontCache.init : Failed to allocate batch_cache")
glyph_pack,error = make_soa( #soa[dynamic]Glyph_Pack_Entry, length = 0, capacity = 1 * Kilobyte )
oversized, error = make( [dynamic]i32, len = 0, cap = 1 * Kilobyte )
to_cache, error = make( [dynamic]i32, len = 0, cap = 1 * Kilobyte )
cached, error = make( [dynamic]i32, len = 0, cap = 1 * Kilobyte )
glyph_buffer.glyph_pack,error = make_soa( #soa[dynamic]Glyph_Pack_Entry, length = 0, capacity = 1 * Kilobyte )
glyph_buffer.oversized, error = make( [dynamic]i32, len = 0, cap = 1 * Kilobyte )
glyph_buffer.to_cache, error = make( [dynamic]i32, len = 0, cap = 1 * Kilobyte )
glyph_buffer.cached, error = make( [dynamic]i32, len = 0, cap = 1 * Kilobyte )
}
parser_init( & parser_ctx, parser_kind )
shaper_init( & shaper_ctx )
parser_init( & ctx.parser_ctx, parser_kind )
shaper_init( & ctx.shaper_ctx )
}
hot_reload :: proc( ctx : ^Context, allocator : Allocator )
@ -506,8 +505,15 @@ draw_text :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size : f32,
entry := ctx.entries[ font ]
font_scale := parser_scale( entry.parser_info, px_size )
shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, font, entry, px_size, font_scale, shaper_shape_text_uncached_advanced )
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, colour, entry, font_scale, position, scale, ctx.snap_width, ctx.snap_height )
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer,
colour,
entry,
font_scale,
position,
scale,
ctx.snap_width,
ctx.snap_height
)
return true
}

View File

@ -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'