Converted string cache table to use HMapChained, initial impl for ui_box_traverse_next_layer_based
This commit is contained in:
		| @@ -72,6 +72,9 @@ pool_list_push_front :: proc( pool : ^PoolList, value : PoolListValue ) | ||||
| 	assert( free_list.num == u64(capacity - size) ) | ||||
|  | ||||
| 	id := array_back( free_list ) | ||||
| 	if pool.dbg_name != "" { | ||||
| 		logf("pool_list: back %v", id) | ||||
| 	} | ||||
| 	array_pop( free_list ) | ||||
| 	items.data[ id ].prev  = -1 | ||||
| 	items.data[ id ].next  = front | ||||
|   | ||||
| @@ -15,6 +15,7 @@ package grime | ||||
|  | ||||
| import "base:runtime" | ||||
| import "core:mem" | ||||
| import "core:strings" | ||||
|  | ||||
| HTable_Minimum_Capacity :: 4 * Kilobyte | ||||
|  | ||||
| @@ -55,7 +56,7 @@ hmap_closest_prime :: proc( capacity : uint ) -> uint | ||||
|  | ||||
| hmap_chained_init :: proc( $HMapChainedType : typeid/HMapChained($Type), lookup_capacity : uint, | ||||
|   allocator               := context.allocator, | ||||
| 	pool_bucket_cap         : uint   = 1 * Kilo, | ||||
| 	pool_bucket_cap         : uint   = 0, | ||||
| 	pool_bucket_reserve_num : uint   = 0, | ||||
| 	pool_alignment          : uint   = mem.DEFAULT_ALIGNMENT, | ||||
| 	dbg_name                : string = "", | ||||
| @@ -69,6 +70,11 @@ hmap_chained_init :: proc( $HMapChainedType : typeid/HMapChained($Type), lookup_ | ||||
| 	raw_mem, error = alloc( size, allocator = allocator ) | ||||
| 	if error != AllocatorError.None do return | ||||
|  | ||||
| 	pool_bucket_cap := pool_bucket_cap | ||||
| 	if pool_bucket_cap == 0 { | ||||
| 		pool_bucket_cap = cast(uint) int(lookup_capacity) * size_of( HMapChainedSlot(Type)) | ||||
| 	} | ||||
|  | ||||
| 	table.header      = cast( ^HMapChainedHeader(Type)) raw_mem | ||||
| 	table.pool, error = pool_init( | ||||
| 		should_zero_buckets = false, | ||||
| @@ -77,7 +83,7 @@ hmap_chained_init :: proc( $HMapChainedType : typeid/HMapChained($Type), lookup_ | ||||
| 		bucket_reserve_num  = pool_bucket_reserve_num, | ||||
| 		alignment           = pool_alignment, | ||||
| 		allocator           = allocator, | ||||
| 		dbg_name            = str_intern(str_fmt("%v: pool", dbg_name)).str, | ||||
| 		dbg_name            = strings.clone(str_fmt_tmp("%v: pool", dbg_name), allocator = allocator), | ||||
| 		enable_mem_tracking = enable_mem_tracking, | ||||
| 	) | ||||
| 	data          := transmute(^^HMapChainedSlot(Type)) memory_after_header(table.header) | ||||
|   | ||||
| @@ -31,7 +31,7 @@ to_str_runes_pair_via_runes  :: #force_inline proc ( content : []rune ) -> StrRu | ||||
|  | ||||
| StringCache :: struct { | ||||
| 	slab      : Slab, | ||||
| 	table     : HMapZPL(StrRunesPair), | ||||
| 	table     : HMapChained(StrRunesPair), | ||||
| } | ||||
|  | ||||
| // This is the default string cache for the runtime module. | ||||
| @@ -70,25 +70,25 @@ str_cache_init :: proc( table_allocator, slabs_allocator : Allocator ) -> (cache | ||||
| 	cache.slab, alloc_error = slab_init( & policy, allocator = slabs_allocator, dbg_name = dbg_name ) | ||||
| 	verify(alloc_error == .None, "Failed to initialize the string cache" ) | ||||
|  | ||||
| 	cache.table, alloc_error = make( HMapZPL(StrRunesPair), 4 * Megabyte, table_allocator, dbg_name ) | ||||
| 	cache.table, alloc_error = make( HMapChained(StrRunesPair), 1 * Kilo, table_allocator, dbg_name = dbg_name ) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| str_cache_reload :: #force_inline proc ( cache : ^StringCache, table_allocator, slabs_allocator : Allocator  ) { | ||||
| 	slab_reload( cache.slab, table_allocator ) | ||||
| 	hmap_zpl_reload( & cache.table, slabs_allocator ) | ||||
| 	hmap_chained_reload( cache.table, slabs_allocator ) | ||||
| } | ||||
|  | ||||
| str_cache_set_module_ctx :: #force_inline proc "contextless" ( cache : ^StringCache ) { Module_String_Cache = cache } | ||||
| str_intern_key           :: #force_inline proc( content : string ) ->  StringKey      { return cast(StringKey) crc32( transmute([]byte) content ) } | ||||
| str_intern_lookup        :: #force_inline proc( key : StringKey )  -> (^StrRunesPair) { return hmap_zpl_get( & Module_String_Cache.table, transmute(u64) key ) } | ||||
| str_intern_lookup        :: #force_inline proc( key : StringKey )  -> (^StrRunesPair) { return hmap_chained_get( Module_String_Cache.table, transmute(u64) key ) } | ||||
|  | ||||
| str_intern :: proc( content : string ) -> StrRunesPair | ||||
| { | ||||
| 	// profile(#procedure) | ||||
| 	cache  := Module_String_Cache | ||||
| 	key    := str_intern_key(content) | ||||
| 	result := hmap_zpl_get( & cache.table, transmute(u64) key ) | ||||
| 	result := hmap_chained_get( cache.table, transmute(u64) key ) | ||||
| 	if result != nil { | ||||
| 		return (result ^) | ||||
| 	} | ||||
| @@ -104,7 +104,7 @@ str_intern :: proc( content : string ) -> StrRunesPair | ||||
| 	verify( alloc_error == .None, "String cache had a backing allocator error" ) | ||||
| 	// slab_validate_pools( cache.slab.backing ) | ||||
|  | ||||
| 	result, alloc_error = hmap_zpl_set( & cache.table, transmute(u64) key, StrRunesPair { transmute(string) str_mem, runes } ) | ||||
| 	result, alloc_error = hmap_chained_set( cache.table, transmute(u64) key, StrRunesPair { transmute(string) str_mem, runes } ) | ||||
| 	verify( alloc_error == .None, "String cache had a backing allocator error" ) | ||||
| 	// slab_validate_pools( cache.slab.backing ) | ||||
|  | ||||
|   | ||||
| @@ -73,7 +73,7 @@ font_provider_startup :: proc() | ||||
| 	font_cache, error = make( HMapChained(FontDef), hmap_closest_prime(1 * Kilo), persistent_allocator(), dbg_name = "font_cache" ) | ||||
| 	verify( error == AllocatorError.None, "Failed to allocate font_cache" ) | ||||
|  | ||||
| 	ve.init( & provider_data.ve_font_cache, .STB_TrueType, allocator = persistent_allocator() ) | ||||
| 	ve.init( & provider_data.ve_font_cache, .STB_TrueType, allocator = persistent_slab_allocator() ) | ||||
| 	log("VEFontCached initialized") | ||||
|  | ||||
| 	ve.configure_snap( & provider_data.ve_font_cache, u32(state.app_window.extent.x * 2.0), u32(state.app_window.extent.y * 2.0) ) | ||||
|   | ||||
| @@ -65,6 +65,11 @@ UI_Parent_Stack_Size      :: 512 | ||||
| // UI_Built_Boxes_Array_Size :: 8 | ||||
| UI_Built_Boxes_Array_Size :: 128 * Kilobyte | ||||
|  | ||||
| UI_RenderQueueEntry :: struct { | ||||
| 	using links : DLL_NodePN(UI_RenderQueueEntry), | ||||
| 	box : ^UI_Box, | ||||
| } | ||||
|  | ||||
| // TODO(Ed): Rename to UI_Context | ||||
| UI_State :: struct { | ||||
| 	// TODO(Ed) : Use these? | ||||
| @@ -77,7 +82,9 @@ UI_State :: struct { | ||||
| 	prev_cache : ^HMapZPL( UI_Box ), | ||||
| 	curr_cache : ^HMapZPL( UI_Box ), | ||||
|  | ||||
| 	render_queue : Array(UI_RenderBoxInfo), | ||||
| 	// render_queue_builder : SubArena, | ||||
| 	render_queue         : DLL_NodeFL(UI_RenderQueueEntry), | ||||
| 	render_list          : Array(UI_RenderBoxInfo), | ||||
|  | ||||
| 	null_box : ^UI_Box, // This was used with the Linked list interface... | ||||
| 	root     : ^UI_Box, | ||||
| @@ -120,7 +127,7 @@ ui_startup :: proc( ui : ^ UI_State, cache_allocator : Allocator /* , cache_rese | ||||
| 	ui.prev_cache = (& ui.caches[0]) | ||||
|  | ||||
| 	allocation_error : AllocatorError | ||||
| 	ui.render_queue, allocation_error = make( Array(UI_RenderBoxInfo), UI_Built_Boxes_Array_Size, cache_allocator, fixed_cap = true ) | ||||
| 	ui.render_list, allocation_error = make( Array(UI_RenderBoxInfo), UI_Built_Boxes_Array_Size, cache_allocator, fixed_cap = true ) | ||||
| 	verify( allocation_error == AllocatorError.None, "Failed to allocate render queue" ) | ||||
|  | ||||
| 	log("ui_startup completed") | ||||
| @@ -132,7 +139,7 @@ ui_reload :: proc( ui : ^ UI_State, cache_allocator : Allocator ) | ||||
| 	for & cache in ui.caches { | ||||
| 		hmap_zpl_reload( & cache, cache_allocator) | ||||
| 	} | ||||
| 	ui.render_queue.backing = cache_allocator | ||||
| 	ui.render_list.backing = cache_allocator | ||||
| } | ||||
|  | ||||
| // TODO(Ed) : Is this even needed? | ||||
| @@ -150,7 +157,7 @@ ui_graph_build_begin :: proc( ui : ^ UI_State, bounds : Vec2 = {} ) | ||||
|  | ||||
| 	stack_clear( & layout_combo_stack ) | ||||
| 	stack_clear( & style_combo_stack ) | ||||
| 	array_clear( render_queue ) | ||||
| 	array_clear( render_list ) | ||||
|  | ||||
| 	curr_cache, prev_cache = swap( curr_cache, prev_cache ) | ||||
|  | ||||
| @@ -187,21 +194,72 @@ ui_graph_build_end :: proc( ui : ^UI_State ) | ||||
| 			} | ||||
| 			computed.content    = computed.bounds | ||||
| 		} | ||||
|  | ||||
| 		for current := root.first; current != nil; current = ui_box_tranverse_next( current ) | ||||
| 		{ | ||||
| 			if ! current.computed.fresh { | ||||
| 				ui_box_compute_layout( current ) | ||||
| 			} | ||||
|  | ||||
| 			// Enqueue for rendering | ||||
| 			array_append( & ui.render_queue, UI_RenderBoxInfo { | ||||
| 				current.computed, | ||||
| 				current.style, | ||||
| 				current.text, | ||||
| 				current.layout.font_size, | ||||
| 				current.layout.border_width, | ||||
| 			}) | ||||
| 		} | ||||
|  | ||||
| 		 | ||||
|  | ||||
| 		// Render order is "layer-based" and thus needs a new traversal done | ||||
| 		// ui.render_queue.first     = new(UI_RenderQueueEntry) | ||||
| 		// ui.render_queue.first.box = root.first | ||||
| 		// for current := root.first.next; current != nil; current = ui_box_traverse_next_layer_based( current ) | ||||
| 		// { | ||||
| 		// 	entry     := new(UI_RenderQueueEntry) | ||||
| 		// 	entry.box  = current | ||||
| 		// 	// Enqueue box to render | ||||
| 		// 	// Would be best to use a linked list tied to a sub-arena | ||||
| 		// 	dll_push_back( & ui.render_queue.first, entry ) | ||||
| 		// 	ui.render_queue.last = entry | ||||
| 		// } | ||||
|  | ||||
| 		// enqueued_id : i32 = 0 | ||||
| 		// for enqueued := ui.render_queue.first; enqueued != nil; enqueued = enqueued.next | ||||
| 		// { | ||||
| 		// 	/* | ||||
| 		// 		For each enqueue box: | ||||
| 		// 		1. Check to see if any overlap (traverse all Queued Entries and check to see if their bounds overlap) | ||||
| 		// 		2. If they do, the box & its children must be popped off the current ancestry layer and moved to the start of the next | ||||
| 		// 			(This could problably be an iteration where we just pop and push_back until we reach the adjacent box of the same layer) | ||||
| 		// 	*/ | ||||
| 		// 	// other_id : i32 = 0 | ||||
| 		// 	for other := enqueued.next; other != nil; other = other.next | ||||
| 		// 	{ | ||||
| 		// 		if intersects_range2( enqueued.box.computed.bounds, other.box.computed.bounds) | ||||
| 		// 		{ | ||||
| 		// 			// Intersection occured, other's box is on top, it and its children must be deferred to the next layer | ||||
| 		// 			next_layer_start := other.next | ||||
| 		// 			for ; next_layer_start != nil; next_layer_start = next_layer_start.next | ||||
| 		// 			{ | ||||
| 		// 				if next_layer_start.box == other.box.first do break | ||||
| 		// 			} | ||||
|  | ||||
| 		// 			other.next            = next_layer_start | ||||
| 		// 			other.prev            = next_layer_start.prev | ||||
| 		// 			next_layer_start.prev = other | ||||
| 		// 			enqueued.next         = other.prev | ||||
| 		// 			break | ||||
| 		// 		} | ||||
| 		// 	} | ||||
| 		// } | ||||
|  | ||||
| 		// Queue should be optimized now to generate the final draw list | ||||
| 		// for enqueued := ui.render_queue.first; enqueued != nil; enqueued = enqueued.next | ||||
| 		// { | ||||
| 		// 	using enqueued.box | ||||
| 		// 	// Enqueue for rendering | ||||
| 		// 	array_append( & ui.render_list, UI_RenderBoxInfo { | ||||
| 		// 		computed, | ||||
| 		// 		style, | ||||
| 		// 		text, | ||||
| 		// 		layout.font_size, | ||||
| 		// 		layout.border_width, | ||||
| 		// 	}) | ||||
| 		// } | ||||
| 	} | ||||
|  | ||||
| 	get_state().ui_context = nil | ||||
|   | ||||
| @@ -124,6 +124,7 @@ ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box) | ||||
|  | ||||
| ui_prev_cached_box :: #force_inline proc( box : ^UI_Box ) -> ^UI_Box { return hmap_zpl_get( ui_context().prev_cache, cast(u64) box.key ) } | ||||
|  | ||||
| // Traveral pritorizes immeidate children | ||||
| ui_box_tranverse_next :: proc "contextless" ( box : ^ UI_Box ) -> (^ UI_Box) | ||||
| { | ||||
| 	using state := get_state() | ||||
| @@ -132,14 +133,13 @@ ui_box_tranverse_next :: proc "contextless" ( box : ^ UI_Box ) -> (^ UI_Box) | ||||
| 	{ | ||||
| 		// Check to make sure parent is present on the screen, if its not don't bother. | ||||
| 		is_app_ui := ui_context == & screen_ui | ||||
| 		if intersects_range2( ui_view_bounds(), box.computed.bounds) | ||||
| 		{ | ||||
| 		if intersects_range2( ui_view_bounds(), box.computed.bounds) { | ||||
| 			return box.first | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if box.next != nil do return box.next | ||||
| 	// There is no more adjacent nodes | ||||
| 	// There are no more adjacent nodes | ||||
|  | ||||
| 	parent := box.parent | ||||
| 	// Attempt to find a parent with a next, otherwise we just return a parent with nil | ||||
| @@ -154,3 +154,33 @@ ui_box_tranverse_next :: proc "contextless" ( box : ^ UI_Box ) -> (^ UI_Box) | ||||
| 	// Lift back up to parent, and set it to its next. | ||||
| 	return parent.next | ||||
| } | ||||
|  | ||||
| // Traveral pritorizes traversing a "anestry layer" | ||||
| ui_box_traverse_next_layer_based :: proc "contextless" ( box : ^UI_Box, skip_intersection_test := false ) -> (^UI_Box) | ||||
| { | ||||
| 	using state := get_state() | ||||
|  | ||||
| 	parent := box.parent | ||||
| 	if parent != nil | ||||
| 	{ | ||||
| 		if parent.last != box | ||||
| 		{ | ||||
| 			if box.next != nil do return box.next | ||||
| 			// There are no more adjacent nodes | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Either is root OR | ||||
| 	// Parent children exhausted, this should be the last box of this ancestry | ||||
| 	// Do children if they are available. | ||||
| 	if box.first != nil | ||||
| 	{ | ||||
| 		// Check to make sure parent is present on the screen, if its not don't bother. | ||||
| 		if ! skip_intersection_test && intersects_range2( ui_view_bounds(), box.computed.bounds) { | ||||
| 			return box.first | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// We should have exhausted the list if we're on the last box of teh last parent | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user