Segregated host/api better. Memory setup is problably solid now.
This commit is contained in:
		
							
								
								
									
										105
									
								
								code/api.odin
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								code/api.odin
									
									
									
									
									
								
							| @@ -3,7 +3,9 @@ package sectr | ||||
| import    "core:dynlib" | ||||
| import    "core:fmt" | ||||
| import    "core:mem" | ||||
| import    "core:mem/virtual" | ||||
| import    "core:os" | ||||
| import    "core:slice" | ||||
| import    "core:strings" | ||||
| import rl "vendor:raylib" | ||||
|  | ||||
| @@ -14,30 +16,60 @@ ModuleAPI :: struct { | ||||
| 	write_time  : os.File_Time, | ||||
| 	lib_version : i32, | ||||
|  | ||||
| 	startup  : type_of( startup       ), | ||||
| 	shutdown : type_of( sectr_shutdown), | ||||
| 	reload   : type_of( reload        ), | ||||
| 	update   : type_of( update        ), | ||||
| 	render   : type_of( render        ) | ||||
| 	startup    : type_of( startup ), | ||||
| 	shutdown   : type_of( sectr_shutdown), | ||||
| 	reload     : type_of( reload ), | ||||
| 	update     : type_of( update ), | ||||
| 	render     : type_of( render ), | ||||
| 	clean_temp : type_of( clean_temp ), | ||||
| } | ||||
|  | ||||
| memory_chunk_size      :: 2 * Gigabyte | ||||
| memory_persistent_size :: 128 * Megabyte | ||||
| memory_trans_temp_size :: (memory_chunk_size - memory_persistent_size ) / 2 | ||||
|  | ||||
| Memory :: struct { | ||||
| 	persistent : ^ mem.Arena, | ||||
| 	transient  : ^ mem.Arena, | ||||
| 	temp       : ^ mem.Arena | ||||
| 	live       : ^ virtual.Arena, | ||||
| 	snapshot   : ^ virtual.Arena, | ||||
| 	persistent : ^ TrackedAllocator, | ||||
| 	transient  : ^ TrackedAllocator, | ||||
| 	temp       : ^ TrackedAllocator | ||||
| } | ||||
|  | ||||
| memory : Memory | ||||
|  | ||||
| @export | ||||
| startup :: proc( persistent, transient, temp : ^ mem.Arena ) | ||||
| startup :: proc( live_mem, snapshot_mem : ^ virtual.Arena ) | ||||
| { | ||||
| 	memory.persistent = persistent | ||||
| 	state            := cast(^State) memory.persistent; using state | ||||
| 	// Setup memory for the first time | ||||
| 	{ | ||||
| 		Arena              :: mem.Arena | ||||
| 		Tracking_Allocator :: mem.Tracking_Allocator | ||||
| 		arena_allocator    :: mem.arena_allocator | ||||
| 		arena_init         :: mem.arena_init | ||||
| 		slice_ptr          :: mem.slice_ptr | ||||
|  | ||||
| 	// Anything allocated by default is considered transient. | ||||
| 	// context.allocator      = mem.arena_allocator( transient ) | ||||
| 	// context.temp_allocator = mem.arena_allocator( temp ) | ||||
| 		arena_size     :: size_of( mem.Arena) | ||||
| 		internals_size :: 4 * Megabyte | ||||
|  | ||||
| 		using memory; | ||||
| 		block := live_mem.curr_block | ||||
|  | ||||
| 		persistent_slice := slice_ptr( block.base, memory_persistent_size ) | ||||
| 		transient_slice  := slice_ptr( memory_after( persistent_slice), memory_trans_temp_size ) | ||||
| 		temp_slice       := slice_ptr( memory_after( transient_slice),  memory_trans_temp_size ) | ||||
|  | ||||
| 		// We assign the beginning of the block to be the host's persistent memory's arena. | ||||
| 		// Then we offset past the arena and determine its slice to be the amount left after for the size of host's persistent. | ||||
| 		persistent = tracked_allocator_init_vmem( persistent_slice, internals_size ) | ||||
| 		transient  = tracked_allocator_init_vmem( transient_slice,  internals_size ) | ||||
| 		temp       = tracked_allocator_init_vmem( temp_slice ,      internals_size ) | ||||
|  | ||||
| 		// context.allocator      = tracked_allocator( transient ) | ||||
| 		// context.temp_allocator = tracked_allocator( temp ) | ||||
| 	} | ||||
| 	state := new( State, tracked_allocator( memory.persistent ) ) | ||||
| 	using state | ||||
|  | ||||
| 	// Rough setup of window with rl stuff | ||||
| 	screen_width  = 1280 | ||||
| @@ -70,25 +102,35 @@ sectr_shutdown :: proc() | ||||
| 	if memory.persistent == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	state := cast( ^ State ) memory.persistent | ||||
| 	state := get_state() | ||||
| 	rl.UnloadFont( state.font_rec_mono_semicasual_reg ) | ||||
| 	rl.CloseWindow() | ||||
| } | ||||
|  | ||||
| @export | ||||
| reload :: proc( persistent, transient, temp : ^ mem.Arena ) | ||||
| reload :: proc( live_mem, snapshot_mem : ^ virtual.Arena ) | ||||
| { | ||||
| 	memory.persistent      = persistent | ||||
| 	memory.transient       = transient | ||||
| 	memory.temp            = temp | ||||
| 	context.allocator      = mem.arena_allocator( transient ) | ||||
| 	context.temp_allocator = mem.arena_allocator( temp ) | ||||
| 	Arena              :: mem.Arena | ||||
| 	Tracking_Allocator :: mem.Tracking_Allocator | ||||
| 	arena_allocator    :: mem.arena_allocator | ||||
| 	slice_ptr          :: mem.slice_ptr | ||||
|  | ||||
| 	using memory; | ||||
| 	block := live_mem.curr_block | ||||
|  | ||||
| 	persistent_slice := slice_ptr( block.base, memory_persistent_size ) | ||||
| 	transient_slice  := slice_ptr( memory_after( persistent_slice), memory_trans_temp_size ) | ||||
| 	temp_slice       := slice_ptr( memory_after( transient_slice),  memory_trans_temp_size ) | ||||
|  | ||||
| 	persistent = cast( ^TrackedAllocator ) & persistent_slice[0] | ||||
| 	transient  = cast( ^TrackedAllocator ) & transient_slice[0] | ||||
| 	temp       = cast( ^TrackedAllocator ) & temp_slice[0] | ||||
| } | ||||
|  | ||||
| @export | ||||
| update :: proc() -> b32 | ||||
| { | ||||
| 	state := cast( ^ State ) memory.persistent | ||||
| 	state := get_state(); using state | ||||
|  | ||||
| 	should_shutdown : b32 = ! cast(b32) rl.WindowShouldClose() | ||||
| 	return should_shutdown | ||||
| @@ -97,7 +139,7 @@ update :: proc() -> b32 | ||||
| @export | ||||
| render :: proc() | ||||
| { | ||||
| 	state := cast( ^ State ) memory.persistent; using state | ||||
| 	state := get_state(); using state | ||||
|  | ||||
| 	rl.BeginDrawing() | ||||
| 	rl.ClearBackground( Color_BG ) | ||||
| @@ -111,7 +153,7 @@ render :: proc() | ||||
| 	{ | ||||
| 		@static draw_text_scratch : [Kilobyte * 64]u8 | ||||
|  | ||||
| 		state := cast( ^ State ) memory.persistent; using state | ||||
| 		state := get_state(); using state | ||||
| 		if ( draw_debug_text_y > 800 ) { | ||||
| 			draw_debug_text_y = 50 | ||||
| 		} | ||||
| @@ -122,10 +164,21 @@ render :: proc() | ||||
| 		draw_debug_text_y += 16 | ||||
| 	} | ||||
|  | ||||
| 	draw_text( "Monitor      : %v", rl.GetMonitorName(0) ) | ||||
| 	// draw_text( "Hot-Reload Count : %v", -1 ) | ||||
|  | ||||
| 	draw_text( "Screen Width : %v", rl.GetScreenWidth() ) | ||||
| 	draw_text( "Screen Height: %v", rl.GetScreenHeight() ) | ||||
| 	// draw_text( "HOT RELOAD BITCHES" ) | ||||
|  | ||||
| 	draw_debug_text_y = 50 | ||||
| } | ||||
|  | ||||
| @export | ||||
| clean_temp :: proc() | ||||
| { | ||||
| 	mem.tracking_allocator_clear( & memory.temp.tracker ) | ||||
| } | ||||
|  | ||||
| get_state :: proc() -> (^ State) | ||||
| { | ||||
| 	return cast(^ State) raw_data( memory.persistent.backing.data ) | ||||
| } | ||||
|   | ||||
| @@ -20,7 +20,17 @@ import       "core:time" | ||||
| import rl    "vendor:raylib" | ||||
| import sectr "../." | ||||
|  | ||||
| TrackedAllocator       :: sectr.TrackedAllocator | ||||
| tracked_allocator      :: sectr.tracked_allocator | ||||
| tracked_allocator_init :: sectr.tracked_allocator_init | ||||
|  | ||||
| path_snapshot :: "VMemChunk_1.snapshot" | ||||
| when ODIN_OS == runtime.Odin_OS_Type.Windows | ||||
| { | ||||
| 	path_sectr_module        :: "sectr.dll" | ||||
| 	path_sectr_live_module   :: "sectr_live.dll" | ||||
| 	path_sectr_debug_symbols :: "sectr.pdb" | ||||
| } | ||||
|  | ||||
| RuntimeState :: struct { | ||||
| 	running   : b32, | ||||
| @@ -29,77 +39,46 @@ RuntimeState :: struct { | ||||
| } | ||||
|  | ||||
| VMemChunk :: struct { | ||||
| 	sarena            : virtual.Arena, | ||||
| 	host_persistent   : ^ mem.Arena, | ||||
| 	host_transient    : ^ mem.Arena, | ||||
| 	sectr_persistent  : ^ mem.Arena, | ||||
| 	sectr_transient   : ^ mem.Arena, | ||||
| 	sectr_temp        : ^ mem.Arena, | ||||
|  | ||||
| 	// snapshot :  | ||||
| 	og_allocator            : mem.Allocator, | ||||
| 	og_temp_allocator       : mem.Allocator, | ||||
| 	host_persistent         : TrackedAllocator, | ||||
| 	host_transient          : TrackedAllocator, | ||||
| 	sectr_live              : virtual.Arena, | ||||
| 	sectr_snapshot          : virtual.Arena | ||||
| } | ||||
|  | ||||
| setup_engine_memory :: proc () -> VMemChunk | ||||
| setup_memory :: proc () -> VMemChunk | ||||
| { | ||||
| 	Arena              :: mem.Arena | ||||
| 	Tracking_Allocator :: mem.Tracking_Allocator | ||||
| 	memory : VMemChunk; using memory | ||||
|  | ||||
| 	Arena      :: mem.Arena | ||||
| 	arena_init :: mem.arena_init | ||||
| 	ptr_offset :: mem.ptr_offset | ||||
| 	slice_ptr  :: mem.slice_ptr | ||||
| 	host_persistent_size :: 32 * Megabyte | ||||
| 	host_transient_size  :: 96 * Megabyte | ||||
| 	internals_size       :: 4  * Megabyte | ||||
|  | ||||
| 	chunk_size :: 2 * Gigabyte | ||||
| 	host_persistent = tracked_allocator_init( host_persistent_size, internals_size ) | ||||
| 	host_transient  = tracked_allocator_init( host_transient_size,  internals_size ) | ||||
|  | ||||
| 	// Setup the static arena for the entire application | ||||
| 	if  result := virtual.arena_init_static( & sarena, chunk_size, chunk_size ); | ||||
| 		result != runtime.Allocator_Error.None | ||||
| 	if  result := virtual.arena_init_static( & sectr_live, sectr.memory_chunk_size, sectr.memory_chunk_size ); | ||||
| 		  result != runtime.Allocator_Error.None | ||||
| 	{ | ||||
| 		// TODO(Ed) : Setup a proper logging interface | ||||
| 		fmt.    printf( "Failed to allocate memory for the engine" ) | ||||
| 		fmt.    printf( "Failed to allocate memory for the sectr module" ) | ||||
| 		runtime.debug_trap() | ||||
| 		os.     exit( -1 ) | ||||
| 		// TODO(Ed) : Figure out the error code enums.. | ||||
| 	} | ||||
|  | ||||
| 	arena_size :: size_of( Arena) | ||||
|  | ||||
| 	persistent_size       :: Megabyte * 128 * 2 | ||||
| 	transient_size        :: (chunk_size - persistent_size * 2) / 2 | ||||
| 	host_persistent_size  :: persistent_size / 4 - arena_size | ||||
| 	host_transient_size   :: transient_size  / 4 - arena_size | ||||
| 	sectr_persistent_size :: persistent_size - host_persistent_size - arena_size | ||||
| 	sectr_trans_temp_size :: (transient_size - host_transient_size) / 2 - arena_size | ||||
|  | ||||
| 	block := memory.sarena.curr_block | ||||
|  | ||||
| 	// We assign the beginning of the block to be the host's persistent memory's arena. | ||||
| 	// Then we offset past the arena and determine its slice to be the amount left after for the size of host's persistent. | ||||
| 	host_persistent        = cast( ^ Arena ) block.base | ||||
| 	host_persistent_slice := slice_ptr( ptr_offset( block.base, arena_size), host_persistent_size) | ||||
| 	arena_init( host_persistent, host_persistent_slice ) | ||||
|  | ||||
| 	// Initialize a sub-section of our virtual memory as a sub-arena | ||||
| 	sub_arena_init :: proc( address : ^ byte, size : int ) -> ( ^ Arena) { | ||||
| 		sub_arena := cast( ^ Arena ) address | ||||
| 		mem_slice := slice_ptr( ptr_offset( address, arena_size), size ) | ||||
| 		arena_init( sub_arena, mem_slice ) | ||||
| 		return sub_arena | ||||
| 	} | ||||
|  | ||||
| 	// Helper to get the the beginning of memory after a slice | ||||
| 	next :: proc( slice : []byte ) -> ( ^ byte) { | ||||
| 		return ptr_offset( & slice[0], len(slice) ) | ||||
| 	} | ||||
|  | ||||
| 	host_transient   = sub_arena_init( next( host_persistent.data),  host_transient_size) | ||||
| 	sectr_persistent = sub_arena_init( next( host_transient.data),   sectr_persistent_size) | ||||
| 	sectr_transient  = sub_arena_init( next( sectr_persistent.data), sectr_trans_temp_size) | ||||
| 	sectr_temp       = sub_arena_init( next( sectr_transient.data),  sectr_trans_temp_size) | ||||
| 	// Reassign default allocators for host | ||||
| 	memory.og_allocator      = context.allocator | ||||
| 	memory.og_temp_allocator = context.temp_allocator | ||||
| 	context.allocator        = tracked_allocator( & memory.host_persistent ) | ||||
| 	context.temp_allocator   = tracked_allocator( & memory.host_transient ) | ||||
| 	return memory; | ||||
| } | ||||
|  | ||||
| setup_snapshot_memory :: proc () | ||||
|  | ||||
| load_sectr_api :: proc ( version_id : i32 ) -> sectr.ModuleAPI | ||||
| { | ||||
| 	loaded_module : sectr.ModuleAPI | ||||
| @@ -112,28 +91,31 @@ load_sectr_api :: proc ( version_id : i32 ) -> sectr.ModuleAPI | ||||
| 		return {} | ||||
| 	} | ||||
|  | ||||
| 	lock_file := fmt.tprintf( "sectr_{0}_locked.dll", version_id ) | ||||
| 	sectr.copy_file_sync( "sectr.dll", lock_file ) | ||||
| 	live_file := path_sectr_live_module | ||||
| 	sectr.copy_file_sync( path_sectr_module, live_file ) | ||||
|  | ||||
| 	lib, load_result := dynlib.load_library( lock_file ) | ||||
| 	lib, load_result := dynlib.load_library( live_file ) | ||||
| 	if ! load_result { | ||||
| 		// TODO(Ed) : Setup a proper logging interface | ||||
| 		fmt.    println( "Failed to load the sectr module." ) | ||||
| 		runtime.debug_trap() | ||||
| 		return {} | ||||
| 	} | ||||
|  | ||||
| 	startup  := cast( type_of( sectr.startup        )) dynlib.symbol_address( lib, "startup" ) | ||||
| 	shutdown := cast( type_of( sectr.sectr_shutdown )) dynlib.symbol_address( lib, "sectr_shutdown" ) | ||||
| 	reload   := cast( type_of( sectr.reload         )) dynlib.symbol_address( lib, "reload" ) | ||||
| 	update   := cast( type_of( sectr.update         )) dynlib.symbol_address( lib, "update" ) | ||||
| 	render   := cast( type_of( sectr.render         )) dynlib.symbol_address( lib, "render" ) | ||||
| 	startup    := cast( type_of( sectr.startup        )) dynlib.symbol_address( lib, "startup" ) | ||||
| 	shutdown   := cast( type_of( sectr.sectr_shutdown )) dynlib.symbol_address( lib, "sectr_shutdown" ) | ||||
| 	reload     := cast( type_of( sectr.reload         )) dynlib.symbol_address( lib, "reload" ) | ||||
| 	update     := cast( type_of( sectr.update         )) dynlib.symbol_address( lib, "update" ) | ||||
| 	render     := cast( type_of( sectr.render         )) dynlib.symbol_address( lib, "render" ) | ||||
| 	clean_temp := cast( type_of( sectr.clean_temp     )) dynlib.symbol_address( lib, "clean_temp" ) | ||||
|  | ||||
| 	missing_symbol : b32 = false | ||||
| 	if startup  == nil do fmt.println("Failed to load sectr.startup symbol") | ||||
| 	if shutdown == nil do fmt.println("Failed to load sectr.shutdown symbol") | ||||
| 	if reload   == nil do fmt.println("Failed to load sectr.reload symbol") | ||||
| 	if update   == nil do fmt.println("Failed to load sectr.update symbol") | ||||
| 	if render   == nil do fmt.println("Failed to load sectr.render symbol") | ||||
| 	if startup    == nil do fmt.println("Failed to load sectr.startup symbol") | ||||
| 	if shutdown   == nil do fmt.println("Failed to load sectr.shutdown symbol") | ||||
| 	if reload     == nil do fmt.println("Failed to load sectr.reload symbol") | ||||
| 	if update     == nil do fmt.println("Failed to load sectr.update symbol") | ||||
| 	if render     == nil do fmt.println("Failed to load sectr.render symbol") | ||||
| 	if clean_temp == nil do fmt.println("Failed to load sector.clean_temp symbol") | ||||
| 	if missing_symbol { | ||||
| 		runtime.debug_trap() | ||||
| 		return {} | ||||
| @@ -144,23 +126,46 @@ load_sectr_api :: proc ( version_id : i32 ) -> sectr.ModuleAPI | ||||
| 		write_time  = write_time, | ||||
| 		lib_version = version_id, | ||||
|  | ||||
| 		startup  = startup, | ||||
| 		shutdown = shutdown, | ||||
| 		reload   = reload, | ||||
| 		update   = update, | ||||
| 		render   = render, | ||||
| 		startup    = startup, | ||||
| 		shutdown   = shutdown, | ||||
| 		reload     = reload, | ||||
| 		update     = update, | ||||
| 		render     = render, | ||||
| 		clean_temp = clean_temp, | ||||
| 	} | ||||
| 	return loaded_module | ||||
| } | ||||
|  | ||||
| unload_sectr_api :: proc ( module : ^ sectr.ModuleAPI ) | ||||
| { | ||||
| 	lock_file := fmt.tprintf( "sectr_{0}_locked.dll", module.lib_version ) | ||||
| 	dynlib.unload_library( module.lib ) | ||||
| 	// os.remove( lock_file ) | ||||
| 	os.remove( path_sectr_live_module ) | ||||
| 	module^ = {} | ||||
| } | ||||
|  | ||||
| sync_sectr_api :: proc ( sectr_api : ^ sectr.ModuleAPI, memory : ^ VMemChunk ) | ||||
| { | ||||
| 	if write_time, result := os.last_write_time_by_name( path_sectr_module ); | ||||
| 	result == os.ERROR_NONE && sectr_api.write_time != write_time | ||||
| 	{ | ||||
| 		version_id := sectr_api.lib_version + 1 | ||||
| 		unload_sectr_api( sectr_api ) | ||||
|  | ||||
| 		// Wait for pdb to unlock (linker may still be writting) | ||||
| 		for ; sectr.is_file_locked( path_sectr_debug_symbols ) && sectr.is_file_locked( path_sectr_live_module ); {} | ||||
| 		time.sleep( time.Millisecond ) | ||||
|  | ||||
| 		sectr_api ^ = load_sectr_api( version_id ) | ||||
| 		if sectr_api.lib_version == 0 { | ||||
| 			fmt.println("Failed to hot-reload the sectr module") | ||||
| 			runtime.debug_trap() | ||||
| 			os.exit(-1) | ||||
| 			// TODO(Ed) : Figure out the error code enums.. | ||||
| 		} | ||||
| 		sectr_api.reload( & memory.sectr_live, & memory.sectr_snapshot ) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| main :: proc() | ||||
| { | ||||
| 	fmt.println("Hellope!") | ||||
| @@ -174,55 +179,35 @@ main :: proc() | ||||
| 		// We're going to make it static for the prototype and separate it from the 'project' memory. | ||||
| 		// Then shove the context allocator for the engine to it. | ||||
| 		// The project's context will use its own subsection arena allocator. | ||||
| 		memory                 = setup_engine_memory() | ||||
| 		context.allocator      = mem.arena_allocator( memory.host_persistent ) | ||||
| 		context.temp_allocator = mem.arena_allocator( memory.host_transient ) | ||||
| 		memory = setup_memory() | ||||
| 	} | ||||
|  | ||||
| 	// Load the Enviornment API for the first-time | ||||
| 	{ | ||||
| 		   sectr_api = load_sectr_api( 1 ) | ||||
| 		if sectr_api.lib_version == 0 { | ||||
| 			// TODO(Ed) : Setup a proper logging interface | ||||
| 			fmt.    println( "Failed to initially load the sectr module" ) | ||||
| 			runtime.debug_trap() | ||||
| 			os.     exit( -1 ) | ||||
| 			// TODO(Ed) : Figure out the error code enums.. | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	running            = true; | ||||
| 	memory             = memory | ||||
| 	sectr_api          = sectr_api | ||||
| 	sectr_api.startup( memory.sectr_persistent, memory.sectr_transient, memory.sectr_temp ) | ||||
| 	sectr_api.startup( & memory.sectr_live, & memory.sectr_snapshot ) | ||||
|  | ||||
| 	// TODO(Ed) : This should have an end status so that we know the reason the engine stopped. | ||||
| 	for ; running ; | ||||
| 	{ | ||||
| 		// Hot-Reload | ||||
| 		if write_time, result := os.last_write_time_by_name("sectr.dll"); | ||||
| 			result == os.ERROR_NONE && sectr_api.write_time != write_time | ||||
| 		{ | ||||
| 			version_id := sectr_api.lib_version + 1 | ||||
| 			unload_sectr_api( & sectr_api ) | ||||
|  | ||||
| 			// Wait for pdb to unlock (linker may still be writting) | ||||
| 			for ; sectr.is_file_locked( "sectr.pdb" ); { | ||||
| 			} | ||||
| 			time.sleep( time.Millisecond ) | ||||
|  | ||||
| 			sectr_api = load_sectr_api( version_id ) | ||||
| 			if sectr_api.lib_version == 0 { | ||||
| 				fmt.println("Failed to hot-reload the sectr module") | ||||
| 				runtime.debug_trap() | ||||
| 				os.exit(-1) | ||||
| 			} | ||||
| 			sectr_api.reload( memory.sectr_persistent, memory.sectr_transient, memory.sectr_temp ) | ||||
| 		} | ||||
| 		sync_sectr_api( & sectr_api, & memory ) | ||||
|  | ||||
| 		running = sectr_api.update() | ||||
| 		sectr_api.render() | ||||
|  | ||||
| 		free_all( mem.arena_allocator( memory.sectr_temp ) ) | ||||
| 		// free_all( mem.arena_allocator( & memory.env_transient ) ) | ||||
| 		          sectr_api.render() | ||||
| 		          sectr_api.clean_temp() | ||||
| 	} | ||||
|  | ||||
| 	// Determine how the run_cyle completed, if it failed due to an error, | ||||
|   | ||||
							
								
								
									
										111
									
								
								code/memory.odin
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								code/memory.odin
									
									
									
									
									
								
							| @@ -4,6 +4,7 @@ import "core:fmt" | ||||
| import "core:mem" | ||||
| import "core:mem/virtual" | ||||
| import "core:runtime" | ||||
| import "core:os" | ||||
|  | ||||
| Byte     :: 1 | ||||
| Kilobyte :: 1024 * Byte | ||||
| @@ -14,8 +15,112 @@ Petabyte :: 1024 * Terabyte | ||||
| Exabyte  :: 1024 * Petabyte | ||||
|  | ||||
| kilobytes :: proc ( kb : $ integer_type ) -> integer_type { | ||||
| 	return kb * 1024 | ||||
| 	return kb * Kilobyte | ||||
| } | ||||
| megabytes :: proc ( kb : $ integer_type ) -> integer_type { | ||||
| 	return kb * 1024 * 1024 | ||||
| megabytes :: proc ( mb : $ integer_type ) -> integer_type { | ||||
| 	return mb * Megabyte | ||||
| } | ||||
| gigabyte  :: proc ( gb : $ integer_type ) -> integer_type { | ||||
| 	return gb * Gigabyte | ||||
| } | ||||
| terabyte  :: proc ( tb : $ integer_type ) -> integer_type { | ||||
| 	return tb * Terabyte | ||||
| } | ||||
|  | ||||
| // Initialize a sub-section of our virtual memory as a sub-arena | ||||
| sub_arena_init :: proc( address : ^ byte, size : int ) -> ( ^ mem.Arena) { | ||||
| 	Arena :: mem.Arena | ||||
|  | ||||
| 	arena_size :: size_of( Arena) | ||||
| 	sub_arena  := cast( ^ Arena ) address | ||||
| 	mem_slice  := mem.slice_ptr( mem.ptr_offset( address, arena_size), size ) | ||||
| 	mem.arena_init( sub_arena, mem_slice ) | ||||
| 	return sub_arena | ||||
| } | ||||
|  | ||||
| // Helper to get the the beginning of memory after a slice | ||||
| memory_after :: proc( slice : []byte ) -> ( ^ byte) { | ||||
| 	return mem.ptr_offset( & slice[0], len(slice) ) | ||||
| } | ||||
|  | ||||
| // Since this is a prototype, all memory is always tracked. No arena is is interfaced directly. | ||||
| TrackedAllocator :: struct { | ||||
| 	backing   : mem.Arena, | ||||
| 	internals : mem.Arena, | ||||
| 	tracker   : mem.Tracking_Allocator, | ||||
| } | ||||
|  | ||||
| tracked_allocator :: proc ( self : ^ TrackedAllocator ) -> mem.Allocator { | ||||
| 	return mem.tracking_allocator( & self.tracker ) | ||||
| } | ||||
|  | ||||
| tracked_allocator_init :: proc( size, internals_size : int ) -> TrackedAllocator | ||||
| { | ||||
| 	result : TrackedAllocator | ||||
|  | ||||
| 	Arena              :: mem.Arena | ||||
| 	Tracking_Allocator :: mem.Tracking_Allocator | ||||
| 	arena_allocator    :: mem.arena_allocator | ||||
| 	arena_init         :: mem.arena_init | ||||
| 	slice_ptr          :: mem.slice_ptr | ||||
|  | ||||
| 	arena_size              :: size_of( Arena) | ||||
| 	backing_size            := size           + arena_size | ||||
| 	internals_size          := internals_size + arena_size | ||||
| 	raw_size                := backing_size + internals_size | ||||
|  | ||||
| 	raw_mem, raw_mem_code := mem.alloc( raw_size ) | ||||
| 	if ( raw_mem_code != mem.Allocator_Error.None ) | ||||
| 	{ | ||||
| 		// TODO(Ed) : Setup a proper logging interface | ||||
| 		fmt.    printf( "Failed to allocate memory for the TrackingAllocator" ) | ||||
| 		runtime.debug_trap() | ||||
| 		os.     exit( -1 ) | ||||
| 		// TODO(Ed) : Figure out the error code enums.. | ||||
| 	} | ||||
| 	arena_init( & result.backing,   slice_ptr( cast( ^ byte) raw_mem,              backing_size   ) ) | ||||
| 	arena_init( & result.internals, slice_ptr( memory_after( result.backing.data), internals_size ) ) | ||||
|  | ||||
| 	backing_allocator   := arena_allocator( & result.backing ) | ||||
| 	internals_allocator := arena_allocator( & result.internals ) | ||||
| 	mem.tracking_allocator_init( & result.tracker, backing_allocator, internals_allocator ) | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| tracked_allocator_init_vmem :: proc( vmem : [] byte, internals_size : int ) -> ^ TrackedAllocator | ||||
| { | ||||
| 	Arena                  :: mem.Arena | ||||
| 	Tracking_Allocator     :: mem.Tracking_Allocator | ||||
| 	arena_allocator        :: mem.arena_allocator | ||||
| 	arena_init             :: mem.arena_init | ||||
| 	tracking_alloator_init :: mem.tracking_allocator_init | ||||
| 	ptr_offset             :: mem.ptr_offset | ||||
| 	slice_ptr              :: mem.slice_ptr | ||||
|  | ||||
| 	arena_size              :: size_of( Arena) | ||||
| 	tracking_allocator_size :: size_of( Tracking_Allocator ) | ||||
| 	backing_size            := len(vmem)    - internals_size | ||||
| 	raw_size                := backing_size + internals_size | ||||
|  | ||||
| 	if backing_size < 0 || len(vmem) < raw_size | ||||
| 	{ | ||||
| 		// TODO(Ed) : Setup a proper logging interface | ||||
| 		fmt.    printf( "Provided virtual memory slice is not large enough to hold the TrackedAllocator" ) | ||||
| 		runtime.debug_trap() | ||||
| 		os.     exit( -1 ) | ||||
| 		// TODO(Ed) : Figure out the error code enums.. | ||||
| 	} | ||||
|  | ||||
| 	result       := cast( ^ TrackedAllocator) & vmem[0] | ||||
| 	result_slice := slice_ptr( & vmem[0], tracking_allocator_size ) | ||||
|  | ||||
| 	backing_slice   := slice_ptr( memory_after( result_slice ), backing_size ) | ||||
| 	internals_slice := slice_ptr( memory_after( backing_slice), internals_size ) | ||||
| 	backing         := & result.backing | ||||
| 	internals       := & result.internals | ||||
| 	arena_init( backing,   backing_slice ) | ||||
| 	arena_init( internals, internals_slice ) | ||||
|  | ||||
| 	tracking_alloator_init( & result.tracker, arena_allocator( backing ), arena_allocator( internals ) ) | ||||
| 	return result | ||||
| } | ||||
|   | ||||
| @@ -12,7 +12,7 @@ debug_text :: proc( content : string, x, y : f32, size : f32 = 16.0, color : rl. | ||||
|  | ||||
| 	font := font | ||||
| 	if ( font.chars == nil ) { | ||||
| 		font = ( cast( ^ State) memory.persistent ).default_font | ||||
| 		font = get_state().default_font | ||||
| 	} | ||||
|  | ||||
| 	rl.DrawTextCodepoints( font, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user