Replaced old memory arena with a new, better one, which also has a test suite
This commit is contained in:
parent
baf4c5d5a6
commit
f261cbd55a
|
@ -6,7 +6,7 @@ SET MyPath=%MyPath:~0,-1%
|
|||
call %MyPath%\_prebuild_win32.bat app debug msvc
|
||||
call %MyPath%\setup_cl.bat
|
||||
|
||||
SET CommonCompilerFlags=-nologo -DDEBUG=1 -DPLATFORM_WINDOWS -FC -WX -W4 -Z7 -Oi -GR- -EHsc -EHa- -MTd -fp:fast -fp:except- -IC:\programs-dev\gs_libs\src
|
||||
SET CommonCompilerFlags=-nologo -DDEBUG=0 -DPLATFORM_WINDOWS -FC -WX -W4 -Z7 -Oi -GR- -EHsc -EHa- -MTd -fp:fast -fp:except- -IC:\programs-dev\gs_libs\src
|
||||
|
||||
SET CommonCompilerFlags=-wd4127 -wd4702 -wd4101 -wd4505 -wd4100 -wd4189 -wd4244 -wd4201 -wd4996 -I%CommonLibs% -Od %CommonCompilerFlags%
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ OperationModeSystemInit(gs_memory_arena* Storage, gs_thread_context ThreadContex
|
|||
Result.ModeMemoryPagesFreeList.Data = PushArray(Storage, gs_data, Result.ModeMemoryPagesFreeList.CountMax);
|
||||
for (u32 Page = 0; Page < Result.ModeMemoryPagesFreeList.CountMax; Page++)
|
||||
{
|
||||
Result.ModeMemoryPagesFreeList.Data[Page] = PushSizeToData(Storage, KB(4));
|
||||
Result.ModeMemoryPagesFreeList.Data[Page] = PushSize(Storage, KB(4));
|
||||
}
|
||||
Result.ModeMemoryPagesFreeList.Count = Result.ModeMemoryPagesFreeList.CountMax;
|
||||
|
||||
|
@ -81,7 +81,7 @@ ActivateOperationMode (operation_mode_system* System, operation_render_proc* Ren
|
|||
//System->ModeMemorySnapshots[ModeIndex] = TakeSnapshotOfArena(&System->Arena);
|
||||
|
||||
Result = &System->ActiveModes[ModeIndex];
|
||||
Result->Memory = CreateMemoryCursor(OperationModeTakeMemoryPage(System));
|
||||
Result->Memory = MemoryCursorCreateFromData(OperationModeTakeMemoryPage(System));
|
||||
Result->Render = RenderProc;
|
||||
|
||||
return Result;
|
||||
|
@ -132,7 +132,7 @@ CreateOperationState_ (operation_mode* Mode, operation_mode_system* System, s32
|
|||
// NOTE(Peter): This isn't a problem if this fires, it just means our page size is too small,
|
||||
// and its time to make the pages dynamically sized
|
||||
Assert(Mode->Memory.Data.Size >= StateSize);
|
||||
u8* Result = PushSizeOnCursor(&Mode->Memory, StateSize).Memory;
|
||||
u8* Result = MemoryCursorPushSize(&Mode->Memory, StateSize).Memory;
|
||||
Mode->OpStateMemory = Result;
|
||||
return Result;
|
||||
}
|
||||
|
|
|
@ -416,7 +416,7 @@ ui_InterfaceReset(ui_interface* Interface)
|
|||
Interface->WidgetsCount = 0;
|
||||
Interface->DrawOrderHead = 0;
|
||||
Interface->DrawOrderRoot = 0;
|
||||
ClearArena(Interface->PerFrameMemory);
|
||||
MemoryArenaClear(Interface->PerFrameMemory);
|
||||
InterfaceAssert(Interface->PerFrameMemory);
|
||||
|
||||
for (u32 i = 0; i < Interface->RetainedStateCount; i++)
|
||||
|
@ -1665,7 +1665,7 @@ ui_InterfaceCreate(context Context, interface_config Style, gs_memory_arena* Per
|
|||
Result.WidgetsCountMax = 4096;
|
||||
Result.Widgets = PushArray(Permanent, ui_widget, Result.WidgetsCountMax);
|
||||
Result.PerFrameMemory = PushStruct(Permanent, gs_memory_arena);
|
||||
*Result.PerFrameMemory = CreateMemoryArena(Context.ThreadContext.Allocator, "Interface Per Frame Memory Arena", KB(32));
|
||||
*Result.PerFrameMemory = MemoryArenaCreate(KB(32), Bytes(8), Context.ThreadContext.Allocator, 0, 0, "Interface Per Frame Memory Arena");
|
||||
InterfaceAssert(Result.PerFrameMemory);
|
||||
|
||||
Result.Permanent = Permanent;
|
||||
|
|
|
@ -55,7 +55,7 @@ FileView_UpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_stat
|
|||
// function
|
||||
char LastChar = WorkingDirectory.Str[WorkingDirectory.Length - 1];
|
||||
Assert(LastChar == '\\' || LastChar == '/');
|
||||
ClearArena(&State->FileNamesArena);
|
||||
MemoryArenaClear(&State->FileNamesArena);
|
||||
|
||||
|
||||
gs_string SanitizedDir = PushString(Context.ThreadContext.Transient, WorkingDirectory.Length + 2);
|
||||
|
@ -90,7 +90,7 @@ FileView_Init(panel* Panel, app_state* State, context Context)
|
|||
// TODO: :FreePanelMemory
|
||||
file_view_state* FileViewState = PushStruct(&State->Permanent, file_view_state);
|
||||
Panel->StateMemory = StructToData(FileViewState, file_view_state);
|
||||
FileViewState->FileNamesArena = CreateMemoryArena(Context.ThreadContext.Allocator, "File View - File Names Arena");
|
||||
FileViewState->FileNamesArena = MemoryArenaCreate(MB(4), Bytes(8), Context.ThreadContext.Allocator, 0, 0, "File View - File Names Arena");
|
||||
|
||||
// TODO(pjs): this shouldn't be stored in permanent
|
||||
FileViewState->DisplayDirectory = PushString(&State->Permanent, 1024);
|
||||
|
|
|
@ -191,12 +191,12 @@ GetMemAmt (u64 BytesCount)
|
|||
internal void
|
||||
RenderProfiler_MemoryView(ui_interface* Interface, ui_widget* Layout, app_state* State, context Context, gs_memory_arena* Memory)
|
||||
{
|
||||
gs_allocator_debug Debug = *Context.ThreadContext.Allocator.Debug;
|
||||
gs_debug_allocations_list* DA = Context.ThreadContext.Allocator.DEBUGAllocList;
|
||||
|
||||
gs_string TempString = PushString(State->Transient, 256);
|
||||
|
||||
mem_amt MemFootprint = GetMemAmt(Debug.TotalAllocSize);
|
||||
u64 AllocCount = Debug.AllocationsCount;
|
||||
|
||||
mem_amt MemFootprint = GetMemAmt(DA->AllocationsSizeTotal);
|
||||
u64 AllocCount = DA->AllocationsCount;
|
||||
|
||||
PrintF(&TempString, "Total Memory Size: %.2f %s | Allocations: %lld", MemFootprint.Size, MemFootprint.Units, AllocCount);
|
||||
ui_Label(Interface, TempString);
|
||||
|
@ -212,16 +212,20 @@ RenderProfiler_MemoryView(ui_interface* Interface, ui_widget* Layout, app_state*
|
|||
}
|
||||
ui_EndRow(Interface);
|
||||
|
||||
ui_BeginList(Interface, MakeString("Alloc List"), 10, Debug.AllocationsCount);
|
||||
ui_BeginList(Interface, MakeString("Alloc List"), 10, DA->AllocationsCount);
|
||||
ui_BeginRow(Interface, 2, &ColumnWidths[0]);
|
||||
for (s32 n = 0; n < Debug.AllocationsCount; n++)
|
||||
{
|
||||
gs_debug_allocation A = Debug.Allocations[n];
|
||||
|
||||
PrintF(&TempString, "%S", A.Location);
|
||||
for (gs_debug_memory_allocation* A = DA->Root;
|
||||
A && A->Next != 0;
|
||||
A = A->Next)
|
||||
{
|
||||
gs_const_string Str = ConstString(A->Loc.File);
|
||||
u64 LastSlash = FindLastFromSet(Str, "\\/");
|
||||
gs_const_string JustFileName = Substring(Str, LastSlash + 1, Str.Length);
|
||||
PrintF(&TempString, "%s:%s(%d)", JustFileName.Str, A->Loc.Function, A->Loc.Line);
|
||||
ui_Label(Interface, TempString);
|
||||
|
||||
mem_amt Amt = GetMemAmt(A.Size);
|
||||
mem_amt Amt = GetMemAmt(A->Size);
|
||||
|
||||
PrintF(&TempString, "%.2f %s", Amt.Size, Amt.Units);
|
||||
ui_Label(Interface, TempString);
|
||||
|
|
|
@ -200,7 +200,7 @@ SculptureView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren
|
|||
u32 NextLEDIndex = 0;
|
||||
for (u32 Job = 0; Job < JobsNeeded; Job++)
|
||||
{
|
||||
gs_data Data = PushSizeToData(State->Transient, sizeof(draw_leds_job_data));
|
||||
gs_data Data = PushSize(State->Transient, sizeof(draw_leds_job_data));
|
||||
draw_leds_job_data* JobData = (draw_leds_job_data*)Data.Memory;
|
||||
JobData->LedBuffer = *LedBuffer;
|
||||
JobData->StartIndex = NextLEDIndex;
|
||||
|
|
|
@ -147,7 +147,7 @@ AnimationSystem_BeginRenderBlockToLedBuffer(animation_system* System, animation_
|
|||
|
||||
for (u32 i = 0; i < JobsCount; i++)
|
||||
{
|
||||
gs_data Data = PushSizeToData(Context.ThreadContext.Transient, sizeof(render_anim_to_led_buffer_job_data));
|
||||
gs_data Data = PushSize(Context.ThreadContext.Transient, sizeof(render_anim_to_led_buffer_job_data));
|
||||
render_anim_to_led_buffer_job_data* JobData = (render_anim_to_led_buffer_job_data*)Data.Memory;
|
||||
JobData->Pattern = Pattern;
|
||||
JobData->Buffer = *Buffer;
|
||||
|
|
|
@ -79,7 +79,7 @@ LedSystem_Create(gs_allocator PlatformMemory, u32 BuffersMax)
|
|||
Result.PlatformMemory = PlatformMemory;
|
||||
// TODO(Peter): Since we have access to PlatformMemory, just realloc Buffers when we fill it up
|
||||
Result.BuffersCountMax = BuffersMax;
|
||||
Result.Buffers = AllocatorAllocArray(PlatformMemory, led_buffer, Result.BuffersCountMax);
|
||||
Result.Buffers = AllocArray(PlatformMemory, led_buffer, Result.BuffersCountMax, "led system");
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
@ -109,9 +109,10 @@ LedSystemTakeFreeBuffer(led_system* System, u32 LedCount)
|
|||
}
|
||||
|
||||
led_buffer* Buffer = &System->Buffers[Result];
|
||||
Buffer->A = MemoryArenaCreate(KB(16),Bytes(8),System->PlatformMemory,0,0,"Led Buffer Arena");
|
||||
Buffer->LedCount = LedCount;
|
||||
Buffer->Colors = AllocatorAllocArray(System->PlatformMemory, pixel, Buffer->LedCount);
|
||||
Buffer->Positions = AllocatorAllocArray(System->PlatformMemory, v4, Buffer->LedCount);
|
||||
Buffer->Colors = PushArray(&Buffer->A, pixel, Buffer->LedCount);
|
||||
Buffer->Positions = PushArray(&Buffer->A, v4, Buffer->LedCount);
|
||||
|
||||
System->LedsCountTotal += LedCount;
|
||||
|
||||
|
@ -123,8 +124,7 @@ LedSystemFreeBuffer(led_system* System, u32 BufferIndex)
|
|||
{
|
||||
Assert(BufferIndex < System->BuffersCountMax);
|
||||
led_buffer* Buffer = &System->Buffers[BufferIndex];
|
||||
AllocatorFreeArray(System->PlatformMemory, Buffer->Colors, pixel, Buffer->LedCount);
|
||||
AllocatorFreeArray(System->PlatformMemory, Buffer->Positions, v4, Buffer->LedCount);
|
||||
MemoryArenaFree(&Buffer->A);
|
||||
System->LedsCountTotal -= Buffer->LedCount;
|
||||
*Buffer = {};
|
||||
}
|
||||
|
@ -209,7 +209,7 @@ LoadAssembly (assembly_array* Assemblies, led_system* LedSystem, gs_memory_arena
|
|||
gs_const_string FileName = Substring(Path, IndexOfLastSlash + 1, Path.Length);
|
||||
|
||||
NewAssembly = AssemblyArray_Take(Assemblies);
|
||||
NewAssembly->Arena = CreateMemoryArena(Context.ThreadContext.Allocator, "Assembly Arena");
|
||||
NewAssembly->Arena = MemoryArenaCreate(MB(4), Bytes(8), Context.ThreadContext.Allocator, 0, 0, "Assembly Arena");
|
||||
|
||||
parser AssemblyParser = ParseAssemblyFile(NewAssembly, FileName, AssemblyFileText, Scratch);
|
||||
if (AssemblyParser.Success)
|
||||
|
@ -218,7 +218,7 @@ LoadAssembly (assembly_array* Assemblies, led_system* LedSystem, gs_memory_arena
|
|||
}
|
||||
else
|
||||
{
|
||||
FreeMemoryArena(&NewAssembly->Arena);
|
||||
MemoryArenaFree(&NewAssembly->Arena);
|
||||
Assemblies->Count -= 1;
|
||||
}
|
||||
|
||||
|
@ -244,7 +244,7 @@ UnloadAssembly (u32 AssemblyIndex, app_state* State, context Context)
|
|||
Assert(AssemblyIndex < State->Assemblies.Count);
|
||||
assembly* Assembly = &State->Assemblies.Values[AssemblyIndex];
|
||||
LedSystemFreeBuffer(&State->LedSystem, Assembly->LedBufferIndex);
|
||||
FreeMemoryArena(&Assembly->Arena);
|
||||
MemoryArenaFree(&Assembly->Arena);
|
||||
AssemblyArray_RemoveAt(&State->Assemblies, AssemblyIndex);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,13 @@ union pixel
|
|||
|
||||
struct led_buffer
|
||||
{
|
||||
// NOTE(PS): This is just a tracking structure,
|
||||
// that enables allocations for a particular buffer
|
||||
// to occur all in contiguous memory
|
||||
// and should not be pushed to after the initial
|
||||
// allocation
|
||||
gs_memory_arena A;
|
||||
|
||||
u32 LedCount;
|
||||
pixel* Colors;
|
||||
v4* Positions;
|
||||
|
|
|
@ -53,7 +53,7 @@ AddressedDataBufferList_Clear(addressed_data_buffer_list* List)
|
|||
{
|
||||
List->Root = 0;
|
||||
List->Head = 0;
|
||||
ClearArena(List->Arena);
|
||||
MemoryArenaClear(List->Arena);
|
||||
}
|
||||
|
||||
internal addressed_data_buffer*
|
||||
|
@ -99,8 +99,8 @@ internal addressed_data_buffer_list
|
|||
AddressedDataBufferList_Create(gs_thread_context TC)
|
||||
{
|
||||
addressed_data_buffer_list Result = {};
|
||||
Result.Arena = AllocatorAllocStruct(TC.Allocator, gs_memory_arena);
|
||||
*Result.Arena = CreateMemoryArena(TC.Allocator, "Addressed Data Buffer List Arena");
|
||||
Result.Arena = AllocStruct(TC.Allocator, gs_memory_arena, "Addressed Data");
|
||||
*Result.Arena = MemoryArenaCreate(KB(256), Bytes(8), TC.Allocator, 0, 0, "Addressed Data Buffer List Arena");
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ struct log_entry
|
|||
|
||||
struct log_buffer
|
||||
{
|
||||
gs_allocator Allocator;
|
||||
gs_memory_arena* Arena;
|
||||
|
||||
u64 EntriesCount;
|
||||
u64 NextEntry;
|
||||
|
@ -33,16 +33,21 @@ struct log_buffer_iter
|
|||
};
|
||||
|
||||
internal log_buffer
|
||||
Log_Init(gs_allocator Allocator, u64 Count)
|
||||
Log_Init(gs_memory_arena* A, u64 Count)
|
||||
{
|
||||
log_buffer Result = {};
|
||||
Result.Allocator = Allocator;
|
||||
Result.Arena = A;
|
||||
Result.EntriesCount = Count;
|
||||
Result.Entries = AllocatorAllocArray(Allocator, log_entry, Result.EntriesCount);
|
||||
Result.Entries = PushArray(A, log_entry, Result.EntriesCount);
|
||||
|
||||
u64 LogStringLength = 512;
|
||||
u64 LogStringBufferSize = LogStringLength * Result.EntriesCount;
|
||||
char* LogStringBuffer = PushArray(A, char, LogStringBufferSize);
|
||||
char* LogStringBufferAt = LogStringBuffer;
|
||||
for (u32 i = 0; i < Result.EntriesCount; i++)
|
||||
{
|
||||
Result.Entries[i].String = AllocatorAllocString(Allocator, 512);
|
||||
Result.Entries[i].String = MakeString(LogStringBufferAt, 0, LogStringLength);
|
||||
LogStringBufferAt += LogStringLength;
|
||||
}
|
||||
|
||||
return Result;
|
||||
|
|
|
@ -13,10 +13,10 @@ UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel Channel
|
|||
// to catch the error where they are different
|
||||
Assert(ChannelSettings.PixelsCount == Strip.LedCount);
|
||||
|
||||
uart_header* Header = PushStructOnCursor(WriteCursor, uart_header);
|
||||
uart_header* Header = MemoryCursorPushStruct(WriteCursor, uart_header);
|
||||
UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812);
|
||||
|
||||
uart_channel* Channel = PushStructOnCursor(WriteCursor, uart_channel);
|
||||
uart_channel* Channel = MemoryCursorPushStruct(WriteCursor, uart_channel);
|
||||
*Channel = ChannelSettings;
|
||||
|
||||
for (u32 i = 0; i < Channel->PixelsCount; i++)
|
||||
|
@ -24,7 +24,7 @@ UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel Channel
|
|||
u32 LedIndex = Strip.LedLUT[i];
|
||||
pixel Color = LedBuffer.Colors[LedIndex];
|
||||
|
||||
u8* OutputPixel = PushArrayOnCursor(WriteCursor, u8, 3);
|
||||
u8* OutputPixel = MemoryCursorPushArray(WriteCursor, u8, 3);
|
||||
|
||||
// TODO(pjs): Use the Output mask
|
||||
#if 1
|
||||
|
@ -46,17 +46,17 @@ UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel Channel
|
|||
}
|
||||
}
|
||||
|
||||
uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer);
|
||||
uart_footer* Footer = MemoryCursorPushStruct(WriteCursor, uart_footer);
|
||||
UART_FillFooter(Footer, (u8*)Header);
|
||||
}
|
||||
|
||||
internal void
|
||||
UART_DrawAll_Create(gs_memory_cursor* WriteCursor)
|
||||
{
|
||||
uart_header* Header = PushStructOnCursor(WriteCursor, uart_header);
|
||||
uart_header* Header = MemoryCursorPushStruct(WriteCursor, uart_header);
|
||||
UART_FillHeader(Header, 1, UART_DRAW_ALL);
|
||||
|
||||
uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer);
|
||||
uart_footer* Footer = MemoryCursorPushStruct(WriteCursor, uart_footer);
|
||||
UART_FillFooter(Footer, (u8*)Header);
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assembli
|
|||
gs_const_string ComPort = At->ComPort;
|
||||
AddressedDataBuffer_SetCOMPort(Buffer, ComPort);
|
||||
|
||||
gs_memory_cursor WriteCursor = CreateMemoryCursor(Buffer->Data);
|
||||
gs_memory_cursor WriteCursor = MemoryCursorCreate(Buffer->Memory, Buffer->MemorySize);
|
||||
|
||||
for (u32 i = 0; i < At->StripIndicesCount; i++)
|
||||
{
|
||||
|
|
|
@ -31,11 +31,11 @@ RELOAD_STATIC_DATA(ReloadStaticData)
|
|||
INITIALIZE_APPLICATION(InitializeApplication)
|
||||
{
|
||||
Context->MemorySize = sizeof(app_state);
|
||||
Context->MemoryBase = AllocatorAlloc(Context->ThreadContext.Allocator, Context->MemorySize).Memory;
|
||||
Context->MemoryBase = Alloc(Context->ThreadContext.Allocator, Context->MemorySize, "Memory Base");
|
||||
app_state* State = (app_state*)Context->MemoryBase;
|
||||
*State = {};
|
||||
|
||||
State->Permanent = CreateMemoryArena(Context->ThreadContext.Allocator, "Permanent");
|
||||
State->Permanent = MemoryArenaCreate(MB(4), Bytes(8), Context->ThreadContext.Allocator,0, 0, "Permanent");
|
||||
State->Transient = Context->ThreadContext.Transient;
|
||||
State->Assemblies = AssemblyArray_Create(8, &State->Permanent);
|
||||
|
||||
|
@ -129,7 +129,7 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
|||
// and need to persist beyond the end of the UpdateAndRender call. In the release version, we won't
|
||||
// zero the Transient arena when we clear it so it wouldn't be a problem, but it is technically
|
||||
// incorrect to clear the arena, and then access the memory later.
|
||||
ClearArena(State->Transient);
|
||||
MemoryArenaClear(State->Transient);
|
||||
Assert(State->UserSpaceDesc.UserData.Memory != 0);
|
||||
|
||||
if (State->RunEditor)
|
||||
|
|
|
@ -117,6 +117,7 @@ struct debug_services
|
|||
debug_interface Interface;
|
||||
|
||||
gs_thread_context Ctx;
|
||||
gs_memory_arena A;
|
||||
|
||||
debug_get_thread_id* GetThreadId;
|
||||
debug_timing_proc* GetWallClock;
|
||||
|
@ -126,13 +127,13 @@ internal void
|
|||
InitializeDebugFrame (debug_frame* Frame, s32 NameHashMax, s32 ThreadCount, s32 ScopeCallsMax, debug_services* Services)
|
||||
{
|
||||
Frame->ScopeNamesMax = NameHashMax;
|
||||
Frame->ScopeNamesHash = AllocatorAllocArray(Services->Ctx.Allocator, scope_name, NameHashMax);
|
||||
Frame->ScopeNamesHash = PushArray(&Services->A, scope_name, NameHashMax);
|
||||
|
||||
// NOTE(Peter): We use the same size as scope names because we're only storing a single instance
|
||||
// per scope. If ScopeNamesMax can't hold all the scopes, this will never get filled and
|
||||
// we should assert and recompile with a resized NameHashMax
|
||||
Frame->CollatedScopesMax = NameHashMax;
|
||||
Frame->CollatedScopes = AllocatorAllocArray(Services->Ctx.Allocator, collated_scope_record, NameHashMax);
|
||||
Frame->CollatedScopes = PushArray(&Services->A, collated_scope_record, NameHashMax);
|
||||
|
||||
for (s32 i = 0; i < Frame->ScopeNamesMax; i++)
|
||||
{
|
||||
|
@ -141,13 +142,13 @@ InitializeDebugFrame (debug_frame* Frame, s32 NameHashMax, s32 ThreadCount, s32
|
|||
}
|
||||
|
||||
Frame->ThreadCount = ThreadCount;
|
||||
Frame->ThreadCalls = AllocatorAllocArray(Services->Ctx.Allocator, debug_scope_record_list, ThreadCount);
|
||||
Frame->ThreadCalls = PushArray(&Services->A, debug_scope_record_list, ThreadCount);
|
||||
|
||||
for (s32 i = 0; i < ThreadCount; i++)
|
||||
{
|
||||
Frame->ThreadCalls[i].Max = ScopeCallsMax;
|
||||
Frame->ThreadCalls[i].Count = 0;
|
||||
Frame->ThreadCalls[i].Calls = AllocatorAllocArray(Services->Ctx.Allocator, scope_record, ScopeCallsMax);
|
||||
Frame->ThreadCalls[i].Calls = PushArray(&Services->A, scope_record, ScopeCallsMax);
|
||||
Frame->ThreadCalls[i].CurrentScopeCallDepth = 0;
|
||||
Frame->ThreadCalls[i].ThreadId = 0;
|
||||
}
|
||||
|
@ -213,9 +214,11 @@ InitDebugServices_DebugMode (debug_services* Services,
|
|||
Services->RecordFrames = true;
|
||||
|
||||
Services->CurrentDebugFrame = 0;
|
||||
Services->A = MemoryArenaCreate(MB(64), Bytes(8), Ctx.Allocator, 0, 0, "Debug Services Allocator");
|
||||
|
||||
s32 NameHashMax = 4096;
|
||||
s32 ScopeCallsMax = 4096;
|
||||
Services->Frames = AllocatorAllocArray(Ctx.Allocator, debug_frame, DEBUG_FRAME_COUNT);
|
||||
Services->Frames = PushArray(&Services->A, debug_frame, DEBUG_FRAME_COUNT);
|
||||
for (s32 i = 0; i < DEBUG_FRAME_COUNT; i++)
|
||||
{
|
||||
InitializeDebugFrame(&Services->Frames[i], NameHashMax, ThreadCount, ScopeCallsMax, Services);
|
||||
|
@ -408,8 +411,8 @@ PushScopeTimeOnFrame (debug_services* Services, s32 NameHash, u64 StartCycles, u
|
|||
if (ThreadList->Count >= ThreadList->Max)
|
||||
{
|
||||
s32 NewMax = (ThreadList->Max + DEBUG_FRAME_GROW_SIZE);
|
||||
AllocatorFreeArray(Services->Ctx.Allocator, ThreadList->Calls, scope_record, ThreadList->Max);
|
||||
ThreadList->Calls = AllocatorAllocArray(Services->Ctx.Allocator, scope_record, NewMax);
|
||||
FreeArray(Services->Ctx.Allocator, ThreadList->Calls, scope_record, ThreadList->Max);
|
||||
ThreadList->Calls = AllocArray(Services->Ctx.Allocator, scope_record, NewMax, "Debug Frame");
|
||||
ThreadList->Max = NewMax;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ AllocateRenderCommandBuffer(u32 MemorySize,
|
|||
gs_memory_arena* Arena,
|
||||
gs_thread_context Ctx)
|
||||
{
|
||||
u8* Memory = PushSize(Arena, MemorySize);
|
||||
u8* Memory = PushSize(Arena, MemorySize).Memory;
|
||||
return AllocateRenderCommandBuffer(Memory, MemorySize, Ctx);
|
||||
}
|
||||
|
||||
|
|
|
@ -265,8 +265,8 @@ ResizeBufferIfNecessary(render_command_buffer* Buffer, s32 DataSize)
|
|||
s32 AdditionSize = Max(SpaceNeeded, COMMAND_BUFFER_MIN_GROW_SIZE);
|
||||
s32 NewSize = Buffer->CommandMemorySize + AdditionSize;
|
||||
|
||||
AllocatorFree(Buffer->Ctx.Allocator, Buffer->CommandMemory, Buffer->CommandMemorySize);
|
||||
Buffer->CommandMemory = AllocatorAlloc(Buffer->Ctx.Allocator, NewSize).Memory;
|
||||
Free(Buffer->Ctx.Allocator, Buffer->CommandMemory, Buffer->CommandMemorySize);
|
||||
Buffer->CommandMemory = Alloc(Buffer->Ctx.Allocator, NewSize, "Renderer");
|
||||
Buffer->CommandMemorySize = NewSize;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -585,14 +585,15 @@ WinMain (
|
|||
)
|
||||
{
|
||||
gs_thread_context ThreadContext = Win32CreateThreadContext();
|
||||
GlobalLogBuffer = AllocatorAllocStruct(ThreadContext.Allocator, log_buffer);
|
||||
*GlobalLogBuffer = Log_Init(ThreadContext.Allocator, 32);
|
||||
|
||||
gs_allocator_debug AllocDebug = {};
|
||||
AllocDebug.AllocationsCountMax = 4096;
|
||||
AllocDebug.Allocations = AllocatorAllocArray(ThreadContext.Allocator, gs_debug_allocation, AllocDebug.AllocationsCountMax);
|
||||
gs_memory_arena PlatformPermanent = MemoryArenaCreate(MB(4),
|
||||
Bytes(8), ThreadContext.Allocator,
|
||||
0,
|
||||
0,
|
||||
"Platform Memory");
|
||||
|
||||
ThreadContext.Allocator.Debug = &AllocDebug;
|
||||
GlobalLogBuffer = AllocStruct(ThreadContext.Allocator, log_buffer, "Global Log Buffer");
|
||||
*GlobalLogBuffer = Log_Init(&PlatformPermanent, 32);
|
||||
|
||||
if (!SetWorkingDirectory(HInstance, ThreadContext)) return 1;
|
||||
|
||||
|
@ -619,8 +620,6 @@ WinMain (
|
|||
CreateOpenGLWindowContext(OpenGLWindowInfo, &MainWindow);
|
||||
}
|
||||
|
||||
gs_memory_arena PlatformPermanent = CreateMemoryArena(Context.ThreadContext.Allocator, "Platform Memory");
|
||||
|
||||
s64 PerformanceCountFrequency = GetPerformanceFrequency();
|
||||
s64 LastFrameEnd = GetWallClock();
|
||||
r32 TargetSecondsPerFrame = 1 / 30.0f;
|
||||
|
@ -667,7 +666,7 @@ WinMain (
|
|||
|
||||
Win32SocketSystem_Init(&PlatformPermanent);
|
||||
|
||||
Win32SerialArray_Create(ThreadContext);
|
||||
Win32SerialArray_Create(&PlatformPermanent);
|
||||
|
||||
render_command_buffer RenderBuffer = {};
|
||||
if (!Context.Headless)
|
||||
|
|
|
@ -122,7 +122,7 @@ InitializeDLLHotReloading(char* SourceDLLName,
|
|||
Win32DLLgs_stringLength(LockFileName), LockFileName,
|
||||
MAX_PATH, Result.LockFilePath);
|
||||
|
||||
Win32Free((u8*)ExePath.Path, ExePath.PathLength);
|
||||
Win32Free((u8*)ExePath.Path, ExePath.PathLength, 0);
|
||||
return Result;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,36 +1,26 @@
|
|||
//
|
||||
// File: win32_foldhaus_memory.h
|
||||
// Author: Peter Slattery
|
||||
// Creation Date: 2020-02-04
|
||||
//
|
||||
//
|
||||
// NOTE: Relies on having imported foldhaus_platform.h prior to this file
|
||||
//
|
||||
#ifndef WIN32_FOLDHAUS_MEMORY_H
|
||||
/* date = May 10th 2021 11:48 pm */
|
||||
|
||||
ALLOCATOR_ALLOC(Win32Alloc)
|
||||
#ifndef GS_MEMORY_WIN32_H
|
||||
#define GS_MEMORY_WIN32_H
|
||||
|
||||
PLATFORM_ALLOC(Win32Alloc)
|
||||
{
|
||||
u8* Result = (u8*)VirtualAlloc(NULL, Size,
|
||||
MEM_COMMIT | MEM_RESERVE,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
if (ResultSize != 0)
|
||||
{
|
||||
*ResultSize = Size;
|
||||
}
|
||||
if (ResultSize) *ResultSize = Size;
|
||||
return Result;
|
||||
}
|
||||
|
||||
ALLOCATOR_FREE(Win32Free)
|
||||
PLATFORM_FREE(Win32Free)
|
||||
{
|
||||
b32 Result = VirtualFree(Ptr, 0, MEM_RELEASE);
|
||||
if (!Result)
|
||||
{
|
||||
s32 Error = GetLastError();
|
||||
// TODO(Peter): I'm waiting to see an error actually occur here
|
||||
// to know what it could possibly be.
|
||||
InvalidCodePath;
|
||||
}
|
||||
VirtualFree(Base, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
#define WIN32_FOLDHAUS_MEMORY_H
|
||||
#endif // WIN32_FOLDHAUS_MEMORY_H
|
||||
internal gs_allocator
|
||||
CreatePlatformAllocator()
|
||||
{
|
||||
return AllocatorCreate(Win32Alloc, Win32Free, 0);
|
||||
}
|
||||
|
||||
#endif //GS_MEMORY_WIN32_H
|
||||
|
|
|
@ -82,7 +82,7 @@ Win32SerialPorts_List(gs_memory_arena* Arena, gs_memory_arena* Transient)
|
|||
|
||||
DWORD SizeNeeded1 = 0;
|
||||
DWORD CountReturned1 = 0;
|
||||
PORT_INFO_1* PortsArray = (PORT_INFO_1*)PushSize(Transient, SizeNeeded0);
|
||||
PORT_INFO_1* PortsArray = (PORT_INFO_1*)PushSize(Transient, SizeNeeded0).Memory;
|
||||
if (EnumPorts(NULL,
|
||||
1,
|
||||
(u8*)PortsArray,
|
||||
|
@ -275,19 +275,19 @@ Win32SerialPort_ReadMessageWhenReady(HANDLE PortHandle, gs_data Data)
|
|||
// Win32SerialArray
|
||||
|
||||
void
|
||||
Win32SerialArray_Create(gs_thread_context Context)
|
||||
Win32SerialArray_Create(gs_memory_arena* A)
|
||||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
|
||||
Win32SerialHandlesCountMax = 32;
|
||||
|
||||
Win32SerialHandles = AllocatorAllocArray(Context.Allocator, HANDLE, Win32SerialHandlesCountMax);
|
||||
Win32SerialPortNames = AllocatorAllocArray(Context.Allocator, gs_string, Win32SerialHandlesCountMax);
|
||||
Win32SerialPortFilled = AllocatorAllocArray(Context.Allocator, s32, Win32SerialHandlesCountMax);
|
||||
Win32SerialHandles = PushArray(A, HANDLE, Win32SerialHandlesCountMax);
|
||||
Win32SerialPortNames = PushArray(A, gs_string, Win32SerialHandlesCountMax);
|
||||
Win32SerialPortFilled = PushArray(A, s32, Win32SerialHandlesCountMax);
|
||||
|
||||
u64 PortNameSize = 256;
|
||||
u64 PortNameBufferSize = PortNameSize * Win32SerialHandlesCountMax;
|
||||
char* PortNameBuffer = AllocatorAllocArray(Context.Allocator, char, PortNameBufferSize);
|
||||
char* PortNameBuffer = PushArray(A, char, PortNameBufferSize);
|
||||
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
|
||||
{
|
||||
char* NameBase = PortNameBuffer + (PortNameSize * i);
|
||||
|
|
|
@ -197,7 +197,7 @@ Win32ConnectSocket(platform_socket_manager* Manager, platform_socket* Socket)
|
|||
}
|
||||
}
|
||||
|
||||
Socket->PlatformHandle = (u8*)Win32Alloc(sizeof(SOCKET), 0);
|
||||
Socket->PlatformHandle = (u8*)Win32Alloc(sizeof(SOCKET), 0, 0);
|
||||
*(SOCKET*)Socket->PlatformHandle = SocketHandle;
|
||||
Result = true;
|
||||
break;
|
||||
|
@ -223,7 +223,7 @@ Win32CloseSocket(platform_socket_manager* Manager, platform_socket* Socket)
|
|||
{
|
||||
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
|
||||
closesocket(*Win32Sock);
|
||||
Win32Free((u8*)Socket->PlatformHandle, sizeof(SOCKET));
|
||||
Win32Free((u8*)Socket->PlatformHandle, sizeof(SOCKET), 0);
|
||||
*Socket = {};
|
||||
return true;
|
||||
}
|
||||
|
@ -299,7 +299,7 @@ Win32SocketReceive(platform_socket_manager* Manager, platform_socket* Socket, gs
|
|||
}
|
||||
return Result;
|
||||
#else
|
||||
gs_data Result = PushSizeToData(Storage, 1024);
|
||||
gs_data Result = PushSize(Storage, 1024);
|
||||
s32 Flags = 0;
|
||||
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
|
||||
s32 BytesReceived = recv(*Win32Sock, (char*)Result.Memory, Result.Size, Flags);
|
||||
|
@ -465,7 +465,7 @@ Win32Socket_Receive(win32_socket* Socket, gs_memory_arena* Storage)
|
|||
}
|
||||
return Result;
|
||||
#else
|
||||
gs_data Result = PushSizeToData(Storage, 1024);
|
||||
gs_data Result = PushSize(Storage, 1024);
|
||||
s32 Flags = 0;
|
||||
s32 BytesReceived = recv(Socket->Socket, (char*)Result.Memory, Result.Size, Flags);
|
||||
if (BytesReceived == SOCKET_ERROR)
|
||||
|
|
|
@ -40,15 +40,15 @@ Win32CreateThreadContext(gs_memory_arena* Transient = 0)
|
|||
{
|
||||
gs_thread_context Result = {0};
|
||||
Result.ThreadInfo.ThreadID = Win32GetThreadId();
|
||||
Result.Allocator = CreateAllocator(Win32Alloc, Win32Free);
|
||||
Result.Allocator = CreatePlatformAllocator();
|
||||
if (Transient != 0)
|
||||
{
|
||||
Result.Transient = Transient;
|
||||
}
|
||||
else
|
||||
{
|
||||
Result.Transient = (gs_memory_arena*)AllocatorAlloc(Result.Allocator, sizeof(gs_memory_arena)).Memory;
|
||||
*Result.Transient = CreateMemoryArena(Result.Allocator, "Tctx Transient");
|
||||
Result.Transient = AllocStruct(Result.Allocator, gs_memory_arena, "Work Queue");
|
||||
*Result.Transient = MemoryArenaCreate(MB(4), Bytes(8), Result.Allocator, 0, 0, "Tctx Transient");
|
||||
}
|
||||
Result.FileHandler = CreateFileHandler(Win32GetFileInfo,
|
||||
Win32ReadEntireFile,
|
||||
|
@ -145,7 +145,7 @@ WorkerThreadProc (LPVOID InputThreadInfo)
|
|||
Entry.IsValid = false;
|
||||
while (true)
|
||||
{
|
||||
ClearArena(ThreadInfo->ThreadContext.Transient);
|
||||
MemoryArenaClear(ThreadInfo->ThreadContext.Transient);
|
||||
Entry = CompleteAndTakeNextJob(ThreadInfo->Queue, Entry, ThreadInfo->ThreadContext);
|
||||
if (Entry.IsValid)
|
||||
{
|
||||
|
@ -182,7 +182,7 @@ CREATE_THREAD(Win32CreateThread)
|
|||
Thread->UserData = UserData;
|
||||
|
||||
// TODO(pjs): ugh, allocation out in the middle of nowhere
|
||||
HANDLE* ThreadHandle = AllocatorAllocStruct(Ctx.Allocator, HANDLE);
|
||||
HANDLE* ThreadHandle = AllocStruct(Ctx.Allocator, HANDLE, "Create Thread");
|
||||
*ThreadHandle = CreateThread(0, 0, Win32ThreadProcWrapper, (void*)Thread, 0, 0);
|
||||
// TODO(pjs): Error checking on the created thread
|
||||
|
||||
|
@ -197,7 +197,7 @@ KILL_THREAD(Win32KillThread)
|
|||
TerminateThread(ThreadHandle, 0);
|
||||
|
||||
// TODO(pjs): see allocation out in the middle of nowhere in Win32CreateThread
|
||||
Win32Free((void*)Thread->PlatformHandle, sizeof(HANDLE));
|
||||
Win32Free((void*)Thread->PlatformHandle, sizeof(HANDLE), 0);
|
||||
|
||||
// TODO(pjs): Error checking
|
||||
return true;
|
||||
|
|
|
@ -369,7 +369,7 @@ BlumenLumen_CustomInit(app_state* State, context Context)
|
|||
// the sculpture's CustomUpdate function;
|
||||
gs_data Result = {};
|
||||
|
||||
Result = PushSizeToData(&State->Permanent, sizeof(blumen_lumen_state));
|
||||
Result = PushSize(&State->Permanent, sizeof(blumen_lumen_state));
|
||||
|
||||
blumen_lumen_state* BLState = (blumen_lumen_state*)Result.Memory;
|
||||
BLState->Running = true;
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
internal void
|
||||
MessageQueue_Init(blumen_network_msg_queue* Queue, gs_memory_arena* Arena)
|
||||
{
|
||||
gs_data MessageQueueData = PushSize(Arena, DEFAULT_QUEUE_ENTRY_SIZE * BLUMEN_MESSAGE_QUEUE_COUNT);
|
||||
gs_memory_cursor C = MemoryCursorCreateFromData(MessageQueueData);
|
||||
|
||||
for (u32 i = 0; i < BLUMEN_MESSAGE_QUEUE_COUNT; i++)
|
||||
{
|
||||
Queue->Buffers[i] = PushSizeToData(Arena, DEFAULT_QUEUE_ENTRY_SIZE);
|
||||
Queue->Buffers[i] = MemoryCursorPushSize(&C, DEFAULT_QUEUE_ENTRY_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -293,7 +293,7 @@ InputQueue_Create(gs_memory_arena* Arena, u32 CountMax)
|
|||
if (CountMax > 0)
|
||||
{
|
||||
s32 Size = sizeof(input_entry) * 32;
|
||||
u8* Memory = PushSize(Arena, Size);
|
||||
u8* Memory = PushSize(Arena, Size).Memory;
|
||||
Result = InputQueue_Create(Memory, Size);
|
||||
}
|
||||
return Result;
|
||||
|
|
|
@ -0,0 +1,528 @@
|
|||
/* date = May 10th 2021 10:19 pm */
|
||||
|
||||
#ifndef GS_MEMORY_H
|
||||
#define GS_MEMORY_H
|
||||
|
||||
#if !defined(Assert)
|
||||
# define Assert(c)
|
||||
#endif
|
||||
|
||||
#if !defined(InvalidCodePath)
|
||||
# define InvalidCodePath
|
||||
#endif
|
||||
|
||||
#if !defined(GS_MEMORY_PROFILE_FUNC)
|
||||
# define GS_MEMORY_PROFILE_FUNC
|
||||
#endif
|
||||
|
||||
#define MemoryClearArray(b,t,s) MemoryClear((u8*)(b), sizeof(t) * (s))
|
||||
internal void
|
||||
MemoryClear(u8* Base, u64 Size)
|
||||
{
|
||||
for (u64 i = 0; i < Size; i++) Base[i] = 0;
|
||||
}
|
||||
|
||||
#ifndef DEBUG_LOC
|
||||
|
||||
typedef struct gs_debug_loc
|
||||
{
|
||||
char* File;
|
||||
char* Function;
|
||||
u32 Line;
|
||||
} gs_debug_loc;
|
||||
|
||||
# define DEBUG_LOC gs_debug_loc{ (char*)__FILE__, (char*)__FUNCTION__, __LINE__ }
|
||||
|
||||
#endif
|
||||
//
|
||||
// Debug Info
|
||||
//
|
||||
|
||||
typedef struct gs_debug_memory_allocation
|
||||
{
|
||||
gs_debug_loc Loc;
|
||||
u64 ArenaHash;
|
||||
u64 Size;
|
||||
|
||||
struct gs_debug_memory_allocation* Next;
|
||||
} gs_debug_memory_allocation;
|
||||
|
||||
typedef struct gs_debug_arena_info
|
||||
{
|
||||
char* ArenaName;
|
||||
u64 AllocationsCount;
|
||||
u64 TotalSize;
|
||||
} gs_debug_arena_info;
|
||||
|
||||
typedef struct gs_debug_allocations_list
|
||||
{
|
||||
gs_debug_memory_allocation* Root;
|
||||
gs_debug_memory_allocation* Head;
|
||||
u64 AllocationsSizeTotal;
|
||||
u64 AllocationsCount;
|
||||
|
||||
u64 ArenaHashesCount;
|
||||
u64* ArenaHashes;
|
||||
gs_debug_arena_info* ArenaInfos;
|
||||
} gs_debug_allocations_list;
|
||||
|
||||
//
|
||||
// Allocator
|
||||
//
|
||||
|
||||
#define PLATFORM_ALLOC(name) void* name(u64 Size, u64* ResultSize, u8* UserData)
|
||||
typedef PLATFORM_ALLOC(platform_alloc);
|
||||
|
||||
#define PLATFORM_FREE(name) void name(void* Base, u64 Size, u8* UserData)
|
||||
typedef PLATFORM_FREE(platform_free);
|
||||
|
||||
typedef struct gs_allocator
|
||||
{
|
||||
platform_alloc* PAlloc;
|
||||
platform_free* PFree;
|
||||
u8* UserData;
|
||||
|
||||
gs_debug_allocations_list* DEBUGAllocList;
|
||||
} gs_allocator;
|
||||
|
||||
PLATFORM_ALLOC(AllocNoOp)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
if (ResultSize) *ResultSize = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
PLATFORM_FREE(FreeNoOp)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
return;
|
||||
}
|
||||
|
||||
internal u64
|
||||
GSMemoryHash(char* Str, u64 Len)
|
||||
{
|
||||
u64 Hash = 5381;
|
||||
for (u32 i = 0; i < Len; i++)
|
||||
{
|
||||
Hash = ((Hash << 5) + Hash) + Str[i];
|
||||
}
|
||||
return Hash;
|
||||
}
|
||||
|
||||
#define Alloc(a,s,an) Alloc_((a),(s),DEBUG_LOC, (char*)(an)).Memory
|
||||
#define AllocStruct(a,t,an) (t*)Alloc_((a),sizeof(t),DEBUG_LOC, (char*)(an)).Memory
|
||||
#define AllocArray(a,t,c,an) (t*)Alloc_((a),sizeof(t)*(c),DEBUG_LOC, (char*)(an)).Memory
|
||||
#define AllocData(a,s,an) Alloc_((a),(s),DEBUG_LOC, (char*)(an))
|
||||
|
||||
internal gs_data
|
||||
Alloc_(gs_allocator A, u64 Size, gs_debug_loc Loc, char* ArenaName)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
gs_data Result = {};
|
||||
Result.Memory = (u8*)A.PAlloc(Size, &Result.Size, A.UserData);
|
||||
|
||||
// Debug
|
||||
{
|
||||
u64 ArenaHash = GSMemoryHash(ArenaName, CStringLength(ArenaName));
|
||||
|
||||
gs_debug_memory_allocation* Allocation = (gs_debug_memory_allocation*)A.PAlloc(sizeof(gs_debug_memory_allocation*), 0, A.UserData);
|
||||
Allocation->Loc = Loc;
|
||||
Allocation->Size = Size;
|
||||
Allocation->ArenaHash = ArenaHash;
|
||||
SLLPushOrInit(A.DEBUGAllocList->Root, A.DEBUGAllocList->Head, Allocation);
|
||||
|
||||
A.DEBUGAllocList->AllocationsSizeTotal += Size;
|
||||
A.DEBUGAllocList->AllocationsCount += 1;
|
||||
|
||||
u64 ArenaStartIndex = ArenaHash % A.DEBUGAllocList->ArenaHashesCount;
|
||||
u64 ArenaIndex = ArenaStartIndex;
|
||||
while (A.DEBUGAllocList->ArenaHashes[ArenaIndex] != 0 &&
|
||||
A.DEBUGAllocList->ArenaHashes[ArenaIndex] != ArenaHash)
|
||||
{
|
||||
ArenaIndex = (ArenaIndex + 1) % A.DEBUGAllocList->ArenaHashesCount;
|
||||
|
||||
// NOTE(PS): this means you've created enough arena's to fill up every
|
||||
// slot in the arena hash table. Go increase the size of of DEBUG_ALLOCATOR_ARENA_MAX
|
||||
Assert(ArenaIndex != ArenaStartIndex);
|
||||
}
|
||||
|
||||
if (A.DEBUGAllocList->ArenaHashes[ArenaIndex] == 0)
|
||||
{
|
||||
A.DEBUGAllocList->ArenaHashes[ArenaIndex] = ArenaHash;
|
||||
|
||||
gs_debug_arena_info AI = {};
|
||||
AI.ArenaName = ArenaName;
|
||||
A.DEBUGAllocList->ArenaInfos[ArenaIndex] = AI;
|
||||
}
|
||||
|
||||
A.DEBUGAllocList->ArenaInfos[ArenaIndex].AllocationsCount += 1;
|
||||
A.DEBUGAllocList->ArenaInfos[ArenaIndex].TotalSize += Size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
#define AllocString(a,s,l) AllocString_((a), (s), DEBUG_LOC, (l))
|
||||
internal gs_string
|
||||
AllocString_(gs_allocator A, u64 Size, gs_debug_loc Loc, char* LocString)
|
||||
{
|
||||
gs_string Result = {};
|
||||
Result.Str = (char*)Alloc_(A, sizeof(char)*Size, Loc, LocString).Memory;
|
||||
Result.Length = 0;
|
||||
Result.Size = Size;
|
||||
return Result;
|
||||
}
|
||||
|
||||
#define Free(a,b,s) Free_((a),(b),(s),DEBUG_LOC)
|
||||
#define FreeStruct(a,b,t) Free_((a),(u8*)(b),sizeof(t),DEBUG_LOC)
|
||||
#define FreeArray(a,b,t,c) Free_((a),(u8*)(b),sizeof(t)*(c),DEBUG_LOC)
|
||||
internal void
|
||||
Free_(gs_allocator A, u8* Base, u64 Size, gs_debug_loc Loc)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
A.PFree(Base, Size, A.UserData);
|
||||
}
|
||||
|
||||
// NOTE(PS): cast function and struct pointers to proper data types
|
||||
// for convenience
|
||||
#define AllocatorCreate(a,f,u) AllocatorCreate_((platform_alloc*)(a),(platform_free*)(f),(u8*)(u))
|
||||
internal gs_allocator
|
||||
AllocatorCreate_(platform_alloc* PAlloc, platform_free* PFree, u8* UserData)
|
||||
{
|
||||
gs_allocator Result = {};
|
||||
Result.PAlloc = PAlloc;
|
||||
Result.PFree = PFree;
|
||||
Result.UserData = UserData;
|
||||
|
||||
if (!PAlloc) Result.PAlloc = AllocNoOp;
|
||||
if (!PFree) Result.PFree = FreeNoOp;
|
||||
|
||||
// @DEBUG
|
||||
#define DEBUG_ALLOCATOR_ARENA_MAX 256
|
||||
Result.DEBUGAllocList = (gs_debug_allocations_list*)PAlloc(sizeof(gs_debug_allocations_list*), 0, UserData);
|
||||
|
||||
Result.DEBUGAllocList->ArenaHashesCount = DEBUG_ALLOCATOR_ARENA_MAX;
|
||||
Result.DEBUGAllocList->ArenaHashes = (u64*)PAlloc(sizeof(u64*) * DEBUG_ALLOCATOR_ARENA_MAX, 0, UserData);
|
||||
Result.DEBUGAllocList->ArenaInfos = (gs_debug_arena_info*)PAlloc(sizeof(gs_debug_arena_info) * DEBUG_ALLOCATOR_ARENA_MAX, 0, UserData);
|
||||
return Result;
|
||||
}
|
||||
|
||||
//
|
||||
// Memory Cursor
|
||||
//
|
||||
|
||||
typedef struct gs_memory_cursor
|
||||
{
|
||||
gs_data Data;
|
||||
u64 Position;
|
||||
} gs_memory_cursor;
|
||||
|
||||
internal gs_memory_cursor
|
||||
MemoryCursorCreate(u8* Base, u64 Size)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
gs_memory_cursor Result = {};
|
||||
Result.Data.Memory = Base;
|
||||
Result.Data.Size = Size;
|
||||
Result.Position = 0;
|
||||
|
||||
return Result;
|
||||
}
|
||||
internal gs_memory_cursor
|
||||
MemoryCursorCreateFromData(gs_data Data)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
return MemoryCursorCreate(Data.Memory, Data.Size);
|
||||
}
|
||||
|
||||
internal u64
|
||||
MemoryCursorRoomLeft(gs_memory_cursor Cursor)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
u64 Result = 0;
|
||||
if (Cursor.Data.Size >= Cursor.Position)
|
||||
{
|
||||
Result = Cursor.Data.Size - Cursor.Position;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal bool
|
||||
MemoryCursorHasRoom(gs_memory_cursor Cursor)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
u64 RoomLeft = MemoryCursorRoomLeft(Cursor);
|
||||
bool Result = RoomLeft > 0;
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal bool
|
||||
MemoryCursorCanPush(gs_memory_cursor Cursor, u64 Size)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
u64 RoomLeft = MemoryCursorRoomLeft(Cursor);
|
||||
bool Result = RoomLeft >= Size;
|
||||
return Result;
|
||||
}
|
||||
|
||||
#define MemoryCursorPushSize(c,s) MemoryCursorPushSize_((c),(s))
|
||||
#define MemoryCursorPushStruct(c,s) (s*)MemoryCursorPushSize_((c),sizeof(s)).Memory
|
||||
#define MemoryCursorPushArray(c,s,l) (s*)MemoryCursorPushSize_((c),sizeof(s)*(l)).Memory
|
||||
internal gs_data
|
||||
MemoryCursorPushSize_(gs_memory_cursor* C, u64 Size)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
gs_data Result = {0};
|
||||
if (MemoryCursorCanPush(*C, Size))
|
||||
{
|
||||
Result.Memory = C->Data.Memory + C->Position;
|
||||
Result.Size = Size,
|
||||
C->Position += Size;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal gs_data
|
||||
MemoryCursorAlign(gs_memory_cursor* C, u64 Alignment)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
u64 Position = RoundUpTo64(C->Position, Alignment);
|
||||
if (Position > C->Data.Size)
|
||||
{
|
||||
Position = C->Data.Size;
|
||||
}
|
||||
u64 AlignmentDist = Position - C->Position;
|
||||
gs_data Result = MemoryCursorPushSize_(C, AlignmentDist);
|
||||
return Result;
|
||||
}
|
||||
|
||||
#define MemoryCursorWriteValue(c,t,v) *PushStructOnCursor((c),(t)) = (v)
|
||||
internal void
|
||||
MemoryCursorWriteBuffer(gs_memory_cursor* C, gs_data Buffer)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
gs_data Dest = MemoryCursorPushSize(C, Buffer.Size);
|
||||
if (Dest.Size == Buffer.Size)
|
||||
{
|
||||
CopyMemoryTo(Buffer.Memory, Dest.Memory, Buffer.Size);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
MemoryCursorPopSize(gs_memory_cursor* C, u64 Size)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
u64 SizeToPop = Size;
|
||||
if (SizeToPop > C->Position)
|
||||
{
|
||||
SizeToPop = C->Position;
|
||||
}
|
||||
|
||||
C->Position -= SizeToPop;
|
||||
}
|
||||
|
||||
internal void
|
||||
MemoryCursorReset(gs_memory_cursor* C)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
C->Position = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Memory Arena
|
||||
//
|
||||
|
||||
typedef struct gs_memory_cursor_sll
|
||||
{
|
||||
gs_memory_cursor Cursor;
|
||||
struct gs_memory_cursor_sll* Next;
|
||||
} gs_memory_cursor_sll;
|
||||
|
||||
typedef struct gs_memory_arena
|
||||
{
|
||||
u64 ChunkSize;
|
||||
u64 Alignment;
|
||||
char* ArenaName;
|
||||
|
||||
gs_memory_cursor_sll* CursorsRoot;
|
||||
gs_memory_cursor_sll* CursorsHead;
|
||||
|
||||
struct gs_memory_arena* Parent;
|
||||
gs_allocator Allocator;
|
||||
u8* UserData;
|
||||
// TODO: some sort of GrowArena function
|
||||
} gs_memory_arena;
|
||||
|
||||
internal gs_memory_arena
|
||||
MemoryArenaCreate(u64 ChunkSize, u64 Alignment, gs_allocator Allocator, gs_memory_arena* Parent, u8* UserData, char* Name)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
gs_memory_arena Result = {};
|
||||
Result.ChunkSize = ChunkSize;
|
||||
Result.Alignment = Alignment;
|
||||
Result.Allocator = Allocator;
|
||||
Result.Parent = Parent;
|
||||
Result.UserData = UserData;
|
||||
Result.ArenaName = Name;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal gs_data PushSize_(gs_memory_arena* Arena, u64 Size, gs_debug_loc Loc);
|
||||
|
||||
internal gs_memory_cursor*
|
||||
MemoryArenaPushCursor(gs_memory_arena* Arena, u64 MinSize, gs_debug_loc Loc)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
gs_memory_cursor* Result = 0;
|
||||
|
||||
u64 CursorSize = MinSize;
|
||||
if (CursorSize < Arena->ChunkSize)
|
||||
{
|
||||
CursorSize = Arena->ChunkSize;
|
||||
}
|
||||
u64 AllocSize = CursorSize + sizeof(gs_memory_cursor_sll);
|
||||
|
||||
gs_data CursorMemory = {0};
|
||||
if (Arena->Parent)
|
||||
{
|
||||
CursorMemory = PushSize_(Arena->Parent, AllocSize, Loc);
|
||||
} else if (Arena->UserData) {
|
||||
// TODO(PS): implement custom MemoryArenaAllocCursor functionality
|
||||
InvalidCodePath;
|
||||
} else {
|
||||
Assert(Arena->Allocator.PAlloc);
|
||||
CursorMemory = Alloc_(Arena->Allocator, AllocSize, Loc, Arena->ArenaName);
|
||||
}
|
||||
|
||||
gs_memory_cursor_sll* CursorEntry = (gs_memory_cursor_sll*)CursorMemory.Memory;
|
||||
if (!Arena->CursorsRoot)
|
||||
{
|
||||
Arena->CursorsRoot = CursorEntry;
|
||||
}
|
||||
if (Arena->CursorsHead)
|
||||
{
|
||||
Arena->CursorsHead->Next = CursorEntry;
|
||||
}
|
||||
Arena->CursorsHead = CursorEntry;
|
||||
|
||||
u8* CursorBase = (u8*)(CursorEntry + 1);
|
||||
CursorEntry->Cursor = MemoryCursorCreate(CursorBase, CursorSize);
|
||||
Result = &CursorEntry->Cursor;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
#define PushSize(a,s) PushSize_((a), (s), DEBUG_LOC)
|
||||
#define PushStruct(a,t) (t*)PushSize_((a), sizeof(t), DEBUG_LOC).Memory
|
||||
#define PushArray(a,t,c) (t*)PushSize_((a), sizeof(t) * (c), DEBUG_LOC).Memory
|
||||
#define PushString(a,c) gs_string{ PushArray((a),char,(c)), 0, (c) }
|
||||
|
||||
internal gs_data
|
||||
PushSize_(gs_memory_arena* Arena, u64 Size, gs_debug_loc Loc)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
gs_data Result = {0};
|
||||
if (Size > 0)
|
||||
{
|
||||
gs_memory_cursor* Cursor = 0;
|
||||
for (gs_memory_cursor_sll* C = Arena->CursorsRoot;
|
||||
C != 0;
|
||||
C = C->Next)
|
||||
{
|
||||
if (MemoryCursorCanPush(C->Cursor, Size))
|
||||
{
|
||||
Cursor = &C->Cursor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(PS): We didn't find a cursor with enough room
|
||||
// for the allocation being requested
|
||||
if (!Cursor)
|
||||
{
|
||||
Cursor = MemoryArenaPushCursor(Arena, Size, Loc);
|
||||
}
|
||||
Assert(Cursor);
|
||||
Assert(MemoryCursorCanPush(*Cursor, Size));
|
||||
|
||||
Result = MemoryCursorPushSize(Cursor, Size);
|
||||
|
||||
gs_data Alignment = MemoryCursorAlign(Cursor, Arena->Alignment);
|
||||
Result.Size += Alignment.Size;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal void
|
||||
MemoryArenaClear(gs_memory_arena* Arena)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
for (gs_memory_cursor_sll* C = Arena->CursorsRoot;
|
||||
C != 0;
|
||||
C = C->Next)
|
||||
{
|
||||
MemoryCursorReset(&C->Cursor);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
MemoryArenaFree(gs_memory_arena* Arena)
|
||||
{
|
||||
GS_MEMORY_PROFILE_FUNC;
|
||||
|
||||
// NOTE(PS): If this isn't a base arena, we can't
|
||||
// really free it.
|
||||
// TODO(PS): Once we have the User Specified codepaths
|
||||
// in, we can probably provide a way for the user to
|
||||
// let us free a custom allocator
|
||||
Assert(Arena->Allocator.PFree);
|
||||
|
||||
gs_allocator A = Arena->Allocator;
|
||||
gs_memory_cursor_sll* At = Arena->CursorsRoot;
|
||||
while (At)
|
||||
{
|
||||
gs_memory_cursor_sll* NextAt = At->Next;
|
||||
|
||||
u64 Size = At->Cursor.Data.Size + sizeof(gs_memory_cursor_sll);
|
||||
Free(A, (u8*)At, Size);
|
||||
|
||||
At = NextAt;
|
||||
}
|
||||
|
||||
Arena->CursorsRoot = 0;
|
||||
Arena->CursorsHead = 0;
|
||||
}
|
||||
|
||||
#ifdef GS_PLATFORM_IMPLEMENTATION
|
||||
|
||||
internal gs_allocator CreatePlatformAllocator();
|
||||
|
||||
# if PLATFORM_WINDOWS
|
||||
# include "./gs_memory_win32.h"
|
||||
# elif PLATFORM_OSX
|
||||
# include "./gs_memory_osx.h"
|
||||
# elif PLATFORM_LINUX
|
||||
# include "./gs_memory_linux.h"
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif //GS_MEMORY_H
|
|
@ -2426,383 +2426,18 @@ DataIsNonEmpty(gs_data Data)
|
|||
return ((Data.Size > 0) && (Data.Memory != 0));
|
||||
}
|
||||
|
||||
internal void* AllocatorAlloc_NoOp(u64 Size, u64* SizeResult) {
|
||||
*SizeResult = 0;
|
||||
return 0;
|
||||
}
|
||||
internal void AllocatorFree_NoOp(void* Base, u64 Size) { return; }
|
||||
|
||||
internal gs_allocator
|
||||
CreateAllocator_(allocator_allocate* Alloc, allocator_free* Free)
|
||||
{
|
||||
if (Alloc == 0)
|
||||
{
|
||||
Alloc = AllocatorAlloc_NoOp;
|
||||
}
|
||||
if (Free == 0)
|
||||
{
|
||||
Free = AllocatorFree_NoOp;
|
||||
}
|
||||
gs_allocator Result = {0};
|
||||
Result.Alloc = Alloc;
|
||||
Result.Free = Free;
|
||||
return Result;
|
||||
}
|
||||
#define CreateAllocator(a, f) CreateAllocator_((allocator_allocate*)(a), (allocator_free*)(f))
|
||||
|
||||
internal void
|
||||
AllocatorDebug_PushAlloc(gs_allocator_debug* Debug, u64 Size, char* Location)
|
||||
{
|
||||
// NOTE(pjs): I don't want this debug procedure to be the reason the
|
||||
// application crashes.
|
||||
if (Debug->AllocationsCount < Debug->AllocationsCountMax)
|
||||
{
|
||||
gs_debug_allocation Allocation = {};
|
||||
|
||||
gs_const_string L = ConstString(Location);
|
||||
|
||||
s64 LastSlash = FindLastFromSet(L, "\\/");
|
||||
if (LastSlash < 0) LastSlash = 0;
|
||||
Allocation.Location = GetStringAfter(L, LastSlash);
|
||||
Allocation.Size = Size;
|
||||
|
||||
Debug->Allocations[Debug->AllocationsCount++] = Allocation;
|
||||
}
|
||||
Debug->TotalAllocSize += Size;
|
||||
}
|
||||
|
||||
internal gs_data
|
||||
AllocatorAlloc_(gs_allocator Allocator, u64 Size, char* Location)
|
||||
{
|
||||
u64 SizeResult = 0;
|
||||
void* Memory = Allocator.Alloc(Size, &SizeResult);
|
||||
if (Allocator.Debug)
|
||||
{
|
||||
AllocatorDebug_PushAlloc(Allocator.Debug, Size, Location);
|
||||
}
|
||||
return CreateData((u8*)Memory, SizeResult);
|
||||
}
|
||||
internal void
|
||||
AllocatorFree_(gs_allocator Allocator, void* Base, u64 Size, char* Location)
|
||||
{
|
||||
if (Base != 0 && Size != 0)
|
||||
{
|
||||
Allocator.Free(Base, Size);
|
||||
if (Allocator.Debug)
|
||||
{
|
||||
// NOTE(pjs): There's no reason we should be going negative
|
||||
// ie. Freeing more memory than we allocated
|
||||
Assert(Allocator.Debug->TotalAllocSize >= Size);
|
||||
Allocator.Debug->TotalAllocSize -= Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define AllocatorAlloc(alloc,size) AllocatorAlloc_((alloc), (size), FileNameAndLineNumberString)
|
||||
#define AllocatorAllocStruct(alloc, type) (type*)(AllocatorAlloc((alloc), sizeof(type)).Memory)
|
||||
#define AllocatorAllocArray(alloc, type, count) (type*)(AllocatorAlloc((alloc), sizeof(type) * (count)).Memory)
|
||||
#define AllocatorAllocString(alloc, size) gs_string{ AllocatorAllocArray((alloc), char, (size)), 0, (size) }
|
||||
#define AllocatorFree(alloc,base,size) AllocatorFree_((alloc), (base), (size), FileNameAndLineNumberString)
|
||||
#define AllocatorFreeArray(alloc,base,type,count) AllocatorFree_((alloc), (base), sizeof(type) * count, FileNameAndLineNumberString)
|
||||
internal gs_memory_cursor
|
||||
CreateMemoryCursor(u8* Base, u64 Size)
|
||||
{
|
||||
gs_memory_cursor Result = {0};
|
||||
Result.Data.Memory = Base;
|
||||
Result.Data.Size = Size;
|
||||
return Result;
|
||||
};
|
||||
internal gs_memory_cursor
|
||||
CreateMemoryCursor(gs_data Data)
|
||||
{
|
||||
return CreateMemoryCursor(Data.Memory, Data.Size);
|
||||
}
|
||||
internal gs_memory_cursor
|
||||
CreateMemoryCursor(gs_allocator Allocator, u64 Size)
|
||||
{
|
||||
gs_data Data = AllocatorAlloc(Allocator, Size);
|
||||
return CreateMemoryCursor(Data);
|
||||
}
|
||||
internal bool
|
||||
CursorHasRoom(gs_memory_cursor Cursor, u64 Size)
|
||||
{
|
||||
bool Result = ((Cursor.Position + Size) <= Cursor.Data.Size);
|
||||
return Result;
|
||||
}
|
||||
internal gs_data
|
||||
PushSizeOnCursor_(gs_memory_cursor* Cursor, u64 Size, char* Location)
|
||||
{
|
||||
gs_data Result = {0};
|
||||
if (CursorHasRoom(*Cursor, Size))
|
||||
{
|
||||
Result.Memory = Cursor->Data.Memory + Cursor->Position;
|
||||
Result.Size = Size;
|
||||
Cursor->Position += Size;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
#define PushSizeOnCursor(cursor,size) PushSizeOnCursor_((cursor), (size), FileNameAndLineNumberString)
|
||||
#define PushStructOnCursor(cursor,type) (type*)PushSizeOnCursor_((cursor), sizeof(type), FileNameAndLineNumberString).Memory
|
||||
#define PushArrayOnCursor(cursor,type,count) (type*)PushSizeOnCursor_((cursor), sizeof(type) * (count), FileNameAndLineNumberString).Memory
|
||||
|
||||
#define MemoryCursor_WriteValue(cursor, type, value) *PushStructOnCursor(cursor, type) = value
|
||||
#define MemoryCursor_WriteBuffer(cursor, buf, len) CopyMemoryTo((u8*)(buf), PushArrayOnCursor((cursor), u8, (len)), (len))
|
||||
|
||||
internal void
|
||||
PopSizeOnCursor(gs_memory_cursor* Cursor, u64 Size)
|
||||
{
|
||||
if (Cursor->Position > Size)
|
||||
{
|
||||
Cursor->Position -= Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
Cursor->Position = 0;
|
||||
}
|
||||
}
|
||||
internal gs_data
|
||||
AlignCursor(gs_memory_cursor* Cursor, u64 Alignment)
|
||||
{
|
||||
u64 Position = RoundUpTo64(Cursor->Position, Alignment);
|
||||
Position = Min(Position, Cursor->Data.Size);
|
||||
u64 NewSize = Position - Cursor->Position;
|
||||
return PushSizeOnCursor(Cursor, NewSize);
|
||||
}
|
||||
internal void
|
||||
ClearCursor(gs_memory_cursor* Cursor)
|
||||
{
|
||||
Cursor->Position = 0;
|
||||
}
|
||||
|
||||
internal void
|
||||
FreeCursorListEntry(gs_allocator Allocator, gs_memory_cursor_list* CursorEntry)
|
||||
{
|
||||
AllocatorFree(Allocator, CursorEntry, CursorEntry->Cursor.Data.Size + sizeof(gs_memory_cursor));
|
||||
}
|
||||
|
||||
internal gs_memory_arena
|
||||
CreateMemoryArena_(arena_type ArenaType, gs_allocator Allocator, u64 ChunkSize, u64 Alignment, gs_memory_arena* ParentArena, char* Name)
|
||||
{
|
||||
// we only want a parent arena if the type is Arena_SubArena
|
||||
Assert(((ArenaType == Arena_BaseArena) && (ParentArena == 0)) ||
|
||||
((ArenaType == Arena_SubArena) && (ParentArena != 0)));
|
||||
|
||||
gs_memory_arena Arena = {};
|
||||
Arena.ArenaName = Name;
|
||||
Arena.Type = ArenaType;
|
||||
Arena.Allocator = Allocator;
|
||||
Arena.Parent = ParentArena;
|
||||
|
||||
#if MEMORY_CURSOR_STATIC_ARRAY
|
||||
Arena.CursorsCountMax = 4096;
|
||||
Arena.Cursors = AllocatorAllocArray(Allocator, gs_memory_cursor_list, Arena.CursorsCountMax);
|
||||
#endif
|
||||
|
||||
Arena.MemoryChunkSize = ChunkSize;
|
||||
Arena.MemoryAlignment = Alignment;
|
||||
return Arena;
|
||||
}
|
||||
|
||||
internal gs_memory_arena
|
||||
CreateMemoryArena(gs_allocator Allocator, char* Name, u64 ChunkSize = KB(4), u64 Alignment = Bytes(8))
|
||||
{
|
||||
return CreateMemoryArena_(Arena_BaseArena, Allocator, ChunkSize, Alignment, 0, Name);
|
||||
}
|
||||
internal gs_memory_arena
|
||||
CreateMemorySubArena(gs_memory_arena* Parent, char* Name, u64 ChunkSize = KB(32), u64 Alignment = Bytes(8))
|
||||
{
|
||||
return CreateMemoryArena_(Arena_SubArena, Parent->Allocator, ChunkSize, Alignment, Parent, Name);
|
||||
}
|
||||
|
||||
internal gs_data PushSize_(gs_memory_arena* Arena, u64 Size, char* Location);
|
||||
|
||||
internal void
|
||||
FreeCursorList(gs_memory_cursor_list* List, gs_allocator Allocator)
|
||||
{
|
||||
#if !MEMORY_CURSOR_STATIC_ARRAY
|
||||
gs_memory_cursor_list* CursorAt = List;
|
||||
while (CursorAt != 0)
|
||||
{
|
||||
gs_memory_cursor_list* Prev = CursorAt->Prev;
|
||||
FreeCursorListEntry(Allocator, CursorAt);
|
||||
CursorAt = Prev;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
internal gs_memory_cursor_list*
|
||||
MemoryArenaNewCursor(gs_memory_arena* Arena, u64 MinSize, char* Location)
|
||||
{
|
||||
#if MEMORY_CURSOR_STATIC_ARRAY
|
||||
u64 AllocSize = Max(MinSize, Arena->MemoryChunkSize);
|
||||
#else
|
||||
// Allocate enough spcae for the minimum size needed + sizeo for the cursor list
|
||||
u64 AllocSize = Max(MinSize, Arena->MemoryChunkSize) + sizeof(gs_memory_cursor_list);
|
||||
#endif
|
||||
|
||||
gs_data Data = {0};
|
||||
switch (Arena->Type)
|
||||
{
|
||||
case Arena_SubArena:
|
||||
{
|
||||
Data = PushSize_(Arena->Parent, AllocSize, Location);
|
||||
}break;
|
||||
|
||||
case Arena_BaseArena:
|
||||
{
|
||||
Data = AllocatorAlloc_(Arena->Allocator, AllocSize, Location);
|
||||
}break;
|
||||
|
||||
InvalidDefaultCase;
|
||||
}
|
||||
|
||||
#if MEMORY_CURSOR_STATIC_ARRAY
|
||||
Assert(Arena->CursorsCount < Arena->CursorsCountMax);
|
||||
gs_memory_cursor_list* Result = Arena->Cursors + Arena->CursorsCount++;
|
||||
Result->Cursor = CreateMemoryCursor(Data.Memory, Data.Size);
|
||||
#else
|
||||
// Fit the memory cursor into the region allocated
|
||||
Assert(MinSize + sizeof(gs_memory_cursor_list) <= Data.Size);
|
||||
gs_memory_cursor_list* Result = (gs_memory_cursor_list*)Data.Memory;
|
||||
u8* CursorMemoryStart = (u8*)(Result + 1);
|
||||
u64 CursorMemorySize = Data.Size - sizeof(gs_memory_cursor_list);
|
||||
Result->Cursor = CreateMemoryCursor(CursorMemoryStart, CursorMemorySize);
|
||||
|
||||
Result->Prev = Arena->CursorList;
|
||||
Result->Next = 0;
|
||||
if (Arena->CursorList != 0)
|
||||
{
|
||||
if (Arena->CursorList->Next != 0)
|
||||
{
|
||||
Result->Next = Arena->CursorList->Next;
|
||||
}
|
||||
Arena->CursorList->Next = Result;
|
||||
}
|
||||
Arena->CursorList = Result;
|
||||
#endif
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal gs_data
|
||||
PushSize_(gs_memory_arena* Arena, u64 Size, char* Location)
|
||||
{
|
||||
gs_data Result = {0};
|
||||
if (Size > 0)
|
||||
{
|
||||
#if MEMORY_CURSOR_STATIC_ARRAY
|
||||
gs_memory_cursor_list* CursorEntry = 0;
|
||||
for (u64 i = 0;
|
||||
i < Arena->CursorsCount;
|
||||
i++)
|
||||
{
|
||||
gs_memory_cursor_list* At = Arena->Cursors + i;
|
||||
if (CursorHasRoom(At->Cursor, Size))
|
||||
{
|
||||
CursorEntry = At;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!CursorEntry)
|
||||
{
|
||||
CursorEntry = MemoryArenaNewCursor(Arena, Size, Location);
|
||||
}
|
||||
|
||||
if (!CursorEntry || !CursorHasRoom(CursorEntry->Cursor, Size))
|
||||
{
|
||||
__debugbreak();
|
||||
|
||||
CursorEntry = 0;
|
||||
for (u64 i = 0;
|
||||
i < Arena->CursorsCount;
|
||||
i++)
|
||||
{
|
||||
gs_memory_cursor_list* At = Arena->Cursors + i;
|
||||
if (CursorHasRoom(At->Cursor, Size))
|
||||
{
|
||||
CursorEntry = At;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!CursorEntry)
|
||||
{
|
||||
CursorEntry = MemoryArenaNewCursor(Arena, Size, Location);
|
||||
}
|
||||
}
|
||||
//Assert(CursorEntry);
|
||||
//Assert(CursorHasRoom(CursorEntry->Cursor, Size));
|
||||
#else
|
||||
|
||||
gs_memory_cursor_list* CursorEntry = Arena->CursorList;
|
||||
if (CursorEntry == 0)
|
||||
{
|
||||
CursorEntry = MemoryArenaNewCursor(Arena, Size, Location);
|
||||
}
|
||||
if (!CursorHasRoom(CursorEntry->Cursor, Size))
|
||||
{
|
||||
while ((CursorEntry != 0) && !CursorHasRoom(CursorEntry->Cursor, Size))
|
||||
{
|
||||
CursorEntry = CursorEntry->Next;
|
||||
}
|
||||
if (CursorEntry == 0)
|
||||
{
|
||||
CursorEntry = MemoryArenaNewCursor(Arena, Size, Location);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Assert(CursorEntry != 0);
|
||||
Assert(CursorHasRoom(CursorEntry->Cursor, Size));
|
||||
Result = PushSizeOnCursor_(&CursorEntry->Cursor, Size, Location);
|
||||
Assert(Result.Memory != 0);
|
||||
|
||||
gs_data Alignment = AlignCursor(&CursorEntry->Cursor, Arena->MemoryAlignment);
|
||||
Result.Size += Alignment.Size;
|
||||
}
|
||||
|
||||
// TODO(Peter): @Cleanup @Efficiency
|
||||
// There is a case I want to handle at some point:
|
||||
// You have a Cursor that is empty, but the size you want to allocate is bigger
|
||||
// than the cursor. So you create a new cursor, of the exact size you need,
|
||||
// immediately fill it up, and push it onto the head of the cursor list. Now,
|
||||
// the list looks like this:
|
||||
// [root] [cursor] ... [empty cursor] [full cursor] [new, empty cursor]
|
||||
// and you'll never use the memory in 'empty cursor'
|
||||
// What I'd like to do is, when you fill up a cursor, it gets pushed back until
|
||||
// the next cursor is more full
|
||||
// NOTE: Thought on this tho - you don't want this behavior in a scratch arena
|
||||
// where usage across frames could change drastically. This matters way more in
|
||||
// a permanent storage (i think)
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal void
|
||||
FreeMemoryArena(gs_memory_arena* Arena)
|
||||
{
|
||||
#if MEMORY_CURSOR_STATIC_ARRAY
|
||||
for (u32 i = 0; i < Arena->CursorsCount; i++)
|
||||
{
|
||||
gs_memory_cursor_list E = Arena->Cursors[i];
|
||||
AllocatorFree(Arena->Allocator, E.Cursor.Data.Memory, E.Cursor.Data.Size);
|
||||
}
|
||||
AllocatorFreeArray(Arena->Allocator, Arena->Cursors, gs_memory_cursor_list, Arena->CursorsCountMax);
|
||||
#else
|
||||
FreeCursorList(Arena->CursorList, Arena->Allocator);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define PushSizeToData(arena, size) PushSize_((arena), (size), FileNameAndLineNumberString)
|
||||
#define PushSize(arena, size) PushSize_((arena), (size), FileNameAndLineNumberString).Memory
|
||||
#define PushStruct(arena, type) (type*)(PushSize_((arena), sizeof(type), FileNameAndLineNumberString).Memory)
|
||||
#define PushArray(arena, type, count) (type*)(PushSize_((arena), sizeof(type) * (count), FileNameAndLineNumberString).Memory)
|
||||
#define PushString(arena, length) MakeString(PushArray((arena), char, (length)), 0, (length));
|
||||
|
||||
#define PushStringF(a,l,f,...) PushStringF_((a),(l),(f), DEBUG_LOC, __VA_ARGS__)
|
||||
internal gs_string
|
||||
PushStringF(gs_memory_arena* Arena, u32 MaxLength, char* Format, ...)
|
||||
PushStringF_(gs_memory_arena* Arena, u32 MaxLength, char* Format, gs_debug_loc Loc, ...)
|
||||
{
|
||||
gs_string Result = PushString(Arena, MaxLength);
|
||||
gs_string Result = gs_string {
|
||||
(char*)PushSize_(Arena, sizeof(char) * MaxLength, Loc).Memory, // Str
|
||||
0, // Length
|
||||
MaxLength, // Size
|
||||
};
|
||||
|
||||
va_list Args;
|
||||
va_start(Args, Format);
|
||||
va_start(Args, Loc);
|
||||
PrintFArgsList(&Result, Format, Args);
|
||||
va_end(Args);
|
||||
|
||||
|
@ -2822,33 +2457,6 @@ PushStringCopy(gs_memory_arena* Arena, gs_const_string String)
|
|||
return Result;
|
||||
}
|
||||
|
||||
internal void
|
||||
ClearArena(gs_memory_arena* Arena)
|
||||
{
|
||||
#if MEMORY_CURSOR_STATIC_ARRAY
|
||||
for (u32 i = 0; i < Arena->CursorsCount; i++)
|
||||
{
|
||||
Arena->Cursors[i].Cursor.Position = 0;
|
||||
}
|
||||
#else
|
||||
gs_memory_cursor_list* First = 0;
|
||||
for (gs_memory_cursor_list* CursorEntry = Arena->CursorList;
|
||||
CursorEntry != 0;
|
||||
CursorEntry = CursorEntry->Prev)
|
||||
{
|
||||
First = CursorEntry;
|
||||
CursorEntry->Cursor.Position = 0;
|
||||
}
|
||||
Arena->CursorList = First;
|
||||
#endif
|
||||
}
|
||||
|
||||
internal void
|
||||
FreeArena(gs_memory_arena* Arena)
|
||||
{
|
||||
FreeMemoryArena(Arena);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
//
|
||||
// Debug Print
|
||||
|
@ -2877,141 +2485,8 @@ DebugPrintF(debug_output Output, char* Format, ...)
|
|||
Output.Print(Output, Message.ConstString);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
//
|
||||
// Dynamic Array
|
||||
|
||||
internal gs_dynarray
|
||||
CreateDynarrayWithStorage(gs_memory_arena Storage, u32 ElementSize, u32 ElementsPerBuffer)
|
||||
{
|
||||
gs_dynarray Result = {};
|
||||
Result.Arena = Storage;
|
||||
Result.ElementSize = ElementSize;
|
||||
Result.ElementsPerBuffer = ElementsPerBuffer;
|
||||
Result.ElementCount = 0;
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal gs_dynarray
|
||||
CreateDynarray_(gs_allocator Allocator, u32 ElementSize, u32 ElementsPerBuffer)
|
||||
{
|
||||
gs_memory_arena Storage = CreateMemoryArena(Allocator, "Dynarray Arena", ElementSize * ElementsPerBuffer);
|
||||
return CreateDynarrayWithStorage(Storage, ElementSize, ElementsPerBuffer);
|
||||
};
|
||||
|
||||
internal gs_dynarray
|
||||
CreateDynarray_(gs_memory_arena* Arena, u32 ElementSize, u32 ElementsPerBuffer)
|
||||
{
|
||||
gs_memory_arena Storage = CreateMemorySubArena(Arena, "Dynarray Sub Arena", ElementSize * ElementsPerBuffer);
|
||||
return CreateDynarrayWithStorage(Storage, ElementSize, ElementsPerBuffer);
|
||||
};
|
||||
|
||||
internal u64
|
||||
CalculateBufferSize(gs_dynarray Array)
|
||||
{
|
||||
u64 Result = Array.ElementsPerBuffer * Array.ElementSize;
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal void
|
||||
GrowDynarray(gs_dynarray* Array)
|
||||
{
|
||||
gs_dynarray_buffer* OldBufferList = Array->Buffers;
|
||||
u64 NewBuffersCount = Array->BuffersCount + 1;
|
||||
gs_dynarray_buffer* NewBufferList = AllocatorAllocArray(Array->Arena.Allocator, gs_dynarray_buffer, NewBuffersCount);
|
||||
if (OldBufferList)
|
||||
{
|
||||
CopyArray(OldBufferList, NewBufferList, gs_dynarray_buffer, Array->BuffersCount);
|
||||
AllocatorFree(Array->Arena.Allocator, OldBufferList, sizeof(gs_dynarray_buffer) * Array->BuffersCount);
|
||||
}
|
||||
u64 BufferSize = CalculateBufferSize(*Array);
|
||||
NewBufferList[Array->BuffersCount].Memory = PushSize(&Array->Arena, BufferSize);
|
||||
Array->Buffers = NewBufferList;
|
||||
Array->BuffersCount = NewBuffersCount;
|
||||
}
|
||||
internal u64
|
||||
DynarraySize(gs_dynarray Array)
|
||||
{
|
||||
u64 Result = Array.BuffersCount * Array.ElementsPerBuffer;
|
||||
return Result;
|
||||
}
|
||||
internal gs_dynarray_handle
|
||||
IndexToHandle(gs_dynarray* Array, u64 Index)
|
||||
{
|
||||
gs_dynarray_handle Result = {0};
|
||||
Result.BufferIndex = Index / Array->ElementsPerBuffer;
|
||||
Result.IndexInBuffer = Index % Array->ElementsPerBuffer;
|
||||
return Result;
|
||||
}
|
||||
internal u64
|
||||
HandleToIndex(gs_dynarray Array, gs_dynarray_handle Handle)
|
||||
{
|
||||
u64 Result = Handle.IndexInBuffer + (Handle.BufferIndex * Array.ElementsPerBuffer);
|
||||
return Result;
|
||||
}
|
||||
internal gs_dynarray_handle
|
||||
TakeFreeElement(gs_dynarray* Array)
|
||||
{
|
||||
gs_dynarray_handle Result = {0};
|
||||
if (Array->ElementCount >= DynarraySize(*Array))
|
||||
{
|
||||
GrowDynarray(Array);
|
||||
}
|
||||
Assert(Array->ElementCount < DynarraySize(*Array));
|
||||
u64 ElementIndex = Array->ElementCount++;
|
||||
Result = IndexToHandle(Array, ElementIndex);
|
||||
return Result;
|
||||
}
|
||||
internal bool
|
||||
HandleIsValid(gs_dynarray Array, gs_dynarray_handle Handle)
|
||||
{
|
||||
bool Result = Handle.IndexInBuffer < Array.ElementsPerBuffer;
|
||||
Result &= Handle.BufferIndex < Array.BuffersCount;
|
||||
return Result;
|
||||
}
|
||||
internal bool
|
||||
IndexIsValid(gs_dynarray Array, u64 Index)
|
||||
{
|
||||
bool Result = Index < DynarraySize(Array);
|
||||
return Result;
|
||||
}
|
||||
internal gs_data
|
||||
GetElementInList_(gs_dynarray* Array, gs_dynarray_handle Handle, u64 SizeRequested)
|
||||
{
|
||||
Assert(SizeRequested == Array->ElementSize);
|
||||
Assert(HandleIsValid(*Array, Handle));
|
||||
gs_dynarray_buffer Buffer = Array->Buffers[Handle.BufferIndex];
|
||||
|
||||
gs_data Result = {0};
|
||||
Result.Memory = Buffer.Memory + (Handle.IndexInBuffer * Array->ElementSize);
|
||||
Result.Size = SizeRequested;
|
||||
|
||||
return Result;
|
||||
}
|
||||
internal gs_data
|
||||
GetElementInList_(gs_dynarray* Array, u64 Index, u64 SizeRequested)
|
||||
{
|
||||
gs_dynarray_handle Handle = IndexToHandle(Array, Index);
|
||||
return GetElementInList_(Array, Handle, SizeRequested);
|
||||
}
|
||||
internal void
|
||||
FreeDynarray(gs_dynarray* Array)
|
||||
{
|
||||
gs_allocator Allocator = Array->Arena.Allocator;
|
||||
u64 BufferSize = CalculateBufferSize(*Array);
|
||||
for (u64 i = 0; i < Array->BuffersCount; i++)
|
||||
{
|
||||
AllocatorFree(Allocator, Array->Buffers[i].Memory, BufferSize);
|
||||
}
|
||||
AllocatorFree(Allocator, Array->Buffers, sizeof(gs_dynarray_buffer) * Array->BuffersCount);
|
||||
}
|
||||
|
||||
#define HandlesAreEqual(ha, hb) ((ha.IndexInBuffer == hb.IndexInBuffer) && (ha.BufferIndex == hb.BufferIndex))
|
||||
|
||||
#define CreateDynarray(allocator,type,elePerBuf) CreateDynarray_((allocator), sizeof(type), (elePerBuf))
|
||||
#define GetElement_(array,type,size,indexOrHandle) (type*)GetElementInList_(array, indexOrHandle, size).Memory
|
||||
#define GetElement(array,type,indexOrHandle) GetElement_(array, type, sizeof(type), indexOrHandle)
|
||||
|
||||
///////////////////////////
|
||||
//
|
||||
// String Builder
|
||||
|
@ -3412,7 +2887,7 @@ ReadEntireFile(gs_file_handler FileHandler, gs_const_string Path)
|
|||
gs_file_info FileInfo = FileHandler.GetFileInfo(FileHandler, Path);
|
||||
if (FileInfo.FileSize > 0)
|
||||
{
|
||||
gs_data FileMemory = PushSizeToData(FileHandler.Transient, FileInfo.FileSize);
|
||||
gs_data FileMemory = PushSize(FileHandler.Transient, FileInfo.FileSize);
|
||||
Result = ReadEntireFile(FileHandler, Path, FileMemory);
|
||||
}
|
||||
return Result;
|
||||
|
|
|
@ -309,8 +309,8 @@ CopyMemory_(u8* From, u8* To, u64 Size)
|
|||
#define SLLPop_(list_tail) list_tail=list_tail=list_tail->next
|
||||
#define SLLPop(list_tail) (SLLPop_((list_tail)))
|
||||
|
||||
#define SLLNext(ele_at) ele_at = ele_at->Next;
|
||||
#define SLLPrev(ele_at) ele_at = ele_at->Prev;
|
||||
#define SLLNext(ele_at) ele_at = ele_at->Next
|
||||
#define SLLPrev(ele_at) ele_at = ele_at->Prev
|
||||
|
||||
#define SLLInit(head,tail,first_ele) head=first_ele, tail=first_ele;
|
||||
|
||||
|
@ -651,95 +651,10 @@ enum
|
|||
gs_Scan_Forward = 1,
|
||||
};
|
||||
|
||||
#define ALLOCATOR_ALLOC(name) void* name(u64 Size, u64* ResultSize)
|
||||
typedef ALLOCATOR_ALLOC(allocator_allocate);
|
||||
|
||||
#define ALLOCATOR_FREE(name) void name(void* Ptr, u64 Size)
|
||||
typedef ALLOCATOR_FREE(allocator_free);
|
||||
internal u64 RoundUpTo64(u64 Value, u64 Alignment);
|
||||
|
||||
struct gs_debug_allocation
|
||||
{
|
||||
gs_const_string Location;
|
||||
u64 Size;
|
||||
};
|
||||
|
||||
struct gs_allocator_debug
|
||||
{
|
||||
u64 TotalAllocSize;
|
||||
|
||||
u64 AllocationsCount;
|
||||
u64 AllocationsCountMax;
|
||||
gs_debug_allocation* Allocations;
|
||||
};
|
||||
|
||||
struct gs_allocator
|
||||
{
|
||||
allocator_allocate* Alloc;
|
||||
allocator_free* Free;
|
||||
|
||||
gs_allocator_debug* Debug;
|
||||
};
|
||||
|
||||
struct gs_memory_cursor
|
||||
{
|
||||
gs_data Data;
|
||||
u64 Position;
|
||||
};
|
||||
|
||||
/* TODO(pjs): Setting MEMORY_CURSOR_STATIC_ARRAY will still compile,
|
||||
However, it introduces a bug that I haven't fully diagnosed.
|
||||
The problem seems to occur when trying to push to a cleared memory arena
|
||||
Where the FirstCursor doesn't have enough room for the allocation, but
|
||||
also FirstCursor->Next points to a valid cursor. The new cursor is put
|
||||
in the middle however we seem to continually keep allocating new
|
||||
cursors forever and losing old ones.
|
||||
The problem in Lumenarium is found in the OutputData structure
|
||||
|
||||
Leaving this in a simplified state for now
|
||||
*/
|
||||
#define MEMORY_CURSOR_STATIC_ARRAY 1
|
||||
|
||||
struct gs_memory_cursor_list
|
||||
{
|
||||
gs_memory_cursor Cursor;
|
||||
#if !MEMORY_CURSOR_STATIC_ARRAY
|
||||
gs_memory_cursor_list* Next;
|
||||
gs_memory_cursor_list* Prev;
|
||||
#endif
|
||||
};
|
||||
|
||||
enum arena_type
|
||||
{
|
||||
Arena_BaseArena,
|
||||
Arena_SubArena,
|
||||
};
|
||||
|
||||
struct gs_memory_arena
|
||||
{
|
||||
arena_type Type;
|
||||
gs_allocator Allocator;
|
||||
gs_memory_arena* Parent;
|
||||
|
||||
#if MEMORY_CURSOR_STATIC_ARRAY
|
||||
gs_memory_cursor_list* Cursors;
|
||||
u64 CursorsCount;
|
||||
u64 CursorsCountMax;
|
||||
#else
|
||||
gs_memory_cursor_list* CursorList;
|
||||
#endif
|
||||
|
||||
u64 MemoryChunkSize;
|
||||
u64 MemoryAlignment;
|
||||
|
||||
char* ArenaName;
|
||||
};
|
||||
|
||||
struct gs_memory_arena_array
|
||||
{
|
||||
gs_memory_arena* Arenas;
|
||||
u32 Count;
|
||||
u32 Size;
|
||||
};
|
||||
#include "gs_memory.h"
|
||||
|
||||
///////////////////////////////
|
||||
//
|
||||
|
|
|
@ -64,11 +64,6 @@ internal void Win32UpdateWindowDimension(window* Window);
|
|||
internal void Win32ResizeDIBSection(win32_offscreen_buffer *Buffer, int Width, int Height);
|
||||
internal void Win32DisplayBufferInWindow(win32_offscreen_buffer* Buffer, window Window);
|
||||
|
||||
// Memory
|
||||
|
||||
internal ALLOCATOR_ALLOC(Win32Alloc);
|
||||
internal ALLOCATOR_FREE(Win32Free);
|
||||
|
||||
///
|
||||
// Utils
|
||||
///
|
||||
|
|
|
@ -177,8 +177,8 @@ FlowerStripToChannel(u8 Flower, u8 Channel)
|
|||
int main(int ArgCount, char** Args)
|
||||
{
|
||||
gs_thread_context Ctx = Win32CreateThreadContext();
|
||||
GlobalLogBuffer = AllocatorAllocStruct(Ctx.Allocator, log_buffer);
|
||||
*GlobalLogBuffer = Log_Init(Ctx.Allocator, 32);
|
||||
GlobalLogBuffer = PushStruct(Ctx.Transient, log_buffer);
|
||||
*GlobalLogBuffer = Log_Init(Ctx.Transient, 32);
|
||||
|
||||
gs_string OutputBuffer0 = PushString(Ctx.Transient, MB(4));
|
||||
gs_string OutputBuffer1 = PushString(Ctx.Transient, MB(4));
|
||||
|
|
|
@ -45,7 +45,7 @@ FindNextHeader(gs_data Data, u8* StartAt)
|
|||
void
|
||||
CreateMessage(gs_data* Data, u8 Count)
|
||||
{
|
||||
gs_memory_cursor WriteCursor = CreateMemoryCursor(*Data);
|
||||
gs_memory_cursor WriteCursor = MemoryCursorCreateFromData(*Data);
|
||||
|
||||
u32 Channels[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
|
@ -58,7 +58,7 @@ CreateMessage(gs_data* Data, u8 Count)
|
|||
for (u32 j = 0; j < sizeof(Channels) / sizeof(u32); j++)
|
||||
{
|
||||
u32 ChannelIndex = Channels[j];
|
||||
uart_header* Header = PushStructOnCursor(&WriteCursor, uart_header);
|
||||
uart_header* Header = MemoryCursorPushStruct(&WriteCursor, uart_header);
|
||||
UART_FillHeader(Header, ChannelIndex, UART_SET_CHANNEL_WS2812);
|
||||
|
||||
if (FirstHeaderAddr == 0)
|
||||
|
@ -66,27 +66,27 @@ CreateMessage(gs_data* Data, u8 Count)
|
|||
FirstHeaderAddr = (u8*)Header;
|
||||
}
|
||||
|
||||
uart_channel* Channel = PushStructOnCursor(&WriteCursor, uart_channel);
|
||||
uart_channel* Channel = MemoryCursorPushStruct(&WriteCursor, uart_channel);
|
||||
Channel->ElementsCount = 3;
|
||||
Channel->ColorPackingOrder = 36; // 10010000
|
||||
Channel->PixelsCount = 300;
|
||||
|
||||
for (u32 i = 0; i < Channel->PixelsCount; i++)
|
||||
{
|
||||
u8* Pixel = PushArrayOnCursor(&WriteCursor, u8, 3);
|
||||
u8* Pixel = MemoryCursorPushArray(&WriteCursor, u8, 3);
|
||||
Pixel[0] = Count;
|
||||
Pixel[1] = 0;
|
||||
Pixel[2] = 255 - Count;
|
||||
}
|
||||
|
||||
uart_footer* Footer = PushStructOnCursor(&WriteCursor, uart_footer);
|
||||
uart_footer* Footer = MemoryCursorPushStruct(&WriteCursor, uart_footer);
|
||||
Footer->CRC = UART_CalculateCRC((u8*)Header, (u8*)(Footer));
|
||||
}
|
||||
|
||||
uart_header* DrawAllHeader = PushStructOnCursor(&WriteCursor, uart_header);
|
||||
uart_header* DrawAllHeader = MemoryCursorPushStruct(&WriteCursor, uart_header);
|
||||
UART_FillHeader(DrawAllHeader, 255, UART_DRAW_ALL);
|
||||
uart_footer* DrawAllFooter =
|
||||
PushStructOnCursor(&WriteCursor, uart_footer);
|
||||
MemoryCursorPushStruct(&WriteCursor, uart_footer);
|
||||
DrawAllFooter->CRC = UART_CalculateCRC((u8*)DrawAllHeader, (u8*)(DrawAllFooter));
|
||||
|
||||
Data->Size = ((u8*)DrawAllFooter - (u8*)FirstHeaderAddr) + sizeof(uart_footer);
|
||||
|
@ -95,8 +95,8 @@ CreateMessage(gs_data* Data, u8 Count)
|
|||
int main(int ArgCount, char** Args)
|
||||
{
|
||||
gs_thread_context Ctx = Win32CreateThreadContext();
|
||||
GlobalLogBuffer = AllocatorAllocStruct(Ctx.Allocator, log_buffer);
|
||||
*GlobalLogBuffer = Log_Init(Ctx.Allocator, 32);
|
||||
GlobalLogBuffer = PushStruct(Ctx.Transient, log_buffer);
|
||||
*GlobalLogBuffer = Log_Init(Ctx.Transient, 32);
|
||||
|
||||
HANDLE SerialHandle = Win32SerialPort_Open("\\\\.\\COM9", Ctx.Transient);
|
||||
Win32SerialPort_SetState(SerialHandle, 2000000, 8, 0, 1);
|
||||
|
@ -108,7 +108,7 @@ int main(int ArgCount, char** Args)
|
|||
{
|
||||
Win32SerialPort_SetRead(SerialHandle);
|
||||
|
||||
gs_data Data = PushSizeToData(Ctx.Transient, KB(32));
|
||||
gs_data Data = PushSize(Ctx.Transient, KB(32));
|
||||
|
||||
Win32SerialPort_SetRead(SerialHandle);
|
||||
u32 ReadSize = Win32SerialPort_ReadMessageWhenReady(SerialHandle, Data);
|
||||
|
@ -173,7 +173,7 @@ int main(int ArgCount, char** Args)
|
|||
}
|
||||
else if (true)
|
||||
{
|
||||
gs_data Data = PushSizeToData(Ctx.Transient, KB(32));
|
||||
gs_data Data = PushSize(Ctx.Transient, KB(32));
|
||||
|
||||
u8 Count = 0;
|
||||
while(true)
|
||||
|
@ -185,7 +185,7 @@ int main(int ArgCount, char** Args)
|
|||
}
|
||||
else if (false)
|
||||
{
|
||||
gs_data Data = PushSizeToData(Ctx.Transient, KB(32));
|
||||
gs_data Data = PushSize(Ctx.Transient, KB(32));
|
||||
gs_file File = Win32ReadEntireFile(Ctx.FileHandler, OutFileName, Data);
|
||||
|
||||
gs_data Messages = {0};
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#include "../app/platform_win32/win32_foldhaus_memory.h"
|
||||
|
||||
internal u32
|
||||
TESTNextRandom(u32* LastRandomValue)
|
||||
NextRandom(u32* LastRandomValue)
|
||||
{
|
||||
u32 Result = *LastRandomValue;
|
||||
Result ^= Result << 13;
|
||||
|
@ -11,64 +9,63 @@ TESTNextRandom(u32* LastRandomValue)
|
|||
return Result;
|
||||
}
|
||||
|
||||
internal void
|
||||
void
|
||||
MemoryArenaTests()
|
||||
{
|
||||
Test("Allocator")
|
||||
{
|
||||
gs_allocator Allocator = CreateAllocator(Win32Alloc, Win32Free);
|
||||
gs_allocator A = CreatePlatformAllocator();
|
||||
|
||||
u8* Data = AllocatorAllocArray(Allocator, u8, 4096);
|
||||
u8* Data = AllocArray(A, u8, 4096, "root");
|
||||
for (int i = 0; i < 4096; i++) Data[i] = (i % MaxU8);
|
||||
bool Success = true;
|
||||
for (int i = 0; i < 4096; i++) Success &= (Data[i] == (i % MaxU8));
|
||||
for (int i = 0; i < 4096; i++) Success &= Data[i] == (i % MaxU8);
|
||||
TestResult(Success);
|
||||
|
||||
AllocatorFreeArray(Allocator, Data, u8, 4096);
|
||||
// idk how to test free
|
||||
FreeArray(A, Data, u8, 4096);
|
||||
TestResult(true); // TODO(PS): How do we test free?
|
||||
}
|
||||
|
||||
Test("Memory Cursor")
|
||||
{
|
||||
gs_allocator A = CreateAllocator(Win32Alloc, Win32Free);
|
||||
gs_allocator A = CreatePlatformAllocator();
|
||||
|
||||
u64 Size = 4096;
|
||||
gs_data D = AllocatorAlloc(A, Size);
|
||||
gs_memory_cursor C = CreateMemoryCursor(D);
|
||||
gs_data D = AllocData(A, Size, "root");
|
||||
gs_memory_cursor C = MemoryCursorCreate(D.Memory, D.Size);
|
||||
|
||||
u64 RoomLeft = CursorRoomLeft(C);
|
||||
u64 RoomLeft = MemoryCursorRoomLeft(C);
|
||||
TestResult(RoomLeft == Size);
|
||||
TestResult(MemoryCursorHasRoom(C));
|
||||
|
||||
TestResult(CursorHasRoom(C, 2048));
|
||||
TestResult(CursorHasRoom(C, Size));
|
||||
TestResult(!CursorHasRoom(C, Size + 1));
|
||||
TestResult(MemoryCursorCanPush(C, 2048));
|
||||
TestResult(MemoryCursorCanPush(C, Size));
|
||||
TestResult(!MemoryCursorCanPush(C, Size + 1));
|
||||
|
||||
for (u64 i = 0; i < 2048; i++)
|
||||
{
|
||||
u8* Byte = PushSizeOnCursor(&C, 1).Memory;
|
||||
u8* Byte = MemoryCursorPushSize(&C, 1).Memory;
|
||||
*Byte = (u8)(i % 256);
|
||||
}
|
||||
RoomLeft = CursorRoomLeft(C);
|
||||
RoomLeft = MemoryCursorRoomLeft(C);
|
||||
TestResult(RoomLeft == (Size - 2048));
|
||||
|
||||
PopSizeOnCursor(&C, 2048);
|
||||
MemoryCursorPopSize(&C, 2048);
|
||||
TestResult(C.Position == 0);
|
||||
|
||||
bool Success = true;
|
||||
for (u64 i = 0; i < 2048; i++)
|
||||
{
|
||||
u8* Byte = PushSizeOnCursor(&C, 1).Memory;
|
||||
u8* Byte = MemoryCursorPushSize(&C, 1).Memory;
|
||||
Success &= *Byte == (u8)(i % 256);
|
||||
}
|
||||
TestResult(Success);
|
||||
|
||||
AllocatorFree(A, D.Memory, D.Size);
|
||||
}
|
||||
|
||||
Test("Memory Arena")
|
||||
{
|
||||
gs_allocator Al = CreateAllocator(Win32Alloc, Win32Free);
|
||||
gs_memory_arena A = CreateMemoryArena(Al, "test", 128, 4);
|
||||
gs_allocator Al = CreatePlatformAllocator();
|
||||
gs_memory_arena A = MemoryArenaCreate(128, 4, Al, 0, 0, "Test");
|
||||
|
||||
// NOTE(PS): We loop through this block 3 times
|
||||
// 1. Make sure the arena works out of the box
|
||||
|
@ -76,42 +73,40 @@ MemoryArenaTests()
|
|||
// 3. Make sure the arena works the same way after freeing
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
gs_data D0 = PushSize_(&A, 32, FileNameAndLineNumberString);
|
||||
gs_data D0 = PushSize_(&A, 32, DEBUG_LOC);
|
||||
TestResult(D0.Size == 32);
|
||||
|
||||
// NOTE(PS): This should still result in 32 bytes
|
||||
// because its going to align the Cursor after
|
||||
// it allocates to a multiple of 4 bytes
|
||||
gs_data D1 = PushSize_(&A, 30, FileNameAndLineNumberString);
|
||||
gs_data D1 = PushSize_(&A, 30, DEBUG_LOC);
|
||||
TestResult(D1.Size == 32);
|
||||
|
||||
// NOTE(PS): Allocating bigger than the size remaining
|
||||
// in the current cursor
|
||||
gs_data D2 = PushSize_(&A, 128, FileNameAndLineNumberString);
|
||||
gs_data D2 = PushSize_(&A, 128, DEBUG_LOC);
|
||||
TestResult(D2.Size == 128);
|
||||
TestResult(A.CursorsCount != 1);
|
||||
TestResult(A.CursorsRoot != A.CursorsHead);
|
||||
|
||||
// NOTE(PS): Because there is still room in cursor
|
||||
// 0, the head of this gs_data should be one byte
|
||||
// past the end of D1
|
||||
gs_data D3 = PushSize_(&A, 32, FileNameAndLineNumberString);
|
||||
gs_data D3 = PushSize_(&A, 32, DEBUG_LOC);
|
||||
TestResult(D3.Memory == D1.Memory + D1.Size);
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
ClearArena(&A);
|
||||
MemoryArenaClear(&A);
|
||||
} else if (i == 1) {
|
||||
FreeMemoryArena(&A);
|
||||
MemoryArenaFree(&A);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FreeMemoryArena(&A);
|
||||
}
|
||||
|
||||
Test("Memory Arena: Push")
|
||||
Test("Memory Arena - Push")
|
||||
{
|
||||
gs_allocator Al = CreateAllocator(Win32Alloc, Win32Free);
|
||||
gs_memory_arena A = CreateMemoryArena(Al, "test", 128, 4);
|
||||
gs_allocator Al = CreatePlatformAllocator();
|
||||
gs_memory_arena A = MemoryArenaCreate(128, 8, Al, 0, 0, "Test");
|
||||
|
||||
// NOTE(PS): This makes sure that the Arena is moving its next allocation
|
||||
// pointer forward the appropriate amount after each allocation. If it isnt'
|
||||
|
@ -133,16 +128,21 @@ MemoryArenaTests()
|
|||
}
|
||||
TestResult(Success);
|
||||
|
||||
FreeArena(&A);
|
||||
}
|
||||
|
||||
int FreeCount = 0;
|
||||
int ClearCount = 0;
|
||||
|
||||
Test("Memory Arena: Stress Test")
|
||||
gs_debug_allocations_list* DEBUGAllocations = 0;
|
||||
|
||||
Test("Memory Arena - Stress Test")
|
||||
{
|
||||
gs_allocator Al = CreateAllocator(Win32Alloc, Win32Free);
|
||||
gs_memory_arena A = CreateMemoryArena(Al, "test", 128, 4);
|
||||
// NOTE(PS): We're going to create thousands of allocations
|
||||
// on the allocator of varying sizes. We're also going to clear
|
||||
// and free the arena at random times to make sure it all works.
|
||||
|
||||
gs_allocator Al = CreatePlatformAllocator();
|
||||
gs_memory_arena A = MemoryArenaCreate(4096, 4, Al, 0, 0, "Test");
|
||||
|
||||
// NOTE(PS): This is an array of allocation sizes
|
||||
// As we repeat the loop we will get values out of this array
|
||||
|
@ -157,19 +157,19 @@ MemoryArenaTests()
|
|||
u32 RandomSeed = 1923;
|
||||
for (u64 i = 0; i < (4096 * 14); i++)
|
||||
{
|
||||
TESTNextRandom(&RandomSeed);
|
||||
NextRandom(&RandomSeed);
|
||||
u32 SizeIndex = RandomSeed % RandomSizesCount;
|
||||
u64 RandomSize = RandomSizes[SizeIndex];
|
||||
|
||||
if (RandomSize == 0)
|
||||
{
|
||||
ClearArena(&A);
|
||||
MemoryArenaClear(&A);
|
||||
ClearCount++;
|
||||
} else if (RandomSize == 2) {
|
||||
FreeArena(&A);
|
||||
MemoryArenaFree(&A);
|
||||
FreeCount++;
|
||||
} else {
|
||||
gs_data D = PushSize_(&A, RandomSize, FileNameAndLineNumberString);
|
||||
gs_data D = PushSize_(&A, RandomSize, DEBUG_LOC);
|
||||
// NOTE(PS): This check has to be >= because the arena
|
||||
// might have adjusted to maintain alignment on this
|
||||
// allocation.
|
||||
|
@ -179,6 +179,24 @@ MemoryArenaTests()
|
|||
|
||||
TestResult(Success);
|
||||
|
||||
DEBUGAllocations = Al.DEBUGAllocList;
|
||||
}
|
||||
|
||||
printf("\tMemory Arena Cleared: %d times\n", ClearCount);
|
||||
printf("\tMemory Arena Freed: %d times\n", FreeCount);
|
||||
|
||||
#if 0
|
||||
printf("\n\nAllocations:\n");
|
||||
for (gs_debug_memory_allocation* ARecord = DEBUGAllocations->Root;
|
||||
ARecord != 0;
|
||||
ARecord = ARecord->Next)
|
||||
{
|
||||
printf("\t");
|
||||
printf("%lld\t%s:%d - %s\n",
|
||||
ARecord->Size,
|
||||
ARecord->Loc.File,
|
||||
ARecord->Loc.Line,
|
||||
ARecord->Loc.Function);
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -14,11 +14,10 @@
|
|||
#include "../gs_libs/gs_path.h"
|
||||
#include "../gs_libs/gs_csv.h"
|
||||
|
||||
#include "../app/platform_win32/win32_foldhaus_memory.h"
|
||||
#include "./memory_arena_tests.cpp"
|
||||
|
||||
gs_memory_arena Scratch = {};
|
||||
void* Alloc(u64 Size, u64* ResultSize) { *ResultSize = Size; return malloc(Size); }
|
||||
void Free(void* Ptr, u64 Size) { return free(Ptr); }
|
||||
|
||||
bool StringTest (gs_const_string StrA, gs_const_string StrB)
|
||||
{
|
||||
|
@ -38,9 +37,76 @@ Flower A 55 32 128 foo, bar, blah, baz, whatever
|
|||
Flower B 123 344 32 foo, bar, blah, baz, whatever
|
||||
Flower C 55 32 128 foo, bar, blah, baz, whatever)FOO";
|
||||
|
||||
struct test_sll
|
||||
{
|
||||
u32 Val;
|
||||
test_sll* Next;
|
||||
};
|
||||
|
||||
int main (int ArgCount, char** Args)
|
||||
{
|
||||
Scratch = CreateMemoryArena(CreateAllocator(Alloc, Free), "Scratch");
|
||||
gs_allocator Al = CreatePlatformAllocator();
|
||||
Scratch = MemoryArenaCreate(KB(4), Bytes(8), Al, 0, 0, "Scratch");
|
||||
|
||||
Test("SLL 1")
|
||||
{
|
||||
test_sll* Root = 0;
|
||||
test_sll* Head = 0;
|
||||
|
||||
test_sll* First = PushStruct(&Scratch, test_sll);
|
||||
First->Val = 0;
|
||||
SLLInit(Root, Head, First);
|
||||
TestResult((Root == First) && (Head == First));
|
||||
|
||||
for (u32 i = 1; i < 4; i++)
|
||||
{
|
||||
test_sll* New = PushStruct(&Scratch, test_sll);
|
||||
New->Val = i;
|
||||
SLLPush(Head, New);
|
||||
TestResult((Root == First) && (Head == New));
|
||||
}
|
||||
|
||||
bool Success = true;
|
||||
u32 i = 0;
|
||||
for (test_sll* At = Root;
|
||||
At && At->Next != 0;
|
||||
SLLNext(At))
|
||||
{
|
||||
Success &= (At->Val == i);
|
||||
i += 1;
|
||||
}
|
||||
TestResult(Success);
|
||||
}
|
||||
|
||||
Test("SLL Push Or Init")
|
||||
{
|
||||
test_sll* Root = 0;
|
||||
test_sll* Head = 0;
|
||||
|
||||
test_sll* First = PushStruct(&Scratch, test_sll);
|
||||
First->Val = 0;
|
||||
SLLPushOrInit(Root, Head, First);
|
||||
TestResult((Root == First) && (Head == First));
|
||||
|
||||
for (u32 i = 1; i < 4; i++)
|
||||
{
|
||||
test_sll* New = PushStruct(&Scratch, test_sll);
|
||||
New->Val = i;
|
||||
SLLPushOrInit(Root, Head, New);
|
||||
TestResult((Root == First) && (Head == New));
|
||||
}
|
||||
|
||||
bool Success = true;
|
||||
u32 i = 0;
|
||||
for (test_sll* At = Root;
|
||||
At && At->Next != 0;
|
||||
SLLNext(At))
|
||||
{
|
||||
Success &= (At->Val == i);
|
||||
i += 1;
|
||||
}
|
||||
TestResult(Success);
|
||||
}
|
||||
|
||||
Test("gs_string")
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue