diff --git a/code/grime/arena_fixed.odin b/code/grime/arena_fixed.odin deleted file mode 100644 index e69de29..0000000 diff --git a/code/grime/arena_vchaining.odin b/code/grime/arena_vchaining.odin deleted file mode 100644 index e69de29..0000000 diff --git a/code/vefontcache/profiling.odin b/code/vefontcache/profiling.odin index 5d832f5..c38dec8 100644 --- a/code/vefontcache/profiling.odin +++ b/code/vefontcache/profiling.odin @@ -2,16 +2,19 @@ package vefontcache // Add profiling hookup here -// import "" +import "codebase:grime" @(deferred_none = profile_end, disabled = DISABLE_PROFILING) profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { + grime.profile_begin(name, loc) } @(disabled = DISABLE_PROFILING) profile_begin :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { + grime.profile_begin(name, loc) } @(disabled = DISABLE_PROFILING) profile_end :: #force_inline proc "contextless" () { + grime.profile_end() } diff --git a/code2/grime/Readme.md b/code2/grime/Readme.md new file mode 100644 index 0000000..6da0bad --- /dev/null +++ b/code2/grime/Readme.md @@ -0,0 +1,7 @@ +# Grime + +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 are no implicit static allocations in Grime. Ideally there are also none from the base/core packages but some probably leak. diff --git a/code2/grime/arenas.odin b/code2/grime/arenas.odin new file mode 100644 index 0000000..9f9e224 --- /dev/null +++ b/code2/grime/arenas.odin @@ -0,0 +1 @@ +package grime diff --git a/code2/grime/context.odin b/code2/grime/context.odin new file mode 100644 index 0000000..686c749 --- /dev/null +++ b/code2/grime/context.odin @@ -0,0 +1,8 @@ +package grime + +// Context :: struct { +// } + +// context_usr :: #force_inline proc( $ Type : typeid ) -> (^Type) { +// return cast(^Type) context.user_ptr +// } diff --git a/code2/grime/linked_list.odin b/code2/grime/linked_list.odin new file mode 100644 index 0000000..3a5af18 --- /dev/null +++ b/code2/grime/linked_list.odin @@ -0,0 +1,20 @@ +package grime + +sll_stack_push_n :: proc "contextless" (curr, n, n_link: ^^$Type) { + (n_link ^) = (curr ^) + (curr ^) = (n ^) +} +sll_queue_push_nz :: proc "contextless" (first: ^$ParentType, last, n: ^^$Type, nil_val: ^Type) { + if (first ^) == nil_val { + (first ^) = n^ + (last ^) = n^ + n^.next = nil_val + } + else { + (last ^).next = n^ + (last ^) = n^ + n^.next = nil_val + } +} +sll_queue_push_n :: #force_inline proc "contextless" (first: $ParentType, last, n: ^^$Type) { sll_queue_push_nz(first, last, n, nil) } + diff --git a/code2/grime/memory.odin b/code2/grime/memory.odin new file mode 100644 index 0000000..05f6dd5 --- /dev/null +++ b/code2/grime/memory.odin @@ -0,0 +1,226 @@ +package grime + +Kilo :: 1024 +Mega :: Kilo * 1024 +Giga :: Mega * 1024 +Tera :: Giga * 1024 + +ptr_cursor :: #force_inline proc "contextless" (ptr: ^$Type) -> [^]Type { return transmute([^]Type) ptr } + +align_pow2 :: proc(x: int, b: int) -> int { + assert(b != 0) + assert((b & (b - 1)) == 0) // Check power of 2 + return ((x + b - 1) & ~(b - 1)) +} +memory_zero_explicit :: proc "contextless" (data: rawptr, len: int) -> rawptr { + mem_zero_volatile(data, len) // Use the volatile mem_zero + atomic_thread_fence(.Seq_Cst) // Prevent reordering + return data +} +memory_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr { + mem_copy(dst, src, len) + return dst +} + +SliceByte :: struct { + data: [^]byte, + len: int +} +SliceRaw :: struct ($Type: typeid) { + data: [^]Type, + len: int, +} +slice :: #force_inline proc "contextless" (s: [^] $Type, num: $Some_Integer) -> [ ]Type { return transmute([]Type) SliceRaw(Type) { s, cast(int) num } } +slice_cursor :: #force_inline proc "contextless" (s: []$Type) -> [^]Type { return transmute([^]Type) raw_data(s) } +slice_assert :: #force_inline proc (s: $SliceType / []$Type) { + assert(len(s) > 0) + assert(s != nil) +} +slice_end :: #force_inline proc "contextless" (s : $SliceType / []$Type) -> ^Type { return & cursor(s)[len(s)] } + +slice_copy :: proc "contextless" (dst, src: $SliceType / []$Type) -> int { + n := max(0, min(len(dst), len(src))) + if n > 0 { + mem_copy(raw_data(dst), raw_data(src), n * size_of(Type)) + } + return n +} + +@(require_results) slice_to_bytes :: proc "contextless" (s: []$Type) -> []byte { return ([^]byte)(raw_data(s))[:len(s) * size_of(Type)] } +@(require_results) slice_raw :: proc "contextless" (s: []$Type) -> SliceRaw(Type) { return transmute(SliceRaw(Type)) s } + +//region Allocator Interface +AllocatorOp :: enum u32 { + Alloc_NoZero = 0, // If Alloc exist, so must No_Zero + Alloc, + Free, + Reset, + Grow_NoZero, + Grow, + Shrink, + Rewind, + SavePoint, + Query, // Must always be implemented +} +AllocatorQueryFlag :: enum u64 { + Alloc, + Free, + Reset, // Wipe the allocator's state + + Shrink, + Grow, + Resize, // Supports both grow and shrink + + Rewind, // Ability to rewind to a save point (ex: arenas, stack), must also be able to save such a point + + // Actually_Resize, + // Is_This_Yours, + + Hint_Fast_Bump, + Hint_General_Heap, + Hint_Per_Frame_Temporary, + Hint_Debug_Support, +} +AllocatorQueryFlags :: bit_set[AllocatorQueryFlag; u64] +AllocatorSP :: struct { + type_sig: AllocatorProc, + slot: int, +} +AllocatorProc :: #type proc (input: AllocatorProc_In, out: ^AllocatorProc_Out) +AllocatorProc_In :: struct { + data: rawptr, + requested_size: int, + alignment: int, + using _ : struct #raw_union { + old_allocation: []byte, + save_point : AllocatorSP, + }, + op: AllocatorOp, +} +AllocatorProc_Out :: struct { + using _ : struct #raw_union { + allocation: []byte, + save_point: AllocatorSP, + }, + features: AllocatorQueryFlags, + left: int, + max_alloc: int, + min_alloc: int, + continuity_break: b32, +} +AllocatorQueryInfo :: struct { + save_point: AllocatorSP, + features: AllocatorQueryFlags, + left: int, + max_alloc: int, + min_alloc: int, + continuity_break: b32, +} +AllocatorInfo :: struct { + procedure: AllocatorProc, + data: rawptr, +} +// #assert(size_of(AllocatorQueryInfo) == size_of(AllocatorProc_Out)) + +MEMORY_ALIGNMENT_DEFAULT :: 2 * size_of(rawptr) + +allocator_query :: proc(ainfo := context.allocator) -> AllocatorQueryInfo { + assert(ainfo.procedure != nil) + out: AllocatorQueryInfo; (cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Query}, transmute(^AllocatorProc_Out) & out) + return out +} +mem_free :: proc(mem: []byte, ainfo := context.allocator) { + assert(ainfo.procedure != nil) + (cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Free, old_allocation = mem}, & {}) +} +mem_reset :: proc(ainfo := context.allocator) { + assert(ainfo.procedure != nil) + (cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Reset}, &{}) +} +mem_rewind :: proc(ainfo := context.allocator, save_point: AllocatorSP) { + assert(ainfo.procedure != nil) + (cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Rewind, save_point = save_point}, & {}) +} +mem_save_point :: proc(ainfo := context.allocator) -> AllocatorSP { + assert(ainfo.procedure != nil) + out: AllocatorProc_Out + (cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .SavePoint}, & out) + return out.save_point +} +mem_alloc :: proc(size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte { + assert(ainfo.procedure != nil) + input := AllocatorProc_In { + data = ainfo.data, + op = no_zero ? .Alloc_NoZero : .Alloc, + requested_size = size, + alignment = alignment, + } + output: AllocatorProc_Out + (cast(AllocatorProc)ainfo.procedure)(input, & output) + return output.allocation +} +mem_grow :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte { + assert(ainfo.procedure != nil) + input := AllocatorProc_In { + data = ainfo.data, + op = no_zero ? .Grow_NoZero : .Grow, + requested_size = size, + alignment = alignment, + old_allocation = mem, + } + output: AllocatorProc_Out + (cast(AllocatorProc)ainfo.procedure)(input, & output) + return output.allocation +} +mem_resize :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte { + assert(ainfo.procedure != nil) + input := AllocatorProc_In { + data = ainfo.data, + op = len(mem) < size ? .Shrink : no_zero ? .Grow_NoZero : .Grow, + requested_size = size, + alignment = alignment, + old_allocation = mem, + } + output: AllocatorProc_Out + (cast(AllocatorProc)ainfo.procedure)(input, & output) + return output.allocation +} +mem_shrink :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte { + assert(ainfo.procedure != nil) + input := AllocatorProc_In { + data = ainfo.data, + op = .Shrink, + requested_size = size, + alignment = alignment, + old_allocation = mem, + } + output: AllocatorProc_Out + (cast(AllocatorProc)ainfo.procedure)(input, & output) + return output.allocation +} + +alloc_type :: proc($Type: typeid, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> ^Type { + assert(ainfo.procedure != nil) + input := AllocatorProc_In { + data = ainfo.data, + op = no_zero ? .Alloc_NoZero : .Alloc, + requested_size = size_of(Type), + alignment = alignment, + } + output: AllocatorProc_Out + (cast(AllocatorProc)ainfo.procedure)(input, & output) + return transmute(^Type) raw_data(output.allocation) +} +alloc_slice :: proc($SliceType: typeid / []$Type, num : int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []Type { + assert(ainfo.procedure != nil) + input := AllocatorProc_In { + data = ainfo.data, + op = no_zero ? .Alloc_NoZero : .Alloc, + requested_size = size_of(Type) * num, + alignment = alignment, + } + output: AllocatorProc_Out + (cast(AllocatorProc)ainfo.procedure)(input, & output) + return transmute([]Type) slice(raw_data(output.allocation), num) +} +//endregion Allocator Interface diff --git a/code2/grime/os.odin b/code2/grime/os.odin new file mode 100644 index 0000000..9f9e224 --- /dev/null +++ b/code2/grime/os.odin @@ -0,0 +1 @@ +package grime diff --git a/code2/grime/pkg_mappings.odin b/code2/grime/pkg_mappings.odin index e69de29..8c6b0a5 100644 --- a/code2/grime/pkg_mappings.odin +++ b/code2/grime/pkg_mappings.odin @@ -0,0 +1,23 @@ +package grime + +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" + Assertion_Failure_Proc :: runtime.Assertion_Failure_Proc + Logger :: runtime.Logger + Random_Generator :: runtime.Random_Generator + slice_copy_overlapping :: runtime.copy_slice + +import core_os "core:os" + // ODIN_OS :: core_os.ODIN_OS + +import "core:slice" + slice_zero :: slice.zero diff --git a/code2/host/Readme.md b/code2/host/Readme.md new file mode 100644 index 0000000..5dbdb3e --- /dev/null +++ b/code2/host/Readme.md @@ -0,0 +1,3 @@ +# Host Module + +The sole job of this module is to provide a bare launch pad and runtime module hot-reload support for the client module (sectr). To achieve this the static memory of the client module is tracked by the host and provides an api for the client to reload itself when a change is detected. The client is reponsible for populating the static memory reference and doing anything else it needs via the host api that it cannot do on its own. diff --git a/code2/host/host.odin b/code2/host/host.odin deleted file mode 100644 index 57ed869..0000000 --- a/code2/host/host.odin +++ /dev/null @@ -1,8 +0,0 @@ -package host - - - -main :: proc() -{ - -} diff --git a/code2/host/launch.odin b/code2/host/launch.odin new file mode 100644 index 0000000..209f8a2 --- /dev/null +++ b/code2/host/launch.odin @@ -0,0 +1,24 @@ +package host + +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" +} + +// Only static memory host has. +host_memory: HostMemory + +main :: proc() +{ + host_memory.host_api.sync_client_module = sync_client_api + host_memory.client_api.startup(& host_memory) +} + +@export +sync_client_api :: proc() +{ + // Fill out detection and reloading of client api. +} diff --git a/code2/host/pkg_mappings.odin b/code2/host/pkg_mappings.odin index e69de29..b5cbee3 100644 --- a/code2/host/pkg_mappings.odin +++ b/code2/host/pkg_mappings.odin @@ -0,0 +1,24 @@ +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" + // Assertion_Failure_Proc :: runtime.Assertion_Failure_Proc + // Logger :: runtime.Logger + +import core_os "core:os" + +import grime "codebase:grime" + +import "codebase:sectr" + Client_API :: sectr.ModuleAPI + HostMemory :: sectr.HostMemory + diff --git a/code2/sectr/Readme.md b/code2/sectr/Readme.md index 06eeca6..d6cb409 100644 --- a/code2/sectr/Readme.md +++ b/code2/sectr/Readme.md @@ -1,2 +1,3 @@ # Sectr Package + diff --git a/code2/sectr/engine/client_api.odin b/code2/sectr/engine/client_api.odin index 82946b0..2c29800 100644 --- a/code2/sectr/engine/client_api.odin +++ b/code2/sectr/engine/client_api.odin @@ -12,23 +12,21 @@ ModuleAPI :: struct { lib: dynlib.Library, // write-time: FileTime, - startup: type_of( startup ), - shutdown: type_of( sectr_shutdown ), - reload: type_of( hot_reload ), - tick: type_of( tick ), - clean_frame: type_of( clean_frame ), + startup: type_of( startup ), + hot_reload: type_of( hot_reload ), } StartupContext :: struct {} @export -startup :: proc(ctx: StartupContext) +startup :: proc(host_mem: ^HostMemory) { + + thread_wide_startup() } -@export -sectr_shutdown :: proc() +thread_wide_startup :: proc() { } @@ -38,15 +36,3 @@ hot_reload :: proc() { } - -@export -tick :: proc() -{ - -} - -@export -clean_frame ::proc() -{ - -} diff --git a/code2/sectr/engine/host_api.odin b/code2/sectr/engine/host_api.odin new file mode 100644 index 0000000..26e5340 --- /dev/null +++ b/code2/sectr/engine/host_api.odin @@ -0,0 +1,16 @@ +package sectr + +HostMemory :: struct { + client_api: ModuleAPI, + client_memory: ^State, + host_api: Host_API, +} + +Host_API :: struct { + launch_thread: #type proc(), + + request_virtual_memory: #type proc(), + request_virtual_mapped_io: #type proc(), + + sync_client_module : #type proc(), +} diff --git a/code2/sectr/pkg_mappings.odin b/code2/sectr/pkg_mappings.odin index 2432dbc..7ba6dc6 100644 --- a/code2/sectr/pkg_mappings.odin +++ b/code2/sectr/pkg_mappings.odin @@ -1 +1,3 @@ package sectr + + diff --git a/code2/sectr/state.odin b/code2/sectr/state.odin index 2432dbc..cc73cc5 100644 --- a/code2/sectr/state.odin +++ b/code2/sectr/state.odin @@ -1 +1,9 @@ package sectr + +// This should be the only global on client module side. +host_memory: ^HostMemory + + +State :: struct { + +} diff --git a/scripts/build.ps1 b/scripts/build.ps1 index f8678b9..bc9d70f 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -66,10 +66,12 @@ $command_run = 'run' $flag_build_mode = '-build-mode:' $flag_build_mode_dll = '-build-mode:dll' +$flag_build_diagnostics = '-build-diagnostics' $flag_collection = '-collection:' $flag_debug = '-debug' $flag_define = '-define:' $flag_default_allocator_nil = '-default-to-nil-allocator' +$flag_default_allocator_panic = '-default-to-panic-allocator' $flag_disable_assert = '-disable-assert' $flag_dynamic_map_calls = '-dynamic-map-calls' $flag_extra_assembler_flags = '-extra_assembler-flags:' @@ -139,7 +141,7 @@ push-location $path_root function build-prototype { push-location $path_code - $project_name = 'sectr2' + $project_name = 'sectr' write-host "`nBuilding Sectr Prototype`n" @@ -213,24 +215,26 @@ push-location $path_root $build_args += $flag_microarch_zen5 $build_args += $flag_use_separate_modules $build_args += $flag_thread_count + $CoreCount_Physical - $build_args += $flag_optimize_none - # $build_args += $flag_optimize_minimal + # $build_args += $flag_optimize_none + $build_args += $flag_optimize_minimal # $build_args += $flag_optimize_speed # $build_args += $falg_optimize_aggressive $build_args += $flag_debug $build_args += $flag_pdb_name + $pdb $build_args += $flag_subsystem + 'windows' # $build_args += $flag_show_system_calls - $build_args += $flag_show_timings $build_args += ($flag_extra_linker_flags + $linker_args ) # $build_args += $flag_no_bounds_check # $build_args += $flag_no_thread_checker # $build_args += $flag_dynamic_map_calls - $build_args += $flag_default_allocator_nil + # $build_args += $flag_default_allocator_nil + $build_args += $flag_default_allocator_panic $build_args += ($flag_max_error_count + '10') # $build_args += $flag_sanitize_address # $build_args += $flag_sanitize_memory # $build_args += $flag_show_debug_messages + $build_args += $flag_show_timings + # $build_args += $flag_build_diagnostics # TODO(Ed): Enforce nil default allocator # foreach ($arg in $build_args) { @@ -297,8 +301,8 @@ push-location $path_root # $build_args += $flag_micro_architecture_native $build_args += $flag_microarch_zen5 $build_args += $flag_thread_count + $CoreCount_Physical - $build_args += $flag_optimize_none - # $build_args += $flag_optimize_minimal + # $build_args += $flag_optimize_none + $build_args += $flag_optimize_minimal # $build_args += $flag_optimize_speed # $build_args += $falg_optimize_aggressive $build_args += $flag_debug @@ -309,10 +313,11 @@ push-location $path_root # $build_args += $flag_show_system_call # $build_args += $flag_no_bounds_check # $build_args += $flag_no_thread_checker - $build_args += $flag_default_allocator_nil + $build_args += $flag_default_allocator_panic $build_args += ($flag_max_error_count + '10') # $build_args += $flag_sanitize_address # $build_args += $flag_sanitize_memory + # $build_args += $flag_build_diagnostics # TODO(Ed): Enforce nil default allocator # foreach ($arg in $build_args) {