diff --git a/code/font/vefontcache/atlas.odin b/code/font/vefontcache/atlas.odin index 77f1ea1..97146f6 100644 --- a/code/font/vefontcache/atlas.odin +++ b/code/font/vefontcache/atlas.odin @@ -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 diff --git a/code/font/vefontcache/draw.odin b/code/font/vefontcache/draw.odin index 54b0570..7f9a157 100644 --- a/code/font/vefontcache/draw.odin +++ b/code/font/vefontcache/draw.odin @@ -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 } } diff --git a/code/font/vefontcache/vefontcache.odin b/code/font/vefontcache/vefontcache.odin index cbd242c..7dc67d2 100644 --- a/code/font/vefontcache/vefontcache.odin +++ b/code/font/vefontcache/vefontcache.odin @@ -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 } diff --git a/scripts/build.ps1 b/scripts/build.ps1 index ec895c5..99726a2 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'