WIP: Untested more process runtime bootstrapping, some decisions on how grime is setup..
This commit is contained in:
@@ -2,6 +2,5 @@
|
||||
|
||||
This is a top-level package to adjust odin to my personalized usage.
|
||||
|
||||
I curate all usage of odin's provided package definitons through here. The client and host packages should never directly import them.
|
||||
There is only one definition with static allocations in Grime. Ideally there are also none, but spall profiler needs a context.
|
||||
|
||||
There are no implicit static allocations in Grime. Ideally there are also none from the base/core packages but some probably leak.
|
||||
|
@@ -1,32 +1,21 @@
|
||||
package grime
|
||||
|
||||
import "core:os"
|
||||
|
||||
// Below should be defined per-package
|
||||
|
||||
ensure :: #force_inline proc( condition : b32, msg : string, location := #caller_location )
|
||||
{
|
||||
if condition {
|
||||
return
|
||||
}
|
||||
ensure :: #force_inline proc( condition : b32, msg : string, location := #caller_location ) {
|
||||
if condition do return
|
||||
log_print( msg, LoggerLevel.Warning, location )
|
||||
debug_trap()
|
||||
}
|
||||
|
||||
// TODO(Ed) : Setup exit codes!
|
||||
fatal :: #force_inline proc( msg : string, exit_code : int = -1, location := #caller_location )
|
||||
{
|
||||
fatal :: #force_inline proc( msg : string, exit_code : int = -1, location := #caller_location ) {
|
||||
log_print( msg, LoggerLevel.Fatal, location )
|
||||
debug_trap()
|
||||
process_exit( exit_code )
|
||||
}
|
||||
|
||||
// TODO(Ed) : Setup exit codes!
|
||||
verify :: #force_inline proc( condition : b32, msg : string, exit_code : int = -1, location := #caller_location )
|
||||
{
|
||||
if condition {
|
||||
return
|
||||
}
|
||||
verify :: #force_inline proc( condition : b32, msg : string, exit_code : int = -1, location := #caller_location ) {
|
||||
if condition do return
|
||||
log_print( msg, LoggerLevel.Fatal, location )
|
||||
debug_trap()
|
||||
process_exit( exit_code )
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package grime
|
||||
|
||||
Context :: struct {
|
||||
OdinContext :: struct {
|
||||
allocator: AllocatorInfo,
|
||||
temp_allocator: AllocatorInfo,
|
||||
assertion_failure_proc: Assertion_Failure_Proc,
|
||||
@@ -14,6 +14,6 @@ Context :: struct {
|
||||
_internal: rawptr,
|
||||
}
|
||||
|
||||
context_usr :: #force_inline proc( $ Type : typeid ) -> (^Type) {
|
||||
context_user :: #force_inline proc( $ Type : typeid ) -> (^Type) {
|
||||
return cast(^Type) context.user_ptr
|
||||
}
|
||||
|
@@ -119,7 +119,6 @@ memory_aign_forward :: #force_inline proc( address, alignment : uintptr) -> uint
|
||||
return aligned_address
|
||||
}
|
||||
|
||||
|
||||
// align_up :: proc(address: uintptr, alignment: uintptr) -> uintptr {
|
||||
// return (address + alignment - 1) & ~(alignment - 1)
|
||||
// }
|
||||
|
@@ -78,8 +78,12 @@ import "core:os"
|
||||
file_truncate :: os.truncate
|
||||
file_write :: os.write
|
||||
|
||||
file_read_entire :: os.read_entire_file
|
||||
file_write_entire :: os.write_entire_file
|
||||
file_read_entire_from_filename :: #force_inline proc(name: string, allocator := context.allocator, loc := #caller_location) -> (data: []byte, success: bool) { return os.read_entire_file_from_filename(name, resolve_odin_allocator(allocator), loc) }
|
||||
file_write_entire :: os.write_entire_file
|
||||
|
||||
file_read_entire :: proc {
|
||||
file_read_entire_from_filename,
|
||||
}
|
||||
|
||||
import "core:strings"
|
||||
StrBuilder :: strings.Builder
|
||||
|
@@ -12,26 +12,21 @@ SpallProfiler :: struct {
|
||||
buffer : spall.Buffer,
|
||||
}
|
||||
|
||||
// @(private)
|
||||
// Module_Context : ^SpallProfiler
|
||||
|
||||
// set_profiler_module_context :: #force_inline proc "contextless" ( ctx : ^SpallProfiler ) {
|
||||
// Module_Context = ctx
|
||||
// }
|
||||
set_profiler_module_context :: #force_inline proc "contextless" ( profiler : ^SpallProfiler ) {
|
||||
static_memory.spall_profiler = profiler
|
||||
}
|
||||
|
||||
DISABLE_PROFILING :: true
|
||||
|
||||
@(deferred_none = profile_end, disabled = DISABLE_PROFILING)
|
||||
profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) {
|
||||
// spall._buffer_begin( & Module_Context.ctx, & Module_Context.buffer, name, "", loc )
|
||||
spall._buffer_begin( & static_memory.spall_profiler.ctx, & static_memory.spall_profiler.buffer, name, "", loc )
|
||||
}
|
||||
|
||||
@(disabled = DISABLE_PROFILING)
|
||||
profile_begin :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) {
|
||||
// spall._buffer_begin( & Module_Context.ctx, & Module_Context.buffer, name, "", loc )
|
||||
spall._buffer_begin( & static_memory.spall_profiler.ctx, & static_memory.spall_profiler.buffer, name, "", loc )
|
||||
}
|
||||
|
||||
@(disabled = DISABLE_PROFILING)
|
||||
profile_end :: #force_inline proc "contextless" () {
|
||||
// spall._buffer_end( & Module_Context.ctx, & Module_Context.buffer)
|
||||
spall._buffer_end( & static_memory.spall_profiler.ctx, & static_memory.spall_profiler.buffer)
|
||||
}
|
||||
|
9
code2/grime/static_memory.odin
Normal file
9
code2/grime/static_memory.odin
Normal file
@@ -0,0 +1,9 @@
|
||||
package grime
|
||||
|
||||
//region STATIC MEMORY
|
||||
static_memory: StaticMemory
|
||||
//endregion STATIC MEMORY
|
||||
|
||||
StaticMemory :: struct {
|
||||
spall_profiler: ^SpallProfiler,
|
||||
}
|
3
code2/gui_code/Readme.md
Normal file
3
code2/gui_code/Readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# gui_code
|
||||
|
||||
This is the UI package used by sectr. It's meant to be optimial for composing complex code visualizations in soft real-time.
|
@@ -1,59 +1,39 @@
|
||||
package host
|
||||
|
||||
import "core:thread"
|
||||
import "core:sync"
|
||||
//region STATIC MEMORY
|
||||
// All program defined process memory here. (There will still be artifacts from the OS CRT and third-party pacakges)
|
||||
host_memory: ProcessMemory
|
||||
@(thread_local) thread_memory: ThreadMemory
|
||||
|
||||
Path_Logs :: "../logs"
|
||||
when ODIN_OS == .Windows
|
||||
{
|
||||
Path_Sectr_Module :: "sectr.dll"
|
||||
Path_Sectr_Live_Module :: "sectr_live.dll"
|
||||
Path_Sectr_Debug_Symbols :: "sectr.pdb"
|
||||
Path_Sectr_Spall_Record :: "sectr.spall"
|
||||
}
|
||||
//endregion STATIC MEMORY
|
||||
|
||||
// Only static memory host has.
|
||||
host_memory: ProcessMemory
|
||||
//region HOST RUNTIME
|
||||
|
||||
@(thread_local)
|
||||
thread_memory: ThreadMemory
|
||||
|
||||
load_client_api :: proc(version_id: int) -> (loaded_module: Client_API)
|
||||
{
|
||||
write_time, result := file_last_write_time_by_name("sectr.dll")
|
||||
if result != OS_ERROR_NONE {
|
||||
load_client_api :: proc(version_id: int) -> (loaded_module: Client_API) {
|
||||
using loaded_module
|
||||
// Make sure we have a dll to work with
|
||||
file_io_err: OS_Error; write_time, file_io_err = file_last_write_time_by_name("sectr.dll")
|
||||
if file_io_err != OS_ERROR_NONE {
|
||||
panic_contextless( "Could not resolve the last write time for sectr")
|
||||
}
|
||||
|
||||
//TODO(Ed): Lets try to minimize this...
|
||||
thread_sleep( Millisecond * 100 )
|
||||
|
||||
// Get the live dll loaded up
|
||||
live_file := Path_Sectr_Live_Module
|
||||
file_copy_sync( Path_Sectr_Module, live_file, allocator = context.temp_allocator )
|
||||
|
||||
lib, load_result := os_lib_load( live_file )
|
||||
if ! load_result {
|
||||
panic( "Failed to load the sectr module." )
|
||||
}
|
||||
|
||||
startup := cast( type_of( host_memory.client_api.startup)) os_lib_get_proc(lib, "startup")
|
||||
tick_lane_startup := cast( type_of( host_memory.client_api.tick_lane_startup)) os_lib_get_proc(lib, "tick_lane_startup")
|
||||
hot_reload := cast( type_of( host_memory.client_api.hot_reload)) os_lib_get_proc(lib, "hot_reload")
|
||||
tick_lane := cast( type_of( host_memory.client_api.tick_lane)) os_lib_get_proc(lib, "tick_lane")
|
||||
clean_frame := cast( type_of( host_memory.client_api.clean_frame)) os_lib_get_proc(lib, "clean_frame")
|
||||
did_load: bool; lib, did_load = os_lib_load( live_file )
|
||||
if ! did_load do panic( "Failed to load the sectr module.")
|
||||
startup = cast( type_of( host_memory.client_api.startup)) os_lib_get_proc(lib, "startup")
|
||||
tick_lane_startup = cast( type_of( host_memory.client_api.tick_lane_startup)) os_lib_get_proc(lib, "tick_lane_startup")
|
||||
hot_reload = cast( type_of( host_memory.client_api.hot_reload)) os_lib_get_proc(lib, "hot_reload")
|
||||
tick_lane = cast( type_of( host_memory.client_api.tick_lane)) os_lib_get_proc(lib, "tick_lane")
|
||||
clean_frame = cast( type_of( host_memory.client_api.clean_frame)) os_lib_get_proc(lib, "clean_frame")
|
||||
if startup == nil do panic("Failed to load sectr.startup symbol" )
|
||||
if tick_lane_startup == nil do panic("Failed to load sectr.tick_lane_startup symbol" )
|
||||
if hot_reload == nil do panic("Failed to load sectr.hot_reload symbol" )
|
||||
if tick_lane == nil do panic("Failed to load sectr.tick_lane symbol" )
|
||||
if clean_frame == nil do panic("Failed to load sectr.clean_frmae symbol" )
|
||||
|
||||
loaded_module.lib = lib
|
||||
loaded_module.write_time = write_time
|
||||
loaded_module.lib_version = version_id
|
||||
loaded_module.startup = startup
|
||||
loaded_module.tick_lane_startup = tick_lane_startup
|
||||
loaded_module.hot_reload = hot_reload
|
||||
loaded_module.tick_lane = tick_lane
|
||||
loaded_module.clean_frame = clean_frame
|
||||
lib_version = version_id
|
||||
return
|
||||
}
|
||||
|
||||
@@ -65,8 +45,9 @@ main :: proc()
|
||||
arena_init(& host_memory.host_scratch, host_memory.host_scratch_buf[:])
|
||||
context.allocator = arena_allocator(& host_memory.host_persist)
|
||||
context.temp_allocator = arena_allocator(& host_memory.host_scratch)
|
||||
// Setup the profiler
|
||||
when SHOULD_SETUP_PROFILERS
|
||||
{
|
||||
// Setup profilers
|
||||
buffer_backing := make([]u8, SPALL_BUFFER_DEFAULT_SIZE * 4)
|
||||
host_memory.spall_profiler.ctx = spall_context_create(Path_Sectr_Spall_Record)
|
||||
host_memory.spall_profiler.buffer = spall_buffer_create(buffer_backing)
|
||||
@@ -120,43 +101,32 @@ main :: proc()
|
||||
host_memory.client_api = load_client_api( 1 )
|
||||
verify( host_memory.client_api.lib_version != 0, "Failed to initially load the sectr module" )
|
||||
}
|
||||
|
||||
// Client API Startup
|
||||
host_memory.host_api.sync_client_module = sync_client_api
|
||||
host_memory.host_api.launch_tick_lane_thread = launch_tick_lane_thread
|
||||
host_memory.client_api.startup(& host_memory, & thread_memory)
|
||||
|
||||
// Start the tick lanes
|
||||
thread_wide_startup()
|
||||
}
|
||||
|
||||
thread_wide_startup :: proc()
|
||||
{
|
||||
assert(thread_memory.id == .Master_Prepper)
|
||||
if THREAD_TICK_LANES > 1 {
|
||||
launch_tick_lane_thread(.Atomic_Accountant)
|
||||
sync.barrier_init(& host_memory.client_api_sync_lock, THREAD_TICK_LANES)
|
||||
/*thread_wide_startup() :: proc()*/ {
|
||||
assert(thread_memory.id == .Master_Prepper)
|
||||
if THREAD_TICK_LANES > 1 {
|
||||
launch_tick_lane_thread(.Atomic_Accountant)
|
||||
barrier_init(& host_memory.client_api_sync_lock, THREAD_TICK_LANES)
|
||||
}
|
||||
host_tick_lane_startup(thread_memory.system_ctx)
|
||||
}
|
||||
host_tick_lane_startup(thread_memory.system_ctx)
|
||||
}
|
||||
|
||||
@export
|
||||
launch_tick_lane_thread :: proc(id : WorkerID) {
|
||||
assert_contextless(thread_memory.id == .Master_Prepper)
|
||||
// TODO(Ed): We need to make our own version of this that doesn't allocate memory.
|
||||
lane_thread := thread.create(host_tick_lane_startup, .High)
|
||||
lane_thread := thread_create(host_tick_lane_startup, .High)
|
||||
lane_thread.user_index = int(id)
|
||||
thread.start(lane_thread)
|
||||
thread_start(lane_thread)
|
||||
}
|
||||
|
||||
host_tick_lane_startup :: proc(lane_thread: ^SysThread) {
|
||||
thread_memory.system_ctx = lane_thread
|
||||
thread_memory.id = cast(WorkerID) lane_thread.user_index
|
||||
host_memory.client_api.tick_lane_startup(& thread_memory)
|
||||
|
||||
host_tick_lane()
|
||||
}
|
||||
|
||||
host_tick_lane :: proc()
|
||||
{
|
||||
delta_ns: Duration
|
||||
@@ -167,6 +137,7 @@ host_tick_lane :: proc()
|
||||
for ; running ;
|
||||
{
|
||||
profile("Host Tick")
|
||||
leader := barrier_wait(& host_memory.client_api_sync_lock)
|
||||
sync_client_api()
|
||||
|
||||
running = host_memory.client_api.tick_lane( duration_seconds(delta_ns), delta_ns )
|
||||
@@ -180,41 +151,40 @@ host_tick_lane :: proc()
|
||||
@export
|
||||
sync_client_api :: proc()
|
||||
{
|
||||
leader := sync.barrier_wait(& host_memory.client_api_sync_lock)
|
||||
free_all(context.temp_allocator)
|
||||
profile(#procedure)
|
||||
if thread_memory.id == .Master_Prepper
|
||||
{
|
||||
write_time, result := file_last_write_time_by_name( Path_Sectr_Module );
|
||||
if result == OS_ERROR_NONE && host_memory.client_api.write_time != write_time
|
||||
if thread_memory.id == .Master_Prepper
|
||||
{
|
||||
cache_coherent_store(& host_memory.client_api_hot_reloaded, true)
|
||||
|
||||
version_id := host_memory.client_api.lib_version + 1
|
||||
unload_client_api( & host_memory.client_api )
|
||||
|
||||
// Wait for pdb to unlock (linker may still be writting)
|
||||
for ; file_is_locked( Path_Sectr_Debug_Symbols ) && file_is_locked( Path_Sectr_Live_Module ); {}
|
||||
thread_sleep( Millisecond * 100 )
|
||||
|
||||
host_memory.client_api = load_client_api( version_id )
|
||||
verify( host_memory.client_api.lib_version != 0, "Failed to hot-reload the sectr module" )
|
||||
profile("Master_Prepper: Reloading client module")
|
||||
write_time, result := file_last_write_time_by_name( Path_Sectr_Module );
|
||||
if result == OS_ERROR_NONE && host_memory.client_api.write_time != write_time
|
||||
{
|
||||
sync_store(& host_memory.client_api_hot_reloaded, true, .Release)
|
||||
version_id := host_memory.client_api.lib_version + 1
|
||||
unload_client_api( & host_memory.client_api )
|
||||
// Wait for pdb to unlock (linker may still be writting)
|
||||
for ; file_is_locked( Path_Sectr_Debug_Symbols ) && file_is_locked( Path_Sectr_Live_Module ); {}
|
||||
thread_sleep( Millisecond * 100 )
|
||||
host_memory.client_api = load_client_api( version_id )
|
||||
verify( host_memory.client_api.lib_version != 0, "Failed to hot-reload the sectr module" )
|
||||
}
|
||||
}
|
||||
}
|
||||
leader = sync.barrier_wait(& host_memory.client_api_sync_lock)
|
||||
if cache_coherent_load(& host_memory.client_api_hot_reloaded)
|
||||
leader := barrier_wait(& host_memory.client_api_sync_lock)
|
||||
if sync_load(& host_memory.client_api_hot_reloaded, .Acquire)
|
||||
{
|
||||
host_memory.client_api.hot_reload(& host_memory, & thread_memory)
|
||||
if thread_memory.id == .Master_Prepper {
|
||||
cache_coherent_store(& host_memory.client_api_hot_reloaded, false)
|
||||
sync_store(& host_memory.client_api_hot_reloaded, false, .Release)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unload_client_api :: proc( module : ^Client_API )
|
||||
{
|
||||
os_lib_unload( module.lib )
|
||||
file_remove( Path_Sectr_Live_Module )
|
||||
module^ = {}
|
||||
log_print("Unloaded sectr API")
|
||||
log_print("Unloaded client API")
|
||||
}
|
||||
|
||||
//endregion HOST RUNTIME
|
||||
|
@@ -1,15 +1,5 @@
|
||||
package host
|
||||
|
||||
// import "base:builtin"
|
||||
// Odin_OS_Type :: type_of(ODIN_OS)
|
||||
|
||||
// import "base:intrinsics"
|
||||
// atomic_thread_fence :: intrinsics.atomic_thread_fence
|
||||
// mem_zero :: intrinsics.mem_zero
|
||||
// mem_zero_volatile :: intrinsics.mem_zero_volatile
|
||||
// mem_copy :: intrinsics.mem_copy_non_overlapping
|
||||
// mem_copy_overlapping :: intrinsics.mem_copy
|
||||
|
||||
import "base:runtime"
|
||||
debug_trap :: runtime.debug_trap
|
||||
|
||||
@@ -31,10 +21,11 @@ import "core:mem"
|
||||
arena_init :: mem.arena_init
|
||||
|
||||
import "core:os"
|
||||
OS_ERROR_NONE :: os.ERROR_NONE
|
||||
OS_Error :: os.Error
|
||||
FileTime :: os.File_Time
|
||||
file_last_write_time_by_name :: os.last_write_time_by_name
|
||||
file_remove :: os.remove
|
||||
OS_ERROR_NONE :: os.ERROR_NONE
|
||||
os_is_directory :: os.is_dir
|
||||
os_make_directory :: os.make_directory
|
||||
os_core_count :: os.processor_core_count
|
||||
@@ -51,9 +42,12 @@ import "core:strings"
|
||||
builder_to_str :: strings.to_string
|
||||
|
||||
import "core:sync"
|
||||
Barrier :: sync.Barrier
|
||||
barrier_init :: sync.barrier_init
|
||||
barrier_wait :: sync.barrier_wait
|
||||
thread_current_id :: sync.current_thread_id
|
||||
cache_coherent_load :: sync.atomic_load
|
||||
cache_coherent_store :: sync.atomic_store
|
||||
sync_load :: sync.atomic_load_explicit
|
||||
sync_store :: sync.atomic_store_explicit
|
||||
|
||||
import "core:time"
|
||||
Millisecond :: time.Millisecond
|
||||
@@ -68,79 +62,74 @@ import "core:time"
|
||||
time_tick_lap_time :: time.tick_lap_time
|
||||
|
||||
import "core:thread"
|
||||
SysThread :: thread.Thread
|
||||
SysThread :: thread.Thread
|
||||
thread_create :: thread.create
|
||||
thread_start :: thread.start
|
||||
|
||||
import grime "codebase:grime"
|
||||
DISABLE_PROFILING :: grime.DISABLE_PROFILING
|
||||
DISABLE_GRIME_PROFILING :: grime.DISABLE_PROFILING
|
||||
|
||||
file_copy_sync :: grime.file_copy_sync
|
||||
file_is_locked :: grime.file_is_locked
|
||||
logger_init :: grime.logger_init
|
||||
to_odin_logger :: grime.to_odin_logger
|
||||
|
||||
import "codebase:sectr"
|
||||
MAX_THREADS :: sectr.MAX_THREADS
|
||||
THREAD_TICK_LANES :: sectr.THREAD_TICK_LANES
|
||||
DISABLE_HOST_PROFILING :: sectr.DISABLE_HOST_PROFILING
|
||||
DISABLE_CLIENT_PROFILING :: sectr.DISABLE_CLIENT_PROFILING
|
||||
|
||||
Path_Logs :: sectr.Path_Logs
|
||||
Path_Sectr_Debug_Symbols :: sectr.Path_Debug_Symbols
|
||||
Path_Sectr_Live_Module :: sectr.Path_Live_Module
|
||||
Path_Sectr_Module :: sectr.Path_Module
|
||||
Path_Sectr_Spall_Record :: sectr.Path_Spall_Record
|
||||
MAX_THREADS :: sectr.MAX_THREADS
|
||||
THREAD_TICK_LANES :: sectr.THREAD_TICK_LANES
|
||||
|
||||
Client_API :: sectr.ModuleAPI
|
||||
ProcessMemory :: sectr.ProcessMemory
|
||||
ThreadMemory :: sectr.ThreadMemory
|
||||
WorkerID :: sectr.WorkerID
|
||||
SpallProfiler :: sectr.SpallProfiler
|
||||
|
||||
ensure :: #force_inline proc( condition : b32, msg : string, location := #caller_location )
|
||||
{
|
||||
if condition {
|
||||
return
|
||||
}
|
||||
ensure :: #force_inline proc( condition : b32, msg : string, location := #caller_location ) {
|
||||
if condition do return
|
||||
log_print( msg, LoggerLevel.Warning, location )
|
||||
debug_trap()
|
||||
}
|
||||
|
||||
// TODO(Ed) : Setup exit codes!
|
||||
fatal :: #force_inline proc( msg : string, exit_code : int = -1, location := #caller_location )
|
||||
{
|
||||
fatal :: #force_inline proc( msg : string, exit_code : int = -1, location := #caller_location ) {
|
||||
log_print( msg, LoggerLevel.Fatal, location )
|
||||
debug_trap()
|
||||
process_exit( exit_code )
|
||||
}
|
||||
|
||||
// TODO(Ed) : Setup exit codes!
|
||||
verify :: #force_inline proc( condition : b32, msg : string, exit_code : int = -1, location := #caller_location )
|
||||
{
|
||||
if condition {
|
||||
return
|
||||
}
|
||||
verify :: #force_inline proc( condition : b32, msg : string, exit_code : int = -1, location := #caller_location ) {
|
||||
if condition do return
|
||||
log_print( msg, LoggerLevel.Fatal, location )
|
||||
debug_trap()
|
||||
process_exit( exit_code )
|
||||
}
|
||||
|
||||
|
||||
log_print :: proc( msg : string, level := LoggerLevel.Info, loc := #caller_location ) {
|
||||
context.allocator = arena_allocator(& host_memory.host_scratch)
|
||||
context.temp_allocator = arena_allocator(& host_memory.host_scratch)
|
||||
log.log( level, msg, location = loc )
|
||||
}
|
||||
|
||||
log_print_fmt :: proc( fmt : string, args : ..any, level := LoggerLevel.Info, loc := #caller_location ) {
|
||||
context.allocator = arena_allocator(& host_memory.host_scratch)
|
||||
context.temp_allocator = arena_allocator(& host_memory.host_scratch)
|
||||
log.logf( level, fmt, ..args, location = loc )
|
||||
}
|
||||
|
||||
@(deferred_none = profile_end, disabled = DISABLE_PROFILING)
|
||||
profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) {
|
||||
spall._buffer_begin( & host_memory.spall_profiler.ctx, & host_memory.spall_profiler.buffer, name, "", loc )
|
||||
}
|
||||
@(deferred_none = profile_end, disabled = DISABLE_HOST_PROFILING) profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { spall._buffer_begin( & host_memory.spall_profiler.ctx, & host_memory.spall_profiler.buffer, name, "", loc ) }
|
||||
@( disabled = DISABLE_HOST_PROFILING) profile_begin :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { spall._buffer_begin( & host_memory.spall_profiler.ctx, & host_memory.spall_profiler.buffer, name, "", loc ) }
|
||||
@( disabled = DISABLE_HOST_PROFILING) profile_end :: #force_inline proc "contextless" () { spall._buffer_end ( & host_memory.spall_profiler.ctx, & host_memory.spall_profiler.buffer) }
|
||||
|
||||
@(disabled = DISABLE_PROFILING)
|
||||
profile_begin :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) {
|
||||
spall._buffer_begin( & host_memory.spall_profiler.ctx, & host_memory.spall_profiler.buffer, name, "", loc )
|
||||
}
|
||||
|
||||
@(disabled = DISABLE_PROFILING)
|
||||
profile_end :: #force_inline proc "contextless" () {
|
||||
spall._buffer_end( & host_memory.spall_profiler.ctx, & host_memory.spall_profiler.buffer)
|
||||
}
|
||||
SHOULD_SETUP_PROFILERS :: \
|
||||
DISABLE_GRIME_PROFILING == false ||
|
||||
DISABLE_CLIENT_PROFILING == false ||
|
||||
DISABLE_HOST_PROFILING == false
|
||||
|
||||
Kilo :: 1024
|
||||
Mega :: Kilo * 1024
|
||||
|
21
code2/sectr/config_compile_time.odin
Normal file
21
code2/sectr/config_compile_time.odin
Normal file
@@ -0,0 +1,21 @@
|
||||
package sectr
|
||||
|
||||
Path_Assets :: "../assets/"
|
||||
Path_Shaders :: "../shaders/"
|
||||
Path_Input_Replay :: "input.sectr_replay"
|
||||
|
||||
|
||||
Path_Logs :: "../logs"
|
||||
when ODIN_OS == .Windows
|
||||
{
|
||||
Path_Module :: "sectr.dll"
|
||||
Path_Live_Module :: "sectr_live.dll"
|
||||
Path_Debug_Symbols :: "sectr.pdb"
|
||||
Path_Spall_Record :: "sectr.spall"
|
||||
}
|
||||
|
||||
DISABLE_CLIENT_PROFILING :: false
|
||||
DISABLE_HOST_PROFILING :: false
|
||||
|
||||
// TODO(Ed): We can technically hot-reload this (spin up or down lanes on reloads)
|
||||
THREAD_TICK_LANES :: 2
|
@@ -1,14 +1,18 @@
|
||||
package sectr
|
||||
|
||||
import "core:dynlib"
|
||||
import "core:sync"
|
||||
// Sokol should only be used here and in the client_api_sokol_callbacks.odin
|
||||
|
||||
Path_Assets :: "../assets/"
|
||||
Path_Shaders :: "../shaders/"
|
||||
Path_Input_Replay :: "input.sectr_replay"
|
||||
import sokol_app "thirdparty:sokol/app"
|
||||
import sokol_gfx "thirdparty:sokol/gfx"
|
||||
import sokol_glue "thirdparty:sokol/glue"
|
||||
import sokol_gp "thirdparty:sokol/gp"
|
||||
|
||||
/*
|
||||
This definies the client interface for the host process to call into
|
||||
*/
|
||||
|
||||
ModuleAPI :: struct {
|
||||
lib: dynlib.Library,
|
||||
lib: DynLibrary,
|
||||
write_time: FileTime,
|
||||
lib_version : int,
|
||||
|
||||
@@ -19,8 +23,6 @@ ModuleAPI :: struct {
|
||||
clean_frame: type_of( clean_frame),
|
||||
}
|
||||
|
||||
StartupContext :: struct {}
|
||||
|
||||
/*
|
||||
Called by host.main when it completes its setup.
|
||||
|
||||
@@ -34,44 +36,63 @@ startup :: proc(host_mem: ^ProcessMemory, thread_mem: ^ThreadMemory)
|
||||
}
|
||||
|
||||
/*
|
||||
Called by sync_client_api when the client module has be reloaded.
|
||||
Called by host.sync_client_api when the client module has be reloaded.
|
||||
Threads will eventually return to their tick_lane upon completion.
|
||||
*/
|
||||
@export
|
||||
hot_reload :: proc(host_mem: ^ProcessMemory, thread_mem: ^ThreadMemory)
|
||||
{
|
||||
thread_ctx = thread_mem
|
||||
if thread_ctx.id == .Master_Prepper {
|
||||
cache_coherent_store(& memory, host_mem, .Release)
|
||||
thread = thread_mem
|
||||
if thread.id == .Master_Prepper {
|
||||
sync_store(& memory, host_mem, .Release)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Called by host_tick_lane_startup
|
||||
Used for lane specific startup operations
|
||||
|
||||
The lane tick cannot be handled it, its call must be done by the host module.
|
||||
(We need threads to not be within a client callstack in the even of a hot-reload)
|
||||
Called by host_tick_lane_startup
|
||||
Used for lane specific startup operations
|
||||
|
||||
The lane tick cannot be handled it, its call must be done by the host module.
|
||||
(We need threads to not be within a client callstack in the even of a hot-reload)
|
||||
*/
|
||||
@export
|
||||
tick_lane_startup :: proc(thread_mem: ^ThreadMemory)
|
||||
{
|
||||
thread_ctx = thread_mem
|
||||
thread_ctx.live_lanes = THREAD_TICK_LANES
|
||||
thread = thread_mem
|
||||
thread.live_lanes = THREAD_TICK_LANES
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
*/
|
||||
@export
|
||||
tick_lane :: proc(host_delta_time_ms: f64, host_delta_ns: Duration) -> (should_close: b64)
|
||||
{
|
||||
@thread_local dummy: int = 0;
|
||||
dummy += 2
|
||||
profile_begin("sokol_app: pre_client_tick")
|
||||
// should_close |= cast(b64) sokol_app.pre_client_frame()
|
||||
profile_end()
|
||||
|
||||
profile_begin("Client Tick")
|
||||
profile_end()
|
||||
|
||||
profile_begin("sokol_app: post_client_tick")
|
||||
profile_end()
|
||||
|
||||
tick_lane_frametime()
|
||||
return true
|
||||
}
|
||||
|
||||
tick_lane_frametime :: proc()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@export
|
||||
clean_frame :: proc()
|
||||
{
|
||||
@thread_local dummy: int = 0;
|
||||
dummy += 1
|
||||
if thread.id == .Master_Prepper
|
||||
{
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@@ -5,6 +5,12 @@ import "core:sync"
|
||||
/*
|
||||
Everything defined for the host module within the client module
|
||||
so that the client module has full awareness of relevant host definitions
|
||||
|
||||
Client interaction with host is very minimal,
|
||||
host will only provide the base runtime for client's tick lanes and job system workers.
|
||||
|
||||
Host is has all statically (data/bss) defined memory for the application, it will not mess with
|
||||
client_memory however.
|
||||
*/
|
||||
|
||||
ProcessMemory :: struct {
|
||||
@@ -19,8 +25,7 @@ ProcessMemory :: struct {
|
||||
logger: Logger,
|
||||
|
||||
// Profiling
|
||||
spall_profiler: SpallProfiler,
|
||||
// TODO(Ed): Try Superluminal!
|
||||
spall_profiler: ^SpallProfiler,
|
||||
|
||||
// Multi-threading
|
||||
threads: [MAX_THREADS](SysThread),
|
||||
@@ -34,12 +39,8 @@ ProcessMemory :: struct {
|
||||
}
|
||||
|
||||
Host_API :: struct {
|
||||
launch_tick_lane_thread: #type proc(WorkerID),
|
||||
|
||||
request_virtual_memory: #type proc(),
|
||||
request_virtual_mapped_io: #type proc(),
|
||||
|
||||
sync_client_module : #type proc(),
|
||||
}
|
||||
|
||||
ThreadMemory :: struct {
|
||||
|
@@ -1,14 +1,36 @@
|
||||
package sectr
|
||||
|
||||
/*
|
||||
All direct non-codebase package symbols should do zero allocations.
|
||||
Any symbol that does must be mapped from the Grime package to properly tirage its allocator to odin's ideomatic interface.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
import "base:intrinsics"
|
||||
debug_trap :: intrinsics.debug_trap
|
||||
|
||||
import "core:dynlib"
|
||||
// Only referenced in ModuleAPI
|
||||
DynLibrary :: dynlib.Library
|
||||
|
||||
import "core:log"
|
||||
LoggerLevel :: log.Level
|
||||
|
||||
import "core:mem"
|
||||
Odin_Arena :: mem.Arena
|
||||
// Used strickly for the logger
|
||||
Odin_Arena :: mem.Arena
|
||||
odin_arena_allocator :: mem.arena_allocator
|
||||
|
||||
import "core:os"
|
||||
FileTime :: os.File_Time
|
||||
FileTime :: os.File_Time
|
||||
process_exit :: os.exit
|
||||
|
||||
import "core:prof/spall"
|
||||
|
||||
import "core:sync"
|
||||
AtomicMutex :: sync.Atomic_Mutex
|
||||
cache_coherent_store :: sync.atomic_store_explicit
|
||||
sync_store :: sync.atomic_store_explicit
|
||||
|
||||
import "core:thread"
|
||||
SysThread :: thread.Thread
|
||||
@@ -17,10 +39,44 @@ import "core:time"
|
||||
Duration :: time.Duration
|
||||
|
||||
import "codebase:grime"
|
||||
Logger :: grime.Logger
|
||||
SpallProfiler :: grime.SpallProfiler
|
||||
Logger :: grime.Logger
|
||||
SpallProfiler :: grime.SpallProfiler
|
||||
|
||||
Kilo :: 1024
|
||||
Mega :: Kilo * 1024
|
||||
Giga :: Mega * 1024
|
||||
Tera :: Giga * 1024
|
||||
|
||||
ensure :: #force_inline proc( condition : b32, msg : string, location := #caller_location ) {
|
||||
if condition do return
|
||||
log_print( msg, LoggerLevel.Warning, location )
|
||||
debug_trap()
|
||||
}
|
||||
// TODO(Ed) : Setup exit codes!
|
||||
fatal :: #force_inline proc( msg : string, exit_code : int = -1, location := #caller_location ) {
|
||||
log_print( msg, LoggerLevel.Fatal, location )
|
||||
debug_trap()
|
||||
process_exit( exit_code )
|
||||
}
|
||||
// TODO(Ed) : Setup exit codes!
|
||||
verify :: #force_inline proc( condition : b32, msg : string, exit_code : int = -1, location := #caller_location ) {
|
||||
if condition do return
|
||||
log_print( msg, LoggerLevel.Fatal, location )
|
||||
debug_trap()
|
||||
process_exit( exit_code )
|
||||
}
|
||||
|
||||
log_print :: proc( msg : string, level := LoggerLevel.Info, loc := #caller_location ) {
|
||||
context.allocator = odin_arena_allocator(& memory.host_scratch)
|
||||
context.temp_allocator = odin_arena_allocator(& memory.host_scratch)
|
||||
log.log( level, msg, location = loc )
|
||||
}
|
||||
log_print_fmt :: proc( fmt : string, args : ..any, level := LoggerLevel.Info, loc := #caller_location ) {
|
||||
context.allocator = odin_arena_allocator(& memory.host_scratch)
|
||||
context.temp_allocator = odin_arena_allocator(& memory.host_scratch)
|
||||
log.logf( level, fmt, ..args, location = loc )
|
||||
}
|
||||
|
||||
@(deferred_none = profile_end, disabled = DISABLE_CLIENT_PROFILING) profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { spall._buffer_begin( & memory.spall_profiler.ctx, & memory.spall_profiler.buffer, name, "", loc ) }
|
||||
@( disabled = DISABLE_CLIENT_PROFILING) profile_begin :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { spall._buffer_begin( & memory.spall_profiler.ctx, & memory.spall_profiler.buffer, name, "", loc ) }
|
||||
@( disabled = DISABLE_CLIENT_PROFILING) profile_end :: #force_inline proc "contextless" () { spall._buffer_end ( & memory.spall_profiler.ctx, & memory.spall_profiler.buffer) }
|
||||
|
@@ -1,12 +1,10 @@
|
||||
package sectr
|
||||
|
||||
//region STATIC MEMORY
|
||||
// This should be the only global on client module side.
|
||||
memory: ^ProcessMemory
|
||||
|
||||
@(thread_local)
|
||||
thread_ctx: ^ThreadMemory
|
||||
|
||||
THREAD_TICK_LANES :: 2
|
||||
memory: ^ProcessMemory
|
||||
@(thread_local) thread: ^ThreadMemory
|
||||
//endregion STATIC MEMORy
|
||||
|
||||
State :: struct {
|
||||
job_system: JobSystemContext,
|
||||
|
Reference in New Issue
Block a user