diff --git a/code/sectr/grime/array.odin b/code/grime/array.odin similarity index 98% rename from code/sectr/grime/array.odin rename to code/grime/array.odin index b1fb55c..51d6949 100644 --- a/code/sectr/grime/array.odin +++ b/code/grime/array.odin @@ -7,7 +7,7 @@ Update 5-26-2024: TODO(Ed): Raw_Dynamic_Array is defined within base:runtime/core.odin and exposes what we need for worst case hot-reloads. So its best to go back to regular dynamic arrays at some point. */ -package sectr +package grime import "core:c/libc" import "core:mem" @@ -295,6 +295,7 @@ array_set_capacity :: proc( self : ^Array( $ Type ), new_capacity : u64 ) -> All if result_code != AllocatorError.None { ensure( false, "Failed to allocate for new array capacity" ) + log( "Failed to allocate for new array capacity", level = LogLevel.Warning ) return result_code } if new_mem == nil { diff --git a/code/sectr/grime/assert.odin b/code/grime/assert.odin similarity index 74% rename from code/sectr/grime/assert.odin rename to code/grime/assert.odin index 2024deb..0b52187 100644 --- a/code/sectr/grime/assert.odin +++ b/code/grime/assert.odin @@ -1,4 +1,4 @@ -package sectr +package grime import "base:runtime" import "core:io" @@ -18,8 +18,6 @@ dump_stacktrace :: proc( allocator := context.temp_allocator ) -> string } table.build(log_table) - // writer_builder_backing : [Kilobyte * 16] u8 - // writer_builder := from_bytes( writer_builder_backing[:] ) writer_builder : StringBuilder str_builder_init( & writer_builder, allocator = allocator ) @@ -34,7 +32,7 @@ dump_stacktrace :: proc( allocator := context.temp_allocator ) -> string return to_string( writer_builder ) } -ensure :: proc( condition : b32, msg : string, location := #caller_location ) +ensure :: #force_inline proc( condition : b32, msg : string, location := #caller_location ) { if condition { return @@ -44,14 +42,15 @@ ensure :: proc( condition : b32, msg : string, location := #caller_location ) } // TODO(Ed) : Setup exit codes! -fatal :: proc( msg : string, exit_code : int = -1, location := #caller_location ) +fatal :: #force_inline proc( msg : string, exit_code : int = -1, location := #caller_location ) { log( msg, LogLevel.Fatal, location ) runtime.debug_trap() os.exit( exit_code ) } -verify :: proc( condition : b32, msg : string, exit_code : int = -1, location := #caller_location ) +// TODO(Ed) : Setup exit codes! +verify :: #force_inline proc( condition : b32, msg : string, exit_code : int = -1, location := #caller_location ) { if condition { return diff --git a/code/sectr/chrono.odin b/code/grime/chrono.odin similarity index 94% rename from code/sectr/chrono.odin rename to code/grime/chrono.odin index ef6dafc..6bf35f3 100644 --- a/code/sectr/chrono.odin +++ b/code/grime/chrono.odin @@ -1,4 +1,4 @@ -package sectr +package grime Nanosecond_To_Microsecond :: 1.0 / (1000.0) Nanosecond_To_Millisecond :: 1.0 / (1000.0 * 1000.0) @@ -31,5 +31,3 @@ MS_To_S :: Millisecond_To_Second S_To_NS :: Second_To_Nanosecond S_To_US :: Second_To_Microsecnd S_To_MS :: Second_To_Millisecond - -Frametime_High_Perf_Threshold_MS :: 1 / 240.0 diff --git a/code/sectr/grime/filesystem.odin b/code/grime/filesystem.odin similarity index 86% rename from code/sectr/grime/filesystem.odin rename to code/grime/filesystem.odin index 121f3d2..36aa957 100644 --- a/code/sectr/grime/filesystem.odin +++ b/code/grime/filesystem.odin @@ -1,12 +1,11 @@ -package sectr - -// TODO(Ed): Review these when os2 is done. +package grime +// TODO(Ed): Review when os2 is done. import "core:fmt" import "core:os" import "base:runtime" -file_copy_sync :: proc( path_src, path_dst: string, allocator := context.temp_allocator ) -> b32 +file_copy_sync :: proc( path_src, path_dst: string, allocator := context.allocator ) -> b32 { file_size : i64 { @@ -34,8 +33,8 @@ file_copy_sync :: proc( path_src, path_dst: string, allocator := context.temp_al return true } -file_exists :: proc( file_path : string ) -> b32 { - path_info, result := file_status( file_path, frame_allocator() ) +file_exists :: proc( file_path : string, allocator := context.allocator ) -> b32 { + path_info, result := file_status( file_path, allocator ) if result != os.ERROR_NONE { return false } diff --git a/code/sectr/grime/linked_list.odin b/code/grime/linked_list.odin similarity index 92% rename from code/sectr/grime/linked_list.odin rename to code/grime/linked_list.odin index ff0828a..d8df31d 100644 --- a/code/sectr/grime/linked_list.odin +++ b/code/grime/linked_list.odin @@ -1,4 +1,9 @@ -package sectr +/* +An intersive singly & double linked list implementation + + +*/ +package grime LL_Node :: struct ( $ Type : typeid ) { next : ^Type, @@ -17,7 +22,7 @@ ll_pop :: #force_inline proc "contextless" ( list_ptr : ^(^ ($ Type)) ) -> ( nod return list } -//region Intrusive Doubly-Linked-List +//#region("Intrusive Doubly-Linked-List") DLL_Node :: struct ( $ Type : typeid ) #raw_union { using _ : struct { @@ -35,11 +40,12 @@ DLL_Node :: struct ( $ Type : typeid ) #raw_union { } DLL_NodeFull :: struct ( $ Type : typeid ) { - // using _ : DLL_NodeFL(Type), first, last : ^Type, prev, next : ^Type, } +// I have specific members commented out here as the RAD Debugger currently doesn't support transparently exposing using members of a struct (yet). + DLL_NodePN :: struct ( $ Type : typeid ) { // using _ : struct { prev, next : ^Type, @@ -187,4 +193,4 @@ dll_full_push_back :: proc "contextless" ( parent : ^$ParentType, node : ^$Type, dll_full_insert_raw( null, parent, parent.last, node ) } -//endregion Intrusive Doubly-Linked-List +//#endregion("Intrusive Doubly-Linked-List") diff --git a/code/sectr/logger.odin b/code/grime/logger.odin similarity index 94% rename from code/sectr/logger.odin rename to code/grime/logger.odin index 4689053..d1904ed 100644 --- a/code/sectr/logger.odin +++ b/code/grime/logger.odin @@ -1,4 +1,4 @@ -package sectr +package grime import "base:runtime" import "core:fmt" @@ -27,12 +27,7 @@ logger_init :: proc( logger : ^ Logger, id : string, file_path : string, file : if file == os.INVALID_HANDLE { logger_file, result_code := file_open( file_path, os.O_RDWR | os.O_CREATE ) - if result_code != os.ERROR_NONE { - // Log failures are fatal and must never occur at runtime (there is no logging) - runtime.debug_trap() - os.exit( -1 ) - // TODO(Ed) : Figure out the error code enums.. - } + assert( result_code == os.ERROR_NONE, "Log failures are fatal and must never occur at runtime (there is no logging)" ) logger.file = logger_file } else { @@ -45,7 +40,6 @@ logger_init :: proc( logger : ^ Logger, id : string, file_path : string, file : log("Initialized Logger") when false { log("This sentence is over 80 characters long on purpose to test the ability of this logger to properfly wrap long as logs with a new line and then at the end of that pad it with the appropraite signature.") - } } @@ -118,7 +112,6 @@ logger_interface :: proc( str_to_file_ln( logger.file, to_string(builder) ) } - // This buffer is used below excluisvely to prevent any allocator recusion when verbose logging from allocators. Logger_Allocator_Buffer : [32 * Kilobyte]u8 diff --git a/code/grime/mappings.odin b/code/grime/mappings.odin new file mode 100644 index 0000000..bb04361 --- /dev/null +++ b/code/grime/mappings.odin @@ -0,0 +1,150 @@ +package grime + +//#region("base") + +import "base:builtin" + copy :: builtin.copy + +import "base:intrinsics" + mem_zero :: intrinsics.mem_zero + ptr_sub :: intrinsics.ptr_sub + type_has_field :: intrinsics.type_has_field + type_elem_type :: intrinsics.type_elem_type + +import "base:runtime" + Byte :: runtime.Byte + Kilobyte :: runtime.Kilobyte + Megabyte :: runtime.Megabyte + Gigabyte :: runtime.Gigabyte + Terabyte :: runtime.Terabyte + Petabyte :: runtime.Petabyte + Exabyte :: runtime.Exabyte + resize_non_zeroed :: runtime.non_zero_mem_resize + SourceCodeLocation :: runtime.Source_Code_Location + +//#endregion("base") + +//#region("core") + +import c "core:c/libc" + mem_fmt :: c.memset + +import "core:dynlib" + +import "core:hash" + crc32 :: hash.crc32 + +import "core:hash/xxhash" + xxh32 :: xxhash.XXH32 + +import fmt_io "core:fmt" + str_fmt_out :: fmt_io.printf + str_fmt_tmp :: fmt_io.tprintf + str_fmt :: fmt_io.aprintf // Decided to make aprintf the default. (It will always be the default allocator) + str_fmt_builder :: fmt_io.sbprintf + str_fmt_buffer :: fmt_io.bprintf + str_to_file_ln :: fmt_io.fprintln + str_tmp_from_any :: fmt_io.tprint + +import "core:math" + +import "core:mem" + align_forward_int :: mem.align_forward_int + align_forward_uint :: mem.align_forward_uint + align_forward_uintptr :: mem.align_forward_uintptr + Allocator :: mem.Allocator + AllocatorError :: mem.Allocator_Error + AllocatorMode :: mem.Allocator_Mode + AllocatorModeSet :: mem.Allocator_Mode_Set + alloc :: mem.alloc + alloc_bytes :: mem.alloc_bytes + alloc_bytes_non_zeroed :: mem.alloc_bytes_non_zeroed + Arena :: mem.Arena + arena_allocator :: mem.arena_allocator + arena_init :: mem.arena_init + byte_slice :: mem.byte_slice + copy_non_overlapping :: mem.copy_non_overlapping + free :: mem.free + is_power_of_two_uintptr :: mem.is_power_of_two + ptr_offset :: mem.ptr_offset + resize :: mem.resize + slice_ptr :: mem.slice_ptr + TrackingAllocator :: mem.Tracking_Allocator + tracking_allocator :: mem.tracking_allocator + tracking_allocator_init :: mem.tracking_allocator_init + +import "core:mem/virtual" + VirtualProtectFlags :: virtual.Protect_Flags + +// TODO(Ed): Use os2 when the package is considered complete. +import "core:os" + FileFlag_Create :: os.O_CREATE + FileFlag_ReadWrite :: os.O_RDWR + FileTime :: os.File_Time + file_close :: os.close + file_open :: os.open + file_read :: os.read + file_remove :: os.remove + file_seek :: os.seek + file_status :: os.stat + file_write :: os.write + +import "core:path/filepath" + file_name_from_path :: filepath.short_stem + +import "core:strconv" + parse_f32 :: strconv.parse_f32 + parse_u64 :: strconv.parse_u64 + parse_uint :: strconv.parse_uint + +import str "core:strings" + StringBuilder :: str.Builder + str_builder_from_bytes :: str.builder_from_bytes + str_builder_init :: str.builder_init + str_builder_to_writer :: str.to_writer + str_builder_to_string :: str.to_string + +import "core:time" + Duration :: time.Duration + duration_seconds :: time.duration_seconds + duration_ms :: time.duration_milliseconds + thread_sleep :: time.sleep + +import "core:unicode" + is_white_space :: unicode.is_white_space + +import "core:unicode/utf8" + str_rune_count :: utf8.rune_count_in_string + runes_to_string :: utf8.runes_to_string + // string_to_runes :: utf8.string_to_runes + +//#endregion("core") + +import "thirdparty:backtrace" + StackTraceData :: backtrace.Trace_Const + stacktrace :: backtrace.trace + stacktrace_lines :: backtrace.lines + +//#region("Proc overload mappings") + +array_append :: proc { + array_append_value, + array_append_array, + array_append_slice, +} + +is_power_of_two :: proc { + is_power_of_two_u32, + is_power_of_two_uintptr, +} + +to_string :: proc { + runes_to_string, + str_builder_to_string, +} + +to_writer :: proc { + str_builder_to_writer, +} + +//#endregion("Proc overload mappings") diff --git a/code/grime/math.odin b/code/grime/math.odin new file mode 100644 index 0000000..4e187d6 --- /dev/null +++ b/code/grime/math.odin @@ -0,0 +1,6 @@ +package grime + +is_power_of_two_u32 :: #force_inline proc "contextless" ( value : u32 ) -> b32 +{ + return value != 0 && ( value & ( value - 1 )) == 0 +} diff --git a/code/sectr/grime/memory.odin b/code/grime/memory.odin similarity index 96% rename from code/sectr/grime/memory.odin rename to code/grime/memory.odin index e40da5a..bc424e4 100644 --- a/code/sectr/grime/memory.odin +++ b/code/grime/memory.odin @@ -1,5 +1,4 @@ -// TODO(Ed) : Move this to a grime package problably -package sectr +package grime import "core:fmt" import "core:mem" @@ -89,3 +88,5 @@ memory_aign_forward :: #force_inline proc( address, alignment : uintptr) -> uint } //endregion Memory Math + +swap :: #force_inline proc( a, b : ^ $Type ) -> ( ^ Type, ^ Type ) { return b, a } diff --git a/code/sectr/grime/memory_tracker.odin b/code/grime/memory_tracker.odin similarity index 83% rename from code/sectr/grime/memory_tracker.odin rename to code/grime/memory_tracker.odin index 29f7b63..80a4c2d 100644 --- a/code/sectr/grime/memory_tracker.odin +++ b/code/grime/memory_tracker.odin @@ -6,7 +6,7 @@ I'm keeping it around as an artifact & for future allocators I may make. */ -package sectr +package grime MemoryTrackerEntry :: struct { start, end : rawptr, @@ -19,14 +19,10 @@ MemoryTracker :: struct { Track_Memory :: false -// tracker_msg_buffer : [Kilobyte * 16]u8 - memtracker_clear :: proc ( tracker : MemoryTracker ) { when ! Track_Memory { return } - // temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:]) - // context.temp_allocator = arena_allocator(& temp_arena) logf("Clearing tracker: %v", tracker.name) memtracker_dump_entries(tracker); @@ -38,8 +34,6 @@ memtracker_init :: proc ( tracker : ^MemoryTracker, allocator : Allocator, num_e when ! Track_Memory { return } - // temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:]) - // context.temp_allocator = arena_allocator(& temp_arena) tracker.name = name @@ -56,8 +50,6 @@ memtracker_register :: proc( tracker : ^MemoryTracker, new_entry : MemoryTracker return } profile(#procedure) - // temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:]) - // context.temp_allocator = arena_allocator(& temp_arena) if tracker.entries.num == tracker.entries.capacity { ensure(false, "Memory tracker entries array full, can no longer register any more allocations") @@ -110,8 +102,6 @@ memtracker_unregister :: proc( tracker : MemoryTracker, to_remove : MemoryTracke return } profile(#procedure) - // temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:]) - // context.temp_allocator = arena_allocator(& temp_arena) entries := array_to_slice(tracker.entries) for idx in 0..< tracker.entries.num @@ -139,8 +129,6 @@ memtracker_check_for_collisions :: proc ( tracker : MemoryTracker ) return } profile(#procedure) - // temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:]) - // context.temp_allocator = arena_allocator(& temp_arena) entries := array_to_slice(tracker.entries) for idx in 1 ..< tracker.entries.num { @@ -161,8 +149,6 @@ memtracker_dump_entries :: proc( tracker : MemoryTracker ) when ! Track_Memory { return } - // temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:]) - // context.temp_allocator = arena_allocator(& temp_arena) log( "Dumping Memory Tracker:") for idx in 0 ..< tracker.entries.num { diff --git a/code/grime/os.odin b/code/grime/os.odin new file mode 100644 index 0000000..8527b58 --- /dev/null +++ b/code/grime/os.odin @@ -0,0 +1,3 @@ +package grime + +OS_Type :: type_of(ODIN_OS) diff --git a/code/grime/profiler.odin b/code/grime/profiler.odin new file mode 100644 index 0000000..d0bec4e --- /dev/null +++ b/code/grime/profiler.odin @@ -0,0 +1,29 @@ +package grime + +import "base:runtime" +import "core:prof/spall" + +SpallProfiler :: struct { + ctx : spall.Context, + buffer : spall.Buffer, +} + +@(private) +Module_Context : ^SpallProfiler + +set_profiler_module_context :: #force_inline proc "contextless" ( ctx : ^SpallProfiler ) { + Module_Context = ctx +} + +@(deferred_none = profile_end) +profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { + spall._buffer_begin( & Module_Context.ctx, & Module_Context.buffer, name, "", loc ) +} + +profile_begin :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { + spall._buffer_begin( & Module_Context.ctx, & Module_Context.buffer, name, "", loc ) +} + +profile_end :: #force_inline proc "contextless" () { + spall._buffer_end( & Module_Context.ctx, & Module_Context.buffer) +} diff --git a/code/sectr/grime/ptr.odin b/code/grime/ptr.odin similarity index 95% rename from code/sectr/grime/ptr.odin rename to code/grime/ptr.odin index 02f3acd..2bfd0c5 100644 --- a/code/sectr/grime/ptr.odin +++ b/code/grime/ptr.odin @@ -1,4 +1,4 @@ -package sectr +package grime // Provides an alternative syntax for pointers diff --git a/code/sectr/grime/string_format.odin b/code/grime/string_token_format.odin similarity index 95% rename from code/sectr/grime/string_format.odin rename to code/grime/string_token_format.odin index 3e04ff0..5d2b0ba 100644 --- a/code/sectr/grime/string_format.odin +++ b/code/grime/string_token_format.odin @@ -1,6 +1,6 @@ // This provides a string generator using a token replacement approach instead of a % verb-syntax to parse. // This was done just for preference as I personally don't like the c-printf-like syntax. -package sectr +package grime diff --git a/code/sectr/grime/windows.odin b/code/grime/timing_windows.odin similarity index 66% rename from code/sectr/grime/windows.odin rename to code/grime/timing_windows.odin index 5e1ecfc..bbbbd6e 100644 --- a/code/sectr/grime/windows.odin +++ b/code/grime/timing_windows.odin @@ -1,4 +1,4 @@ -package sectr +package grime import "core:c" import "core:c/libc" @@ -8,8 +8,6 @@ import core_virtual "core:mem/virtual" import "core:strings" import win32 "core:sys/windows" -when ODIN_OS == OS_Type.Windows { - thread__highres_wait :: proc( desired_ms : f64, loc := #caller_location ) -> b32 { // label_backing : [1 * Megabyte]u8 @@ -72,41 +70,3 @@ set__scheduler_granularity :: proc "contextless" ( desired_ms : u32 ) -> b32 { WIN32_ERROR_INVALID_ADDRESS :: 487 WIN32_ERROR_COMMITMENT_LIMIT :: 1455 - -@(require_results) -virtual__reserve :: proc "contextless" ( base_address : uintptr, size : uint ) -> ( vmem : VirtualMemoryRegion, alloc_error : AllocatorError ) -{ - header_size := cast(uint) memory_align_formula(size_of(VirtualMemoryRegionHeader), mem.DEFAULT_ALIGNMENT) - - result := win32.VirtualAlloc( rawptr(base_address), header_size + size, win32.MEM_RESERVE, win32.PAGE_READWRITE ) - if result == nil { - alloc_error = .Out_Of_Memory - return - } - result = win32.VirtualAlloc( rawptr(base_address), header_size, win32.MEM_COMMIT, win32.PAGE_READWRITE ) - if result == nil - { - switch err := win32.GetLastError(); err - { - case 0: - alloc_error = .Invalid_Argument - return - - case WIN32_ERROR_INVALID_ADDRESS, WIN32_ERROR_COMMITMENT_LIMIT: - alloc_error = .Out_Of_Memory - return - } - - alloc_error = .Out_Of_Memory - return - } - - vmem.base_address = cast(^VirtualMemoryRegionHeader) result - vmem.reserve_start = cast([^]byte) (uintptr(vmem.base_address) + uintptr(header_size)) - vmem.reserved = size - vmem.committed = header_size - alloc_error = .None - return -} - -} // END: ODIN_OS == runtime.Odin_OS_Type.Windows diff --git a/code/sectr/grime/unicode.odin b/code/grime/unicode.odin similarity index 98% rename from code/sectr/grime/unicode.odin rename to code/grime/unicode.odin index b933517..2ee7365 100644 --- a/code/sectr/grime/unicode.odin +++ b/code/grime/unicode.odin @@ -1,10 +1,7 @@ -package sectr +package grime rune16 :: distinct u16 - - - // Exposing the alloc_error @(require_results) string_to_runes :: proc ( content : string, allocator := context.allocator) -> (runes : []rune, alloc_error : AllocatorError) #optional_allocator_error { diff --git a/code/sectr/grime/virtual_arena.odin b/code/grime/virtual_arena.odin similarity index 97% rename from code/sectr/grime/virtual_arena.odin rename to code/grime/virtual_arena.odin index d942480..6c81864 100644 --- a/code/sectr/grime/virtual_arena.odin +++ b/code/grime/virtual_arena.odin @@ -12,7 +12,7 @@ No other part of the program will directly touch the vitual memory interface dir Thus for the scope of this prototype the Virtual Arena are the only interfaces to dynamic address spaces for the runtime of the client app. The host application as well ideally (although this may not be the case for a while) */ -package sectr +package grime import "base:intrinsics" import "base:runtime" @@ -25,8 +25,8 @@ VArena_GrowthPolicyProc :: #type proc( commit_used, committed, reserved, request VArena :: struct { using vmem : VirtualMemoryRegion, - dbg_name : string, tracker : MemoryTracker, + dbg_name : string, commit_used : uint, growth_policy : VArena_GrowthPolicyProc, allow_any_reize : b32, @@ -242,12 +242,14 @@ varena_allocator_proc :: proc( old_memory_offset := uintptr(old_memory) + uintptr(old_size) current_offset := uintptr(arena.reserve_start) + uintptr(arena.commit_used) - // if old_size < page_size { - // // We're dealing with an allocation that requested less than the minimum allocated on vmem. - // // Provide them more of their actual memory - // data = byte_slice( old_memory, size ) - // return - // } + when false { + if old_size < page_size { + // We're dealing with an allocation that requested less than the minimum allocated on vmem. + // Provide them more of their actual memory + data = byte_slice( old_memory, size ) + return + } + } verify( old_memory_offset == current_offset || arena.allow_any_reize, "Cannot resize existing allocation in vitual arena to a larger size unless it was the last allocated" ) diff --git a/code/sectr/grime/virtual_memory.odin b/code/grime/virtual_memory.odin similarity index 99% rename from code/sectr/grime/virtual_memory.odin rename to code/grime/virtual_memory.odin index 7b8aa02..a2227a7 100644 --- a/code/sectr/grime/virtual_memory.odin +++ b/code/grime/virtual_memory.odin @@ -1,7 +1,7 @@ /* Virtual Memory OS Interface This is an alternative to the virtual core library provided by odin, suppport setting the base address among other things. */ -package sectr +package grime import core_virtual "core:mem/virtual" import "core:os" diff --git a/code/grime/virtual_memory_windows.odin b/code/grime/virtual_memory_windows.odin new file mode 100644 index 0000000..4628454 --- /dev/null +++ b/code/grime/virtual_memory_windows.odin @@ -0,0 +1,40 @@ +package grime + +import "core:mem" +import win32 "core:sys/windows" + +@(require_results) +virtual__reserve :: proc "contextless" ( base_address : uintptr, size : uint ) -> ( vmem : VirtualMemoryRegion, alloc_error : AllocatorError ) +{ + header_size := cast(uint) memory_align_formula(size_of(VirtualMemoryRegionHeader), mem.DEFAULT_ALIGNMENT) + + result := win32.VirtualAlloc( rawptr(base_address), header_size + size, win32.MEM_RESERVE, win32.PAGE_READWRITE ) + if result == nil { + alloc_error = .Out_Of_Memory + return + } + result = win32.VirtualAlloc( rawptr(base_address), header_size, win32.MEM_COMMIT, win32.PAGE_READWRITE ) + if result == nil + { + switch err := win32.GetLastError(); err + { + case 0: + alloc_error = .Invalid_Argument + return + + case WIN32_ERROR_INVALID_ADDRESS, WIN32_ERROR_COMMITMENT_LIMIT: + alloc_error = .Out_Of_Memory + return + } + + alloc_error = .Out_Of_Memory + return + } + + vmem.base_address = cast(^VirtualMemoryRegionHeader) result + vmem.reserve_start = cast([^]byte) (uintptr(vmem.base_address) + uintptr(header_size)) + vmem.reserved = size + vmem.committed = header_size + alloc_error = .None + return +} diff --git a/code/host/host.odin b/code/host/host.odin index d8ae4ae..d781e0b 100644 --- a/code/host/host.odin +++ b/code/host/host.odin @@ -62,12 +62,15 @@ import "core:time" thread_sleep :: time.sleep import "core:prof/spall" import rl "vendor:raylib" -import sectr "../sectr" + +import "codebase:grime" + file_copy_sync :: grime.file_copy_sync + file_is_locked :: grime.file_is_locked + varena_init :: grime.varena_init + +import "codebase:sectr" VArena :: sectr.VArena - varena_init :: sectr.varena_init fatal :: sectr.fatal - file_is_locked :: sectr.file_is_locked - file_copy_sync :: sectr.file_copy_sync Logger :: sectr.Logger logger_init :: sectr.logger_init LogLevel :: sectr.LogLevel @@ -167,7 +170,7 @@ load_sectr_api :: proc( version_id : i32 ) -> (loaded_module : sectr.ModuleAPI) } live_file := Path_Sectr_Live_Module - file_copy_sync( Path_Sectr_Module, live_file ) + file_copy_sync( Path_Sectr_Module, live_file, allocator = context.temp_allocator ) lib, load_result := os_lib_load( live_file ) if ! load_result { diff --git a/code/sectr/Readme.md b/code/sectr/Readme.md new file mode 100644 index 0000000..06eeca6 --- /dev/null +++ b/code/sectr/Readme.md @@ -0,0 +1,2 @@ +# Sectr Package + diff --git a/code/sectr/engine/client_api.odin b/code/sectr/engine/client_api.odin index aacfce3..fec44a8 100644 --- a/code/sectr/engine/client_api.odin +++ b/code/sectr/engine/client_api.odin @@ -39,7 +39,8 @@ ModuleAPI :: struct { startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem, files_buffer_mem : ^VArena, host_logger : ^Logger ) { spall.SCOPED_EVENT( & prof.ctx, & prof.buffer, #procedure ) - Memory_App.profiler = prof + // Memory_App.profiler = prof + set_profiler_module_context( prof ) startup_tick := time.tick_now() @@ -376,7 +377,7 @@ sectr_shutdown :: proc() reload :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem, files_buffer_mem : ^VArena, host_logger : ^ Logger ) { spall.SCOPED_EVENT( & prof.ctx, & prof.buffer, #procedure ) - Memory_App.profiler = prof + set_profiler_module_context( prof ) context.logger = to_odin_logger( & Memory_App.logger ) using Memory_App; @@ -434,6 +435,8 @@ reload :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem, log("Module reloaded") } +Frametime_High_Perf_Threshold_MS :: 1 / 240.0 + @export tick :: proc( host_delta_time_ms : f64, host_delta_ns : Duration ) -> b32 { @@ -488,7 +491,7 @@ tick_work_frame :: #force_inline proc( host_delta_time_ms : f64 ) -> b32 debug.draw_UI_padding_bounds = false debug.draw_ui_content_bounds = false - config.engine_refresh_hz = 10000 + config.engine_refresh_hz = 165 // config.color_theme = App_Thm_Light // config.color_theme = App_Thm_Dusk diff --git a/code/sectr/grime/hashmap_zpl.odin b/code/sectr/grime/hashmap_zpl.odin index c36412f..f399257 100644 --- a/code/sectr/grime/hashmap_zpl.odin +++ b/code/sectr/grime/hashmap_zpl.odin @@ -47,11 +47,7 @@ HMapZPL :: struct ( $ Type : typeid ) { entries : Array( HMapZPL_Entry(Type) ), } -hamp_zpl_init :: proc( $ Type : typeid, allocator : Allocator ) -> ( HMapZPL( Type), AllocatorError ) { - return hamp_zpl_init_reserve( Type, allocator ) -} - -hamp_zpl_init_reserve :: proc +hamp_zpl_init :: proc ( $ Type : typeid, allocator : Allocator, num : u64, dbg_name : string = "" ) -> ( HMapZPL( Type), AllocatorError ) { result : HMapZPL(Type) @@ -126,7 +122,7 @@ hamp_zpl_rehash :: proc( ht : ^ HMapZPL( $ Type ), new_num : u64 ) -> AllocatorE ensure( false, "ZPL HMAP IS REHASHING" ) last_added_index : i64 - new_ht, init_result := hamp_zpl_init_reserve( Type, ht.table.backing, new_num, ht.table.dbg_name ) + new_ht, init_result := hamp_zpl_init( Type, ht.table.backing, new_num, ht.table.dbg_name ) if init_result != AllocatorError.None { ensure( false, "New hamp_zpl failed to allocate" ) return init_result diff --git a/code/sectr/grime/grime.odin b/code/sectr/grime/mappings.odin similarity index 69% rename from code/sectr/grime/grime.odin rename to code/sectr/grime/mappings.odin index 79f11ba..9dba11b 100644 --- a/code/sectr/grime/grime.odin +++ b/code/sectr/grime/mappings.odin @@ -1,15 +1,17 @@ package sectr -#region("Import Aliases") +#region("base") import "base:builtin" copy :: builtin.copy + import "base:intrinsics" mem_zero :: intrinsics.mem_zero ptr_sub :: intrinsics.ptr_sub type_has_field :: intrinsics.type_has_field type_elem_type :: intrinsics.type_elem_type + import "base:runtime" Byte :: runtime.Byte Kilobyte :: runtime.Kilobyte @@ -20,12 +22,22 @@ import "base:runtime" Exabyte :: runtime.Exabyte resize_non_zeroed :: runtime.non_zero_mem_resize SourceCodeLocation :: runtime.Source_Code_Location + debug_trap :: runtime.debug_trap + +#endregion("base") + +#region("core") + import c "core:c/libc" -import "core:dynlib" + +// import "core:dynlib" + import "core:hash" crc32 :: hash.crc32 + import "core:hash/xxhash" xxh32 :: xxhash.XXH32 + import fmt_io "core:fmt" str_fmt_out :: fmt_io.printf str_fmt_tmp :: fmt_io.tprintf @@ -34,7 +46,9 @@ import fmt_io "core:fmt" str_fmt_buffer :: fmt_io.bprintf str_to_file_ln :: fmt_io.fprintln str_tmp_from_any :: fmt_io.tprint + import "core:math" + import "core:mem" align_forward_int :: mem.align_forward_int align_forward_uint :: mem.align_forward_uint @@ -59,9 +73,12 @@ import "core:mem" TrackingAllocator :: mem.Tracking_Allocator tracking_allocator :: mem.tracking_allocator tracking_allocator_init :: mem.tracking_allocator_init + import "core:mem/virtual" VirtualProtectFlags :: virtual.Protect_Flags + // import "core:odin" + import "core:os" FileFlag_Create :: os.O_CREATE FileFlag_ReadWrite :: os.O_RDWR @@ -73,37 +90,152 @@ import "core:os" file_seek :: os.seek file_status :: os.stat file_write :: os.write + import "core:path/filepath" file_name_from_path :: filepath.short_stem + import "core:strconv" parse_f32 :: strconv.parse_f32 parse_u64 :: strconv.parse_u64 parse_uint :: strconv.parse_uint + import str "core:strings" StringBuilder :: str.Builder str_builder_from_bytes :: str.builder_from_bytes str_builder_init :: str.builder_init str_builder_to_writer :: str.to_writer str_builder_to_string :: str.to_string + import "core:time" Duration :: time.Duration duration_seconds :: time.duration_seconds duration_ms :: time.duration_milliseconds thread_sleep :: time.sleep + import "core:unicode" is_white_space :: unicode.is_white_space + import "core:unicode/utf8" str_rune_count :: utf8.rune_count_in_string runes_to_string :: utf8.runes_to_string // string_to_runes :: utf8.string_to_runes + +#endregion("core") + import "thirdparty:backtrace" StackTraceData :: backtrace.Trace_Const stacktrace :: backtrace.trace stacktrace_lines :: backtrace.lines -#endregion("Import Aliases") +import "codebase:grime" + // asserts + ensure :: grime.ensure + fatal :: grime.fatal + verify :: grime.verify -#region("Proc overload mappings") + // chrono + NS_To_MS :: grime.NS_To_MS + NS_To_US :: grime.NS_To_US + NS_To_S :: grime.NS_To_S + + US_To_NS :: grime.US_To_NS + US_To_MS :: grime.US_To_MS + US_To_S :: grime.US_To_S + + MS_To_NS :: grime.MS_To_NS + MS_To_US :: grime.MS_To_US + MS_To_S :: grime.MS_To_S + + S_To_NS :: grime.S_To_NS + S_To_US :: grime.S_To_US + S_To_MS :: grime.S_To_MS + + // container + Array :: grime.Array + + array_to_slice :: grime.array_to_slice + array_init_reserve :: grime.array_init_reserve + array_append :: grime.array_append + array_append_at :: grime.array_append_at + array_clear :: grime.array_clear + array_free :: grime.array_free + array_grow_formula :: grime.array_grow_formula + array_remove_at :: grime.array_remove_at + array_resize :: grime.array_resize + + // filesystem + file_exists :: grime.file_exists + file_rewind :: grime.file_rewind + + // linked lists + LL_Node :: grime.LL_Node + + ll_push :: grime.ll_push + ll_pop :: grime.ll_pop + + DLL_Node :: grime.DLL_Node + DLL_NodeFull :: grime.DLL_NodeFull + DLL_NodePN :: grime.DLL_NodePN + DLL_NodeFL :: grime.DLL_NodeFL + + dll_full_push_back :: grime.dll_full_push_back + dll_full_pop :: grime.dll_full_pop + dll_push_back :: grime.dll_push_back + dll_pop_back :: grime.dll_pop_back + + // logger + Logger :: grime.Logger + LogLevel :: grime.LogLevel + + to_odin_logger :: grime.to_odin_logger + logger_init :: grime.logger_init + log :: grime.log + logf :: grime.logf + + // memory + MemoryTracker :: grime.MemoryTracker + MemoryTrackerEntry :: grime.MemoryTrackerEntry + + memtracker_clear :: grime.memtracker_clear + memtracker_init :: grime.memtracker_init + memtracker_register_auto_name :: grime.memtracker_register_auto_name + memtracker_register_auto_name_slice :: grime.memtracker_register_auto_name_slice + memtracker_unregister :: grime.memtracker_unregister + + + calc_padding_with_header :: grime.calc_padding_with_header + memory_after_header :: grime.memory_after_header + memory_after :: grime.memory_after + swap :: grime.swap + + // profiler + SpallProfiler :: grime.SpallProfiler + + set_profiler_module_context :: grime.set_profiler_module_context + + profile :: grime.profile + profile_begin :: grime.profile_begin + profile_end :: grime.profile_end + + // os + OS_Type :: grime.OS_Type + + // timing + when ODIN_OS == OS_Type.Windows { + set__scheduler_granularity :: grime.set__scheduler_granularity + } + + // unicode + string_to_runes :: grime.string_to_runes + string_to_runes_array :: grime.string_to_runes_array + + // virutal memory + VArena :: grime.VArena + VirtualMemoryRegion :: grime.VirtualMemoryRegion + + varena_allocator :: grime.varena_allocator + +#region("Procedure overload mappings") // This has to be done on a per-module basis. @@ -111,12 +243,6 @@ add :: proc { add_range2, } -array_append :: proc { - array_append_value, - array_append_array, - array_append_slice, -} - bivec3 :: proc { bivec3_via_f32s, vec3_to_bivec3, @@ -359,7 +485,3 @@ wedge :: proc { } #endregion("Proc overload mappings") - -OS_Type :: type_of(ODIN_OS) - -swap :: #force_inline proc( a, b : ^ $Type ) -> ( ^ Type, ^ Type ) { return b, a } diff --git a/code/sectr/grime/profiler.odin b/code/sectr/grime/profiler.odin deleted file mode 100644 index 023c1ae..0000000 --- a/code/sectr/grime/profiler.odin +++ /dev/null @@ -1,22 +0,0 @@ -package sectr - -import "base:runtime" -import "core:prof/spall" - -SpallProfiler :: struct { - ctx : spall.Context, - buffer : spall.Buffer, -} - -@(deferred_none=profile_end) -profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { - spall._buffer_begin( & Memory_App.profiler.ctx, & Memory_App.profiler.buffer, name, "", loc ) -} - -profile_begin :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { - spall._buffer_begin( & Memory_App.profiler.ctx, & Memory_App.profiler.buffer, name, "", loc ) -} - -profile_end :: #force_inline proc "contextless" () { - spall._buffer_end( & Memory_App.profiler.ctx, & Memory_App.profiler.buffer) -} diff --git a/code/sectr/grime/string_interning.odin b/code/sectr/grime/string_interning.odin index 29f02ad..aa3b955 100644 --- a/code/sectr/grime/string_interning.odin +++ b/code/sectr/grime/string_interning.odin @@ -66,7 +66,7 @@ str_cache_init :: proc( /*allocator : Allocator*/ ) -> ( cache : StringCache ) { cache.slab, alloc_error = slab_init( & policy, allocator = persistent_allocator(), dbg_name = dbg_name ) verify(alloc_error == .None, "Failed to initialize the string cache" ) - cache.table, alloc_error = hamp_zpl_init_reserve( StrRunesPair, persistent_allocator(), 4 * Megabyte, dbg_name ) + cache.table, alloc_error = hamp_zpl_init( StrRunesPair, persistent_allocator(), 4 * Megabyte, dbg_name ) return } diff --git a/code/sectr/ui/core/state.odin b/code/sectr/ui/core/base.odin similarity index 98% rename from code/sectr/ui/core/state.odin rename to code/sectr/ui/core/base.odin index b0bf25b..e54846c 100644 --- a/code/sectr/ui/core/state.odin +++ b/code/sectr/ui/core/base.odin @@ -133,7 +133,7 @@ ui_startup :: proc( ui : ^ UI_State, cache_allocator : Allocator /* , cache_rese ui^ = {} for & cache in ui.caches { - box_cache, allocation_error := hamp_zpl_init_reserve( UI_Box, cache_allocator, UI_Built_Boxes_Array_Size ) + box_cache, allocation_error := hamp_zpl_init( UI_Box, cache_allocator, UI_Built_Boxes_Array_Size ) verify( allocation_error == AllocatorError.None, "Failed to allocate box cache" ) cache = box_cache }