WIP: Untested more process runtime bootstrapping, some decisions on how grime is setup..

This commit is contained in:
2025-10-13 12:47:16 -04:00
parent 4abd2401f0
commit 0d904fba7c
15 changed files with 257 additions and 203 deletions

View 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

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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) }

View File

@@ -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,