diff --git a/code/grime/virtual_arena.odin b/code/grime/virtual_arena.odin index edf0f34..1633bd9 100644 --- a/code/grime/virtual_arena.odin +++ b/code/grime/virtual_arena.odin @@ -62,7 +62,10 @@ varena_allocator :: proc( arena : ^VArena ) -> ( allocator : Allocator ) { // Default growth_policy is nil varena_init :: proc( base_address : uintptr, to_reserve, to_commit : uint, - growth_policy : VArena_GrowthPolicyProc, allow_any_resize : b32 = false, dbg_name : string, enable_mem_tracking : b32 = false, + growth_policy: VArena_GrowthPolicyProc = nil, + allow_any_resize: b32 = false, + dbg_name: string = "", + enable_mem_tracking: b32 = false, ) -> ( arena : VArena, alloc_error : AllocatorError) { page_size := uint(virtual_get_page_size()) @@ -78,8 +81,8 @@ varena_init :: proc( base_address : uintptr, to_reserve, to_commit : uint, return } - arena.vmem = vmem - arena.commit_used = 0 + arena.vmem = vmem + arena.commit_used = 0 if growth_policy == nil { arena.growth_policy = varena_default_growth_policy diff --git a/code/host/host.odin b/code/host/host.odin index 3a10efe..4af76c8 100644 --- a/code/host/host.odin +++ b/code/host/host.odin @@ -71,6 +71,7 @@ import "codebase:grime" import "codebase:sectr" VArena :: sectr.VArena fatal :: sectr.fatal + JobSystemContext :: sectr.JobSystemContext Logger :: sectr.Logger logger_init :: sectr.logger_init LogLevel :: sectr.LogLevel @@ -106,6 +107,8 @@ RuntimeState :: struct { running : b32, client_memory : ClientMemory, sectr_api : sectr.ModuleAPI, + + job_system: JobSystemContext, } ClientMemory :: struct { diff --git a/code/sectr/app/state.odin b/code/sectr/app/state.odin index a2ccc83..b0059e9 100644 --- a/code/sectr/app/state.odin +++ b/code/sectr/app/state.odin @@ -10,8 +10,11 @@ Str_App_State := "App State" //region Memory +// Data segment Memory for sectr module. Memory_App : Memory +// General memory configuration + Memory_Base_Address_Persistent :: Terabyte * 1 Memory_Base_Address_Frame :: Memory_Base_Address_Persistent + Memory_Reserve_Persistent * 2 Memory_Base_Address_Transient :: Memory_Base_Address_Frame + Memory_Reserve_Frame * 2 @@ -29,13 +32,6 @@ Memory_Commit_Initial_Frame :: 4 * Kilobyte Memory_Commit_Initial_Transient :: 4 * Kilobyte Memory_Commit_Initial_Filebuffer :: 4 * Kilobyte -MemorySnapshot :: struct { - persistent : []u8, - frame : []u8, - transient : []u8, - // files_buffer cannot be restored from snapshot -} - Memory :: struct { persistent : ^VArena, frame : ^VArena, @@ -44,15 +40,12 @@ Memory :: struct { state : ^State, - // Should only be used for small memory allocation iterations - // Not for large memory env states - snapshot : MemorySnapshot, - replay : ReplayState, logger : Logger, profiler : ^SpallProfiler } + persistent_allocator :: proc() -> Allocator { result := varena_allocator( Memory_App.persistent ) return result @@ -97,37 +90,6 @@ transient_slab_allocator :: proc() -> Allocator { return result } -// TODO(Ed) : Implment host memory mapping api -save_snapshot :: proc( snapshot : ^MemorySnapshot ) -{ - // Make sure the snapshot size is able to hold the current size of the arenas - // Grow the files & mapping otherwise - { - // TODO(Ed) : Implement eventually - } - - persistent := Memory_App.persistent - mem.copy_non_overlapping( & snapshot.persistent[0], persistent.reserve_start, int(persistent.commit_used) ) - - frame := Memory_App.frame - mem.copy_non_overlapping( & snapshot.frame[0], frame.reserve_start, int(frame.commit_used) ) - - transient := Memory_App.transient - mem.copy_non_overlapping( & snapshot.transient[0], transient.reserve_start, int(transient.commit_used) ) -} - -// TODO(Ed) : Implment host memory mapping api -load_snapshot :: proc( snapshot : ^MemorySnapshot ) { - persistent := Memory_App.persistent - mem.copy_non_overlapping( persistent.reserve_start, & snapshot.persistent[0], int(persistent.commit_used) ) - - frame := Memory_App.frame - mem.copy_non_overlapping( frame.reserve_start, & snapshot.frame[0], int(frame.commit_used) ) - - transient := Memory_App.transient - mem.copy_non_overlapping( transient.reserve_start, & snapshot.transient[0], int(transient.commit_used) ) -} - // TODO(Ed) : Implement usage of this MemoryConfig :: struct { reserve_persistent : uint, @@ -220,6 +182,8 @@ State :: struct { transient_clear_time : f32, // Time in seconds for the usual period to clear transient transient_clear_elapsed : f32, // Time since last clear + job_system : JobSystemContext, + string_cache : StringCache, input_data : [2]InputState, diff --git a/code/sectr/engine/client_api.odin b/code/sectr/engine/client_api.odin index e184de7..79beff7 100644 --- a/code/sectr/engine/client_api.odin +++ b/code/sectr/engine/client_api.odin @@ -626,6 +626,7 @@ clean_frame :: proc() free_all( frame_allocator() ) + // TODO(Ed): Delete this we are no longer using the temp_allocator this way. transient_clear_elapsed += frametime_delta32() if transient_clear_elapsed >= transient_clear_time && ! transinet_clear_lock { diff --git a/code/sectr/engine/host_api.odin b/code/sectr/engine/host_api.odin new file mode 100644 index 0000000..f1cec99 --- /dev/null +++ b/code/sectr/engine/host_api.odin @@ -0,0 +1,8 @@ +package sectr + + +Host_API :: struct { + // request_virtual_memory: HostAPI_RequestVirtualMemory, + // request_virtual_mapped_io: HostAPI_RequestVirtaulMappedIO, + // enqueue_job: , +} diff --git a/code/sectr/engine/job_system.odin b/code/sectr/engine/job_system.odin new file mode 100644 index 0000000..3cc73ce --- /dev/null +++ b/code/sectr/engine/job_system.odin @@ -0,0 +1,75 @@ +package sectr + +ThreadProc :: #type proc(data: rawptr) + +IgnoredThreads :: bit_set[ 0 ..< 64 ] + +JobProc :: #type proc(data: rawptr) + +JobGroup :: struct { + counter: u64, +} + +JobPriority :: enum { + Medium = 0, + Low, + High, +} + +Job :: struct { + next: ^Job, + cb: JobProc, + data: rawptr, + group: ^JobGroup, + ignored: IgnoredThreads, + dbg_lbl: string, +} + +JobList :: struct { + head: ^Job, + mutex: AtomicMutex, +} + +JobSystemContext :: struct { + job_lists: [JobPriority]JobList, + worker_cb: ThreadProc, + worker_data: rawptr, + counter: int, + workers: [] ^ThreadWorkerContext, + running: b32, +} + +ThreadWorkerContext :: struct { + system_ctx: Thread, + index: int, +} + +// Hard constraint for Windows +JOB_SYSTEM_MAX_WORKER_THREADS :: 64 + +/* +Threads are setup upfront during the client API's startup. + + +*/ + +jobsys_startup :: proc(ctx: ^JobSystemContext, num_workers : int, worker_exec: ThreadProc, worker_data: rawptr) { + ctx^ = { + worker_cb = worker_exec, + worker_data = worker_data, + counter = 1, + } + // Determine number of physical cores + // Allocate worker contextes based on number of physical cores - 1 (main thread managed by host included assumed to be index 0) + // + // num_hw_threads = min(JOB_SYSTEM_MAX_WORKER_THREADS, ) + // jobsys_worker_make : +} + +thread_worker_exec :: proc(_: rawptr) { + +} + +jobsys_shutdown :: proc(ctx: ^JobSystemContext) { + +} diff --git a/code/sectr/grime/pkg_mappings.odin b/code/sectr/grime/pkg_mappings.odin index 9afe3dd..ef26aac 100644 --- a/code/sectr/grime/pkg_mappings.odin +++ b/code/sectr/grime/pkg_mappings.odin @@ -126,6 +126,9 @@ import "core:path/filepath" import "core:slice" +import "core:sync" + AtomicMutex :: sync.Atomic_Mutex + import "core:strconv" parse_f32 :: strconv.parse_f32 parse_u64 :: strconv.parse_u64 @@ -147,6 +150,9 @@ import "core:time" time_now :: time.now Time :: time.Time +import "core:thread" + Thread :: thread.Thread + import "core:unicode" is_white_space :: unicode.is_white_space @@ -348,6 +354,8 @@ import "codebase:grime" varena_allocator :: grime.varena_allocator + VArena_GrowthPolicyProc :: grime.VArena_GrowthPolicyProc + //endregion codebase //region Procedure overload mappings diff --git a/code/sectr/ui/core/layout_compute.odin b/code/sectr/ui/core/layout_compute.odin index cd94856..1251493 100644 --- a/code/sectr/ui/core/layout_compute.odin +++ b/code/sectr/ui/core/layout_compute.odin @@ -1,163 +1,5 @@ package sectr -ui_layout_children_horizontally :: proc( container : ^UI_Box, direction : UI_LayoutDirection_X, width_ref : ^f32 = nil ) -{ - container_width : f32 - if width_ref != nil { - container_width = width_ref ^ - } - else { - container_width = container.computed.content.max.x - container.computed.content.min.x - } - container_height := container.computed.content.max.y - container.computed.content.min.y - - // do layout calculations for the children - total_stretch_ratio : f32 = 0.0 - size_req_children : f32 = 0 - for child := container.first; child != nil; child = child.next - { - using child.layout - scaled_width_by_height : b32 = b32(.Scale_Width_By_Height_Ratio in flags) - if .Scale_Width_By_Height_Ratio in flags - { - size_req_children += size.min.x * container_height - continue - } - if .Fixed_Width in flags - { - size_req_children += size.min.x - continue - } - - size_req_children += size.min.x - total_stretch_ratio += anchor.ratio.x - } - - avail_flex_space := container_width - size_req_children - - allocate_space :: proc( child : ^UI_Box, total_stretch_ratio, avail_flex_space, container_height : f32 ) -> (space_allocated : f32) - { - using child.layout - if .Scale_Width_By_Height_Ratio in flags { - size.min.y = container_height - space_allocated = size.min.x * container_height - } - else if ! (.Fixed_Width in flags) { - potential_size := anchor.ratio.x * (1 / total_stretch_ratio) * avail_flex_space - space_allocated = max(potential_size, size.min.x) - size.min.x = space_allocated - } - else { - space_allocated = size.min.x - } - space_allocated -= margins.left - margins.right - size.min.x -= margins.left - margins.right - flags |= {.Fixed_Width} - return - } - - space_used : f32 = 0.0 - switch direction{ - case .Left_To_Right: - for child := container.first; child != nil; child = child.next { - using child.layout - child_width := allocate_space(child, total_stretch_ratio, avail_flex_space, container_height) - anchor = range2({0, anchor.bottom}, {0, anchor.top}) - alignment = {0, alignment.y} - pos.x = space_used - space_used += child_width + child.layout.margins.left + child.layout.margins.right - } - case .Right_To_Left: - for child := container.first; child != nil; child = child.next { - using child.layout - child_width := allocate_space(child, total_stretch_ratio, avail_flex_space, container_height) - anchor = range2({1, anchor.bottom}, {0, anchor.top}) - alignment = {1, alignment.y} - pos.x = space_used - space_used -= child_width + child.layout.margins.left + child.layout.margins.right - } - } -} - -ui_layout_children_vertically :: proc( container : ^UI_Box, direction : UI_LayoutDirection_Y, height_ref : ^f32 = nil ) -{ - container_height : f32 - if height_ref != nil { - container_height = height_ref ^ - } - else { - container_height = container.computed.content.max.y - container.computed.content.min.y - } - container_width := container.computed.content.max.x - container.computed.content.min.x - - // do layout calculations for the children - total_stretch_ratio : f32 = 0.0 - size_req_children : f32 = 0 - for child := container.first; child != nil; child = child.next - { - using child.layout - scaled_height_by_width : b32 = b32(.Scale_Height_By_Width_Ratio in flags) - if scaled_height_by_width { - size_req_children += size.min.y * container_width - continue - } - if .Fixed_Height in flags - { - size_req_children += size.min.y - continue - } - - size_req_children += size.min.y - total_stretch_ratio += anchor.ratio.y - } - - avail_flex_space := container_height - size_req_children - - allocate_space :: proc( child : ^UI_Box, total_stretch_ratio, avail_flex_space, container_width : f32 ) -> (space_allocated : f32) - { - using child.layout - if .Scale_Height_By_Width_Ratio in flags { - size.min.x = container_width - space_allocated = size.min.y * container_width - } - if ! (.Fixed_Height in flags) { - potential_size := (anchor.ratio.y * (1 / total_stretch_ratio) * avail_flex_space) - space_allocated = max(potential_size, size.min.y) - size.min.y = space_allocated - } - else { - space_allocated = size.min.y - } - space_allocated -= margins.top - margins.bottom - size.min.y -= margins.top - margins.bottom - flags |= {.Fixed_Height} - return - } - - space_used : f32 = 0 - switch direction - { - case .Top_To_Bottom: - for child := container.first; child != nil; child = child.next { - using child.layout - child_height := allocate_space(child, total_stretch_ratio, avail_flex_space, container_width) - anchor = range2({anchor.left, 1}, {anchor.right, 0}) - alignment = {alignment.x, 1} - pos.y = space_used - space_used -= child_height - child.layout.margins.top - child.layout.margins.bottom - } - case .Bottom_To_Top: - for child := container.first; child != nil; child = child.next { - using child.layout - child_height := allocate_space(child, total_stretch_ratio, avail_flex_space, container_width) - anchor = range2({anchor.left,0}, {anchor.right, 0}) - alignment = {alignment.x, 0} - pos.y = space_used - space_used += child_height - child.layout.margins.top - child.layout.margins.bottom - } - } -} - ui_box_compute_layout :: proc( box : ^UI_Box, dont_mark_fresh : b32 = false, ancestors_layout_required : b32 = false, @@ -410,3 +252,161 @@ ui_box_compute_layout_children :: proc( box : ^UI_Box ) ui_box_compute_layout( current ) } } + +ui_layout_children_horizontally :: proc( container : ^UI_Box, direction : UI_LayoutDirection_X, width_ref : ^f32 = nil ) +{ + container_width : f32 + if width_ref != nil { + container_width = width_ref ^ + } + else { + container_width = container.computed.content.max.x - container.computed.content.min.x + } + container_height := container.computed.content.max.y - container.computed.content.min.y + + // do layout calculations for the children + total_stretch_ratio : f32 = 0.0 + size_req_children : f32 = 0 + for child := container.first; child != nil; child = child.next + { + using child.layout + scaled_width_by_height : b32 = b32(.Scale_Width_By_Height_Ratio in flags) + if .Scale_Width_By_Height_Ratio in flags + { + size_req_children += size.min.x * container_height + continue + } + if .Fixed_Width in flags + { + size_req_children += size.min.x + continue + } + + size_req_children += size.min.x + total_stretch_ratio += anchor.ratio.x + } + + avail_flex_space := container_width - size_req_children + + allocate_space :: proc( child : ^UI_Box, total_stretch_ratio, avail_flex_space, container_height : f32 ) -> (space_allocated : f32) + { + using child.layout + if .Scale_Width_By_Height_Ratio in flags { + size.min.y = container_height + space_allocated = size.min.x * container_height + } + else if ! (.Fixed_Width in flags) { + potential_size := anchor.ratio.x * (1 / total_stretch_ratio) * avail_flex_space + space_allocated = max(potential_size, size.min.x) + size.min.x = space_allocated + } + else { + space_allocated = size.min.x + } + space_allocated -= margins.left - margins.right + size.min.x -= margins.left - margins.right + flags |= {.Fixed_Width} + return + } + + space_used : f32 = 0.0 + switch direction{ + case .Left_To_Right: + for child := container.first; child != nil; child = child.next { + using child.layout + child_width := allocate_space(child, total_stretch_ratio, avail_flex_space, container_height) + anchor = range2({0, anchor.bottom}, {0, anchor.top}) + alignment = {0, alignment.y} + pos.x = space_used + space_used += child_width + child.layout.margins.left + child.layout.margins.right + } + case .Right_To_Left: + for child := container.first; child != nil; child = child.next { + using child.layout + child_width := allocate_space(child, total_stretch_ratio, avail_flex_space, container_height) + anchor = range2({1, anchor.bottom}, {0, anchor.top}) + alignment = {1, alignment.y} + pos.x = space_used + space_used -= child_width + child.layout.margins.left + child.layout.margins.right + } + } +} + +ui_layout_children_vertically :: proc( container : ^UI_Box, direction : UI_LayoutDirection_Y, height_ref : ^f32 = nil ) +{ + container_height : f32 + if height_ref != nil { + container_height = height_ref ^ + } + else { + container_height = container.computed.content.max.y - container.computed.content.min.y + } + container_width := container.computed.content.max.x - container.computed.content.min.x + + // do layout calculations for the children + total_stretch_ratio : f32 = 0.0 + size_req_children : f32 = 0 + for child := container.first; child != nil; child = child.next + { + using child.layout + scaled_height_by_width : b32 = b32(.Scale_Height_By_Width_Ratio in flags) + if scaled_height_by_width { + size_req_children += size.min.y * container_width + continue + } + if .Fixed_Height in flags + { + size_req_children += size.min.y + continue + } + + size_req_children += size.min.y + total_stretch_ratio += anchor.ratio.y + } + + avail_flex_space := container_height - size_req_children + + allocate_space :: proc( child : ^UI_Box, total_stretch_ratio, avail_flex_space, container_width : f32 ) -> (space_allocated : f32) + { + using child.layout + if .Scale_Height_By_Width_Ratio in flags { + size.min.x = container_width + space_allocated = size.min.y * container_width + } + if ! (.Fixed_Height in flags) { + potential_size := (anchor.ratio.y * (1 / total_stretch_ratio) * avail_flex_space) + space_allocated = max(potential_size, size.min.y) + size.min.y = space_allocated + } + else { + space_allocated = size.min.y + } + space_allocated -= margins.top - margins.bottom + size.min.y -= margins.top - margins.bottom + flags |= {.Fixed_Height} + return + } + + space_used : f32 = 0 + switch direction + { + case .Top_To_Bottom: + for child := container.first; child != nil; child = child.next { + using child.layout + child_height := allocate_space(child, total_stretch_ratio, avail_flex_space, container_width) + anchor = range2({anchor.left, 1}, {anchor.right, 0}) + alignment = {alignment.x, 1} + pos.y = space_used + space_used -= child_height - child.layout.margins.top - child.layout.margins.bottom + } + case .Bottom_To_Top: + for child := container.first; child != nil; child = child.next { + using child.layout + child_height := allocate_space(child, total_stretch_ratio, avail_flex_space, container_width) + anchor = range2({anchor.left,0}, {anchor.right, 0}) + alignment = {alignment.x, 0} + pos.y = space_used + space_used += child_height - child.layout.margins.top - child.layout.margins.bottom + } + } +}