2024-01-21 20:38:02 -08:00
|
|
|
package host
|
|
|
|
|
2024-02-08 07:50:36 -08:00
|
|
|
import "base:runtime"
|
2024-01-21 20:38:02 -08:00
|
|
|
import "core:dynlib"
|
|
|
|
import "core:io"
|
|
|
|
import "core:fmt"
|
|
|
|
import "core:log"
|
|
|
|
import "core:mem"
|
|
|
|
import "core:mem/virtual"
|
|
|
|
Byte :: 1
|
|
|
|
Kilobyte :: 1024 * Byte
|
|
|
|
Megabyte :: 1024 * Kilobyte
|
|
|
|
Gigabyte :: 1024 * Megabyte
|
|
|
|
Terabyte :: 1024 * Gigabyte
|
|
|
|
Petabyte :: 1024 * Terabyte
|
|
|
|
Exabyte :: 1024 * Petabyte
|
|
|
|
import "core:os"
|
|
|
|
import "core:strings"
|
2024-01-22 00:47:53 -08:00
|
|
|
import "core:time"
|
2024-01-21 20:38:02 -08:00
|
|
|
import rl "vendor:raylib"
|
|
|
|
import sectr "../."
|
|
|
|
|
2024-01-29 22:29:48 -08:00
|
|
|
TrackedAllocator :: sectr.TrackedAllocator
|
|
|
|
tracked_allocator :: sectr.tracked_allocator
|
|
|
|
tracked_allocator_init :: sectr.tracked_allocator_init
|
|
|
|
|
2024-01-25 07:49:57 -08:00
|
|
|
path_snapshot :: "VMemChunk_1.snapshot"
|
2024-01-29 22:29:48 -08:00
|
|
|
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"
|
|
|
|
}
|
2024-01-25 07:49:57 -08:00
|
|
|
|
2024-01-21 20:38:02 -08:00
|
|
|
RuntimeState :: struct {
|
2024-01-22 00:47:53 -08:00
|
|
|
running : b32,
|
|
|
|
memory : VMemChunk,
|
2024-01-21 20:38:02 -08:00
|
|
|
sectr_api : sectr.ModuleAPI,
|
|
|
|
}
|
|
|
|
|
|
|
|
VMemChunk :: struct {
|
2024-01-29 22:29:48 -08:00
|
|
|
og_allocator : mem.Allocator,
|
|
|
|
og_temp_allocator : mem.Allocator,
|
|
|
|
host_persistent : TrackedAllocator,
|
|
|
|
host_transient : TrackedAllocator,
|
|
|
|
sectr_live : virtual.Arena,
|
2024-02-08 07:50:36 -08:00
|
|
|
sectr_snapshot : []u8
|
2024-01-21 20:38:02 -08:00
|
|
|
}
|
|
|
|
|
2024-01-29 22:29:48 -08:00
|
|
|
setup_memory :: proc () -> VMemChunk
|
2024-01-21 20:38:02 -08:00
|
|
|
{
|
2024-01-29 22:29:48 -08:00
|
|
|
Arena :: mem.Arena
|
|
|
|
Tracking_Allocator :: mem.Tracking_Allocator
|
2024-01-22 00:47:53 -08:00
|
|
|
memory : VMemChunk; using memory
|
2024-01-21 20:38:02 -08:00
|
|
|
|
2024-01-29 22:29:48 -08:00
|
|
|
host_persistent_size :: 32 * Megabyte
|
|
|
|
host_transient_size :: 96 * Megabyte
|
|
|
|
internals_size :: 4 * Megabyte
|
2024-01-21 20:38:02 -08:00
|
|
|
|
2024-01-29 22:29:48 -08:00
|
|
|
host_persistent = tracked_allocator_init( host_persistent_size, internals_size )
|
|
|
|
host_transient = tracked_allocator_init( host_transient_size, internals_size )
|
2024-01-25 07:49:57 -08:00
|
|
|
|
2024-01-21 20:38:02 -08:00
|
|
|
// Setup the static arena for the entire application
|
|
|
|
{
|
2024-02-08 07:50:36 -08:00
|
|
|
result := virtual.arena_init_static( & sectr_live, sectr.memory_chunk_size, sectr.memory_chunk_size )
|
|
|
|
if result != runtime.Allocator_Error.None
|
|
|
|
{
|
|
|
|
// TODO(Ed) : Setup a proper logging interface
|
|
|
|
fmt. printf( "Failed to allocate live memory for the sectr module" )
|
|
|
|
runtime.debug_trap()
|
|
|
|
os. exit( -1 )
|
|
|
|
// TODO(Ed) : Figure out the error code enums..
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup memory mapped io for snapshots
|
|
|
|
{
|
|
|
|
file_resize :: os.ftruncate
|
|
|
|
|
|
|
|
snapshot_file, open_error := os.open( path_snapshot, os.O_RDWR | os.O_CREATE )
|
|
|
|
if ( open_error != os.ERROR_NONE )
|
|
|
|
{
|
|
|
|
// TODO(Ed) : Setup a proper logging interface
|
|
|
|
fmt. printf( "Failed to open snapshot file for the sectr module" )
|
|
|
|
runtime.debug_trap()
|
|
|
|
os. exit( -1 )
|
|
|
|
// TODO(Ed) : Figure out the error code enums..
|
|
|
|
}
|
|
|
|
file_resize( snapshot_file, sectr.memory_chunk_size )
|
|
|
|
|
|
|
|
map_error : virtual.Map_File_Error
|
|
|
|
sectr_snapshot, map_error = virtual.map_file_from_file_descriptor( uintptr(snapshot_file), { virtual.Map_File_Flag.Read, virtual.Map_File_Flag.Write } )
|
|
|
|
if map_error != virtual.Map_File_Error.None
|
|
|
|
{
|
|
|
|
// TODO(Ed) : Setup a proper logging interface
|
|
|
|
fmt. printf( "Failed to allocate snapshot memory for the sectr module" )
|
|
|
|
runtime.debug_trap()
|
|
|
|
os. exit( -1 )
|
|
|
|
// TODO(Ed) : Figure out the error code enums..
|
|
|
|
}
|
|
|
|
|
|
|
|
os.close(snapshot_file)
|
2024-01-21 20:38:02 -08:00
|
|
|
}
|
|
|
|
|
2024-01-29 22:29:48 -08:00
|
|
|
// 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 )
|
2024-01-21 20:38:02 -08:00
|
|
|
return memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
load_sectr_api :: proc ( version_id : i32 ) -> sectr.ModuleAPI
|
|
|
|
{
|
|
|
|
loaded_module : sectr.ModuleAPI
|
|
|
|
|
2024-01-22 00:47:53 -08:00
|
|
|
write_time,
|
2024-01-21 20:38:02 -08:00
|
|
|
result := os.last_write_time_by_name("sectr.dll")
|
|
|
|
if result != os.ERROR_NONE {
|
|
|
|
fmt. println("Could not resolve the last write time for sectr.dll")
|
|
|
|
runtime.debug_trap()
|
|
|
|
return {}
|
|
|
|
}
|
|
|
|
|
2024-01-29 22:29:48 -08:00
|
|
|
live_file := path_sectr_live_module
|
|
|
|
sectr.copy_file_sync( path_sectr_module, live_file )
|
2024-01-21 20:38:02 -08:00
|
|
|
|
2024-01-29 22:29:48 -08:00
|
|
|
lib, load_result := dynlib.load_library( live_file )
|
2024-01-21 20:38:02 -08:00
|
|
|
if ! load_result {
|
2024-01-29 22:29:48 -08:00
|
|
|
// TODO(Ed) : Setup a proper logging interface
|
2024-01-21 20:38:02 -08:00
|
|
|
fmt. println( "Failed to load the sectr module." )
|
|
|
|
runtime.debug_trap()
|
|
|
|
return {}
|
|
|
|
}
|
|
|
|
|
2024-01-29 22:29:48 -08:00
|
|
|
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" )
|
2024-01-22 00:47:53 -08:00
|
|
|
|
|
|
|
missing_symbol : b32 = false
|
2024-01-29 22:29:48 -08:00
|
|
|
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")
|
2024-01-22 00:47:53 -08:00
|
|
|
if missing_symbol {
|
|
|
|
runtime.debug_trap()
|
|
|
|
return {}
|
|
|
|
}
|
|
|
|
|
2024-01-21 20:38:02 -08:00
|
|
|
loaded_module = {
|
|
|
|
lib = lib,
|
2024-01-22 00:47:53 -08:00
|
|
|
write_time = write_time,
|
2024-01-21 20:38:02 -08:00
|
|
|
lib_version = version_id,
|
|
|
|
|
2024-01-29 22:29:48 -08:00
|
|
|
startup = startup,
|
|
|
|
shutdown = shutdown,
|
|
|
|
reload = reload,
|
|
|
|
update = update,
|
|
|
|
render = render,
|
|
|
|
clean_temp = clean_temp,
|
2024-01-21 20:38:02 -08:00
|
|
|
}
|
|
|
|
return loaded_module
|
|
|
|
}
|
|
|
|
|
2024-01-22 00:47:53 -08:00
|
|
|
unload_sectr_api :: proc ( module : ^ sectr.ModuleAPI )
|
|
|
|
{
|
|
|
|
dynlib.unload_library( module.lib )
|
2024-01-29 22:29:48 -08:00
|
|
|
os.remove( path_sectr_live_module )
|
2024-01-22 00:47:53 -08:00
|
|
|
module^ = {}
|
|
|
|
}
|
|
|
|
|
2024-01-29 22:29:48 -08:00
|
|
|
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..
|
|
|
|
}
|
2024-02-08 07:50:36 -08:00
|
|
|
sectr_api.reload( memory.sectr_live, memory.sectr_snapshot )
|
2024-01-29 22:29:48 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-21 20:38:02 -08:00
|
|
|
main :: proc()
|
|
|
|
{
|
|
|
|
fmt.println("Hellope!")
|
|
|
|
|
2024-01-22 00:47:53 -08:00
|
|
|
state : RuntimeState
|
|
|
|
using state
|
|
|
|
|
2024-01-21 20:38:02 -08:00
|
|
|
// Basic Giant VMem Block
|
|
|
|
{
|
|
|
|
// By default odin uses a growing arena for the runtime context
|
|
|
|
// 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.
|
2024-01-29 22:29:48 -08:00
|
|
|
memory = setup_memory()
|
2024-01-21 20:38:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Load the Enviornment API for the first-time
|
|
|
|
{
|
|
|
|
sectr_api = load_sectr_api( 1 )
|
|
|
|
if sectr_api.lib_version == 0 {
|
2024-01-29 22:29:48 -08:00
|
|
|
// TODO(Ed) : Setup a proper logging interface
|
2024-01-21 20:38:02 -08:00
|
|
|
fmt. println( "Failed to initially load the sectr module" )
|
|
|
|
runtime.debug_trap()
|
|
|
|
os. exit( -1 )
|
2024-01-29 22:29:48 -08:00
|
|
|
// TODO(Ed) : Figure out the error code enums..
|
2024-01-21 20:38:02 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-22 00:47:53 -08:00
|
|
|
running = true;
|
|
|
|
memory = memory
|
|
|
|
sectr_api = sectr_api
|
2024-02-08 07:50:36 -08:00
|
|
|
sectr_api.startup( memory.sectr_live, memory.sectr_snapshot )
|
2024-01-21 20:38:02 -08:00
|
|
|
|
2024-01-22 00:47:53 -08:00
|
|
|
// TODO(Ed) : This should have an end status so that we know the reason the engine stopped.
|
|
|
|
for ; running ;
|
2024-01-21 20:38:02 -08:00
|
|
|
{
|
|
|
|
// Hot-Reload
|
2024-01-29 22:29:48 -08:00
|
|
|
sync_sectr_api( & sectr_api, & memory )
|
2024-01-21 20:38:02 -08:00
|
|
|
|
2024-01-22 00:47:53 -08:00
|
|
|
running = sectr_api.update()
|
2024-01-29 22:29:48 -08:00
|
|
|
sectr_api.render()
|
|
|
|
sectr_api.clean_temp()
|
2024-01-21 20:38:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Determine how the run_cyle completed, if it failed due to an error,
|
|
|
|
// fallback the env to a failsafe state and reload the run_cycle.
|
|
|
|
{
|
|
|
|
// TODO(Ed): Implement this.
|
|
|
|
}
|
|
|
|
|
2024-01-22 00:47:53 -08:00
|
|
|
sectr_api.shutdown()
|
|
|
|
unload_sectr_api( & sectr_api )
|
2024-01-21 20:38:02 -08:00
|
|
|
}
|