Replaced old memory arena with a new, better one, which also has a test suite

This commit is contained in:
PS 2021-08-06 18:19:30 -05:00
parent baf4c5d5a6
commit f261cbd55a
33 changed files with 10388 additions and 10380 deletions

View File

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

View File

@ -14,77 +14,77 @@ typedef OPERATION_RENDER_PROC(operation_render_proc);
struct operation_mode
{
input_command_registry Commands;
operation_render_proc* Render;
gs_memory_cursor Memory;
u8* OpStateMemory;
input_command_registry Commands;
operation_render_proc* Render;
gs_memory_cursor Memory;
u8* OpStateMemory;
};
#define OPERATION_MODES_MAX 32
struct operation_mode_system
{
s32 ActiveModesCount;
operation_mode ActiveModes[OPERATION_MODES_MAX];
//arena_snapshot ModeMemorySnapshots[OPERATION_MODES_MAX];
gs_data_array ModeMemoryPagesFreeList;
// NOTE(Peter): This acts as mode scoped memory. When a mode gets activated, it can allocate
// temporary memory which then gets freed when the mode is deactivated
gs_memory_arena Arena;
s32 ActiveModesCount;
operation_mode ActiveModes[OPERATION_MODES_MAX];
//arena_snapshot ModeMemorySnapshots[OPERATION_MODES_MAX];
gs_data_array ModeMemoryPagesFreeList;
// NOTE(Peter): This acts as mode scoped memory. When a mode gets activated, it can allocate
// temporary memory which then gets freed when the mode is deactivated
gs_memory_arena Arena;
};
internal operation_mode_system
OperationModeSystemInit(gs_memory_arena* Storage, gs_thread_context ThreadContext)
{
operation_mode_system Result = {0};
// TODO(Peter): Do we really need an arena? Can this just operate in constant memory footprint?
Result.Arena.Allocator = ThreadContext.Allocator;
Result.ModeMemoryPagesFreeList.CountMax = 8;
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.Count = Result.ModeMemoryPagesFreeList.CountMax;
return Result;
operation_mode_system Result = {0};
// TODO(Peter): Do we really need an arena? Can this just operate in constant memory footprint?
Result.Arena.Allocator = ThreadContext.Allocator;
Result.ModeMemoryPagesFreeList.CountMax = 8;
Result.ModeMemoryPagesFreeList.Data = PushArray(Storage, gs_data, Result.ModeMemoryPagesFreeList.CountMax);
for (u32 Page = 0; Page < Result.ModeMemoryPagesFreeList.CountMax; Page++)
{
Result.ModeMemoryPagesFreeList.Data[Page] = PushSize(Storage, KB(4));
}
Result.ModeMemoryPagesFreeList.Count = Result.ModeMemoryPagesFreeList.CountMax;
return Result;
}
internal gs_data
OperationModeTakeMemoryPage(operation_mode_system* System)
{
Assert(System->ModeMemoryPagesFreeList.Count > 0);
gs_data Result = {0};
System->ModeMemoryPagesFreeList.Count -= 1;
u64 LastIndex = System->ModeMemoryPagesFreeList.Count;
Result = System->ModeMemoryPagesFreeList.Data[LastIndex];
return Result;
Assert(System->ModeMemoryPagesFreeList.Count > 0);
gs_data Result = {0};
System->ModeMemoryPagesFreeList.Count -= 1;
u64 LastIndex = System->ModeMemoryPagesFreeList.Count;
Result = System->ModeMemoryPagesFreeList.Data[LastIndex];
return Result;
}
internal void
OperationModeFreeMemoryPage(operation_mode_system* System, gs_data Data)
{
Assert(System->ModeMemoryPagesFreeList.Count < System->ModeMemoryPagesFreeList.CountMax);
u64 LastIndex = System->ModeMemoryPagesFreeList.Count;
System->ModeMemoryPagesFreeList.Count += 1;
System->ModeMemoryPagesFreeList.Data[LastIndex] = Data;
Assert(System->ModeMemoryPagesFreeList.Count < System->ModeMemoryPagesFreeList.CountMax);
u64 LastIndex = System->ModeMemoryPagesFreeList.Count;
System->ModeMemoryPagesFreeList.Count += 1;
System->ModeMemoryPagesFreeList.Data[LastIndex] = Data;
}
internal operation_mode*
ActivateOperationMode (operation_mode_system* System, operation_render_proc* RenderProc)
{
Assert(System->ActiveModesCount < OPERATION_MODES_MAX);
operation_mode* Result = 0;
s32 ModeIndex = System->ActiveModesCount++;
//System->ModeMemorySnapshots[ModeIndex] = TakeSnapshotOfArena(&System->Arena);
Result = &System->ActiveModes[ModeIndex];
Result->Memory = CreateMemoryCursor(OperationModeTakeMemoryPage(System));
Result->Render = RenderProc;
return Result;
Assert(System->ActiveModesCount < OPERATION_MODES_MAX);
operation_mode* Result = 0;
s32 ModeIndex = System->ActiveModesCount++;
//System->ModeMemorySnapshots[ModeIndex] = TakeSnapshotOfArena(&System->Arena);
Result = &System->ActiveModes[ModeIndex];
Result->Memory = MemoryCursorCreateFromData(OperationModeTakeMemoryPage(System));
Result->Render = RenderProc;
return Result;
}
#define ActivateOperationModeWithCommands(sys, cmds, render) \
@ -93,30 +93,30 @@ ActivateOperationModeWithCommands_(sys, cmds, (s32)(sizeof(cmds) / sizeof(cmds[0
internal operation_mode*
ActivateOperationModeWithCommands_(operation_mode_system* System, input_command* Commands, s32 CommandsCount, operation_render_proc* RenderProc)
{
operation_mode* NewMode = ActivateOperationMode(System, RenderProc);
operation_mode* NewMode = ActivateOperationMode(System, RenderProc);
#if 0
InitializeInputCommandRegistry(&NewMode->Commands, CommandsCount, &System->Arena);
for (s32 i = 0; i < CommandsCount; i++)
{
input_command Command = Commands[i];
RegisterKeyPressCommand(&NewMode->Commands, Command.Key, Command.Flags, Command.Mdfr, Command.Proc);
}
InitializeInputCommandRegistry(&NewMode->Commands, CommandsCount, &System->Arena);
for (s32 i = 0; i < CommandsCount; i++)
{
input_command Command = Commands[i];
RegisterKeyPressCommand(&NewMode->Commands, Command.Key, Command.Flags, Command.Mdfr, Command.Proc);
}
#else
NewMode->Commands.Commands = Commands;
NewMode->Commands.Size = CommandsCount;
NewMode->Commands.Used = CommandsCount;
NewMode->Commands.Commands = Commands;
NewMode->Commands.Size = CommandsCount;
NewMode->Commands.Used = CommandsCount;
#endif
return NewMode;
return NewMode;
}
internal void
DeactivateCurrentOperationMode (operation_mode_system* System)
{
Assert(System->ActiveModesCount > 0);
s32 ModeIndex = --System->ActiveModesCount;
OperationModeFreeMemoryPage(System, System->ActiveModes[ModeIndex].Memory.Data);
//ClearArenaToSnapshot(&System->Arena, System->ModeMemorySnapshots[ModeIndex]);
Assert(System->ActiveModesCount > 0);
s32 ModeIndex = --System->ActiveModesCount;
OperationModeFreeMemoryPage(System, System->ActiveModes[ModeIndex].Memory.Data);
//ClearArenaToSnapshot(&System->Arena, System->ModeMemorySnapshots[ModeIndex]);
}
#define CreateOperationState(mode, modeSystem, stateType) \
@ -129,12 +129,12 @@ DeactivateCurrentOperationMode (operation_mode_system* System)
internal u8*
CreateOperationState_ (operation_mode* Mode, operation_mode_system* System, s32 StateSize)
{
// 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;
Mode->OpStateMemory = Result;
return Result;
// 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 = MemoryCursorPushSize(&Mode->Memory, StateSize).Memory;
Mode->OpStateMemory = Result;
return Result;
}

File diff suppressed because it is too large Load Diff

View File

@ -7,42 +7,42 @@
enum file_view_mode
{
FileViewMode_Load,
FileViewMode_Save,
FileViewMode_Load,
FileViewMode_Save,
};
struct file_view_state
{
file_view_mode Mode;
gs_string WorkingDirectory;
gs_string DisplayDirectory;
gs_memory_arena FileNamesArena;
gs_file_info_array FileNames;
gs_file_info SelectedFile;
file_view_mode Mode;
gs_string WorkingDirectory;
gs_string DisplayDirectory;
gs_memory_arena FileNamesArena;
gs_file_info_array FileNames;
gs_file_info SelectedFile;
};
internal void
FileView_SetMode(panel* Panel, file_view_mode Mode)
{
file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state);
FileViewState->Mode = Mode;
file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state);
FileViewState->Mode = Mode;
}
internal void
FileView_Exit_(panel* FileViewPanel, app_state* State, context Context)
{
// TODO(pjs): Free State->FileNamesArena
Assert(FileViewPanel->IsModalOverrideFor != 0);
panel* ReturnTo = FileViewPanel->IsModalOverrideFor;
if (ReturnTo->ModalOverrideCB)
{
ReturnTo->ModalOverrideCB(FileViewPanel, State, Context);
}
Panel_PopModalOverride(ReturnTo, &State->PanelSystem);
// TODO(pjs): Free State->FileNamesArena
Assert(FileViewPanel->IsModalOverrideFor != 0);
panel* ReturnTo = FileViewPanel->IsModalOverrideFor;
if (ReturnTo->ModalOverrideCB)
{
ReturnTo->ModalOverrideCB(FileViewPanel, State, Context);
}
Panel_PopModalOverride(ReturnTo, &State->PanelSystem);
}
global input_command* FileView_Commands = 0;
@ -51,35 +51,35 @@ s32 FileView_CommandsCount = 0;
internal void
FileView_UpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_state* State, context Context)
{
// NOTE(pjs): make sure we're only passing valid directory paths to the
// function
char LastChar = WorkingDirectory.Str[WorkingDirectory.Length - 1];
Assert(LastChar == '\\' || LastChar == '/');
ClearArena(&State->FileNamesArena);
// NOTE(pjs): make sure we're only passing valid directory paths to the
// function
char LastChar = WorkingDirectory.Str[WorkingDirectory.Length - 1];
Assert(LastChar == '\\' || LastChar == '/');
MemoryArenaClear(&State->FileNamesArena);
gs_string SanitizedDir = PushString(Context.ThreadContext.Transient, WorkingDirectory.Length + 2);
SanitizePath(WorkingDirectory, &SanitizedDir, Context.ThreadContext.Transient);
if (SanitizedDir.Str[SanitizedDir.Length - 1] != '\\')
{
AppendPrintF(&SanitizedDir, "\\");
}
gs_const_string SanitizedDisplayDir = SanitizedDir.ConstString;
gs_file_info NewWorkingDir = GetFileInfo(Context.ThreadContext.FileHandler, SanitizedDir.ConstString);
if (NewWorkingDir.IsDirectory)
{
AppendPrintF(&SanitizedDir, "*");
NullTerminate(&SanitizedDir);
State->FileNames = EnumerateDirectory(Context.ThreadContext.FileHandler, &State->FileNamesArena, SanitizedDir.ConstString, EnumerateDirectory_IncludeDirectories);
gs_string SanitizedDir = PushString(Context.ThreadContext.Transient, WorkingDirectory.Length + 2);
SanitizePath(WorkingDirectory, &SanitizedDir, Context.ThreadContext.Transient);
if (SanitizedDir.Str[SanitizedDir.Length - 1] != '\\')
{
AppendPrintF(&SanitizedDir, "\\");
}
gs_const_string SanitizedDisplayDir = SanitizedDir.ConstString;
gs_file_info NewWorkingDir = GetFileInfo(Context.ThreadContext.FileHandler, SanitizedDir.ConstString);
if (NewWorkingDir.IsDirectory)
{
AppendPrintF(&SanitizedDir, "*");
NullTerminate(&SanitizedDir);
State->FileNames = EnumerateDirectory(Context.ThreadContext.FileHandler, &State->FileNamesArena, SanitizedDir.ConstString, EnumerateDirectory_IncludeDirectories);
// NOTE(pjs): we might be printing from State->WorkingDirectory to State->WorkingDirectory
// in some cases. Shouldn't be a problem but it is unnecessary
PrintF(&State->WorkingDirectory, "%S", SanitizedDir.ConstString);
PrintF(&State->DisplayDirectory, "%S", SanitizedDisplayDir);
}
// NOTE(pjs): we might be printing from State->WorkingDirectory to State->WorkingDirectory
// in some cases. Shouldn't be a problem but it is unnecessary
PrintF(&State->WorkingDirectory, "%S", SanitizedDir.ConstString);
PrintF(&State->DisplayDirectory, "%S", SanitizedDisplayDir);
}
}
GSMetaTag(panel_init);
@ -87,16 +87,16 @@ GSMetaTag(panel_type_file_view);
internal void
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");
// TODO(pjs): this shouldn't be stored in permanent
FileViewState->DisplayDirectory = PushString(&State->Permanent, 1024);
FileViewState->WorkingDirectory = PushString(&State->Permanent, 1024);
FileView_UpdateWorkingDirectory(ConstString(".\\"), FileViewState, Context);
// TODO: :FreePanelMemory
file_view_state* FileViewState = PushStruct(&State->Permanent, file_view_state);
Panel->StateMemory = StructToData(FileViewState, file_view_state);
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);
FileViewState->WorkingDirectory = PushString(&State->Permanent, 1024);
FileView_UpdateWorkingDirectory(ConstString(".\\"), FileViewState, Context);
}
GSMetaTag(panel_cleanup);
@ -104,7 +104,7 @@ GSMetaTag(panel_type_file_view);
internal void
FileView_Cleanup(panel* Panel, app_state* State)
{
}
GSMetaTag(panel_render);
@ -112,87 +112,87 @@ GSMetaTag(panel_type_file_view);
internal void
FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state);
ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("FileView Layout"));
file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state);
ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("FileView Layout"));
{
ui_BeginRow(&State->Interface, 3);
{
ui_BeginRow(&State->Interface, 3);
if (FileViewState->Mode == FileViewMode_Save)
{
if (ui_Button(&State->Interface, MakeString("Save")))
{
if (FileViewState->Mode == FileViewMode_Save)
{
if (ui_Button(&State->Interface, MakeString("Save")))
{
if (!FileViewState->SelectedFile.Path.Str)
{
FileViewState->SelectedFile.Path = FileViewState->DisplayDirectory.ConstString;
}
FileView_Exit_(Panel, State, Context);
}
}
if (ui_Button(&State->Interface, MakeString("Exit")))
{
FileView_Exit_(Panel, State, Context);
}
if (!FileViewState->SelectedFile.Path.Str)
{
FileViewState->SelectedFile.Path = FileViewState->DisplayDirectory.ConstString;
}
FileView_Exit_(Panel, State, Context);
}
ui_EndRow(&State->Interface);
// Header
if (ui_TextEntry(&State->Interface, MakeString("pwd"), &FileViewState->DisplayDirectory))
{
// if last character is a slash, update pwd, and clear the filter string
// otherwise update the filter string
gs_string Pwd = FileViewState->DisplayDirectory;
char LastChar = Pwd.Str[Pwd.Length - 1];
if (LastChar == '\\' || LastChar == '/')
{
FileView_UpdateWorkingDirectory(Pwd.ConstString, FileViewState, Context);
}
else
{
}
}
// File Display
ui_BeginList(&State->Interface, MakeString("Files"), 10, FileViewState->FileNames.Count);
for (u32 i = 0; i < FileViewState->FileNames.Count; i++)
{
gs_file_info File = FileViewState->FileNames.Values[i];
u32 LastSlashIndex = FindLast(File.Path, File.Path.Length - 2, '\\');
gs_const_string FileName = Substring(File.Path, LastSlashIndex + 1, File.Path.Length);
gs_string PathString = PushString(State->Transient, FileName.Length);
PrintF(&PathString, "%S", FileName);
if (ui_LayoutListButton(&State->Interface, PathString, i))
{
if (File.IsDirectory)
{
FileView_UpdateWorkingDirectory(File.Path, FileViewState, Context);
}
else
{
FileViewState->SelectedFile = File;
switch (FileViewState->Mode)
{
case FileViewMode_Load:
{
FileView_Exit_(Panel, State, Context);
} break;
case FileViewMode_Save:
{
} break;
}
}
}
}
ui_EndList(&State->Interface);
}
if (ui_Button(&State->Interface, MakeString("Exit")))
{
FileView_Exit_(Panel, State, Context);
}
}
ui_PopLayout(&State->Interface, MakeString("FileView Layout"));
ui_EndRow(&State->Interface);
// Header
if (ui_TextEntry(&State->Interface, MakeString("pwd"), &FileViewState->DisplayDirectory))
{
// if last character is a slash, update pwd, and clear the filter string
// otherwise update the filter string
gs_string Pwd = FileViewState->DisplayDirectory;
char LastChar = Pwd.Str[Pwd.Length - 1];
if (LastChar == '\\' || LastChar == '/')
{
FileView_UpdateWorkingDirectory(Pwd.ConstString, FileViewState, Context);
}
else
{
}
}
// File Display
ui_BeginList(&State->Interface, MakeString("Files"), 10, FileViewState->FileNames.Count);
for (u32 i = 0; i < FileViewState->FileNames.Count; i++)
{
gs_file_info File = FileViewState->FileNames.Values[i];
u32 LastSlashIndex = FindLast(File.Path, File.Path.Length - 2, '\\');
gs_const_string FileName = Substring(File.Path, LastSlashIndex + 1, File.Path.Length);
gs_string PathString = PushString(State->Transient, FileName.Length);
PrintF(&PathString, "%S", FileName);
if (ui_LayoutListButton(&State->Interface, PathString, i))
{
if (File.IsDirectory)
{
FileView_UpdateWorkingDirectory(File.Path, FileViewState, Context);
}
else
{
FileViewState->SelectedFile = File;
switch (FileViewState->Mode)
{
case FileViewMode_Load:
{
FileView_Exit_(Panel, State, Context);
} break;
case FileViewMode_Save:
{
} break;
}
}
}
}
ui_EndList(&State->Interface);
}
ui_PopLayout(&State->Interface, MakeString("FileView Layout"));
}

View File

@ -13,7 +13,7 @@ GSMetaTag(panel_type_profiler);
internal void
ProfilerView_Init(panel* Panel, app_state* State, context Context)
{
}
GSMetaTag(panel_cleanup);
@ -21,213 +21,217 @@ GSMetaTag(panel_type_profiler);
internal void
ProfilerView_Cleanup(panel* Panel, app_state* State)
{
}
internal void
RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, debug_frame* VisibleFrame, gs_memory_arena* Transient)
{
rect2 Bounds = ui_LayoutRemaining(*Layout);
r32 Width = Rect2Width(Bounds);
r32 DepthHeight = 32;
rect2 Bounds = ui_LayoutRemaining(*Layout);
r32 Width = Rect2Width(Bounds);
r32 DepthHeight = 32;
s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
r32 FrameTotalCycles = (r32)(VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles);
r32 NextThreadTop = Bounds.Max.y;
for (s32 t = 0; t < VisibleFrame->ThreadCount; t++)
{
debug_scope_record_list ThreadCalls = VisibleFrame->ThreadCalls[t];
s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
r32 FrameTotalCycles = (r32)(VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles);
gs_string String = PushString(Transient, 256);
r32 NextThreadTop = Bounds.Max.y;
r32 ThreadScopeMin = Bounds.Max.y;
for (s32 t = 0; t < VisibleFrame->ThreadCount; t++)
//PrintF(&String, "Thread %d", ThreadCalls.ThreadId);
//ui_Label(Interface, String, rect2{ThreadScopeMin);
r32 Hue = (r32)(t) / (r32)(VisibleFrame->ThreadCount);
Hue += (.5f * (t % 2));
v4 ThreadHSV = v4{ 360.0f * Hue, .5f, 1.0f, 1.0f };
v4 ThreadRGB = HSVToRGB(ThreadHSV);
for (s32 i = 0; i < ThreadCalls.Count; i++)
{
debug_scope_record_list ThreadCalls = VisibleFrame->ThreadCalls[t];
gs_string String = PushString(Transient, 256);
r32 ThreadScopeMin = Bounds.Max.y;
//PrintF(&String, "Thread %d", ThreadCalls.ThreadId);
//ui_Label(Interface, String, rect2{ThreadScopeMin);
r32 Hue = (r32)(t) / (r32)(VisibleFrame->ThreadCount);
Hue += (.5f * (t % 2));
v4 ThreadHSV = v4{ 360.0f * Hue, .5f, 1.0f, 1.0f };
v4 ThreadRGB = HSVToRGB(ThreadHSV);
for (s32 i = 0; i < ThreadCalls.Count; i++)
scope_record* Record = ThreadCalls.Calls + i;
scope_name* Name = GetOrAddNameHashEntry(VisibleFrame, Record->NameHash);
s64 OffsetStart = Record->StartCycles - FrameStartCycles;
s64 OffsetEnd = Record->EndCycles - FrameStartCycles;
r32 PercentStart = (r32)(OffsetStart) / FrameTotalCycles;
r32 PercentEnd = (r32)(OffsetEnd) / FrameTotalCycles;
r32 PercentWidth = PercentEnd - PercentStart;
rect2 ScopeBounds = {
v2{0, 0},
v2{PercentWidth * Width, DepthHeight - 4},
};
v2 Offset = {
Bounds.Min.x + (PercentStart * Width),
NextThreadTop - ((Record->CallDepth + 1) * DepthHeight)
};
ScopeBounds = Rect2Translate(ScopeBounds, Offset);
ThreadScopeMin = Min(ScopeBounds.Min.y, ThreadScopeMin);
if (Rect2Width(ScopeBounds) >= 1)
{
v4 Color = ThreadRGB;
if (PointIsInRect(ScopeBounds, Interface->Mouse.Pos))
{
scope_record* Record = ThreadCalls.Calls + i;
scope_name* Name = GetOrAddNameHashEntry(VisibleFrame, Record->NameHash);
s64 OffsetStart = Record->StartCycles - FrameStartCycles;
s64 OffsetEnd = Record->EndCycles - FrameStartCycles;
r32 PercentStart = (r32)(OffsetStart) / FrameTotalCycles;
r32 PercentEnd = (r32)(OffsetEnd) / FrameTotalCycles;
r32 PercentWidth = PercentEnd - PercentStart;
rect2 ScopeBounds = {
v2{0, 0},
v2{PercentWidth * Width, DepthHeight - 4},
};
v2 Offset = {
Bounds.Min.x + (PercentStart * Width),
NextThreadTop - ((Record->CallDepth + 1) * DepthHeight)
};
ScopeBounds = Rect2Translate(ScopeBounds, Offset);
ThreadScopeMin = Min(ScopeBounds.Min.y, ThreadScopeMin);
if (Rect2Width(ScopeBounds) >= 1)
{
v4 Color = ThreadRGB;
if (PointIsInRect(ScopeBounds, Interface->Mouse.Pos))
{
Color = GreenV4;
ui_BeginMousePopup(Interface, rect2{ 25, 25, 300, 57 }, LayoutDirection_TopDown, MakeString("Hover"));
{
s64 Cycles = (Record->EndCycles - Record->StartCycles);
r32 PercentFrame = (r32)(Cycles) / FrameTotalCycles;
PrintF(&String, "%S : %.2f%% frame | %dcy",
Name->Name,
PercentFrame,
Cycles);
ui_Label(Interface, String);
}
ui_EndMousePopup(Interface);
}
ui_FillRect(Interface, ScopeBounds, Color);
ui_OutlineRect(Interface, ScopeBounds, 1, BlackV4);
}
Color = GreenV4;
ui_BeginMousePopup(Interface, rect2{ 25, 25, 300, 57 }, LayoutDirection_TopDown, MakeString("Hover"));
{
s64 Cycles = (Record->EndCycles - Record->StartCycles);
r32 PercentFrame = (r32)(Cycles) / FrameTotalCycles;
PrintF(&String, "%S : %.2f%% frame | %dcy",
Name->Name,
PercentFrame,
Cycles);
ui_Label(Interface, String);
}
ui_EndMousePopup(Interface);
}
NextThreadTop = ThreadScopeMin;
ui_FillRect(Interface, ScopeBounds, Color);
ui_OutlineRect(Interface, ScopeBounds, 1, BlackV4);
}
}
NextThreadTop = ThreadScopeMin;
}
}
internal void
RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory)
{
char Backbuffer[256];
gs_string String = MakeString(Backbuffer, 0, 256);
ui_column_spec ColumnWidths[] = {
{ UIColumnSize_Fixed, 256 },
{ UIColumnSize_Fixed, 128 },
{ UIColumnSize_Fixed, 128 },
{ UIColumnSize_Fixed, 128 },
{ UIColumnSize_Fixed, 128 }};
ui_BeginRow(Interface, 5, &ColumnWidths[0]);
char Backbuffer[256];
gs_string String = MakeString(Backbuffer, 0, 256);
ui_column_spec ColumnWidths[] = {
{ UIColumnSize_Fixed, 256 },
{ UIColumnSize_Fixed, 128 },
{ UIColumnSize_Fixed, 128 },
{ UIColumnSize_Fixed, 128 },
{ UIColumnSize_Fixed, 128 }};
ui_BeginRow(Interface, 5, &ColumnWidths[0]);
{
ui_Label(Interface, MakeString("Procedure"));
ui_Label(Interface, MakeString("% Frame"));
ui_Label(Interface, MakeString("Seconds"));
ui_Label(Interface, MakeString("Cycles"));
ui_Label(Interface, MakeString("Calls"));
}
ui_EndRow(Interface);
s32 CountedScopes = 0;
for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++)
{
scope_name NameEntry = VisibleFrame->ScopeNamesHash[n];
if (NameEntry.Hash != 0)
{
ui_Label(Interface, MakeString("Procedure"));
ui_Label(Interface, MakeString("% Frame"));
ui_Label(Interface, MakeString("Seconds"));
ui_Label(Interface, MakeString("Cycles"));
ui_Label(Interface, MakeString("Calls"));
CountedScopes += 1;
}
ui_EndRow(Interface);
s32 CountedScopes = 0;
for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++)
}
ui_BeginList(Interface, MakeString("Scope List"), 10, CountedScopes);
ui_BeginRow(Interface, 5, &ColumnWidths[0]);
for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++)
{
scope_name NameEntry = VisibleFrame->ScopeNamesHash[n];
if (NameEntry.Hash != 0)
{
scope_name NameEntry = VisibleFrame->ScopeNamesHash[n];
if (NameEntry.Hash != 0)
{
CountedScopes += 1;
}
collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n;
PrintF(&String, "%S", NameEntry.Name);
ui_Label(Interface, String);
PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime);
ui_Label(Interface, String);
PrintF(&String, "%fs", CollatedRecord->TotalSeconds);
ui_Label(Interface, String);
PrintF(&String, "%dcy", CollatedRecord->TotalCycles);
ui_Label(Interface, String);
PrintF(&String, "%d", CollatedRecord->CallCount);
ui_Label(Interface, String);
}
ui_BeginList(Interface, MakeString("Scope List"), 10, CountedScopes);
ui_BeginRow(Interface, 5, &ColumnWidths[0]);
for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++)
{
scope_name NameEntry = VisibleFrame->ScopeNamesHash[n];
if (NameEntry.Hash != 0)
{
collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n;
PrintF(&String, "%S", NameEntry.Name);
ui_Label(Interface, String);
PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime);
ui_Label(Interface, String);
PrintF(&String, "%fs", CollatedRecord->TotalSeconds);
ui_Label(Interface, String);
PrintF(&String, "%dcy", CollatedRecord->TotalCycles);
ui_Label(Interface, String);
PrintF(&String, "%d", CollatedRecord->CallCount);
ui_Label(Interface, String);
}
}
ui_EndRow(Interface);
ui_EndList(Interface);
}
ui_EndRow(Interface);
ui_EndList(Interface);
}
struct mem_amt
{
u64 OrigSize;
r64 Size;
char* Units;
u64 OrigSize;
r64 Size;
char* Units;
};
internal mem_amt
GetMemAmt (u64 BytesCount)
{
mem_amt Result = {};
Result.OrigSize = BytesCount;
Result.Size = (r64)BytesCount;
Result.Units = "bytes";
u32 i = 0;
char* UnitList[] = { "kb", "mb", "gb", "tb" };
while (Result.Size > 1024) {
Result.Size /= 1024.0;
Result.Units = UnitList[i++];
}
return Result;
mem_amt Result = {};
Result.OrigSize = BytesCount;
Result.Size = (r64)BytesCount;
Result.Units = "bytes";
u32 i = 0;
char* UnitList[] = { "kb", "mb", "gb", "tb" };
while (Result.Size > 1024) {
Result.Size /= 1024.0;
Result.Units = UnitList[i++];
}
return Result;
}
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_string TempString = PushString(State->Transient, 256);
mem_amt MemFootprint = GetMemAmt(Debug.TotalAllocSize);
u64 AllocCount = Debug.AllocationsCount;
PrintF(&TempString, "Total Memory Size: %.2f %s | Allocations: %lld", MemFootprint.Size, MemFootprint.Units, AllocCount);
gs_debug_allocations_list* DA = Context.ThreadContext.Allocator.DEBUGAllocList;
gs_string TempString = PushString(State->Transient, 256);
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);
ui_column_spec ColumnWidths[] = {
{ UIColumnSize_Fill, 0 },
{ UIColumnSize_Fixed,256 },
};
ui_BeginRow(Interface, 2, &ColumnWidths[0]);
{
ui_Label(Interface, MakeString("Location"));
ui_Label(Interface, MakeString("Alloc Size"));
}
ui_EndRow(Interface);
ui_BeginList(Interface, MakeString("Alloc List"), 10, DA->AllocationsCount);
ui_BeginRow(Interface, 2, &ColumnWidths[0]);
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);
ui_column_spec ColumnWidths[] = {
{ UIColumnSize_Fill, 0 },
{ UIColumnSize_Fixed,256 },
};
ui_BeginRow(Interface, 2, &ColumnWidths[0]);
{
ui_Label(Interface, MakeString("Location"));
ui_Label(Interface, MakeString("Alloc Size"));
}
ui_EndRow(Interface);
mem_amt Amt = GetMemAmt(A->Size);
ui_BeginList(Interface, MakeString("Alloc List"), 10, Debug.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);
ui_Label(Interface, TempString);
mem_amt Amt = GetMemAmt(A.Size);
PrintF(&TempString, "%.2f %s", Amt.Size, Amt.Units);
ui_Label(Interface, TempString);
}
ui_EndRow(Interface);
ui_EndList(Interface);
PrintF(&TempString, "%.2f %s", Amt.Size, Amt.Units);
ui_Label(Interface, TempString);
}
ui_EndRow(Interface);
ui_EndList(Interface);
}
GSMetaTag(panel_render);
@ -235,120 +239,120 @@ GSMetaTag(panel_type_profiler);
internal void
ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
gs_memory_arena* Memory = State->Transient;
gs_string String = PushString(Memory, 256);
gs_memory_arena* Memory = State->Transient;
gs_string String = PushString(Memory, 256);
v4 FrameColors[] = { GreenV4, YellowV4, RedV4, WhiteV4 };
r32 FrameListHeight = 64;
rect2 FrameListBounds, ProcListBounds;
RectHSplitAtDistanceFromTop(PanelBounds, FrameListHeight, &FrameListBounds, &ProcListBounds);
rect2 FrameListInner = RectInset(FrameListBounds, 4);
s32 FramesToDisplay = DEBUG_FRAME_COUNT;
if (FramesToDisplay != 0)
{
r32 SingleFrameStep = Rect2Width(FrameListInner) / FramesToDisplay;
r32 SingleFrameWidth = (r32)((s32)SingleFrameStep - 2);
v4 FrameColors[] = { GreenV4, YellowV4, RedV4, WhiteV4 };
r32 FrameListHeight = 64;
rect2 FrameListBounds, ProcListBounds;
RectHSplitAtDistanceFromTop(PanelBounds, FrameListHeight, &FrameListBounds, &ProcListBounds);
rect2 FrameListInner = RectInset(FrameListBounds, 4);
s32 FramesToDisplay = DEBUG_FRAME_COUNT;
if (FramesToDisplay != 0)
ui_OutlineRect(&State->Interface, FrameListBounds, 2, WhiteV4);
if (MouseButtonHeldDown(Context.Mouse.LeftButtonState))
{
r32 SingleFrameStep = Rect2Width(FrameListInner) / FramesToDisplay;
r32 SingleFrameWidth = (r32)((s32)SingleFrameStep - 2);
ui_OutlineRect(&State->Interface, FrameListBounds, 2, WhiteV4);
if (MouseButtonHeldDown(Context.Mouse.LeftButtonState))
if (PointIsInRect(FrameListBounds, Context.Mouse.Pos))
{
v2 LocalMouse = Rect2GetRectLocalPoint(FrameListBounds, Context.Mouse.Pos);
s32 ClosestFrameIndex = (LocalMouse.x / SingleFrameStep);
if (ClosestFrameIndex >= 0 && ClosestFrameIndex < FramesToDisplay)
{
if (PointIsInRect(FrameListBounds, Context.Mouse.Pos))
{
v2 LocalMouse = Rect2GetRectLocalPoint(FrameListBounds, Context.Mouse.Pos);
s32 ClosestFrameIndex = (LocalMouse.x / SingleFrameStep);
if (ClosestFrameIndex >= 0 && ClosestFrameIndex < FramesToDisplay)
{
GlobalDebugServices->RecordFrames = false;
GlobalDebugServices->CurrentDebugFrame = ClosestFrameIndex;
}
}
}
rect2 FrameBounds = MakeRect2MinDim(FrameListInner.Min, v2{SingleFrameWidth, Rect2Height(FrameListInner)});
for (s32 F = 0; F < DEBUG_FRAME_COUNT; F++)
{
rect2 PositionedFrameBounds = Rect2TranslateX(FrameBounds, F * SingleFrameStep);
s32 FramesAgo = (GlobalDebugServices->CurrentDebugFrame - F);
if (FramesAgo < 0) { FramesAgo += DEBUG_FRAME_COUNT; }
v4 Color = FrameColors[Clamp(0, FramesAgo, 3)];
ui_FillRect(&State->Interface, PositionedFrameBounds, Color);
GlobalDebugServices->RecordFrames = false;
GlobalDebugServices->CurrentDebugFrame = ClosestFrameIndex;
}
}
}
ui_widget* Layout = ui_PushLayout(&State->Interface, ProcListBounds, LayoutDirection_TopDown, MakeString("Profiler Layout"));
debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices);
if (VisibleFrame)
rect2 FrameBounds = MakeRect2MinDim(FrameListInner.Min, v2{SingleFrameWidth, Rect2Height(FrameListInner)});
for (s32 F = 0; F < DEBUG_FRAME_COUNT; F++)
{
ui_BeginRow(&State->Interface, 4);
{
s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles;
u32 CurrentDebugFrame = GlobalDebugServices->CurrentDebugFrame - 1;
PrintF(&String, "Frame %d", CurrentDebugFrame);
ui_Label(&State->Interface, String);
PrintF(&String, "Total Cycles: %lld", FrameTotalCycles);
ui_Label(&State->Interface, String);
// NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could
// be removed, or used for something else
ui_ReserveBounds(&State->Interface, Layout, true);
if (ui_Button(&State->Interface, MakeString("Resume Recording")))
{
GlobalDebugServices->RecordFrames = true;
}
}
ui_EndRow(&State->Interface);
rect2 PositionedFrameBounds = Rect2TranslateX(FrameBounds, F * SingleFrameStep);
s32 FramesAgo = (GlobalDebugServices->CurrentDebugFrame - F);
if (FramesAgo < 0) { FramesAgo += DEBUG_FRAME_COUNT; }
v4 Color = FrameColors[Clamp(0, FramesAgo, 3)];
ui_FillRect(&State->Interface, PositionedFrameBounds, Color);
}
ui_BeginRow(&State->Interface, 8);
}
ui_widget* Layout = ui_PushLayout(&State->Interface, ProcListBounds, LayoutDirection_TopDown, MakeString("Profiler Layout"));
debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices);
if (VisibleFrame)
{
ui_BeginRow(&State->Interface, 4);
{
if (ui_Button(&State->Interface, MakeString("Profiler")))
{
GlobalDebugServices->Interface.FrameView = DebugUI_Profiler;
}
if (ui_Button(&State->Interface, MakeString("List View")))
{
GlobalDebugServices->Interface.FrameView = DebugUI_ScopeList;
}
if (ui_Button(&State->Interface, MakeString("Memory")))
{
GlobalDebugServices->Interface.FrameView = DebugUI_MemoryView;
}
s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles;
u32 CurrentDebugFrame = GlobalDebugServices->CurrentDebugFrame - 1;
PrintF(&String, "Frame %d", CurrentDebugFrame);
ui_Label(&State->Interface, String);
PrintF(&String, "Total Cycles: %lld", FrameTotalCycles);
ui_Label(&State->Interface, String);
// NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could
// be removed, or used for something else
ui_ReserveBounds(&State->Interface, Layout, true);
if (ui_Button(&State->Interface, MakeString("Resume Recording")))
{
GlobalDebugServices->RecordFrames = true;
}
}
ui_EndRow(&State->Interface);
switch (GlobalDebugServices->Interface.FrameView)
}
ui_BeginRow(&State->Interface, 8);
{
if (ui_Button(&State->Interface, MakeString("Profiler")))
{
case DebugUI_Profiler:
{
if (VisibleFrame)
{
RenderProfiler_ScopeVisualization(&State->Interface, Layout, VisibleFrame, Memory);
}
}break;
case DebugUI_ScopeList:
{
if (VisibleFrame)
{
RenderProfiler_ListVisualization(&State->Interface, Layout, VisibleFrame, Memory);
}
}break;
case DebugUI_MemoryView:
{
RenderProfiler_MemoryView(&State->Interface, Layout, State, Context, Memory);
}break;
InvalidDefaultCase;
GlobalDebugServices->Interface.FrameView = DebugUI_Profiler;
}
if (ui_Button(&State->Interface, MakeString("List View")))
{
GlobalDebugServices->Interface.FrameView = DebugUI_ScopeList;
}
if (ui_Button(&State->Interface, MakeString("Memory")))
{
GlobalDebugServices->Interface.FrameView = DebugUI_MemoryView;
}
}
ui_EndRow(&State->Interface);
switch (GlobalDebugServices->Interface.FrameView)
{
case DebugUI_Profiler:
{
if (VisibleFrame)
{
RenderProfiler_ScopeVisualization(&State->Interface, Layout, VisibleFrame, Memory);
}
}break;
ui_PopLayout(&State->Interface, MakeString("Profiler Layout"));
case DebugUI_ScopeList:
{
if (VisibleFrame)
{
RenderProfiler_ListVisualization(&State->Interface, Layout, VisibleFrame, Memory);
}
}break;
case DebugUI_MemoryView:
{
RenderProfiler_MemoryView(&State->Interface, Layout, State, Context, Memory);
}break;
InvalidDefaultCase;
}
ui_PopLayout(&State->Interface, MakeString("Profiler Layout"));
}

View File

@ -13,49 +13,49 @@
struct sculpture_view_panel_state
{
camera Camera;
camera Camera;
};
// 3D Mouse View
OPERATION_STATE_DEF(mouse_rotate_view_operation_state)
{
v4 CameraStartPos;
camera* Camera;
v4 CameraStartPos;
camera* Camera;
};
OPERATION_RENDER_PROC(Update3DViewMouseRotate)
{
mouse_rotate_view_operation_state* OpState = (mouse_rotate_view_operation_state*)Operation.OpStateMemory;
v2 TotalDeltaPos = Mouse.Pos - Mouse.DownPos;
m44 XRotation = M44RotationX(-TotalDeltaPos.y * PIXEL_TO_WORLD_SCALE);
m44 YRotation = M44RotationY(TotalDeltaPos.x * PIXEL_TO_WORLD_SCALE);
m44 Combined = XRotation * YRotation;
OpState->Camera->Position = (Combined * OpState->CameraStartPos).xyz;
mouse_rotate_view_operation_state* OpState = (mouse_rotate_view_operation_state*)Operation.OpStateMemory;
v2 TotalDeltaPos = Mouse.Pos - Mouse.DownPos;
m44 XRotation = M44RotationX(-TotalDeltaPos.y * PIXEL_TO_WORLD_SCALE);
m44 YRotation = M44RotationY(TotalDeltaPos.x * PIXEL_TO_WORLD_SCALE);
m44 Combined = XRotation * YRotation;
OpState->Camera->Position = (Combined * OpState->CameraStartPos).xyz;
}
FOLDHAUS_INPUT_COMMAND_PROC(End3DViewMouseRotate)
{
DeactivateCurrentOperationMode(&State->Modes);
DeactivateCurrentOperationMode(&State->Modes);
}
input_command MouseRotateViewCommands [] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, End3DViewMouseRotate},
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, End3DViewMouseRotate},
};
FOLDHAUS_INPUT_COMMAND_PROC(Begin3DViewMouseRotate)
{
sculpture_view_panel_state* PanelState = Panel_GetStateStruct(Panel, sculpture_view_panel_state);
operation_mode* RotateViewMode = ActivateOperationModeWithCommands(&State->Modes, MouseRotateViewCommands, Update3DViewMouseRotate);
mouse_rotate_view_operation_state* OpState = CreateOperationState(RotateViewMode,
&State->Modes,
mouse_rotate_view_operation_state);
OpState->CameraStartPos = ToV4Point(PanelState->Camera.Position);
OpState->Camera = &PanelState->Camera;
sculpture_view_panel_state* PanelState = Panel_GetStateStruct(Panel, sculpture_view_panel_state);
operation_mode* RotateViewMode = ActivateOperationModeWithCommands(&State->Modes, MouseRotateViewCommands, Update3DViewMouseRotate);
mouse_rotate_view_operation_state* OpState = CreateOperationState(RotateViewMode,
&State->Modes,
mouse_rotate_view_operation_state);
OpState->CameraStartPos = ToV4Point(PanelState->Camera.Position);
OpState->Camera = &PanelState->Camera;
}
// ----------------
@ -63,7 +63,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(Begin3DViewMouseRotate)
GSMetaTag(panel_commands);
GSMetaTag(panel_type_sculpture_view);
global input_command SculptureView_Commands[] = {
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, Begin3DViewMouseRotate },
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, Begin3DViewMouseRotate },
};
global s32 SculptureView_CommandsCount = 1;
@ -72,16 +72,16 @@ GSMetaTag(panel_type_sculpture_view);
internal void
SculptureView_Init(panel* Panel, app_state* State, context Context)
{
sculpture_view_panel_state* PanelState = PushStruct(&State->Permanent, sculpture_view_panel_state);
PanelState->Camera.FieldOfView = 45.0f;
PanelState->Camera.AspectRatio = RectAspectRatio(State->WindowBounds);
PanelState->Camera.Near = .1f;
PanelState->Camera.Far = 800.0f;
PanelState->Camera.Position = v3{0, 0, 400};
PanelState->Camera.LookAt = v3{0, 0, 0};
Panel->StateMemory = StructToData(PanelState, sculpture_view_panel_state);
sculpture_view_panel_state* PanelState = PushStruct(&State->Permanent, sculpture_view_panel_state);
PanelState->Camera.FieldOfView = 45.0f;
PanelState->Camera.AspectRatio = RectAspectRatio(State->WindowBounds);
PanelState->Camera.Near = .1f;
PanelState->Camera.Far = 800.0f;
PanelState->Camera.Position = v3{0, 0, 400};
PanelState->Camera.LookAt = v3{0, 0, 0};
Panel->StateMemory = StructToData(PanelState, sculpture_view_panel_state);
}
GSMetaTag(panel_cleanup);
@ -89,92 +89,92 @@ GSMetaTag(panel_type_sculpture_view);
internal void
SculptureView_Cleanup(panel* Panel, app_state* State)
{
}
struct draw_leds_job_data
{
v4 CameraPosition;
led_buffer LedBuffer;
s32 StartIndex;
s32 OnePastLastIndex;
render_quad_batch_constructor* Batch;
quad_batch_constructor_reserved_range BatchReservedRange;
r32 LEDHalfWidth;
v4 CameraPosition;
led_buffer LedBuffer;
s32 StartIndex;
s32 OnePastLastIndex;
render_quad_batch_constructor* Batch;
quad_batch_constructor_reserved_range BatchReservedRange;
r32 LEDHalfWidth;
};
internal void
DrawLedsInBuffer(led_buffer LedBuffer, s32 StartIndex, s32 OnePastLastIndex, render_quad_batch_constructor* Batch, quad_batch_constructor_reserved_range ReservedRange, r32 LedHalfWidth)
{
s32 TrisUsed = 0;
s32 TrisUsed = 0;
v4 P0_In = v4{-LedHalfWidth, -LedHalfWidth, 0, 1};
v4 P1_In = v4{LedHalfWidth, -LedHalfWidth, 0, 1};
v4 P2_In = v4{LedHalfWidth, LedHalfWidth, 0, 1};
v4 P3_In = v4{-LedHalfWidth, LedHalfWidth, 0, 1};
v2 UV0 = v2{0, 0};
v2 UV1 = v2{1, 0};
v2 UV2 = v2{1, 1};
v2 UV3 = v2{0, 1};
Assert(OnePastLastIndex <= (s32)LedBuffer.LedCount);
for (s32 LedIndex = StartIndex; LedIndex < OnePastLastIndex; LedIndex++)
{
pixel PixelColor = LedBuffer.Colors[LedIndex];
v4 Color = v4{PixelColor.R / 255.f, PixelColor.G / 255.f, PixelColor.B / 255.f, 1.0f};
v4 P0_In = v4{-LedHalfWidth, -LedHalfWidth, 0, 1};
v4 P1_In = v4{LedHalfWidth, -LedHalfWidth, 0, 1};
v4 P2_In = v4{LedHalfWidth, LedHalfWidth, 0, 1};
v4 P3_In = v4{-LedHalfWidth, LedHalfWidth, 0, 1};
v4 Position = LedBuffer.Positions[LedIndex];
v4 PositionOffset = ToV4Vec(Position.xyz);
v4 P0 = P0_In + PositionOffset;
v4 P1 = P1_In + PositionOffset;
v4 P2 = P2_In + PositionOffset;
v4 P3 = P3_In + PositionOffset;
v2 UV0 = v2{0, 0};
v2 UV1 = v2{1, 0};
v2 UV2 = v2{1, 1};
v2 UV3 = v2{0, 1};
Assert(OnePastLastIndex <= (s32)LedBuffer.LedCount);
for (s32 LedIndex = StartIndex; LedIndex < OnePastLastIndex; LedIndex++)
{
pixel PixelColor = LedBuffer.Colors[LedIndex];
v4 Color = v4{PixelColor.R / 255.f, PixelColor.G / 255.f, PixelColor.B / 255.f, 1.0f};
v4 Position = LedBuffer.Positions[LedIndex];
v4 PositionOffset = ToV4Vec(Position.xyz);
v4 P0 = P0_In + PositionOffset;
v4 P1 = P1_In + PositionOffset;
v4 P2 = P2_In + PositionOffset;
v4 P3 = P3_In + PositionOffset;
SetTri3DInBatch(Batch, ReservedRange.Start + TrisUsed++, P0, P1, P2, UV0, UV1, UV2, Color, Color, Color);
SetTri3DInBatch(Batch, ReservedRange.Start + TrisUsed++, P0, P2, P3, UV0, UV2, UV3, Color, Color, Color);
}
SetTri3DInBatch(Batch, ReservedRange.Start + TrisUsed++, P0, P1, P2, UV0, UV1, UV2, Color, Color, Color);
SetTri3DInBatch(Batch, ReservedRange.Start + TrisUsed++, P0, P2, P3, UV0, UV2, UV3, Color, Color, Color);
}
}
internal void
DrawLEDsInBufferRangeJob (gs_thread_context Context, gs_data JobData)
{
DEBUG_TRACK_FUNCTION;
draw_leds_job_data* Data = (draw_leds_job_data*)JobData.Memory;
DrawLedsInBuffer(Data->LedBuffer, Data->StartIndex, Data->OnePastLastIndex, Data->Batch, Data->BatchReservedRange, Data->LEDHalfWidth);
DEBUG_TRACK_FUNCTION;
draw_leds_job_data* Data = (draw_leds_job_data*)JobData.Memory;
DrawLedsInBuffer(Data->LedBuffer, Data->StartIndex, Data->OnePastLastIndex, Data->Batch, Data->BatchReservedRange, Data->LEDHalfWidth);
}
internal void
DrawQuad(render_command_buffer* RenderBuffer, v4 C, r32 Rad, v4 Color)
{
v4 P0 = C + v4{-Rad,-Rad,0,0};
v4 P1 = C + v4{ Rad,-Rad,0,0};
v4 P2 = C + v4{ Rad,Rad,0,0};
v4 P3 = C + v4{ -Rad,Rad,0,0};
PushRenderQuad3D(RenderBuffer, P0, P1, P2, P3, Color);
v4 P0 = C + v4{-Rad,-Rad,0,0};
v4 P1 = C + v4{ Rad,-Rad,0,0};
v4 P2 = C + v4{ Rad,Rad,0,0};
v4 P3 = C + v4{ -Rad,Rad,0,0};
PushRenderQuad3D(RenderBuffer, P0, P1, P2, P3, Color);
}
internal v2
SculptureView_WorldToScreenPosition(v4 WorldPosition, camera Camera, rect2 PanelBounds)
{
v2 Result = {0};
r32 PanelW = Rect2Width(PanelBounds);
r32 PanelH = Rect2Height(PanelBounds);
m44 Matrix = GetCameraPerspectiveProjectionMatrix(Camera) * GetCameraModelViewMatrix(Camera);
v4 WorldPos = Matrix * WorldPosition;
// this is the Perspective Divide
v2 ProjectedPos = WorldPos.xy / WorldPos.w;
// Projection gets us in a range [-1, 1], and we want [0, width]
ProjectedPos.x = ((ProjectedPos.x / 2) * PanelW) + (PanelW / 2);
ProjectedPos.y = ((ProjectedPos.y / 2) * PanelH) + (PanelH / 2);
Result = ProjectedPos + PanelBounds.Min;
return Result;
v2 Result = {0};
r32 PanelW = Rect2Width(PanelBounds);
r32 PanelH = Rect2Height(PanelBounds);
m44 Matrix = GetCameraPerspectiveProjectionMatrix(Camera) * GetCameraModelViewMatrix(Camera);
v4 WorldPos = Matrix * WorldPosition;
// this is the Perspective Divide
v2 ProjectedPos = WorldPos.xy / WorldPos.w;
// Projection gets us in a range [-1, 1], and we want [0, width]
ProjectedPos.x = ((ProjectedPos.x / 2) * PanelW) + (PanelW / 2);
ProjectedPos.y = ((ProjectedPos.y / 2) * PanelH) + (PanelH / 2);
Result = ProjectedPos + PanelBounds.Min;
return Result;
}
GSMetaTag(panel_render);
@ -182,62 +182,62 @@ GSMetaTag(panel_type_sculpture_view);
internal void
SculptureView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
DEBUG_TRACK_SCOPE(RenderSculpture);
sculpture_view_panel_state* PanelState = Panel_GetStateStruct(Panel, sculpture_view_panel_state);
PanelState->Camera.AspectRatio = RectAspectRatio(PanelBounds);
PushRenderPerspective(RenderBuffer, PanelBounds, PanelState->Camera);
u32 MaxLEDsPerJob = 2048;
render_quad_batch_constructor RenderLEDsBatch = PushRenderQuad3DBatch(RenderBuffer, State->LedSystem.LedsCountTotal);
u32 FocusPixel = 100;
for (u32 BufferIndex = 0; BufferIndex < State->LedSystem.BuffersCount; BufferIndex++)
DEBUG_TRACK_SCOPE(RenderSculpture);
sculpture_view_panel_state* PanelState = Panel_GetStateStruct(Panel, sculpture_view_panel_state);
PanelState->Camera.AspectRatio = RectAspectRatio(PanelBounds);
PushRenderPerspective(RenderBuffer, PanelBounds, PanelState->Camera);
u32 MaxLEDsPerJob = 2048;
render_quad_batch_constructor RenderLEDsBatch = PushRenderQuad3DBatch(RenderBuffer, State->LedSystem.LedsCountTotal);
u32 FocusPixel = 100;
for (u32 BufferIndex = 0; BufferIndex < State->LedSystem.BuffersCount; BufferIndex++)
{
led_buffer* LedBuffer = LedSystemGetBuffer(&State->LedSystem, BufferIndex);
u32 JobsNeeded = U32DivideRoundUp(LedBuffer->LedCount, MaxLEDsPerJob);
u32 NextLEDIndex = 0;
for (u32 Job = 0; Job < JobsNeeded; Job++)
{
led_buffer* LedBuffer = LedSystemGetBuffer(&State->LedSystem, BufferIndex);
u32 JobsNeeded = U32DivideRoundUp(LedBuffer->LedCount, MaxLEDsPerJob);
u32 NextLEDIndex = 0;
for (u32 Job = 0; Job < JobsNeeded; Job++)
{
gs_data Data = PushSizeToData(State->Transient, sizeof(draw_leds_job_data));
draw_leds_job_data* JobData = (draw_leds_job_data*)Data.Memory;
JobData->LedBuffer = *LedBuffer;
JobData->StartIndex = NextLEDIndex;
JobData->OnePastLastIndex = Min(JobData->StartIndex + MaxLEDsPerJob, LedBuffer->LedCount);
s32 JobLedCount = JobData->OnePastLastIndex - JobData->StartIndex;
JobData->Batch = &RenderLEDsBatch;
JobData->BatchReservedRange = ReserveRangeInQuadConstructor(JobData->Batch, JobLedCount * 2);
JobData->LEDHalfWidth = .5f;
JobData->CameraPosition = ToV4Point(PanelState->Camera.Position);
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;
JobData->OnePastLastIndex = Min(JobData->StartIndex + MaxLEDsPerJob, LedBuffer->LedCount);
s32 JobLedCount = JobData->OnePastLastIndex - JobData->StartIndex;
JobData->Batch = &RenderLEDsBatch;
JobData->BatchReservedRange = ReserveRangeInQuadConstructor(JobData->Batch, JobLedCount * 2);
JobData->LEDHalfWidth = .5f;
JobData->CameraPosition = ToV4Point(PanelState->Camera.Position);
#if 1
Context.GeneralWorkQueue->PushWorkOnQueue(Context.GeneralWorkQueue, (thread_proc*)DrawLEDsInBufferRangeJob, Data, ConstString("Sculpture Draw LEDS"));
Context.GeneralWorkQueue->PushWorkOnQueue(Context.GeneralWorkQueue, (thread_proc*)DrawLEDsInBufferRangeJob, Data, ConstString("Sculpture Draw LEDS"));
#else
DrawLedsInBuffer(JobData->LedBuffer, JobData->StartIndex, JobData->OnePastLastIndex, JobData->Batch, JobData->BatchReservedRange, JobData->LEDHalfWidth);
DrawLedsInBuffer(JobData->LedBuffer, JobData->StartIndex, JobData->OnePastLastIndex, JobData->Batch, JobData->BatchReservedRange, JobData->LEDHalfWidth);
#endif
NextLEDIndex = JobData->OnePastLastIndex;
}
NextLEDIndex = JobData->OnePastLastIndex;
}
}
// TODO(Peter): I don't like the fact that setting an orthographic view inside a panel render function
// needs to relyon the window bounds rather than the panel bounds. Ideally the panel only needs to know where
// itself is, and nothing else.
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
if (State->Assemblies.Count > 0)
{
assembly Assembly = State->Assemblies.Values[0];
led_buffer* LedBuffer = LedSystemGetBuffer(&State->LedSystem, Assembly.LedBufferIndex);
// TODO(Peter): I don't like the fact that setting an orthographic view inside a panel render function
// needs to relyon the window bounds rather than the panel bounds. Ideally the panel only needs to know where
// itself is, and nothing else.
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
if (State->Assemblies.Count > 0)
{
assembly Assembly = State->Assemblies.Values[0];
led_buffer* LedBuffer = LedSystemGetBuffer(&State->LedSystem, Assembly.LedBufferIndex);
v4 LedPosition = LedBuffer->Positions[FocusPixel];
v2 LedOnScreenPosition = SculptureView_WorldToScreenPosition(LedPosition, PanelState->Camera, PanelBounds);
gs_string Tempgs_string = PushString(State->Transient, 256);
PrintF(&Tempgs_string, "Hot Id: %u, ZIndex: %u | Active Id: %u", State->Interface.HotWidget.Id,
State->Interface.HotWidget.ZIndex,State->Interface.ActiveWidget.Id);
DrawString(RenderBuffer, Tempgs_string, State->Interface.Style.Font, v2{PanelBounds.Min.x + 100, PanelBounds.Max.y - 200}, WhiteV4, -1, GreenV4);
}
Context.GeneralWorkQueue->CompleteQueueWork(Context.GeneralWorkQueue, Context.ThreadContext);
v4 LedPosition = LedBuffer->Positions[FocusPixel];
v2 LedOnScreenPosition = SculptureView_WorldToScreenPosition(LedPosition, PanelState->Camera, PanelBounds);
gs_string Tempgs_string = PushString(State->Transient, 256);
PrintF(&Tempgs_string, "Hot Id: %u, ZIndex: %u | Active Id: %u", State->Interface.HotWidget.Id,
State->Interface.HotWidget.ZIndex,State->Interface.ActiveWidget.Id);
DrawString(RenderBuffer, Tempgs_string, State->Interface.Style.Font, v2{PanelBounds.Min.x + 100, PanelBounds.Max.y - 200}, WhiteV4, -1, GreenV4);
}
Context.GeneralWorkQueue->CompleteQueueWork(Context.GeneralWorkQueue, Context.ThreadContext);
}
#define FOLDHAUS_PANEL_SCULPTURE_VIEW_H

View File

@ -8,122 +8,122 @@
internal pixel
LedBlend_Overwrite(pixel PixelA, pixel PixelB, u8* UserData)
{
r32 MagB = (r32)(PixelB.R + PixelB.G + PixelB.B) / (255 * 3);
pixel Result = {};
Result.R = (u8)LerpR32(MagB, PixelA.R, PixelB.R);
Result.G = (u8)LerpR32(MagB, PixelA.G, PixelB.G);
Result.B = (u8)LerpR32(MagB, PixelA.B, PixelB.B);
r32 MagB = (r32)(PixelB.R + PixelB.G + PixelB.B) / (255 * 3);
pixel Result = {};
Result.R = (u8)LerpR32(MagB, PixelA.R, PixelB.R);
Result.G = (u8)LerpR32(MagB, PixelA.G, PixelB.G);
Result.B = (u8)LerpR32(MagB, PixelA.B, PixelB.B);
#if 0
pixel Result = PixelB;
if (PixelB.R == 0 &&
PixelB.G == 0 &&
PixelB.B == 0)
{
Result = PixelA;
}
pixel Result = PixelB;
if (PixelB.R == 0 &&
PixelB.G == 0 &&
PixelB.B == 0)
{
Result = PixelA;
}
#endif
return Result;
return Result;
}
internal pixel
LedBlend_Lerp(pixel PixelA, pixel PixelB, u8* UserData)
{
r32 BOpacity = *(r32*)UserData;
pixel Result = {};
r32 AOpacity = 1.0f - BOpacity;
Result.R = (u8)((PixelA.R * AOpacity) + (PixelB.R * BOpacity));
Result.G = (u8)((PixelA.G * AOpacity) + (PixelB.G * BOpacity));
Result.B = (u8)((PixelA.B * AOpacity) + (PixelB.B * BOpacity));
return Result;
r32 BOpacity = *(r32*)UserData;
pixel Result = {};
r32 AOpacity = 1.0f - BOpacity;
Result.R = (u8)((PixelA.R * AOpacity) + (PixelB.R * BOpacity));
Result.G = (u8)((PixelA.G * AOpacity) + (PixelB.G * BOpacity));
Result.B = (u8)((PixelA.B * AOpacity) + (PixelB.B * BOpacity));
return Result;
}
internal pixel
LedBlend_Add(pixel PixelA, pixel PixelB, u8* UserData)
{
pixel Result = {};
u32 R = (u32)PixelA.R + (u32)PixelB.R;
u32 G = (u32)PixelA.G + (u32)PixelB.G;
u32 B = (u32)PixelA.B + (u32)PixelB.B;
Result.R = (u8)Min(R, (u32)255);
Result.G = (u8)Min(G, (u32)255);
Result.B = (u8)Min(B, (u32)255);
return Result;
pixel Result = {};
u32 R = (u32)PixelA.R + (u32)PixelB.R;
u32 G = (u32)PixelA.G + (u32)PixelB.G;
u32 B = (u32)PixelA.B + (u32)PixelB.B;
Result.R = (u8)Min(R, (u32)255);
Result.G = (u8)Min(G, (u32)255);
Result.B = (u8)Min(B, (u32)255);
return Result;
}
internal pixel
LedBlend_Multiply(pixel PixelA, pixel PixelB, u8* UserData)
{
pixel Result = {};
r32 DR = (r32)PixelA.R / 255.f;
r32 DG = (r32)PixelA.G / 255.f;
r32 DB = (r32)PixelA.B / 255.f;
r32 SR = (r32)PixelB.R / 255.f;
r32 SG = (r32)PixelB.G / 255.f;
r32 SB = (r32)PixelB.B / 255.f;
Result.R = (u8)((DR * SR) * 255.f);
Result.G = (u8)((DG * SG) * 255.f);
Result.B = (u8)((DB * SB) * 255.f);
return Result;
pixel Result = {};
r32 DR = (r32)PixelA.R / 255.f;
r32 DG = (r32)PixelA.G / 255.f;
r32 DB = (r32)PixelA.B / 255.f;
r32 SR = (r32)PixelB.R / 255.f;
r32 SG = (r32)PixelB.G / 255.f;
r32 SB = (r32)PixelB.B / 255.f;
Result.R = (u8)((DR * SR) * 255.f);
Result.G = (u8)((DG * SG) * 255.f);
Result.B = (u8)((DB * SB) * 255.f);
return Result;
}
internal pixel
LedBlend_Overlay(pixel PixelA, pixel PixelB, u8* UserData)
{
pixel Result = {};
return Result;
pixel Result = {};
return Result;
}
internal led_blend_proc*
LedBlend_GetProc(blend_mode BlendMode)
{
led_blend_proc* Result = 0;
switch (BlendMode)
{
case BlendMode_Overwrite: { Result = LedBlend_Overwrite; }break;
case BlendMode_Add: { Result = LedBlend_Add; }break;
case BlendMode_Multiply: { Result = LedBlend_Multiply; }break;
InvalidDefaultCase;
}
return Result;
led_blend_proc* Result = 0;
switch (BlendMode)
{
case BlendMode_Overwrite: { Result = LedBlend_Overwrite; }break;
case BlendMode_Add: { Result = LedBlend_Add; }break;
case BlendMode_Multiply: { Result = LedBlend_Multiply; }break;
InvalidDefaultCase;
}
return Result;
}
struct pattern_args
{
assembly Assembly;
gs_memory_arena* Transient;
u8* UserData;
assembly Assembly;
gs_memory_arena* Transient;
u8* UserData;
};
struct render_anim_to_led_buffer_job_data
{
animation_pattern Pattern;
led_buffer Buffer;
led_buffer_range BufferRange;
pattern_args PatternArgs;
r32 SecondsIntoBlock;
animation_pattern Pattern;
led_buffer Buffer;
led_buffer_range BufferRange;
pattern_args PatternArgs;
r32 SecondsIntoBlock;
};
internal void
AnimationSystem_RenderAnimationToLedBufferJob(gs_thread_context Context, gs_data Data)
{
render_anim_to_led_buffer_job_data JobData = *(render_anim_to_led_buffer_job_data*)Data.Memory;
JobData.Pattern.Proc(&JobData.Buffer,
JobData.BufferRange,
JobData.PatternArgs.Assembly,
JobData.SecondsIntoBlock,
JobData.PatternArgs.Transient,
JobData.PatternArgs.UserData);
render_anim_to_led_buffer_job_data JobData = *(render_anim_to_led_buffer_job_data*)Data.Memory;
JobData.Pattern.Proc(&JobData.Buffer,
JobData.BufferRange,
JobData.PatternArgs.Assembly,
JobData.SecondsIntoBlock,
JobData.PatternArgs.Transient,
JobData.PatternArgs.UserData);
}
#define MULTITHREAD_PATTERN_RENDERING 1
@ -132,61 +132,61 @@ internal void
AnimationSystem_BeginRenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, animation_pattern_array Patterns, pattern_args PatternArgs,
context Context)
{
DEBUG_TRACK_FUNCTION;
DEBUG_TRACK_FUNCTION;
u32 FramesIntoBlock = System->CurrentFrame - Block.Range.Min;
r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame;
animation_pattern Pattern = Patterns_GetPattern(Patterns, Block.AnimationProcHandle);
Assert(Pattern.Proc);
if (System->Multithreaded && Pattern.Multithreaded)
{
u32 JobsCount = 4;
u32 LedsPerJob = Buffer->LedCount / JobsCount;
u32 FramesIntoBlock = System->CurrentFrame - Block.Range.Min;
r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame;
animation_pattern Pattern = Patterns_GetPattern(Patterns, Block.AnimationProcHandle);
Assert(Pattern.Proc);
if (System->Multithreaded && Pattern.Multithreaded)
for (u32 i = 0; i < JobsCount; i++)
{
u32 JobsCount = 4;
u32 LedsPerJob = Buffer->LedCount / JobsCount;
for (u32 i = 0; i < JobsCount; i++)
{
gs_data Data = PushSizeToData(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;
JobData->BufferRange.First = LedsPerJob * i;
JobData->BufferRange.OnePastLast = LedsPerJob * (i + 1);
JobData->PatternArgs = PatternArgs;
JobData->SecondsIntoBlock = SecondsIntoBlock;
Context.GeneralWorkQueue->PushWorkOnQueue(Context.GeneralWorkQueue,
(thread_proc*)AnimationSystem_RenderAnimationToLedBufferJob,
Data,
ConstString("Render Pattern To Buffer"));
}
}
else
{
led_buffer_range Range = {};
Range.First = 0;
Range.OnePastLast = Buffer->LedCount;
Pattern.Proc(Buffer, Range, PatternArgs.Assembly, SecondsIntoBlock, PatternArgs.Transient, PatternArgs.UserData);
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;
JobData->BufferRange.First = LedsPerJob * i;
JobData->BufferRange.OnePastLast = LedsPerJob * (i + 1);
JobData->PatternArgs = PatternArgs;
JobData->SecondsIntoBlock = SecondsIntoBlock;
Context.GeneralWorkQueue->PushWorkOnQueue(Context.GeneralWorkQueue,
(thread_proc*)AnimationSystem_RenderAnimationToLedBufferJob,
Data,
ConstString("Render Pattern To Buffer"));
}
}
else
{
led_buffer_range Range = {};
Range.First = 0;
Range.OnePastLast = Buffer->LedCount;
Pattern.Proc(Buffer, Range, PatternArgs.Assembly, SecondsIntoBlock, PatternArgs.Transient, PatternArgs.UserData);
}
}
internal void
AnimationSystem_EndRenderBlockToLedBuffer (animation_system* System, context Context)
{
if (System->Multithreaded)
{
Context.GeneralWorkQueue->CompleteQueueWork(Context.GeneralWorkQueue, Context.ThreadContext);
}
if (System->Multithreaded)
{
Context.GeneralWorkQueue->CompleteQueueWork(Context.GeneralWorkQueue, Context.ThreadContext);
}
}
// NOTE(pjs): This mirrors animation_layer_frame to account
// for overlapping
struct layer_led_buffer
{
led_buffer HotBuffer;
led_buffer NextHotBuffer;
led_buffer HotBuffer;
led_buffer NextHotBuffer;
};
internal led_buffer
@ -199,80 +199,80 @@ RenderAnimationToLedBuffer (animation_system* System,
gs_memory_arena* Transient,
context Context)
{
DEBUG_TRACK_FUNCTION;
DEBUG_TRACK_FUNCTION;
led_buffer AccBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
// Create the LayerLEDBuffers
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
{
layer_led_buffer TempBuffer = {};
led_buffer AccBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
// Create the LayerLEDBuffers
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
if (CurrFrame.Layers[Layer].HasHot)
{
layer_led_buffer TempBuffer = {};
if (CurrFrame.Layers[Layer].HasHot)
{
TempBuffer.HotBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
if (CurrFrame.Layers[Layer].HasNextHot)
{
TempBuffer.NextHotBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
}
}
LayerBuffers[Layer] = TempBuffer;
TempBuffer.HotBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
if (CurrFrame.Layers[Layer].HasNextHot)
{
TempBuffer.NextHotBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
}
}
// Render Each layer's block to the appropriate temp buffer
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
LayerBuffers[Layer] = TempBuffer;
}
// Render Each layer's block to the appropriate temp buffer
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
{
animation_layer_frame LayerFrame = CurrFrame.Layers[Layer];
if (LayerFrame.HasHot)
{
animation_layer_frame LayerFrame = CurrFrame.Layers[Layer];
if (LayerFrame.HasHot)
{
led_buffer TempBuffer = LayerBuffers[Layer].HotBuffer;
animation_block Block = LayerFrame.Hot;
AnimationSystem_BeginRenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs, Context);
}
if (LayerFrame.HasNextHot)
{
led_buffer TempBuffer = LayerBuffers[Layer].NextHotBuffer;
animation_block Block = LayerFrame.NextHot;
AnimationSystem_BeginRenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs, Context);
}
AnimationSystem_EndRenderBlockToLedBuffer(System, Context);
led_buffer TempBuffer = LayerBuffers[Layer].HotBuffer;
animation_block Block = LayerFrame.Hot;
AnimationSystem_BeginRenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs, Context);
}
// Blend together any layers that have a hot and next hot buffer
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
if (LayerFrame.HasNextHot)
{
animation_layer_frame LayerFrame = CurrFrame.Layers[Layer];
layer_led_buffer LayerBuffer = LayerBuffers[Layer];
if (LayerFrame.HasNextHot)
{
LedBuffer_Blend(LayerBuffer.HotBuffer,
LayerBuffer.NextHotBuffer,
&LayerBuffer.HotBuffer,
LedBlend_Lerp,
(u8*)&LayerFrame.NextHotOpacity);
}
led_buffer TempBuffer = LayerBuffers[Layer].NextHotBuffer;
animation_block Block = LayerFrame.NextHot;
AnimationSystem_BeginRenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs, Context);
}
// Consolidate Temp Buffers back into AssemblyLedBuffer
// We do this in reverse order so that they go from top to bottom
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
AnimationSystem_EndRenderBlockToLedBuffer(System, Context);
}
// Blend together any layers that have a hot and next hot buffer
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
{
animation_layer_frame LayerFrame = CurrFrame.Layers[Layer];
layer_led_buffer LayerBuffer = LayerBuffers[Layer];
if (LayerFrame.HasNextHot)
{
if (CurrFrame.Layers[Layer].HasHot)
{
led_blend_proc* Blend = LedBlend_GetProc(CurrFrame.Layers[Layer].BlendMode);
LedBuffer_Blend(AccBuffer,
LayerBuffers[Layer].HotBuffer,
&AccBuffer,
Blend,
0);
}
LedBuffer_Blend(LayerBuffer.HotBuffer,
LayerBuffer.NextHotBuffer,
&LayerBuffer.HotBuffer,
LedBlend_Lerp,
(u8*)&LayerFrame.NextHotOpacity);
}
return AccBuffer;
}
// Consolidate Temp Buffers back into AssemblyLedBuffer
// We do this in reverse order so that they go from top to bottom
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
{
if (CurrFrame.Layers[Layer].HasHot)
{
led_blend_proc* Blend = LedBlend_GetProc(CurrFrame.Layers[Layer].BlendMode);
LedBuffer_Blend(AccBuffer,
LayerBuffers[Layer].HotBuffer,
&AccBuffer,
Blend,
0);
}
}
return AccBuffer;
}
internal void
@ -283,92 +283,92 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse
context Context,
u8* UserData)
{
DEBUG_TRACK_FUNCTION;
r32 FrameTime = AnimationSystem_GetCurrentTime(*System);
DEBUG_TRACK_FUNCTION;
r32 FrameTime = AnimationSystem_GetCurrentTime(*System);
#if 1
animation_array Animations = System->Animations;
animation_fade_group FadeGroup = System->ActiveFadeGroup;
animation_array Animations = System->Animations;
animation_fade_group FadeGroup = System->ActiveFadeGroup;
animation* FromAnim = AnimationArray_Get(Animations, FadeGroup.From);
animation_frame FromFrame = AnimationSystem_CalculateAnimationFrame(System, FromAnim, Transient);
layer_led_buffer* FromLayerBuffers = PushArray(Transient, layer_led_buffer, FromFrame.LayersCount);
animation* ToAnim = AnimationArray_Get(Animations, FadeGroup.To);
animation_frame ToFrame = {0};
layer_led_buffer* ToLayerBuffers = 0;
if (ToAnim)
{
ToFrame = AnimationSystem_CalculateAnimationFrame(System, ToAnim, Transient);
ToLayerBuffers = PushArray(Transient, layer_led_buffer, ToFrame.LayersCount);
}
for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++)
{
assembly Assembly = Assemblies.Values[AssemblyIndex];
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
animation* FromAnim = AnimationArray_Get(Animations, FadeGroup.From);
animation_frame FromFrame = AnimationSystem_CalculateAnimationFrame(System, FromAnim, Transient);
layer_led_buffer* FromLayerBuffers = PushArray(Transient, layer_led_buffer, FromFrame.LayersCount);
pattern_args PatternArgs = {};
PatternArgs.Assembly = Assembly;
PatternArgs.Transient = Transient;
PatternArgs.UserData = UserData;
animation* ToAnim = AnimationArray_Get(Animations, FadeGroup.To);
animation_frame ToFrame = {0};
layer_led_buffer* ToLayerBuffers = 0;
if (ToAnim)
{
ToFrame = AnimationSystem_CalculateAnimationFrame(System, ToAnim, Transient);
ToLayerBuffers = PushArray(Transient, layer_led_buffer, ToFrame.LayersCount);
}
for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++)
{
assembly Assembly = Assemblies.Values[AssemblyIndex];
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
pattern_args PatternArgs = {};
PatternArgs.Assembly = Assembly;
PatternArgs.Transient = Transient;
PatternArgs.UserData = UserData;
led_buffer FromBuffer = RenderAnimationToLedBuffer(System,
PatternArgs,
FromFrame,
FromLayerBuffers,
AssemblyLedBuffer,
Patterns,
Transient,
Context);
led_buffer ConsolidatedBuffer = FromBuffer;
if (ToAnim) {
led_buffer ToBuffer = RenderAnimationToLedBuffer(System,
PatternArgs,
ToFrame,
ToLayerBuffers,
AssemblyLedBuffer,
Patterns,
Transient,
Context);
r32 BlendPercent = FadeGroup.FadeElapsed / FadeGroup.FadeDuration;
LedBuffer_Blend(FromBuffer, ToBuffer, &ConsolidatedBuffer, LedBlend_Lerp, (u8*)&BlendPercent);
}
LedBuffer_Copy(ConsolidatedBuffer, AssemblyLedBuffer);
led_buffer FromBuffer = RenderAnimationToLedBuffer(System,
PatternArgs,
FromFrame,
FromLayerBuffers,
AssemblyLedBuffer,
Patterns,
Transient,
Context);
led_buffer ConsolidatedBuffer = FromBuffer;
if (ToAnim) {
led_buffer ToBuffer = RenderAnimationToLedBuffer(System,
PatternArgs,
ToFrame,
ToLayerBuffers,
AssemblyLedBuffer,
Patterns,
Transient,
Context);
r32 BlendPercent = FadeGroup.FadeElapsed / FadeGroup.FadeDuration;
LedBuffer_Blend(FromBuffer, ToBuffer, &ConsolidatedBuffer, LedBlend_Lerp, (u8*)&BlendPercent);
}
LedBuffer_Copy(ConsolidatedBuffer, AssemblyLedBuffer);
}
#else
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(System, ActiveAnim, Transient);
for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++)
{
assembly Assembly = Assemblies.Values[AssemblyIndex];
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(System, ActiveAnim, Transient);
for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++)
{
assembly Assembly = Assemblies.Values[AssemblyIndex];
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
pattern_args PatternArgs = {};
PatternArgs.Assembly = Assembly;
PatternArgs.Transient = Transient;
PatternArgs.UserData = UserData;
led_buffer AccBuffer = RenderAnimationToLedBuffer(System,
PatternArgs,
CurrFrame,
LayerBuffers,
AssemblyLedBuffer,
Patterns,
Transient);
LedBuffer_Copy(AccBuffer, AssemblyLedBuffer);
}
pattern_args PatternArgs = {};
PatternArgs.Assembly = Assembly;
PatternArgs.Transient = Transient;
PatternArgs.UserData = UserData;
led_buffer AccBuffer = RenderAnimationToLedBuffer(System,
PatternArgs,
CurrFrame,
LayerBuffers,
AssemblyLedBuffer,
Patterns,
Transient);
LedBuffer_Copy(AccBuffer, AssemblyLedBuffer);
}
#endif
System->LastUpdatedFrame = System->CurrentFrame;
System->LastUpdatedFrame = System->CurrentFrame;
}
#define FOLDHAUS_ANIMATION_RENDERER_CPP

View File

@ -14,35 +14,35 @@
internal assembly_array
AssemblyArray_Create(u32 CountMax, gs_memory_arena* Storage)
{
assembly_array Result = {0};
Result.CountMax = CountMax;
Result.Values = PushArray(Storage, assembly, Result.CountMax);
return Result;
assembly_array Result = {0};
Result.CountMax = CountMax;
Result.Values = PushArray(Storage, assembly, Result.CountMax);
return Result;
}
internal u32
AssemblyArray_Push(assembly_array* Array, assembly Assembly)
{
Assert(Array->Count < Array->CountMax);
u32 Index = Array->Count++;
Array->Values[Index] = Assembly;
Array->Values[Index].AssemblyIndex = Index;
return Index;
Assert(Array->Count < Array->CountMax);
u32 Index = Array->Count++;
Array->Values[Index] = Assembly;
Array->Values[Index].AssemblyIndex = Index;
return Index;
}
internal assembly*
AssemblyArray_Take(assembly_array* Array)
{
u32 Index = AssemblyArray_Push(Array, {});
assembly* Result = Array->Values + Index;
return Result;
u32 Index = AssemblyArray_Push(Array, {});
assembly* Result = Array->Values + Index;
return Result;
}
internal void
AssemblyArray_RemoveAt(assembly_array* Array, u32 Index)
{
u32 LastAssemblyIndex = --Array->Count;
Array->Values[Index] = Array->Values[LastAssemblyIndex];
u32 LastAssemblyIndex = --Array->Count;
Array->Values[Index] = Array->Values[LastAssemblyIndex];
}
typedef bool assembly_array_filter_proc(assembly A);
@ -52,18 +52,18 @@ bool AssemblyFilter_OutputsViaUART(assembly A) { return A.OutputMode == NetworkP
internal assembly_array
AssemblyArray_Filter(assembly_array Array, assembly_array_filter_proc* Filter, gs_memory_arena* Storage)
{
assembly_array Result = AssemblyArray_Create(Array.Count, Storage);
for (u32 i = 0; i < Array.Count; i++)
assembly_array Result = AssemblyArray_Create(Array.Count, Storage);
for (u32 i = 0; i < Array.Count; i++)
{
assembly At = Array.Values[i];
if (Filter(At))
{
assembly At = Array.Values[i];
if (Filter(At))
{
AssemblyArray_Push(&Result, At);
}
AssemblyArray_Push(&Result, At);
}
return Result;
}
return Result;
}
///////////////////////////
@ -75,177 +75,177 @@ AssemblyArray_Filter(assembly_array Array, assembly_array_filter_proc* Filter, g
internal led_system
LedSystem_Create(gs_allocator PlatformMemory, u32 BuffersMax)
{
led_system Result = {};
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);
return Result;
led_system Result = {};
Result.PlatformMemory = PlatformMemory;
// TODO(Peter): Since we have access to PlatformMemory, just realloc Buffers when we fill it up
Result.BuffersCountMax = BuffersMax;
Result.Buffers = AllocArray(PlatformMemory, led_buffer, Result.BuffersCountMax, "led system");
return Result;
}
internal u32
LedSystemTakeFreeBuffer(led_system* System, u32 LedCount)
{
s32 Result = -1;
if (System->BuffersCount < System->BuffersCountMax)
s32 Result = -1;
if (System->BuffersCount < System->BuffersCountMax)
{
Result = System->BuffersCount++;
}
else
{
// NOTE(Peter): Look for a buffer that's flagged as empty
for (u32 i = 0; i < System->BuffersCount; i++)
{
Result = System->BuffersCount++;
if (System->Buffers[i].LedCount == 0
&& System->Buffers[i].Colors == 0
&& System->Buffers[i].Positions == 0)
{
Result = i;
break;
}
}
else
{
// NOTE(Peter): Look for a buffer that's flagged as empty
for (u32 i = 0; i < System->BuffersCount; i++)
{
if (System->Buffers[i].LedCount == 0
&& System->Buffers[i].Colors == 0
&& System->Buffers[i].Positions == 0)
{
Result = i;
break;
}
}
Assert(Result >= 0); // NOTE(Peter): We ran out of room for led buffers
}
led_buffer* Buffer = &System->Buffers[Result];
Buffer->LedCount = LedCount;
Buffer->Colors = AllocatorAllocArray(System->PlatformMemory, pixel, Buffer->LedCount);
Buffer->Positions = AllocatorAllocArray(System->PlatformMemory, v4, Buffer->LedCount);
System->LedsCountTotal += LedCount;
return (u32)Result;
Assert(Result >= 0); // NOTE(Peter): We ran out of room for led buffers
}
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 = PushArray(&Buffer->A, pixel, Buffer->LedCount);
Buffer->Positions = PushArray(&Buffer->A, v4, Buffer->LedCount);
System->LedsCountTotal += LedCount;
return (u32)Result;
}
internal void
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);
System->LedsCountTotal -= Buffer->LedCount;
*Buffer = {};
Assert(BufferIndex < System->BuffersCountMax);
led_buffer* Buffer = &System->Buffers[BufferIndex];
MemoryArenaFree(&Buffer->A);
System->LedsCountTotal -= Buffer->LedCount;
*Buffer = {};
}
internal void
LedBufferSetLed(led_buffer* Buffer, u32 Led, v4 Position)
{
Assert(Led < Buffer->LedCount);
Buffer->Positions[Led] = Position;
Assert(Led < Buffer->LedCount);
Buffer->Positions[Led] = Position;
}
internal u32
Assembly_ConstructStrip(assembly* Assembly, led_buffer* LedBuffer, v2_strip* StripAt, strip_gen_data GenData, v4 RootPosition, u32 LedStartIndex, u32 LedLUTStartIndex)
{
u32 LedsAdded = 0;
switch (GenData.Method)
u32 LedsAdded = 0;
switch (GenData.Method)
{
case StripGeneration_InterpolatePoints:
{
case StripGeneration_InterpolatePoints:
{
strip_gen_interpolate_points InterpPoints = GenData.InterpolatePoints;
v4 WS_StripStart = RootPosition + ToV4Point(InterpPoints.StartPosition * Assembly->Scale);
v4 WS_StripEnd = RootPosition + ToV4Point(InterpPoints.EndPosition * Assembly->Scale);
v4 SingleStep = (WS_StripEnd - WS_StripStart) / (r32)InterpPoints.LedCount;
for (u32 Step = 0; Step < InterpPoints.LedCount; Step++)
{
s32 LedIndex = LedStartIndex + LedsAdded++;
v4 LedPosition = WS_StripStart + (SingleStep * Step);
LedBufferSetLed(LedBuffer, LedIndex, LedPosition);
StripAt->LedLUT[Step + LedLUTStartIndex] = LedIndex;
}
}break;
case StripGeneration_Sequence:
{
strip_gen_sequence Sequence = GenData.Sequence;
for (u32 i = 0; i < Sequence.ElementsCount; i++)
{
strip_gen_data SegmentGenData = Sequence.Elements[i];
LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, SegmentGenData, RootPosition, LedStartIndex + LedsAdded, LedsAdded);
}
}break;
InvalidDefaultCase;
}
strip_gen_interpolate_points InterpPoints = GenData.InterpolatePoints;
v4 WS_StripStart = RootPosition + ToV4Point(InterpPoints.StartPosition * Assembly->Scale);
v4 WS_StripEnd = RootPosition + ToV4Point(InterpPoints.EndPosition * Assembly->Scale);
v4 SingleStep = (WS_StripEnd - WS_StripStart) / (r32)InterpPoints.LedCount;
for (u32 Step = 0; Step < InterpPoints.LedCount; Step++)
{
s32 LedIndex = LedStartIndex + LedsAdded++;
v4 LedPosition = WS_StripStart + (SingleStep * Step);
LedBufferSetLed(LedBuffer, LedIndex, LedPosition);
StripAt->LedLUT[Step + LedLUTStartIndex] = LedIndex;
}
}break;
return LedsAdded;
case StripGeneration_Sequence:
{
strip_gen_sequence Sequence = GenData.Sequence;
for (u32 i = 0; i < Sequence.ElementsCount; i++)
{
strip_gen_data SegmentGenData = Sequence.Elements[i];
LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, SegmentGenData, RootPosition, LedStartIndex + LedsAdded, LedsAdded);
}
}break;
InvalidDefaultCase;
}
return LedsAdded;
}
internal void
ConstructAssemblyFromDefinition (assembly* Assembly, led_system* LedSystem)
{
Assembly->LedBufferIndex = LedSystemTakeFreeBuffer(LedSystem, Assembly->LedCountTotal);
led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly->LedBufferIndex);
Assembly->LedBufferIndex = LedSystemTakeFreeBuffer(LedSystem, Assembly->LedCountTotal);
led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly->LedBufferIndex);
v4 RootPosition = ToV4Vec(Assembly->Center);
// Add Leds
u32 LedsAdded = 0;
for (u32 StripIdx = 0; StripIdx < Assembly->StripCount; StripIdx++)
{
v2_strip* StripAt = &Assembly->Strips[StripIdx];
StripAt->LedLUT = PushArray(&Assembly->Arena, u32, StripAt->LedCount);
v4 RootPosition = ToV4Vec(Assembly->Center);
// Add Leds
u32 LedsAdded = 0;
for (u32 StripIdx = 0; StripIdx < Assembly->StripCount; StripIdx++)
{
v2_strip* StripAt = &Assembly->Strips[StripIdx];
StripAt->LedLUT = PushArray(&Assembly->Arena, u32, StripAt->LedCount);
strip_gen_data GenData = StripAt->GenerationData;
LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, GenData, RootPosition, LedsAdded, 0);
}
strip_gen_data GenData = StripAt->GenerationData;
LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, GenData, RootPosition, LedsAdded, 0);
}
}
internal assembly*
LoadAssembly (assembly_array* Assemblies, led_system* LedSystem, gs_memory_arena* Scratch, context Context, gs_const_string Path, log_buffer* GlobalLog)
{
assembly* NewAssembly = 0;
assembly* NewAssembly = 0;
gs_file AssemblyFile = ReadEntireFile(Context.ThreadContext.FileHandler, Path);
if (FileNoError(AssemblyFile))
{
gs_string AssemblyFileText = MakeString((char*)AssemblyFile.Memory);
gs_file AssemblyFile = ReadEntireFile(Context.ThreadContext.FileHandler, Path);
if (FileNoError(AssemblyFile))
s32 IndexOfLastSlash = FindLast(Path, '\\');
gs_const_string FileName = Substring(Path, IndexOfLastSlash + 1, Path.Length);
NewAssembly = AssemblyArray_Take(Assemblies);
NewAssembly->Arena = MemoryArenaCreate(MB(4), Bytes(8), Context.ThreadContext.Allocator, 0, 0, "Assembly Arena");
parser AssemblyParser = ParseAssemblyFile(NewAssembly, FileName, AssemblyFileText, Scratch);
if (AssemblyParser.Success)
{
gs_string AssemblyFileText = MakeString((char*)AssemblyFile.Memory);
s32 IndexOfLastSlash = FindLast(Path, '\\');
gs_const_string FileName = Substring(Path, IndexOfLastSlash + 1, Path.Length);
NewAssembly = AssemblyArray_Take(Assemblies);
NewAssembly->Arena = CreateMemoryArena(Context.ThreadContext.Allocator, "Assembly Arena");
parser AssemblyParser = ParseAssemblyFile(NewAssembly, FileName, AssemblyFileText, Scratch);
if (AssemblyParser.Success)
{
ConstructAssemblyFromDefinition(NewAssembly, LedSystem);
}
else
{
FreeMemoryArena(&NewAssembly->Arena);
Assemblies->Count -= 1;
}
for (parser_error* ErrorAt = AssemblyParser.ErrorsRoot;
ErrorAt != 0;
ErrorAt = ErrorAt->Next)
{
Log_Error(GlobalLogBuffer, ErrorAt->Message.Str);
}
ConstructAssemblyFromDefinition(NewAssembly, LedSystem);
}
else
{
Log_Error(GlobalLog, "Unable to load assembly file");
MemoryArenaFree(&NewAssembly->Arena);
Assemblies->Count -= 1;
}
return NewAssembly;
for (parser_error* ErrorAt = AssemblyParser.ErrorsRoot;
ErrorAt != 0;
ErrorAt = ErrorAt->Next)
{
Log_Error(GlobalLogBuffer, ErrorAt->Message.Str);
}
}
else
{
Log_Error(GlobalLog, "Unable to load assembly file");
}
return NewAssembly;
}
internal void
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);
AssemblyArray_RemoveAt(&State->Assemblies, AssemblyIndex);
Assert(AssemblyIndex < State->Assemblies.Count);
assembly* Assembly = &State->Assemblies.Values[AssemblyIndex];
LedSystemFreeBuffer(&State->LedSystem, Assembly->LedBufferIndex);
MemoryArenaFree(&Assembly->Arena);
AssemblyArray_RemoveAt(&State->Assemblies, AssemblyIndex);
}
// Querying Assemblies
@ -253,30 +253,30 @@ UnloadAssembly (u32 AssemblyIndex, app_state* State, context Context)
internal led_strip_list
AssemblyStripsGetWithTagValue(assembly Assembly, gs_const_string TagName, gs_const_string TagValue, gs_memory_arena* Storage)
{
led_strip_list Result = {0};
// TODO(pjs): @Optimization
// We can probably come back here and do this allocation procedurally, or in buckets, or with
// a linked list. But for now, I just want to get this up and running
Result.CountMax = Assembly.StripCount;
Result.StripIndices = PushArray(Storage, u32, Result.CountMax);
u64 NameHash = HashDJB2ToU32(StringExpand(TagName));
u64 ValueHash = 0;
if (TagValue.Length > 0)
led_strip_list Result = {0};
// TODO(pjs): @Optimization
// We can probably come back here and do this allocation procedurally, or in buckets, or with
// a linked list. But for now, I just want to get this up and running
Result.CountMax = Assembly.StripCount;
Result.StripIndices = PushArray(Storage, u32, Result.CountMax);
u64 NameHash = HashDJB2ToU32(StringExpand(TagName));
u64 ValueHash = 0;
if (TagValue.Length > 0)
{
ValueHash = HashDJB2ToU32(StringExpand(TagValue));
}
for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++)
{
v2_strip StripAt = Assembly.Strips[StripIndex];
if (AssemblyStrip_HasTagValue(StripAt, NameHash, ValueHash))
{
ValueHash = HashDJB2ToU32(StringExpand(TagValue));
Result.StripIndices[Result.Count++] = StripIndex;
}
for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++)
{
v2_strip StripAt = Assembly.Strips[StripIndex];
if (AssemblyStrip_HasTagValue(StripAt, NameHash, ValueHash))
{
Result.StripIndices[Result.Count++] = StripIndex;
}
}
return Result;
}
return Result;
}
#define FOLDHAUS_ASSEMBLY_CPP

View File

@ -7,165 +7,172 @@
enum network_protocol
{
NetworkProtocol_SACN,
NetworkProtocol_ArtNet,
NetworkProtocol_UART,
NetworkProtocol_Count,
NetworkProtocol_SACN,
NetworkProtocol_ArtNet,
NetworkProtocol_UART,
NetworkProtocol_Count,
};
union pixel
{
struct
{
u8 R;
u8 G;
u8 B;
};
u8 Channels[3];
struct
{
u8 R;
u8 G;
u8 B;
};
u8 Channels[3];
};
struct led_buffer
{
u32 LedCount;
pixel* Colors;
v4* Positions;
// 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;
};
struct led_buffer_range
{
u32 First;
u32 OnePastLast;
u32 First;
u32 OnePastLast;
};
struct led_system
{
gs_allocator PlatformMemory;
u32 BuffersCountMax;
u32 BuffersCount;
led_buffer* Buffers;
u32 LedsCountTotal;
gs_allocator PlatformMemory;
u32 BuffersCountMax;
u32 BuffersCount;
led_buffer* Buffers;
u32 LedsCountTotal;
};
struct v2_tag
{
u64 NameHash;
u64 ValueHash;
u64 NameHash;
u64 ValueHash;
};
struct strip_sacn_addr
{
s32 StartUniverse;
s32 StartChannel;
s32 StartUniverse;
s32 StartChannel;
};
struct strip_uart_addr
{
u8 Channel;
gs_string ComPort;
// This may not be used based on the value of the parent
// assembly's NetworkPortMode field
u8 Channel;
gs_string ComPort;
// This may not be used based on the value of the parent
// assembly's NetworkPortMode field
};
enum strip_gen_method
{
StripGeneration_InterpolatePoints,
StripGeneration_Sequence,
StripGeneration_Count,
StripGeneration_InterpolatePoints,
StripGeneration_Sequence,
StripGeneration_Count,
};
typedef struct strip_gen_data strip_gen_data;
struct strip_gen_interpolate_points
{
v3 StartPosition;
v3 EndPosition;
u32 LedCount;
v3 StartPosition;
v3 EndPosition;
u32 LedCount;
};
struct strip_gen_sequence
{
strip_gen_data* Elements;
u32 ElementsCount;
strip_gen_data* Elements;
u32 ElementsCount;
};
struct strip_gen_data
{
strip_gen_method Method;
strip_gen_interpolate_points InterpolatePoints;
strip_gen_sequence Sequence;
strip_gen_method Method;
strip_gen_interpolate_points InterpolatePoints;
strip_gen_sequence Sequence;
};
struct v2_strip
{
s32 ControlBoxID; // TODO(Peter): I don't think we need this anymore
strip_sacn_addr SACNAddr;
strip_uart_addr UARTAddr;
strip_gen_data GenerationData;
u32 LedCount;
u32* LedLUT;
u32 TagsCount;
v2_tag* Tags;
s32 ControlBoxID; // TODO(Peter): I don't think we need this anymore
strip_sacn_addr SACNAddr;
strip_uart_addr UARTAddr;
strip_gen_data GenerationData;
u32 LedCount;
u32* LedLUT;
u32 TagsCount;
v2_tag* Tags;
};
struct led_strip_list
{
u32 Count;
u32 CountMax;
u32* StripIndices;
u32 Count;
u32 CountMax;
u32* StripIndices;
};
enum network_port_mode
{
// This enum defines the scope which contains what network
// port each address should be sent over.
NetworkPortMode_GlobalPort,
// GlobalPort means that the port is defined in the assembly structure
NetworkPortMode_PortPerStrip,
// PortPerStrip means that the address stored in the strip structure
// should be used, and each strip might have a different port
NetworkPortMode_Count,
// This enum defines the scope which contains what network
// port each address should be sent over.
NetworkPortMode_GlobalPort,
// GlobalPort means that the port is defined in the assembly structure
NetworkPortMode_PortPerStrip,
// PortPerStrip means that the address stored in the strip structure
// should be used, and each strip might have a different port
NetworkPortMode_Count,
};
struct assembly
{
gs_memory_arena Arena;
u32 AssemblyIndex;
gs_string Name;
gs_string FilePath;
r32 Scale;
v3 Center;
v3 MinLedPos, MaxLedPos;
s32 LedCountTotal;
u32 LedBufferIndex;
u32 StripCount;
v2_strip* Strips;
network_protocol OutputMode;
network_port_mode NetPortMode;
gs_string UARTComPort;
gs_memory_arena Arena;
u32 AssemblyIndex;
gs_string Name;
gs_string FilePath;
r32 Scale;
v3 Center;
v3 MinLedPos, MaxLedPos;
s32 LedCountTotal;
u32 LedBufferIndex;
u32 StripCount;
v2_strip* Strips;
network_protocol OutputMode;
network_port_mode NetPortMode;
gs_string UARTComPort;
};
struct assembly_array
{
u32 CountMax;
u32 Count;
assembly* Values;
u32 CountMax;
u32 Count;
assembly* Values;
};
typedef pixel led_blend_proc(pixel A, pixel B, u8* UserData);
@ -173,118 +180,118 @@ typedef pixel led_blend_proc(pixel A, pixel B, u8* UserData);
internal led_buffer*
LedSystemGetBuffer(led_system* System, u32 Index)
{
led_buffer* Result = &System->Buffers[Index];
return Result;
led_buffer* Result = &System->Buffers[Index];
return Result;
}
internal void
LedBuffer_ClearToBlack(led_buffer* Buffer)
{
for (u32 i = 0; i < Buffer->LedCount; i++)
{
Buffer->Colors[i].R = 0;
Buffer->Colors[i].G = 0;
Buffer->Colors[i].B = 0;
}
for (u32 i = 0; i < Buffer->LedCount; i++)
{
Buffer->Colors[i].R = 0;
Buffer->Colors[i].G = 0;
Buffer->Colors[i].B = 0;
}
}
internal void
LedBuffer_Copy(led_buffer From, led_buffer* To)
{
DEBUG_TRACK_FUNCTION;
Assert(From.LedCount == To->LedCount);
u32 LedCount = To->LedCount;
for (u32 i = 0; i < LedCount; i++)
{
To->Colors[i] = From.Colors[i];
}
DEBUG_TRACK_FUNCTION;
Assert(From.LedCount == To->LedCount);
u32 LedCount = To->LedCount;
for (u32 i = 0; i < LedCount; i++)
{
To->Colors[i] = From.Colors[i];
}
}
internal void
LedBuffer_Blend(led_buffer A, led_buffer B, led_buffer* Dest, led_blend_proc* BlendProc, u8* UserData)
{
DEBUG_TRACK_FUNCTION;
Assert(A.LedCount == B.LedCount);
Assert(Dest->LedCount == A.LedCount);
Assert(BlendProc);
u32 LedCount = Dest->LedCount;
for (u32 i = 0; i < LedCount; i++)
{
pixel PA = A.Colors[i];
pixel PB = B.Colors[i];
Dest->Colors[i] = BlendProc(PA, PB, UserData);
}
DEBUG_TRACK_FUNCTION;
Assert(A.LedCount == B.LedCount);
Assert(Dest->LedCount == A.LedCount);
Assert(BlendProc);
u32 LedCount = Dest->LedCount;
for (u32 i = 0; i < LedCount; i++)
{
pixel PA = A.Colors[i];
pixel PB = B.Colors[i];
Dest->Colors[i] = BlendProc(PA, PB, UserData);
}
}
internal led_buffer
LedBuffer_CreateCopyCleared (led_buffer Buffer, gs_memory_arena* Arena)
{
DEBUG_TRACK_FUNCTION;
led_buffer Result = {};
Result.LedCount = Buffer.LedCount;
Result.Positions = Buffer.Positions;
Result.Colors = PushArray(Arena, pixel, Buffer.LedCount);
LedBuffer_ClearToBlack(&Result);
return Result;
DEBUG_TRACK_FUNCTION;
led_buffer Result = {};
Result.LedCount = Buffer.LedCount;
Result.Positions = Buffer.Positions;
Result.Colors = PushArray(Arena, pixel, Buffer.LedCount);
LedBuffer_ClearToBlack(&Result);
return Result;
}
internal u32
StripGenData_CountLeds(strip_gen_data Data)
{
u32 Result = 0;
switch (Data.Method)
u32 Result = 0;
switch (Data.Method)
{
case StripGeneration_InterpolatePoints:
{
case StripGeneration_InterpolatePoints:
{
Result += Data.InterpolatePoints.LedCount;
}break;
case StripGeneration_Sequence:
{
for (u32 i = 0; i < Data.Sequence.ElementsCount; i++)
{
Result += StripGenData_CountLeds(Data.Sequence.Elements[i]);
}
}break;
InvalidDefaultCase;
}
Result += Data.InterpolatePoints.LedCount;
}break;
return Result;
case StripGeneration_Sequence:
{
for (u32 i = 0; i < Data.Sequence.ElementsCount; i++)
{
Result += StripGenData_CountLeds(Data.Sequence.Elements[i]);
}
}break;
InvalidDefaultCase;
}
return Result;
}
internal bool
AssemblyStrip_HasTagValue(v2_strip Strip, u64 NameHash, u64 ValueHash)
{
bool Result = false;
for (u32 i = 0; i < Strip.TagsCount; i++)
bool Result = false;
for (u32 i = 0; i < Strip.TagsCount; i++)
{
v2_tag TagAt = Strip.Tags[i];
if (TagAt.NameHash == NameHash)
{
v2_tag TagAt = Strip.Tags[i];
if (TagAt.NameHash == NameHash)
{
// NOTE(pjs): We can pass an empty string to the Value parameter,
// and it will match all values of Tag
if (ValueHash == 0 || ValueHash == TagAt.ValueHash)
{
Result = true;
break;
}
}
// NOTE(pjs): We can pass an empty string to the Value parameter,
// and it will match all values of Tag
if (ValueHash == 0 || ValueHash == TagAt.ValueHash)
{
Result = true;
break;
}
}
return Result;
}
return Result;
}
internal bool
AssemblyStrip_HasTagValueSLOW(v2_strip Strip, char* Name, char* Value)
{
u64 NameHash = HashDJB2ToU32(Name);
u64 ValueHash = HashDJB2ToU32(Value);
return AssemblyStrip_HasTagValue(Strip, NameHash, ValueHash);
u64 NameHash = HashDJB2ToU32(Name);
u64 ValueHash = HashDJB2ToU32(Value);
return AssemblyStrip_HasTagValue(Strip, NameHash, ValueHash);
}
#define FOLDHAUS_ASSEMBLY_H

View File

@ -11,97 +11,97 @@
enum data_buffer_address_type
{
AddressType_NetworkIP,
AddressType_ComPort,
AddressType_Invalid,
AddressType_NetworkIP,
AddressType_ComPort,
AddressType_Invalid,
};
struct addressed_data_buffer
{
union
union
{
struct
{
struct
{
u8* Memory;
u32 MemorySize;
};
gs_data Data;
u8* Memory;
u32 MemorySize;
};
data_buffer_address_type AddressType;
// IP Address
platform_socket_handle SendSocket;
u32 V4SendAddress;
u32 SendPort;
// COM
gs_const_string ComPort;
addressed_data_buffer* Next;
gs_data Data;
};
data_buffer_address_type AddressType;
// IP Address
platform_socket_handle SendSocket;
u32 V4SendAddress;
u32 SendPort;
// COM
gs_const_string ComPort;
addressed_data_buffer* Next;
};
struct addressed_data_buffer_list
{
gs_memory_arena* Arena;
addressed_data_buffer* Root;
addressed_data_buffer* Head;
gs_memory_arena* Arena;
addressed_data_buffer* Root;
addressed_data_buffer* Head;
};
internal void
AddressedDataBufferList_Clear(addressed_data_buffer_list* List)
{
List->Root = 0;
List->Head = 0;
ClearArena(List->Arena);
List->Root = 0;
List->Head = 0;
MemoryArenaClear(List->Arena);
}
internal addressed_data_buffer*
AddressedDataBufferList_PushEmpty(addressed_data_buffer_list* List)
{
addressed_data_buffer* Result = PushStruct(List->Arena, addressed_data_buffer);
*Result = {0};
Result->Next = 0;
Result->MemorySize = 0;
Result->Memory = 0;
SLLPushOrInit(List->Root, List->Head, Result);
return Result;
addressed_data_buffer* Result = PushStruct(List->Arena, addressed_data_buffer);
*Result = {0};
Result->Next = 0;
Result->MemorySize = 0;
Result->Memory = 0;
SLLPushOrInit(List->Root, List->Head, Result);
return Result;
}
internal addressed_data_buffer*
AddressedDataBufferList_Push(addressed_data_buffer_list* List, u32 BufferSize)
{
addressed_data_buffer* Result = AddressedDataBufferList_PushEmpty(List);
Result->MemorySize = BufferSize;
Result->Memory = PushArray(List->Arena, u8, Result->MemorySize);
return Result;
addressed_data_buffer* Result = AddressedDataBufferList_PushEmpty(List);
Result->MemorySize = BufferSize;
Result->Memory = PushArray(List->Arena, u8, Result->MemorySize);
return Result;
}
internal void
AddressedDataBuffer_SetNetworkAddress(addressed_data_buffer* Buffer, platform_socket_handle SendSocket, u32 V4SendAddress, u32 SendPort)
{
Buffer->AddressType = AddressType_NetworkIP;
Buffer->SendSocket = SendSocket;
Buffer->V4SendAddress = V4SendAddress;
Buffer->SendPort = SendPort;
Buffer->AddressType = AddressType_NetworkIP;
Buffer->SendSocket = SendSocket;
Buffer->V4SendAddress = V4SendAddress;
Buffer->SendPort = SendPort;
}
internal void
AddressedDataBuffer_SetCOMPort(addressed_data_buffer* Buffer, gs_const_string ComPort)
{
Buffer->AddressType = AddressType_ComPort;
Buffer->ComPort = ComPort;
Buffer->AddressType = AddressType_ComPort;
Buffer->ComPort = ComPort;
}
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");
return Result;
addressed_data_buffer_list Result = {};
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;
}
#define FOLDHAUS_ADDRESSED_DATA_H

View File

@ -5,79 +5,84 @@
enum log_entry_type
{
LogEntry_Message,
LogEntry_Error,
LogEntry_Message,
LogEntry_Error,
};
struct log_entry
{
log_entry_type Type;
gs_string String;
log_entry_type Type;
gs_string String;
};
struct log_buffer
{
gs_allocator Allocator;
u64 EntriesCount;
u64 NextEntry;
log_entry* Entries;
gs_memory_arena* Arena;
u64 EntriesCount;
u64 NextEntry;
log_entry* Entries;
};
struct log_buffer_iter
{
log_buffer* Buffer;
u64 Start;
u64 IndexAt;
log_entry* At;
log_buffer* Buffer;
u64 Start;
u64 IndexAt;
log_entry* At;
};
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.EntriesCount = Count;
Result.Entries = AllocatorAllocArray(Allocator, log_entry, Result.EntriesCount);
for (u32 i = 0; i < Result.EntriesCount; i++)
{
Result.Entries[i].String = AllocatorAllocString(Allocator, 512);
}
return Result;
log_buffer Result = {};
Result.Arena = A;
Result.EntriesCount = Count;
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 = MakeString(LogStringBufferAt, 0, LogStringLength);
LogStringBufferAt += LogStringLength;
}
return Result;
}
internal u64
Log_GetNextIndex(log_buffer Log, u64 At)
{
u64 Result = At + 1;
if (Result >= Log.EntriesCount)
{
Result = 0;
}
return Result;
u64 Result = At + 1;
if (Result >= Log.EntriesCount)
{
Result = 0;
}
return Result;
}
internal log_entry*
Log_TakeNextEntry(log_buffer* Log)
{
log_entry* Result = Log->Entries + Log->NextEntry;
Log->NextEntry = Log_GetNextIndex(*Log, Log->NextEntry);
return Result;
log_entry* Result = Log->Entries + Log->NextEntry;
Log->NextEntry = Log_GetNextIndex(*Log, Log->NextEntry);
return Result;
}
internal void
Log_PrintFVarArgs(log_buffer* Log, log_entry_type Type, char* Format, va_list Args)
{
log_entry* NextEntry = Log_TakeNextEntry(Log);
NextEntry->String.Length = 0;
NextEntry->Type = Type;
PrintFArgsList(&NextEntry->String, Format, Args);
NullTerminate(&NextEntry->String);
log_entry* NextEntry = Log_TakeNextEntry(Log);
NextEntry->String.Length = 0;
NextEntry->Type = Type;
PrintFArgsList(&NextEntry->String, Format, Args);
NullTerminate(&NextEntry->String);
#if DEBUG
OutputDebugStringA(NextEntry->String.Str);
OutputDebugStringA(NextEntry->String.Str);
#endif
}
@ -86,36 +91,36 @@ Log_PrintFVarArgs(log_buffer* Log, log_entry_type Type, char* Format, va_list Ar
internal void
Log_PrintF(log_buffer* Log, log_entry_type Type, char* Format, ...)
{
va_list Args;
va_start(Args, Format);
Log_PrintFVarArgs(Log, Type, Format, Args);
va_end(Args);
va_list Args;
va_start(Args, Format);
Log_PrintFVarArgs(Log, Type, Format, Args);
va_end(Args);
}
internal log_buffer_iter
Log_GetIter(log_buffer* Buffer)
{
log_buffer_iter Result = {};
Result.Buffer = Buffer;
Result.Start = Buffer->NextEntry;
Result.IndexAt = Result.Start;
Result.At = Result.Buffer->Entries + Result.IndexAt;
return Result;
log_buffer_iter Result = {};
Result.Buffer = Buffer;
Result.Start = Buffer->NextEntry;
Result.IndexAt = Result.Start;
Result.At = Result.Buffer->Entries + Result.IndexAt;
return Result;
}
internal bool
LogIter_CanAdvance(log_buffer_iter Iter)
{
u64 Next = Log_GetNextIndex(*Iter.Buffer, Iter.IndexAt);
bool Result = Next != Iter.Start;
return Result;
u64 Next = Log_GetNextIndex(*Iter.Buffer, Iter.IndexAt);
bool Result = Next != Iter.Start;
return Result;
}
internal void
LogIter_Advance(log_buffer_iter* Iter)
{
Iter->IndexAt = Log_GetNextIndex(*Iter->Buffer, Iter->IndexAt);
Iter->At = Iter->Buffer->Entries + Iter->IndexAt;
Iter->IndexAt = Log_GetNextIndex(*Iter->Buffer, Iter->IndexAt);
Iter->At = Iter->Buffer->Entries + Iter->IndexAt;
}
#endif //FOLDHAUS_LOG_H

View File

@ -9,163 +9,163 @@
internal void
UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel ChannelSettings, v2_strip Strip, led_buffer LedBuffer)
{
// NOTE(pjs): This is just here because the information is duplicated and I want to be sure
// to catch the error where they are different
Assert(ChannelSettings.PixelsCount == Strip.LedCount);
// NOTE(pjs): This is just here because the information is duplicated and I want to be sure
// to catch the error where they are different
Assert(ChannelSettings.PixelsCount == Strip.LedCount);
uart_header* Header = MemoryCursorPushStruct(WriteCursor, uart_header);
UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812);
uart_channel* Channel = MemoryCursorPushStruct(WriteCursor, uart_channel);
*Channel = ChannelSettings;
for (u32 i = 0; i < Channel->PixelsCount; i++)
{
u32 LedIndex = Strip.LedLUT[i];
pixel Color = LedBuffer.Colors[LedIndex];
uart_header* Header = PushStructOnCursor(WriteCursor, uart_header);
UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812);
u8* OutputPixel = MemoryCursorPushArray(WriteCursor, u8, 3);
uart_channel* Channel = PushStructOnCursor(WriteCursor, uart_channel);
*Channel = ChannelSettings;
for (u32 i = 0; i < Channel->PixelsCount; i++)
{
u32 LedIndex = Strip.LedLUT[i];
pixel Color = LedBuffer.Colors[LedIndex];
u8* OutputPixel = PushArrayOnCursor(WriteCursor, u8, 3);
// TODO(pjs): Use the Output mask
// TODO(pjs): Use the Output mask
#if 1
OutputPixel[0] = Color.R;
OutputPixel[1] = Color.G;
OutputPixel[2] = Color.B;
OutputPixel[0] = Color.R;
OutputPixel[1] = Color.G;
OutputPixel[2] = Color.B;
#else
OutputPixel[0] = 255;
OutputPixel[1] = 255;
OutputPixel[2] = 255;
OutputPixel[0] = 255;
OutputPixel[1] = 255;
OutputPixel[2] = 255;
#endif
if (Channel->ElementsCount == 4)
{
// TODO(pjs): Calculate white from the RGB components?
// Generally we just need a good way to handle the white channel,
// both in the renderer and in output
//OutputPixel[Channel->WhiteIndex] = Color.W;
}
if (Channel->ElementsCount == 4)
{
// TODO(pjs): Calculate white from the RGB components?
// Generally we just need a good way to handle the white channel,
// both in the renderer and in output
//OutputPixel[Channel->WhiteIndex] = Color.W;
}
uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer);
UART_FillFooter(Footer, (u8*)Header);
}
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_FillHeader(Header, 1, UART_DRAW_ALL);
uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer);
UART_FillFooter(Footer, (u8*)Header);
uart_header* Header = MemoryCursorPushStruct(WriteCursor, uart_header);
UART_FillHeader(Header, 1, UART_DRAW_ALL);
uart_footer* Footer = MemoryCursorPushStruct(WriteCursor, uart_footer);
UART_FillFooter(Footer, (u8*)Header);
}
internal void
UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem, gs_memory_arena* Transient)
{
uart_channel ChannelSettings = {0};
ChannelSettings.ElementsCount = 3;
ChannelSettings.ColorPackingOrder = 36;
uart_channel ChannelSettings = {0};
ChannelSettings.ElementsCount = 3;
ChannelSettings.ColorPackingOrder = 36;
// NOTE(pjs): This is the minimum size of every UART message. SetChannelBuffer messages will
// be bigger than this, but their size is based on the number of pixels in each channel
u32 MessageBaseSize = UART_MESSAGE_MIN_SIZE;
for (u32 AssemblyIdx = 0; AssemblyIdx < Assemblies.Count; AssemblyIdx++)
{
assembly Assembly = Assemblies.Values[AssemblyIdx];
led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
// NOTE(pjs): This is the minimum size of every UART message. SetChannelBuffer messages will
// be bigger than this, but their size is based on the number of pixels in each channel
u32 MessageBaseSize = UART_MESSAGE_MIN_SIZE;
for (u32 AssemblyIdx = 0; AssemblyIdx < Assemblies.Count; AssemblyIdx++)
struct strips_to_data_buffer
{
assembly Assembly = Assemblies.Values[AssemblyIdx];
led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
struct strips_to_data_buffer
gs_const_string ComPort;
u32* StripIndices;
u32 StripIndicesCount;
u32 StripIndicesCountMax;
u64 LedCount;
u8** ChannelsStart;
strips_to_data_buffer* Next;
};
u32 BuffersNeededCount = 0;
strips_to_data_buffer* BuffersNeededHead = 0;
strips_to_data_buffer* BuffersNeededTail = 0;
for (u32 StripIdx = 0; StripIdx < Assembly.StripCount; StripIdx++)
{
v2_strip StripAt = Assembly.Strips[StripIdx];
// If there is a buffer for this com port already created
// we use that
strips_to_data_buffer* BufferSelected = 0;
for (strips_to_data_buffer* At = BuffersNeededHead;
At!= 0;
At = At->Next)
{
if (StringsEqual(At->ComPort, StripAt.UARTAddr.ComPort.ConstString))
{
gs_const_string ComPort;
u32* StripIndices;
u32 StripIndicesCount;
u32 StripIndicesCountMax;
u64 LedCount;
u8** ChannelsStart;
strips_to_data_buffer* Next;
};
u32 BuffersNeededCount = 0;
strips_to_data_buffer* BuffersNeededHead = 0;
strips_to_data_buffer* BuffersNeededTail = 0;
for (u32 StripIdx = 0; StripIdx < Assembly.StripCount; StripIdx++)
{
v2_strip StripAt = Assembly.Strips[StripIdx];
// If there is a buffer for this com port already created
// we use that
strips_to_data_buffer* BufferSelected = 0;
for (strips_to_data_buffer* At = BuffersNeededHead;
At!= 0;
At = At->Next)
{
if (StringsEqual(At->ComPort, StripAt.UARTAddr.ComPort.ConstString))
{
BufferSelected = At;
break;
}
}
// if no existing buffer for this com port
// create a new one
if (!BufferSelected)
{
BufferSelected = PushStruct(Transient, strips_to_data_buffer);
*BufferSelected = {};
BufferSelected->ComPort = StripAt.UARTAddr.ComPort.ConstString;
// we don't know at this point how many indices per
// com port so just make enough room to fit all the strips
// if necessary
BufferSelected->StripIndicesCountMax = Assembly.StripCount;
BufferSelected->StripIndices = PushArray(Transient, u32, BufferSelected->StripIndicesCountMax);
BufferSelected->LedCount = 0;
BufferSelected->Next = 0;
SLLPushOrInit(BuffersNeededHead, BuffersNeededTail, BufferSelected);
BuffersNeededCount += 1;
}
Assert(BufferSelected->StripIndicesCount < BufferSelected->StripIndicesCountMax);
u32 Index = BufferSelected->StripIndicesCount++;
BufferSelected->StripIndices[Index] = StripIdx;
BufferSelected->LedCount += StripAt.LedCount;
BufferSelected = At;
break;
}
}
// if no existing buffer for this com port
// create a new one
if (!BufferSelected)
{
BufferSelected = PushStruct(Transient, strips_to_data_buffer);
*BufferSelected = {};
BufferSelected->ComPort = StripAt.UARTAddr.ComPort.ConstString;
// we don't know at this point how many indices per
// com port so just make enough room to fit all the strips
// if necessary
BufferSelected->StripIndicesCountMax = Assembly.StripCount;
BufferSelected->StripIndices = PushArray(Transient, u32, BufferSelected->StripIndicesCountMax);
BufferSelected->LedCount = 0;
BufferSelected->Next = 0;
for (strips_to_data_buffer* At = BuffersNeededHead;
At!= 0;
At = At->Next)
{
u32 TotalBufferSize = MessageBaseSize * Assembly.StripCount; // SetChannelBuffer messages
TotalBufferSize += MessageBaseSize; // DrawAll message
TotalBufferSize += ChannelSettings.ElementsCount * At->LedCount; // pixels * channels per pixel
At->ChannelsStart = PushArray(Transient, u8*, At->StripIndicesCount);
addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, TotalBufferSize);
gs_const_string ComPort = At->ComPort;
AddressedDataBuffer_SetCOMPort(Buffer, ComPort);
gs_memory_cursor WriteCursor = CreateMemoryCursor(Buffer->Data);
for (u32 i = 0; i < At->StripIndicesCount; i++)
{
u32 StripIdx = At->StripIndices[i];
v2_strip StripAt = Assembly.Strips[StripIdx];
ChannelSettings.PixelsCount = StripAt.LedCount;
UART_SetChannelBuffer_Create(&WriteCursor, ChannelSettings, StripAt, *LedBuffer);
}
UART_DrawAll_Create(&WriteCursor);
}
SLLPushOrInit(BuffersNeededHead, BuffersNeededTail, BufferSelected);
BuffersNeededCount += 1;
}
Assert(BufferSelected->StripIndicesCount < BufferSelected->StripIndicesCountMax);
u32 Index = BufferSelected->StripIndicesCount++;
BufferSelected->StripIndices[Index] = StripIdx;
BufferSelected->LedCount += StripAt.LedCount;
}
for (strips_to_data_buffer* At = BuffersNeededHead;
At!= 0;
At = At->Next)
{
u32 TotalBufferSize = MessageBaseSize * Assembly.StripCount; // SetChannelBuffer messages
TotalBufferSize += MessageBaseSize; // DrawAll message
TotalBufferSize += ChannelSettings.ElementsCount * At->LedCount; // pixels * channels per pixel
At->ChannelsStart = PushArray(Transient, u8*, At->StripIndicesCount);
addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, TotalBufferSize);
gs_const_string ComPort = At->ComPort;
AddressedDataBuffer_SetCOMPort(Buffer, ComPort);
gs_memory_cursor WriteCursor = MemoryCursorCreate(Buffer->Memory, Buffer->MemorySize);
for (u32 i = 0; i < At->StripIndicesCount; i++)
{
u32 StripIdx = At->StripIndices[i];
v2_strip StripAt = Assembly.Strips[StripIdx];
ChannelSettings.PixelsCount = StripAt.LedCount;
UART_SetChannelBuffer_Create(&WriteCursor, ChannelSettings, StripAt, *LedBuffer);
}
UART_DrawAll_Create(&WriteCursor);
}
}
}

View File

@ -10,190 +10,190 @@
RELOAD_STATIC_DATA(ReloadStaticData)
{
GlobalDebugServices = DebugServices;
GlobalLogBuffer = LogBuffer;
if (AppReady)
GlobalDebugServices = DebugServices;
GlobalLogBuffer = LogBuffer;
if (AppReady)
{
app_state* State = (app_state*)Context.MemoryBase;
State->PanelSystem.PanelDefs = GlobalPanelDefs;
State->PanelSystem.PanelDefsCount = GlobalPanelDefsCount;
gs_data UserData = State->UserSpaceDesc.UserData;
State->UserSpaceDesc = BlumenLumen_UserSpaceCreate();
if (UserData.Memory && !State->UserSpaceDesc.UserData.Memory)
{
app_state* State = (app_state*)Context.MemoryBase;
State->PanelSystem.PanelDefs = GlobalPanelDefs;
State->PanelSystem.PanelDefsCount = GlobalPanelDefsCount;
gs_data UserData = State->UserSpaceDesc.UserData;
State->UserSpaceDesc = BlumenLumen_UserSpaceCreate();
if (UserData.Memory && !State->UserSpaceDesc.UserData.Memory)
{
State->UserSpaceDesc.UserData = UserData;
}
US_LoadPatterns(&State->UserSpaceDesc, State, Context);
State->UserSpaceDesc.UserData = UserData;
}
US_LoadPatterns(&State->UserSpaceDesc, State, Context);
}
}
INITIALIZE_APPLICATION(InitializeApplication)
{
Context->MemorySize = sizeof(app_state);
Context->MemoryBase = AllocatorAlloc(Context->ThreadContext.Allocator, Context->MemorySize).Memory;
app_state* State = (app_state*)Context->MemoryBase;
*State = {};
Context->MemorySize = sizeof(app_state);
Context->MemoryBase = Alloc(Context->ThreadContext.Allocator, Context->MemorySize, "Memory Base");
app_state* State = (app_state*)Context->MemoryBase;
*State = {};
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);
State->CommandQueue = CommandQueue_Create(&State->Permanent, 32);
animation_system_desc AnimSysDesc = {};
AnimSysDesc.Storage = &State->Permanent;
AnimSysDesc.AnimArrayCount = 32;
AnimSysDesc.SecondsPerFrame = 1.0f / 24.0f;
State->AnimationSystem = AnimationSystem_Init(AnimSysDesc);
if (!Context->Headless)
{
interface_config IConfig = {0};
IConfig.FontSize = 14;
IConfig.PanelBG = v4{ .3f, .3f, .3f, 1.f };
IConfig.ButtonColor_Inactive = BlackV4;
IConfig.ButtonColor_Active = v4{ .1f, .1f, .1f, 1.f };
IConfig.ButtonColor_Selected = v4{ .3f, .3f, .3f, 1.f };
IConfig.TextColor = WhiteV4;
IConfig.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f };
IConfig.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f };
IConfig.ListBGHover = v4{ .22f, .22f, .22f, 1.f };
IConfig.ListBGSelected = v4{ .44f, .44f, .44f, 1.f };
IConfig.Margin = v2{5, 5};
State->Interface = ui_InterfaceCreate(*Context, IConfig, &State->Permanent);
State->Permanent = CreateMemoryArena(Context->ThreadContext.Allocator, "Permanent");
State->Transient = Context->ThreadContext.Transient;
State->Assemblies = AssemblyArray_Create(8, &State->Permanent);
PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent);
State->CommandQueue = CommandQueue_Create(&State->Permanent, 32);
}
State->SACN = SACN_Initialize(*Context);
State->LedSystem = LedSystem_Create(Context->ThreadContext.Allocator, 128);
State->AssemblyDebugState = AssemblyDebug_Create(&State->Permanent);
State->AssemblyDebugState.Brightness = 255;
State->AssemblyDebugState.Override = ADS_Override_None;
State->Modes = OperationModeSystemInit(&State->Permanent, Context->ThreadContext);
ReloadStaticData(*Context, GlobalDebugServices, GlobalLogBuffer, true);
US_CustomInit(&State->UserSpaceDesc, State, *Context);
if (!Context->Headless)
{
// NOTE(pjs): This just sets up the default panel layout
panel* RootPanel = PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, *Context);
SplitPanel(RootPanel, .25f, PanelSplit_Horizontal, &State->PanelSystem, State, *Context);
animation_system_desc AnimSysDesc = {};
AnimSysDesc.Storage = &State->Permanent;
AnimSysDesc.AnimArrayCount = 32;
AnimSysDesc.SecondsPerFrame = 1.0f / 24.0f;
State->AnimationSystem = AnimationSystem_Init(AnimSysDesc);
panel* AnimPanel = RootPanel->Bottom;
Panel_SetType(AnimPanel, &State->PanelSystem, PanelType_AnimationTimeline, State, *Context);
if (!Context->Headless)
{
interface_config IConfig = {0};
IConfig.FontSize = 14;
IConfig.PanelBG = v4{ .3f, .3f, .3f, 1.f };
IConfig.ButtonColor_Inactive = BlackV4;
IConfig.ButtonColor_Active = v4{ .1f, .1f, .1f, 1.f };
IConfig.ButtonColor_Selected = v4{ .3f, .3f, .3f, 1.f };
IConfig.TextColor = WhiteV4;
IConfig.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f };
IConfig.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f };
IConfig.ListBGHover = v4{ .22f, .22f, .22f, 1.f };
IConfig.ListBGSelected = v4{ .44f, .44f, .44f, 1.f };
IConfig.Margin = v2{5, 5};
State->Interface = ui_InterfaceCreate(*Context, IConfig, &State->Permanent);
PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent);
}
panel* TopPanel = RootPanel->Top;
SplitPanel(TopPanel, .5f, PanelSplit_Vertical, &State->PanelSystem, State, *Context);
State->SACN = SACN_Initialize(*Context);
panel* LeftPanel = TopPanel->Left;
SplitPanel(LeftPanel, .5f, PanelSplit_Vertical, &State->PanelSystem, State, *Context);
State->LedSystem = LedSystem_Create(Context->ThreadContext.Allocator, 128);
State->AssemblyDebugState = AssemblyDebug_Create(&State->Permanent);
State->AssemblyDebugState.Brightness = 255;
State->AssemblyDebugState.Override = ADS_Override_None;
panel* Profiler = LeftPanel->Right;
Panel_SetType(Profiler, &State->PanelSystem, PanelType_MessageLog, State, *Context);
State->Modes = OperationModeSystemInit(&State->Permanent, Context->ThreadContext);
panel* Hierarchy = LeftPanel->Left;
Panel_SetType(Hierarchy, &State->PanelSystem, PanelType_AssemblyDebug, State, *Context);
ReloadStaticData(*Context, GlobalDebugServices, GlobalLogBuffer, true);
US_CustomInit(&State->UserSpaceDesc, State, *Context);
if (!Context->Headless)
{
// NOTE(pjs): This just sets up the default panel layout
panel* RootPanel = PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, *Context);
SplitPanel(RootPanel, .25f, PanelSplit_Horizontal, &State->PanelSystem, State, *Context);
panel* AnimPanel = RootPanel->Bottom;
Panel_SetType(AnimPanel, &State->PanelSystem, PanelType_AnimationTimeline, State, *Context);
panel* TopPanel = RootPanel->Top;
SplitPanel(TopPanel, .5f, PanelSplit_Vertical, &State->PanelSystem, State, *Context);
panel* LeftPanel = TopPanel->Left;
SplitPanel(LeftPanel, .5f, PanelSplit_Vertical, &State->PanelSystem, State, *Context);
panel* Profiler = LeftPanel->Right;
Panel_SetType(Profiler, &State->PanelSystem, PanelType_MessageLog, State, *Context);
panel* Hierarchy = LeftPanel->Left;
Panel_SetType(Hierarchy, &State->PanelSystem, PanelType_AssemblyDebug, State, *Context);
}
State->RunEditor = !Context->Headless;
}
State->RunEditor = !Context->Headless;
}
internal void
BuildAssemblyData (app_state* State, context Context, addressed_data_buffer_list* OutputData)
{
#define SEND_DATA
#ifdef SEND_DATA
// NOTE(pjs): Building data buffers to be sent out to the sculpture
// This array is used on the platform side to actually send the information
assembly_array SACNAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaSACN, State->Transient);
assembly_array UARTAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaUART, State->Transient);
SACN_BuildOutputData(&State->SACN, OutputData, SACNAssemblies, &State->LedSystem);
UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem, State->Transient);
// NOTE(pjs): Building data buffers to be sent out to the sculpture
// This array is used on the platform side to actually send the information
assembly_array SACNAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaSACN, State->Transient);
assembly_array UARTAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaUART, State->Transient);
SACN_BuildOutputData(&State->SACN, OutputData, SACNAssemblies, &State->LedSystem);
UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem, State->Transient);
#endif
}
UPDATE_AND_RENDER(UpdateAndRender)
{
DEBUG_TRACK_FUNCTION;
app_state* State = (app_state*)Context->MemoryBase;
// NOTE(Peter): We do this at the beginning because all the render commands are stored in Transient,
// 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);
DEBUG_TRACK_FUNCTION;
app_state* State = (app_state*)Context->MemoryBase;
// NOTE(Peter): We do this at the beginning because all the render commands are stored in Transient,
// 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.
MemoryArenaClear(State->Transient);
Assert(State->UserSpaceDesc.UserData.Memory != 0);
if (State->RunEditor)
{
Editor_Update(State, Context, InputQueue);
}
AnimationSystem_Update(&State->AnimationSystem, Context->DeltaTime);
if (AnimationSystem_NeedsRender(State->AnimationSystem))
{
Assert(State->UserSpaceDesc.UserData.Memory != 0);
if (State->RunEditor)
AnimationSystem_RenderToLedBuffers(&State->AnimationSystem,
State->Assemblies,
&State->LedSystem,
State->Patterns,
State->Transient,
*Context,
State->UserSpaceDesc.UserData.Memory);
}
Assert(State->UserSpaceDesc.UserData.Memory != 0);
US_CustomUpdate(&State->UserSpaceDesc, State, Context);
Assert(State->UserSpaceDesc.UserData.Memory != 0);
AssemblyDebug_OverrideOutput(State->AssemblyDebugState,
State->Assemblies,
State->LedSystem);
if (State->RunEditor)
{
Editor_Render(State, Context, RenderBuffer);
}
ResetWorkQueue(Context->GeneralWorkQueue);
Assert(State->UserSpaceDesc.UserData.Memory != 0);
BuildAssemblyData(State, *Context, OutputData);
// NOTE(PS): We introduced this in order to test some things on the
// blumen lumen circuit boards, to see if they were getting out
// of sync
if (State->SendEmptyPackets) {
for (addressed_data_buffer* At = OutputData->Root;
At != 0;
At = At->Next)
{
Editor_Update(State, Context, InputQueue);
}
AnimationSystem_Update(&State->AnimationSystem, Context->DeltaTime);
if (AnimationSystem_NeedsRender(State->AnimationSystem))
{
Assert(State->UserSpaceDesc.UserData.Memory != 0);
AnimationSystem_RenderToLedBuffers(&State->AnimationSystem,
State->Assemblies,
&State->LedSystem,
State->Patterns,
State->Transient,
*Context,
State->UserSpaceDesc.UserData.Memory);
}
Assert(State->UserSpaceDesc.UserData.Memory != 0);
US_CustomUpdate(&State->UserSpaceDesc, State, Context);
Assert(State->UserSpaceDesc.UserData.Memory != 0);
AssemblyDebug_OverrideOutput(State->AssemblyDebugState,
State->Assemblies,
State->LedSystem);
if (State->RunEditor)
{
Editor_Render(State, Context, RenderBuffer);
}
ResetWorkQueue(Context->GeneralWorkQueue);
Assert(State->UserSpaceDesc.UserData.Memory != 0);
BuildAssemblyData(State, *Context, OutputData);
// NOTE(PS): We introduced this in order to test some things on the
// blumen lumen circuit boards, to see if they were getting out
// of sync
if (State->SendEmptyPackets) {
for (addressed_data_buffer* At = OutputData->Root;
At != 0;
At = At->Next)
{
ZeroMemoryBlock(At->Memory, At->MemorySize);
}
ZeroMemoryBlock(At->Memory, At->MemorySize);
}
}
}
CLEANUP_APPLICATION(CleanupApplication)
{
app_state* State = (app_state*)Context.MemoryBase;
for (u32 i = 0; i < State->Assemblies.Count; i++)
{
assembly Assembly = State->Assemblies.Values[i];
led_buffer LedBuffer = State->LedSystem.Buffers[Assembly.LedBufferIndex];
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0});
}
BuildAssemblyData(State, Context, OutputData);
US_CustomCleanup(&State->UserSpaceDesc, State, Context);
SACN_Cleanup(&State->SACN, Context);
app_state* State = (app_state*)Context.MemoryBase;
for (u32 i = 0; i < State->Assemblies.Count; i++)
{
assembly Assembly = State->Assemblies.Values[i];
led_buffer LedBuffer = State->LedSystem.Buffers[Assembly.LedBufferIndex];
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0});
}
BuildAssemblyData(State, Context, OutputData);
US_CustomCleanup(&State->UserSpaceDesc, State, Context);
SACN_Cleanup(&State->SACN, Context);
}
#define FOLDHAUS_APP_CPP

View File

@ -11,71 +11,71 @@
#define SCOPE_NAME_LENGTH 256
struct scope_record
{
u32 NameHash;
s64 StartCycles;
s64 EndCycles;
s32 CallDepth;
u32 NameHash;
s64 StartCycles;
s64 EndCycles;
s32 CallDepth;
};
struct collated_scope_record
{
u32 NameHash;
s64 TotalCycles;
s32 CallCount;
r32 PercentFrameTime;
r32 TotalSeconds;
r32 AverageSecondsPerCall;
u32 NameHash;
s64 TotalCycles;
s32 CallCount;
r32 PercentFrameTime;
r32 TotalSeconds;
r32 AverageSecondsPerCall;
};
#define SCOPE_NAME_BUFFER_LENGTH 128
struct scope_name
{
u32 Hash;
gs_string Name;
char Buffer[SCOPE_NAME_BUFFER_LENGTH];
u32 Hash;
gs_string Name;
char Buffer[SCOPE_NAME_BUFFER_LENGTH];
};
struct debug_scope_record_list
{
s32 ThreadId;
s32 Max;
s32 Count;
scope_record* Calls;
s32 CurrentScopeCallDepth;
s32 ThreadId;
s32 Max;
s32 Count;
scope_record* Calls;
s32 CurrentScopeCallDepth;
};
#define DEBUG_FRAME_GROW_SIZE 8102
struct debug_frame
{
s64 FrameStartCycles;
s64 FrameEndCycles;
s32 ScopeNamesMax;
s32 ScopeNamesCount;
scope_name* ScopeNamesHash;
s32 ThreadCount;
debug_scope_record_list* ThreadCalls;
s32 CollatedScopesMax;
collated_scope_record* CollatedScopes;
s64 FrameStartCycles;
s64 FrameEndCycles;
s32 ScopeNamesMax;
s32 ScopeNamesCount;
scope_name* ScopeNamesHash;
s32 ThreadCount;
debug_scope_record_list* ThreadCalls;
s32 CollatedScopesMax;
collated_scope_record* CollatedScopes;
};
enum debug_ui_view
{
DebugUI_Profiler,
DebugUI_ScopeList,
DebugUI_MemoryView,
DebugUI_Count,
DebugUI_Profiler,
DebugUI_ScopeList,
DebugUI_MemoryView,
DebugUI_Count,
};
struct debug_interface
{
s32 FrameView;
s32 FrameView;
};
typedef s32 debug_get_thread_id();
@ -86,18 +86,18 @@ typedef u8* debug_realloc(u8* Memory, s32 OldSize, s32 NewSize);
#define HISTOGRAM_DEPTH 10
struct debug_histogram_entry
{
char ScopeName_[SCOPE_NAME_LENGTH];
gs_string ScopeName;
u32 PerFrame_Cycles[HISTOGRAM_DEPTH];
u32 PerFrame_CallCount[HISTOGRAM_DEPTH];
s32 CurrentFrame;
// NOTE(Peter): Cached Values, recalculated ever frame
u32 Average_Cycles;
u32 Average_CallCount;
u32 Total_Cycles;
u32 Total_CallCount;
char ScopeName_[SCOPE_NAME_LENGTH];
gs_string ScopeName;
u32 PerFrame_Cycles[HISTOGRAM_DEPTH];
u32 PerFrame_CallCount[HISTOGRAM_DEPTH];
s32 CurrentFrame;
// NOTE(Peter): Cached Values, recalculated ever frame
u32 Average_Cycles;
u32 Average_CallCount;
u32 Total_Cycles;
u32 Total_CallCount;
};
#if DEBUG
@ -108,72 +108,73 @@ struct debug_histogram_entry
struct debug_services
{
s64 PerformanceCountFrequency;
b32 RecordFrames;
s32 CurrentDebugFrame;
debug_frame* Frames;
debug_interface Interface;
gs_thread_context Ctx;
debug_get_thread_id* GetThreadId;
debug_timing_proc* GetWallClock;
s64 PerformanceCountFrequency;
b32 RecordFrames;
s32 CurrentDebugFrame;
debug_frame* Frames;
debug_interface Interface;
gs_thread_context Ctx;
gs_memory_arena A;
debug_get_thread_id* GetThreadId;
debug_timing_proc* GetWallClock;
};
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);
// 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);
for (s32 i = 0; i < Frame->ScopeNamesMax; i++)
{
scope_name* Entry = Frame->ScopeNamesHash + i;
Entry->Name = MakeString(Entry->Buffer, 0, SCOPE_NAME_BUFFER_LENGTH);
}
Frame->ThreadCount = ThreadCount;
Frame->ThreadCalls = AllocatorAllocArray(Services->Ctx.Allocator, 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].CurrentScopeCallDepth = 0;
Frame->ThreadCalls[i].ThreadId = 0;
}
for (s32 c = 0; c < Frame->CollatedScopesMax; c++)
{
Frame->CollatedScopes[c].NameHash = 0;
}
Frame->ScopeNamesMax = 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 = PushArray(&Services->A, collated_scope_record, NameHashMax);
for (s32 i = 0; i < Frame->ScopeNamesMax; i++)
{
scope_name* Entry = Frame->ScopeNamesHash + i;
Entry->Name = MakeString(Entry->Buffer, 0, SCOPE_NAME_BUFFER_LENGTH);
}
Frame->ThreadCount = 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 = PushArray(&Services->A, scope_record, ScopeCallsMax);
Frame->ThreadCalls[i].CurrentScopeCallDepth = 0;
Frame->ThreadCalls[i].ThreadId = 0;
}
for (s32 c = 0; c < Frame->CollatedScopesMax; c++)
{
Frame->CollatedScopes[c].NameHash = 0;
}
}
internal void
StartDebugFrame(debug_frame* Frame, debug_services* Services)
{
Frame->FrameStartCycles = Services->GetWallClock();
for (s32 i = 0; i < Frame->ThreadCount; i++)
{
Frame->ThreadCalls[i].Count = 0;
Frame->ThreadCalls[i].CurrentScopeCallDepth = 0;
}
for (s32 c = 0; c < Frame->CollatedScopesMax; c++)
{
s32 Hash = Frame->CollatedScopes[c].NameHash;
Frame->CollatedScopes[c] = {};
Frame->CollatedScopes[c].NameHash = Hash;
}
Frame->FrameStartCycles = Services->GetWallClock();
for (s32 i = 0; i < Frame->ThreadCount; i++)
{
Frame->ThreadCalls[i].Count = 0;
Frame->ThreadCalls[i].CurrentScopeCallDepth = 0;
}
for (s32 c = 0; c < Frame->CollatedScopesMax; c++)
{
s32 Hash = Frame->CollatedScopes[c].NameHash;
Frame->CollatedScopes[c] = {};
Frame->CollatedScopes[c].NameHash = Hash;
}
}
internal void
@ -184,17 +185,17 @@ InitDebugServices_OffMode (debug_services* Services,
gs_thread_context Ctx,
s32 ThreadCount)
{
*Services = {0};
Services->Ctx = Ctx;
Services->GetWallClock = GetWallClock;
Services->GetThreadId = GetThreadId;
Services->RecordFrames = false;
Services->Frames = 0;
Services->CurrentDebugFrame = 0;
Services->PerformanceCountFrequency = PerformanceCountFrequency;
*Services = {0};
Services->Ctx = Ctx;
Services->GetWallClock = GetWallClock;
Services->GetThreadId = GetThreadId;
Services->RecordFrames = false;
Services->Frames = 0;
Services->CurrentDebugFrame = 0;
Services->PerformanceCountFrequency = PerformanceCountFrequency;
}
@ -206,227 +207,229 @@ InitDebugServices_DebugMode (debug_services* Services,
gs_thread_context Ctx,
s32 ThreadCount)
{
Services->Ctx = Ctx;
Services->GetWallClock = GetWallClock;
Services->GetThreadId = GetThreadId;
Services->RecordFrames = true;
Services->CurrentDebugFrame = 0;
s32 NameHashMax = 4096;
s32 ScopeCallsMax = 4096;
Services->Frames = AllocatorAllocArray(Ctx.Allocator, debug_frame, DEBUG_FRAME_COUNT);
for (s32 i = 0; i < DEBUG_FRAME_COUNT; i++)
{
InitializeDebugFrame(&Services->Frames[i], NameHashMax, ThreadCount, ScopeCallsMax, Services);
}
Services->PerformanceCountFrequency = PerformanceCountFrequency;
Services->Ctx = Ctx;
Services->GetWallClock = GetWallClock;
Services->GetThreadId = GetThreadId;
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 = 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);
}
Services->PerformanceCountFrequency = PerformanceCountFrequency;
}
internal debug_frame*
GetCurrentDebugFrame (debug_services* Services)
{
debug_frame* Result = Services->Frames + Services->CurrentDebugFrame;
return Result;
debug_frame* Result = Services->Frames + Services->CurrentDebugFrame;
return Result;
}
internal debug_frame*
GetLastDebugFrame(debug_services* Services)
{
if (!Services->Frames) return 0;
s32 Index = (Services->CurrentDebugFrame - 1);
if (Index < 0) { Index += DEBUG_FRAME_COUNT; }
debug_frame* Result = Services->Frames + Index;
return Result;
if (!Services->Frames) return 0;
s32 Index = (Services->CurrentDebugFrame - 1);
if (Index < 0) { Index += DEBUG_FRAME_COUNT; }
debug_frame* Result = Services->Frames + Index;
return Result;
}
internal s32
GetIndexForNameHash(debug_frame* Frame, u32 NameHash)
{
s32 Result = -1;
for (s32 Offset = 0; Offset < Frame->ScopeNamesMax; Offset++)
s32 Result = -1;
for (s32 Offset = 0; Offset < Frame->ScopeNamesMax; Offset++)
{
u32 Index = (NameHash + Offset) % Frame->ScopeNamesMax;
if (Frame->ScopeNamesHash[Index].Hash == NameHash)
{
u32 Index = (NameHash + Offset) % Frame->ScopeNamesMax;
if (Frame->ScopeNamesHash[Index].Hash == NameHash)
{
Result = Index;
break;
}
Result = Index;
break;
}
// NOTE(Peter): Its not technically wrong to return a -1 here, just means we didn't find it.
// At the time of writing however, this function is only being called in contexts where we
// know there should be an entry in the Name table, so a -1 actually indicates a problem.
Assert(Result >= 0);
return Result;
}
// NOTE(Peter): Its not technically wrong to return a -1 here, just means we didn't find it.
// At the time of writing however, this function is only being called in contexts where we
// know there should be an entry in the Name table, so a -1 actually indicates a problem.
Assert(Result >= 0);
return Result;
}
internal debug_scope_record_list*
GetScopeListForThreadInFrame(debug_services* Services, debug_frame* Frame)
{
debug_scope_record_list* List = 0;
s32 CurrentThreadId = Services->GetThreadId();
for (s32 Offset = 0; Offset < Frame->ThreadCount; Offset++)
debug_scope_record_list* List = 0;
s32 CurrentThreadId = Services->GetThreadId();
for (s32 Offset = 0; Offset < Frame->ThreadCount; Offset++)
{
s32 Index = (CurrentThreadId + Offset) % Frame->ThreadCount;
if (Frame->ThreadCalls[Index].ThreadId == CurrentThreadId)
{
s32 Index = (CurrentThreadId + Offset) % Frame->ThreadCount;
if (Frame->ThreadCalls[Index].ThreadId == CurrentThreadId)
{
List = Frame->ThreadCalls + Index;
break;
}
else if (Frame->ThreadCalls[Index].ThreadId == 0)
{
Frame->ThreadCalls[Index].ThreadId = CurrentThreadId;
List = Frame->ThreadCalls + Index;
break;
}
List = Frame->ThreadCalls + Index;
break;
}
Assert(List);
return List;
else if (Frame->ThreadCalls[Index].ThreadId == 0)
{
Frame->ThreadCalls[Index].ThreadId = CurrentThreadId;
List = Frame->ThreadCalls + Index;
break;
}
}
Assert(List);
return List;
}
internal void
CollateThreadScopeCalls (debug_scope_record_list* ThreadRecords, debug_frame* Frame)
{
for (s32 i = 0; i < ThreadRecords->Count; i++)
for (s32 i = 0; i < ThreadRecords->Count; i++)
{
scope_record Record = ThreadRecords->Calls[i];
s32 Index = GetIndexForNameHash (Frame, Record.NameHash);
collated_scope_record* CollatedRecord = Frame->CollatedScopes + Index;
if (CollatedRecord->NameHash != Record.NameHash)
{
scope_record Record = ThreadRecords->Calls[i];
s32 Index = GetIndexForNameHash (Frame, Record.NameHash);
collated_scope_record* CollatedRecord = Frame->CollatedScopes + Index;
if (CollatedRecord->NameHash != Record.NameHash)
{
CollatedRecord->NameHash = Record.NameHash;
CollatedRecord->TotalCycles = 0;
CollatedRecord->CallCount = 0;
}
CollatedRecord->TotalCycles += Record.EndCycles - Record.StartCycles;
CollatedRecord->CallCount += 1;
CollatedRecord->NameHash = Record.NameHash;
CollatedRecord->TotalCycles = 0;
CollatedRecord->CallCount = 0;
}
CollatedRecord->TotalCycles += Record.EndCycles - Record.StartCycles;
CollatedRecord->CallCount += 1;
}
}
internal void
EndDebugFrame (debug_services* Services)
{
debug_frame* ClosingFrame = GetCurrentDebugFrame(Services);
ClosingFrame->FrameEndCycles = Services->GetWallClock();
s64 FrameTotalCycles = ClosingFrame->FrameEndCycles - ClosingFrame->FrameStartCycles;
for (s32 t = 0; t < ClosingFrame->ThreadCount; t++)
debug_frame* ClosingFrame = GetCurrentDebugFrame(Services);
ClosingFrame->FrameEndCycles = Services->GetWallClock();
s64 FrameTotalCycles = ClosingFrame->FrameEndCycles - ClosingFrame->FrameStartCycles;
for (s32 t = 0; t < ClosingFrame->ThreadCount; t++)
{
CollateThreadScopeCalls(ClosingFrame->ThreadCalls + t, ClosingFrame);
}
s32 ScopeNamesCount = 0;
for (s32 n = 0; n < ClosingFrame->ScopeNamesMax; n++)
{
if (ClosingFrame->ScopeNamesHash[n].Hash != 0)
{
CollateThreadScopeCalls(ClosingFrame->ThreadCalls + t, ClosingFrame);
collated_scope_record* CollatedRecord = ClosingFrame->CollatedScopes + n;
CollatedRecord->TotalSeconds = (r32)CollatedRecord->TotalCycles / (r32)Services->PerformanceCountFrequency;
CollatedRecord->PercentFrameTime = (r32)CollatedRecord->TotalCycles / (r32)FrameTotalCycles;
CollatedRecord->AverageSecondsPerCall = CollatedRecord->TotalSeconds / CollatedRecord->CallCount;
ScopeNamesCount += 1;
}
s32 ScopeNamesCount = 0;
for (s32 n = 0; n < ClosingFrame->ScopeNamesMax; n++)
{
if (ClosingFrame->ScopeNamesHash[n].Hash != 0)
{
collated_scope_record* CollatedRecord = ClosingFrame->CollatedScopes + n;
CollatedRecord->TotalSeconds = (r32)CollatedRecord->TotalCycles / (r32)Services->PerformanceCountFrequency;
CollatedRecord->PercentFrameTime = (r32)CollatedRecord->TotalCycles / (r32)FrameTotalCycles;
CollatedRecord->AverageSecondsPerCall = CollatedRecord->TotalSeconds / CollatedRecord->CallCount;
ScopeNamesCount += 1;
}
}
ClosingFrame->ScopeNamesCount = ScopeNamesCount;
s32 FramesCount = DEBUG_FRAME_COUNT;
if (FramesCount > 0)
{
Services->CurrentDebugFrame = (Services->CurrentDebugFrame + 1) % FramesCount;
}
StartDebugFrame(&Services->Frames[Services->CurrentDebugFrame], Services);
}
ClosingFrame->ScopeNamesCount = ScopeNamesCount;
s32 FramesCount = DEBUG_FRAME_COUNT;
if (FramesCount > 0)
{
Services->CurrentDebugFrame = (Services->CurrentDebugFrame + 1) % FramesCount;
}
StartDebugFrame(&Services->Frames[Services->CurrentDebugFrame], Services);
}
internal u32
HashScopeName (char* ScopeName)
{
// djb2 hash
u32 Hash = 5381;
char* C = ScopeName;
while(*C)
{
Hash = ((Hash << 5) + Hash) + *C;
C++;
}
return Hash;
// djb2 hash
u32 Hash = 5381;
char* C = ScopeName;
while(*C)
{
Hash = ((Hash << 5) + Hash) + *C;
C++;
}
return Hash;
}
internal scope_name*
GetOrAddNameHashEntry(debug_frame* Frame, u32 NameHash)
{
scope_name* Result = 0;
for (s32 Offset = 0; Offset < Frame->ScopeNamesMax; Offset++)
scope_name* Result = 0;
for (s32 Offset = 0; Offset < Frame->ScopeNamesMax; Offset++)
{
u32 Index = (NameHash + Offset) % Frame->ScopeNamesMax;
if ((Frame->ScopeNamesHash[Index].Hash == 0) || (Frame->ScopeNamesHash[Index].Hash == NameHash))
{
u32 Index = (NameHash + Offset) % Frame->ScopeNamesMax;
if ((Frame->ScopeNamesHash[Index].Hash == 0) || (Frame->ScopeNamesHash[Index].Hash == NameHash))
{
Result = Frame->ScopeNamesHash + Index;
break;
}
Result = Frame->ScopeNamesHash + Index;
break;
}
return Result;
}
return Result;
}
internal u32
BeginTrackingScopeAndGetNameHash (debug_services* Services, char* ScopeName)
{
debug_frame* CurrentFrame = GetCurrentDebugFrame(Services);
debug_scope_record_list* ThreadList = GetScopeListForThreadInFrame(Services, CurrentFrame);
ThreadList->CurrentScopeCallDepth++;
u32 NameHash = HashScopeName(ScopeName);
scope_name* Entry = GetOrAddNameHashEntry(CurrentFrame, NameHash);
if (Entry->Hash == 0) // If its new
{
Entry->Hash = NameHash;
// TODO(Peter): need to initialize all entry name gs_strings to point at the buffer
// This will break eventually. when it does, do this ^^^^ when on startup
PrintF(&Entry->Name, "%s", ScopeName);
}
return NameHash;
debug_frame* CurrentFrame = GetCurrentDebugFrame(Services);
debug_scope_record_list* ThreadList = GetScopeListForThreadInFrame(Services, CurrentFrame);
ThreadList->CurrentScopeCallDepth++;
u32 NameHash = HashScopeName(ScopeName);
scope_name* Entry = GetOrAddNameHashEntry(CurrentFrame, NameHash);
if (Entry->Hash == 0) // If its new
{
Entry->Hash = NameHash;
// TODO(Peter): need to initialize all entry name gs_strings to point at the buffer
// This will break eventually. when it does, do this ^^^^ when on startup
PrintF(&Entry->Name, "%s", ScopeName);
}
return NameHash;
}
internal void
PushScopeTimeOnFrame (debug_services* Services, s32 NameHash, u64 StartCycles, u64 EndCycles)
{
debug_frame* CurrentFrame = GetCurrentDebugFrame(Services);
debug_scope_record_list* ThreadList = GetScopeListForThreadInFrame(Services, CurrentFrame);
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);
ThreadList->Max = NewMax;
}
Assert(ThreadList->Count < ThreadList->Max);
s32 EntryIndex = ThreadList->Count++;
scope_record* Record = ThreadList->Calls + EntryIndex;
Record->NameHash = NameHash;
Record->StartCycles = StartCycles;
Record->EndCycles = EndCycles;
Record->CallDepth = --ThreadList->CurrentScopeCallDepth;
debug_frame* CurrentFrame = GetCurrentDebugFrame(Services);
debug_scope_record_list* ThreadList = GetScopeListForThreadInFrame(Services, CurrentFrame);
if (ThreadList->Count >= ThreadList->Max)
{
s32 NewMax = (ThreadList->Max + DEBUG_FRAME_GROW_SIZE);
FreeArray(Services->Ctx.Allocator, ThreadList->Calls, scope_record, ThreadList->Max);
ThreadList->Calls = AllocArray(Services->Ctx.Allocator, scope_record, NewMax, "Debug Frame");
ThreadList->Max = NewMax;
}
Assert(ThreadList->Count < ThreadList->Max);
s32 EntryIndex = ThreadList->Count++;
scope_record* Record = ThreadList->Calls + EntryIndex;
Record->NameHash = NameHash;
Record->StartCycles = StartCycles;
Record->EndCycles = EndCycles;
Record->CallDepth = --ThreadList->CurrentScopeCallDepth;
}
internal r32 DEBUGGetSecondsElapsed (s64 Start, s64 End, r32 PerformanceCountFrequency)
{
r32 Result = ((r32)(End - Start) / (r32)PerformanceCountFrequency);
return Result;
r32 Result = ((r32)(End - Start) / (r32)PerformanceCountFrequency);
return Result;
}
#if DEBUG
@ -438,32 +441,32 @@ internal r32 DEBUGGetSecondsElapsed (s64 Start, s64 End, r32 PerformanceCountFre
#endif
struct scope_tracker
{
s64 ScopeStart;
u32 ScopeNameHash;
debug_services* DebugServices;
scope_tracker(char* ScopeName, debug_services* DebugServices)
s64 ScopeStart;
u32 ScopeNameHash;
debug_services* DebugServices;
scope_tracker(char* ScopeName, debug_services* DebugServices)
{
if (DebugServices->RecordFrames)
{
if (DebugServices->RecordFrames)
{
this->ScopeNameHash = BeginTrackingScopeAndGetNameHash(DebugServices, ScopeName);
this->ScopeStart = DebugServices->GetWallClock();
this->DebugServices = DebugServices;
}
else
{
this->DebugServices = 0;
}
this->ScopeNameHash = BeginTrackingScopeAndGetNameHash(DebugServices, ScopeName);
this->ScopeStart = DebugServices->GetWallClock();
this->DebugServices = DebugServices;
}
~scope_tracker()
else
{
if (this->DebugServices) // NOTE(Peter): If DebugServices == 0, then we werent' recording this frame
{
s64 ScopeEnd = this->DebugServices->GetWallClock();
PushScopeTimeOnFrame(this->DebugServices, this->ScopeNameHash, this->ScopeStart, ScopeEnd);
}
this->DebugServices = 0;
}
}
~scope_tracker()
{
if (this->DebugServices) // NOTE(Peter): If DebugServices == 0, then we werent' recording this frame
{
s64 ScopeEnd = this->DebugServices->GetWallClock();
PushScopeTimeOnFrame(this->DebugServices, this->ScopeNameHash, this->ScopeStart, ScopeEnd);
}
}
};

View File

@ -8,190 +8,190 @@
internal render_command_buffer
AllocateRenderCommandBuffer (u8* Memory, s32 Size, gs_thread_context Ctx)
{
render_command_buffer Result = {};
Result.CommandMemory = Memory;
Result.CommandMemorySize = Size;
Result.CommandMemoryUsed = 0;
Result.Ctx = Ctx;
return Result;
render_command_buffer Result = {};
Result.CommandMemory = Memory;
Result.CommandMemorySize = Size;
Result.CommandMemoryUsed = 0;
Result.Ctx = Ctx;
return Result;
}
internal render_command_buffer
AllocateRenderCommandBuffer(u32 MemorySize,
gs_memory_arena* Arena,
gs_thread_context Ctx)
{
u8* Memory = PushSize(Arena, MemorySize);
return AllocateRenderCommandBuffer(Memory, MemorySize, Ctx);
u8* Memory = PushSize(Arena, MemorySize).Memory;
return AllocateRenderCommandBuffer(Memory, MemorySize, Ctx);
}
internal void
Render3DQuadBatch (u8* CommandData, s32 TriCount)
{
DEBUG_TRACK_FUNCTION;
v4* Vertecies = (v4*)(CommandData + BATCH_3D_VERTECIES_OFFSET(TriCount));
v2* UVs = (v2*)(CommandData + BATCH_3D_UVS_OFFSET(TriCount));
v4* Colors = (v4*)(CommandData + BATCH_3D_COLORS_OFFSET(TriCount));
DEBUG_TRACK_FUNCTION;
v4* Vertecies = (v4*)(CommandData + BATCH_3D_VERTECIES_OFFSET(TriCount));
v2* UVs = (v2*)(CommandData + BATCH_3D_UVS_OFFSET(TriCount));
v4* Colors = (v4*)(CommandData + BATCH_3D_COLORS_OFFSET(TriCount));
#if IMMEDIATE_MODE_RENDERING
for (s32 Tri = 0; Tri < TriCount; Tri++)
{
v4 P0 = Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 0)];
v4 P1 = Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 1)];
v4 P2 = Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 2)];
v2 UV0 = UVs[BATCH_3D_UV_INDEX(Tri, 0)];
v2 UV1 = UVs[BATCH_3D_UV_INDEX(Tri, 1)];
v2 UV2 = UVs[BATCH_3D_UV_INDEX(Tri, 2)];
v4 C0 = Colors[BATCH_3D_COLOR_INDEX(Tri, 0)];
v4 C1 = Colors[BATCH_3D_COLOR_INDEX(Tri, 1)];
v4 C2 = Colors[BATCH_3D_COLOR_INDEX(Tri, 2)];
for (s32 Tri = 0; Tri < TriCount; Tri++)
{
v4 P0 = Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 0)];
v4 P1 = Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 1)];
v4 P2 = Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 2)];
v2 UV0 = UVs[BATCH_3D_UV_INDEX(Tri, 0)];
v2 UV1 = UVs[BATCH_3D_UV_INDEX(Tri, 1)];
v2 UV2 = UVs[BATCH_3D_UV_INDEX(Tri, 2)];
v4 C0 = Colors[BATCH_3D_COLOR_INDEX(Tri, 0)];
v4 C1 = Colors[BATCH_3D_COLOR_INDEX(Tri, 1)];
v4 C2 = Colors[BATCH_3D_COLOR_INDEX(Tri, 2)];
OpenGLDraw3DTri(P0, P1, P2, UV0, UV1, UV2, C0, C1, C2);
}
OpenGLDraw3DTri(P0, P1, P2, UV0, UV1, UV2, C0, C1, C2);
}
#else
OpenGLRenderTriBuffer((u8*)Vertecies, 4, (u8*)UVs, 2, (u8*)Colors, 4, TriCount * 3);
OpenGLRenderTriBuffer((u8*)Vertecies, 4, (u8*)UVs, 2, (u8*)Colors, 4, TriCount * 3);
#endif
}
internal void
Render2DQuadBatch (u8* CommandData, s32 QuadCount)
{
DEBUG_TRACK_FUNCTION;
v2* Vertecies = (v2*)(CommandData + BATCH_2D_VERTECIES_OFFSET(QuadCount));
v2* UVs = (v2*)(CommandData + BATCH_2D_UVS_OFFSET(QuadCount));
v4* Colors = (v4*)(CommandData + BATCH_2D_COLORS_OFFSET(QuadCount));
DEBUG_TRACK_FUNCTION;
v2* Vertecies = (v2*)(CommandData + BATCH_2D_VERTECIES_OFFSET(QuadCount));
v2* UVs = (v2*)(CommandData + BATCH_2D_UVS_OFFSET(QuadCount));
v4* Colors = (v4*)(CommandData + BATCH_2D_COLORS_OFFSET(QuadCount));
#if IMMEDIATE_MODE_RENDERING
for (s32 Quad = 0; Quad < QuadCount; Quad++)
for (s32 Quad = 0; Quad < QuadCount; Quad++)
{
for (s32 Tri = 0; Tri < 2; Tri++)
{
for (s32 Tri = 0; Tri < 2; Tri++)
{
v2 P0 = Vertecies[BATCH_2D_VERTEX_INDEX(Quad, Tri, 0)];
v2 P1 = Vertecies[BATCH_2D_VERTEX_INDEX(Quad, Tri, 1)];
v2 P2 = Vertecies[BATCH_2D_VERTEX_INDEX(Quad, Tri, 2)];
v2 UV0 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 0)];
v2 UV1 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 1)];
v2 UV2 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 2)];
v4 C0 = Colors[BATCH_2D_COLOR_INDEX(Quad, Tri, 0)];
v4 C1 = Colors[BATCH_2D_COLOR_INDEX(Quad, Tri, 1)];
v4 C2 = Colors[BATCH_2D_COLOR_INDEX(Quad, Tri, 2)];
OpenGLDraw2DTri(P0, P1, P2, UV0, UV1, UV2, C0, C1, C2);
}
v2 P0 = Vertecies[BATCH_2D_VERTEX_INDEX(Quad, Tri, 0)];
v2 P1 = Vertecies[BATCH_2D_VERTEX_INDEX(Quad, Tri, 1)];
v2 P2 = Vertecies[BATCH_2D_VERTEX_INDEX(Quad, Tri, 2)];
v2 UV0 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 0)];
v2 UV1 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 1)];
v2 UV2 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 2)];
v4 C0 = Colors[BATCH_2D_COLOR_INDEX(Quad, Tri, 0)];
v4 C1 = Colors[BATCH_2D_COLOR_INDEX(Quad, Tri, 1)];
v4 C2 = Colors[BATCH_2D_COLOR_INDEX(Quad, Tri, 2)];
OpenGLDraw2DTri(P0, P1, P2, UV0, UV1, UV2, C0, C1, C2);
}
}
#else
OpenGLRenderTriBuffer((u8*)Vertecies, 2, (u8*)UVs, 2, (u8*)Colors, 4, QuadCount * 2 * 3);
OpenGLRenderTriBuffer((u8*)Vertecies, 2, (u8*)UVs, 2, (u8*)Colors, 4, QuadCount * 2 * 3);
#endif
}
internal void
RenderCommandBuffer (render_command_buffer CommandBuffer)
{
DEBUG_TRACK_FUNCTION;
glMatrixMode(GL_TEXTURE_2D);
glLoadIdentity();
glClearColor(0.1f, 0.1f, 0.1f, 1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
b32 GLTextureEnabled = false;
u8* CurrentPosition = CommandBuffer.CommandMemory;
while(CurrentPosition < CommandBuffer.CommandMemory + CommandBuffer.CommandMemoryUsed)
DEBUG_TRACK_FUNCTION;
glMatrixMode(GL_TEXTURE_2D);
glLoadIdentity();
glClearColor(0.1f, 0.1f, 0.1f, 1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
b32 GLTextureEnabled = false;
u8* CurrentPosition = CommandBuffer.CommandMemory;
while(CurrentPosition < CommandBuffer.CommandMemory + CommandBuffer.CommandMemoryUsed)
{
render_command_header* CommandHeader = (render_command_header*)CurrentPosition;
CurrentPosition += sizeof(render_command_header);
switch (CommandHeader->Type)
{
render_command_header* CommandHeader = (render_command_header*)CurrentPosition;
CurrentPosition += sizeof(render_command_header);
switch (CommandHeader->Type)
case RenderCommand_render_command_set_render_mode:
{
DEBUG_TRACK_SCOPE(SetRenderMode);
render_command_set_render_mode* Command = (render_command_set_render_mode*)(CommandHeader + 1);
glViewport(Command->ViewOffsetX, Command->ViewOffsetY,
Command->ViewWidth, Command->ViewHeight);
LoadModelView(Command->ModelView.Array);
LoadProjection(Command->Projection.Array);
if (Command->UseDepthBuffer)
{
case RenderCommand_render_command_set_render_mode:
{
DEBUG_TRACK_SCOPE(SetRenderMode);
render_command_set_render_mode* Command = (render_command_set_render_mode*)(CommandHeader + 1);
glViewport(Command->ViewOffsetX, Command->ViewOffsetY,
Command->ViewWidth, Command->ViewHeight);
LoadModelView(Command->ModelView.Array);
LoadProjection(Command->Projection.Array);
if (Command->UseDepthBuffer)
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
}
else
{
glDisable(GL_DEPTH_TEST);
}
CurrentPosition += sizeof(render_command_set_render_mode);
}break;
case RenderCommand_render_command_clear_screen:
{
DEBUG_TRACK_SCOPE(RendererClearScreen);
render_command_clear_screen* Command = (render_command_clear_screen*)(CommandHeader + 1);
ClearRenderBuffer();
CurrentPosition += sizeof(render_command_clear_screen);
}break;
case RenderCommand_render_batch_command_quad_2d:
{
render_batch_command_quad_2d* Command = (render_batch_command_quad_2d*)(CommandHeader + 1);
if (GLTextureEnabled) { glDisable(GL_TEXTURE_2D); GLTextureEnabled = false; }
u8* CommandData = (u8*)(Command + 1);
Render2DQuadBatch(CommandData, Command->QuadCount);
CurrentPosition += sizeof(render_batch_command_quad_2d) + Command->DataSize;
}break;
case RenderCommand_render_batch_command_quad_3d:
{
render_batch_command_quad_3d* Command = (render_batch_command_quad_3d*)(CommandHeader + 1);
if (GLTextureEnabled) { glDisable(GL_TEXTURE_2D); GLTextureEnabled = false; }
u8* CommandData = (u8*)(Command + 1);
Render3DQuadBatch(CommandData, Command->QuadCount * 2);
CurrentPosition += sizeof(render_batch_command_quad_3d) + Command->DataSize;
}break;
case RenderCommand_render_batch_command_texture_2d:
{
render_batch_command_texture_2d* Command = (render_batch_command_texture_2d*)(CommandHeader + 1);
if (!GLTextureEnabled) { glEnable(GL_TEXTURE_2D); GLTextureEnabled = true; }
Assert(Command->Texture.Handle > 0);
glBindTexture(GL_TEXTURE_2D, Command->Texture.Handle);
u8* CommandData = (u8*)(Command + 1);
Render2DQuadBatch(CommandData, Command->QuadCount);
CurrentPosition += sizeof(render_batch_command_texture_2d) + Command->DataSize;
}break;
default:
{
InvalidCodePath;
}break;
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
}
else
{
glDisable(GL_DEPTH_TEST);
}
CurrentPosition += sizeof(render_command_set_render_mode);
}break;
case RenderCommand_render_command_clear_screen:
{
DEBUG_TRACK_SCOPE(RendererClearScreen);
render_command_clear_screen* Command = (render_command_clear_screen*)(CommandHeader + 1);
ClearRenderBuffer();
CurrentPosition += sizeof(render_command_clear_screen);
}break;
case RenderCommand_render_batch_command_quad_2d:
{
render_batch_command_quad_2d* Command = (render_batch_command_quad_2d*)(CommandHeader + 1);
if (GLTextureEnabled) { glDisable(GL_TEXTURE_2D); GLTextureEnabled = false; }
u8* CommandData = (u8*)(Command + 1);
Render2DQuadBatch(CommandData, Command->QuadCount);
CurrentPosition += sizeof(render_batch_command_quad_2d) + Command->DataSize;
}break;
case RenderCommand_render_batch_command_quad_3d:
{
render_batch_command_quad_3d* Command = (render_batch_command_quad_3d*)(CommandHeader + 1);
if (GLTextureEnabled) { glDisable(GL_TEXTURE_2D); GLTextureEnabled = false; }
u8* CommandData = (u8*)(Command + 1);
Render3DQuadBatch(CommandData, Command->QuadCount * 2);
CurrentPosition += sizeof(render_batch_command_quad_3d) + Command->DataSize;
}break;
case RenderCommand_render_batch_command_texture_2d:
{
render_batch_command_texture_2d* Command = (render_batch_command_texture_2d*)(CommandHeader + 1);
if (!GLTextureEnabled) { glEnable(GL_TEXTURE_2D); GLTextureEnabled = true; }
Assert(Command->Texture.Handle > 0);
glBindTexture(GL_TEXTURE_2D, Command->Texture.Handle);
u8* CommandData = (u8*)(Command + 1);
Render2DQuadBatch(CommandData, Command->QuadCount);
CurrentPosition += sizeof(render_batch_command_texture_2d) + Command->DataSize;
}break;
default:
{
InvalidCodePath;
}break;
}
}
}
internal void
ClearRenderBuffer (render_command_buffer* Buffer)
{
Buffer->CommandMemoryUsed = 0;
Buffer->CommandMemoryUsed = 0;
}
#define FOLDHAUS_RENDERER_CPP

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -11,92 +11,92 @@
// DLL
struct win32_dll_refresh
{
FILETIME LastWriteTime;
HMODULE DLL;
bool IsValid;
char SourceDLLPath[MAX_PATH];
char WorkingDLLPath[MAX_PATH];
char LockFilePath[MAX_PATH];
FILETIME LastWriteTime;
HMODULE DLL;
bool IsValid;
char SourceDLLPath[MAX_PATH];
char WorkingDLLPath[MAX_PATH];
char LockFilePath[MAX_PATH];
};
internal int
Win32DLLgs_stringLength(char* gs_string)
{
char* At = gs_string;
while (*At) { At++; };
return At - gs_string;
char* At = gs_string;
while (*At) { At++; };
return At - gs_string;
}
internal int
Win32DLLConcatgs_strings(int ALength, char* A, int BLength, char* B, int DestLength, char* Dest)
{
char* Dst = Dest;
char* AAt = A;
int ALengthToCopy = ALength < DestLength ? ALength : DestLength;
for (s32 a = 0; a < ALength; a++)
{
*Dst++ = *AAt++;
}
char* BAt = B;
int DestLengthRemaining = DestLength - (Dst - Dest);
int BLengthToCopy = BLength < DestLengthRemaining ? BLength : DestLength;
for (s32 b = 0; b < BLengthToCopy; b++)
{
*Dst++ = *BAt++;
}
int DestLengthOut = Dst - Dest;
int NullTermIndex = DestLengthOut < DestLength ? DestLengthOut : DestLength;
Dest[NullTermIndex] = 0;
return DestLengthOut;
char* Dst = Dest;
char* AAt = A;
int ALengthToCopy = ALength < DestLength ? ALength : DestLength;
for (s32 a = 0; a < ALength; a++)
{
*Dst++ = *AAt++;
}
char* BAt = B;
int DestLengthRemaining = DestLength - (Dst - Dest);
int BLengthToCopy = BLength < DestLengthRemaining ? BLength : DestLength;
for (s32 b = 0; b < BLengthToCopy; b++)
{
*Dst++ = *BAt++;
}
int DestLengthOut = Dst - Dest;
int NullTermIndex = DestLengthOut < DestLength ? DestLengthOut : DestLength;
Dest[NullTermIndex] = 0;
return DestLengthOut;
}
internal void
GetApplicationPath(system_path* Result)
{
Assert(Result->Path);
Result->PathLength = GetModuleFileNameA(0, Result->Path, Result->PathLength);
u32 CharactersScanned = 0;
u32 IndexOfLastSlash = 0;
char *Scan = Result->Path;
while(*Scan)
Assert(Result->Path);
Result->PathLength = GetModuleFileNameA(0, Result->Path, Result->PathLength);
u32 CharactersScanned = 0;
u32 IndexOfLastSlash = 0;
char *Scan = Result->Path;
while(*Scan)
{
if (*Scan == '\\')
{
if (*Scan == '\\')
{
Result->IndexOfLastSlash = CharactersScanned + 1;
}
Scan++;
CharactersScanned++;
Result->IndexOfLastSlash = CharactersScanned + 1;
}
Scan++;
CharactersScanned++;
}
}
internal b32
LoadApplicationDLL(char* DLLName, win32_dll_refresh* DLLResult)
{
b32 Success = false;
Assert(DLLResult->DLL == 0);
DLLResult->DLL = LoadLibraryA(DLLName);
if (DLLResult->DLL)
{
Success = true;
DLLResult->IsValid = true;
}
return Success;
b32 Success = false;
Assert(DLLResult->DLL == 0);
DLLResult->DLL = LoadLibraryA(DLLName);
if (DLLResult->DLL)
{
Success = true;
DLLResult->IsValid = true;
}
return Success;
}
internal void
UnloadApplicationDLL(win32_dll_refresh* DLL)
{
if (DLL->DLL)
{
FreeLibrary(DLL->DLL);
}
DLL->DLL = 0;
DLL->IsValid = false;
if (DLL->DLL)
{
FreeLibrary(DLL->DLL);
}
DLL->DLL = 0;
DLL->IsValid = false;
}
internal win32_dll_refresh
@ -104,57 +104,57 @@ InitializeDLLHotReloading(char* SourceDLLName,
char* WorkingDLLFileName,
char* LockFileName)
{
win32_dll_refresh Result = {};
Result.IsValid = false;
system_path ExePath = {};
ExePath.PathLength = MAX_PATH;
ExePath.Path = (char*)VirtualAlloc(NULL, ExePath.PathLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
GetApplicationPath(&ExePath);
Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path,
Win32DLLgs_stringLength(SourceDLLName), SourceDLLName,
MAX_PATH, Result.SourceDLLPath);
Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path,
Win32DLLgs_stringLength(WorkingDLLFileName), WorkingDLLFileName,
MAX_PATH, Result.WorkingDLLPath);
Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path,
Win32DLLgs_stringLength(LockFileName), LockFileName,
MAX_PATH, Result.LockFilePath);
Win32Free((u8*)ExePath.Path, ExePath.PathLength);
return Result;
win32_dll_refresh Result = {};
Result.IsValid = false;
system_path ExePath = {};
ExePath.PathLength = MAX_PATH;
ExePath.Path = (char*)VirtualAlloc(NULL, ExePath.PathLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
GetApplicationPath(&ExePath);
Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path,
Win32DLLgs_stringLength(SourceDLLName), SourceDLLName,
MAX_PATH, Result.SourceDLLPath);
Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path,
Win32DLLgs_stringLength(WorkingDLLFileName), WorkingDLLFileName,
MAX_PATH, Result.WorkingDLLPath);
Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path,
Win32DLLgs_stringLength(LockFileName), LockFileName,
MAX_PATH, Result.LockFilePath);
Win32Free((u8*)ExePath.Path, ExePath.PathLength, 0);
return Result;
}
internal b32
HotLoadDLL(win32_dll_refresh* DLL)
{
b32 DidReload = false;
FILETIME UpdatedLastWriteTime = {};
WIN32_FIND_DATA FindData = {};
HANDLE FileHandle = FindFirstFileA(DLL->SourceDLLPath, &FindData);
if (FileHandle != INVALID_HANDLE_VALUE)
b32 DidReload = false;
FILETIME UpdatedLastWriteTime = {};
WIN32_FIND_DATA FindData = {};
HANDLE FileHandle = FindFirstFileA(DLL->SourceDLLPath, &FindData);
if (FileHandle != INVALID_HANDLE_VALUE)
{
UpdatedLastWriteTime = FindData.ftLastWriteTime;
FindClose(FileHandle);
}
if (CompareFileTime(&UpdatedLastWriteTime, &DLL->LastWriteTime))
{
WIN32_FILE_ATTRIBUTE_DATA Ignored;
if (!GetFileAttributesEx(DLL->LockFilePath, GetFileExInfoStandard, &Ignored))
{
UpdatedLastWriteTime = FindData.ftLastWriteTime;
FindClose(FileHandle);
UnloadApplicationDLL(DLL);
CopyFileA(DLL->SourceDLLPath, DLL->WorkingDLLPath, FALSE);
LoadApplicationDLL(DLL->WorkingDLLPath, DLL);
DLL->LastWriteTime = UpdatedLastWriteTime;
DidReload = true;
}
if (CompareFileTime(&UpdatedLastWriteTime, &DLL->LastWriteTime))
{
WIN32_FILE_ATTRIBUTE_DATA Ignored;
if (!GetFileAttributesEx(DLL->LockFilePath, GetFileExInfoStandard, &Ignored))
{
UnloadApplicationDLL(DLL);
CopyFileA(DLL->SourceDLLPath, DLL->WorkingDLLPath, FALSE);
LoadApplicationDLL(DLL->WorkingDLLPath, DLL);
DLL->LastWriteTime = UpdatedLastWriteTime;
DidReload = true;
}
}
return DidReload;
}
return DidReload;
}

View File

@ -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;
}
return Result;
u8* Result = (u8*)VirtualAlloc(NULL, Size,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
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

View File

@ -13,367 +13,367 @@ global s32* Win32SerialPortFilled;
DCB
Win32SerialPort_GetState(HANDLE ComPortHandle)
{
DEBUG_TRACK_FUNCTION;
DCB ControlSettings = {0};
ZeroStruct(&ControlSettings);
ControlSettings.DCBlength = sizeof(ControlSettings);
bool Success = GetCommState(ComPortHandle, &ControlSettings);
Assert(Success);
return ControlSettings;
DEBUG_TRACK_FUNCTION;
DCB ControlSettings = {0};
ZeroStruct(&ControlSettings);
ControlSettings.DCBlength = sizeof(ControlSettings);
bool Success = GetCommState(ComPortHandle, &ControlSettings);
Assert(Success);
return ControlSettings;
}
void
Win32SerialPort_SetState(HANDLE ComPortHandle, u32 BaudRate, u8 ByteSize, u8 Parity, u8 StopBits)
{
DEBUG_TRACK_FUNCTION;
DCB ControlSettings = Win32SerialPort_GetState(ComPortHandle);
// TODO(pjs): Validate BaudRate - There's only certain rates that are valid right?
ControlSettings.BaudRate = BaudRate;
if (Parity == NOPARITY)
{
ControlSettings.Parity = Parity;
ControlSettings.fParity = 0;
}
if (Parity == EVENPARITY || Parity == ODDPARITY)
{
ControlSettings.Parity = Parity;
ControlSettings.fParity = 1;
}
ControlSettings.StopBits = StopBits;
ControlSettings.ByteSize = ByteSize;
ControlSettings.fBinary = true;
ControlSettings.fOutxCtsFlow = false;
ControlSettings.fOutxDsrFlow = false;
ControlSettings.fDtrControl = DTR_CONTROL_DISABLE;
ControlSettings.fDsrSensitivity = 0;
ControlSettings.fRtsControl = RTS_CONTROL_DISABLE;
ControlSettings.fOutX = false;
ControlSettings.fInX = false;
ControlSettings.fErrorChar = 0;
ControlSettings.fNull = false;
ControlSettings.fAbortOnError = false;
ControlSettings.wReserved = false;
ControlSettings.XonLim = 2;
ControlSettings.XoffLim = 4;
ControlSettings.XonChar = 0x13;
ControlSettings.XoffChar = 0x19;
ControlSettings.EvtChar = 0;
bool Success = SetCommState(ComPortHandle, &ControlSettings);
DEBUG_TRACK_FUNCTION;
DCB ControlSettings = Win32SerialPort_GetState(ComPortHandle);
// TODO(pjs): Validate BaudRate - There's only certain rates that are valid right?
ControlSettings.BaudRate = BaudRate;
if (Parity == NOPARITY)
{
ControlSettings.Parity = Parity;
ControlSettings.fParity = 0;
}
if (Parity == EVENPARITY || Parity == ODDPARITY)
{
ControlSettings.Parity = Parity;
ControlSettings.fParity = 1;
}
ControlSettings.StopBits = StopBits;
ControlSettings.ByteSize = ByteSize;
ControlSettings.fBinary = true;
ControlSettings.fOutxCtsFlow = false;
ControlSettings.fOutxDsrFlow = false;
ControlSettings.fDtrControl = DTR_CONTROL_DISABLE;
ControlSettings.fDsrSensitivity = 0;
ControlSettings.fRtsControl = RTS_CONTROL_DISABLE;
ControlSettings.fOutX = false;
ControlSettings.fInX = false;
ControlSettings.fErrorChar = 0;
ControlSettings.fNull = false;
ControlSettings.fAbortOnError = false;
ControlSettings.wReserved = false;
ControlSettings.XonLim = 2;
ControlSettings.XoffLim = 4;
ControlSettings.XonChar = 0x13;
ControlSettings.XoffChar = 0x19;
ControlSettings.EvtChar = 0;
bool Success = SetCommState(ComPortHandle, &ControlSettings);
}
gs_const_string_array
Win32SerialPorts_List(gs_memory_arena* Arena, gs_memory_arena* Transient)
{
gs_const_string_array Result = {};
gs_const_string_array Result = {};
DWORD SizeNeeded0 = 0;
DWORD CountReturned0 = 0;
EnumPorts(NULL, 1, 0, 0, &SizeNeeded0, &CountReturned0);
Assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
DWORD SizeNeeded1 = 0;
DWORD CountReturned1 = 0;
PORT_INFO_1* PortsArray = (PORT_INFO_1*)PushSize(Transient, SizeNeeded0).Memory;
if (EnumPorts(NULL,
1,
(u8*)PortsArray,
SizeNeeded0,
&SizeNeeded1,
&CountReturned1))
{
Result.CountMax = (u64)CountReturned1;
Result.Strings = PushArray(Arena, gs_const_string, Result.CountMax);
DWORD SizeNeeded0 = 0;
DWORD CountReturned0 = 0;
EnumPorts(NULL, 1, 0, 0, &SizeNeeded0, &CountReturned0);
Assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
DWORD SizeNeeded1 = 0;
DWORD CountReturned1 = 0;
PORT_INFO_1* PortsArray = (PORT_INFO_1*)PushSize(Transient, SizeNeeded0);
if (EnumPorts(NULL,
1,
(u8*)PortsArray,
SizeNeeded0,
&SizeNeeded1,
&CountReturned1))
for (; Result.Count < Result.CountMax; Result.Count++)
{
Result.CountMax = (u64)CountReturned1;
Result.Strings = PushArray(Arena, gs_const_string, Result.CountMax);
for (; Result.Count < Result.CountMax; Result.Count++)
{
u64 Index = Result.Count;
u64 StrLen = CStringLength(PortsArray[Index].pName);
gs_string Str = PushString(Arena, StrLen);
PrintF(&Str, "%.*s", StrLen, PortsArray[Index].pName);
Result.Strings[Result.Count] = Str.ConstString;
}
u64 Index = Result.Count;
u64 StrLen = CStringLength(PortsArray[Index].pName);
gs_string Str = PushString(Arena, StrLen);
PrintF(&Str, "%.*s", StrLen, PortsArray[Index].pName);
Result.Strings[Result.Count] = Str.ConstString;
}
return Result;
}
return Result;
}
bool
Win32SerialPort_Exists(char* PortName, gs_memory_arena* Transient)
{
bool Result = false;
if (PortName != 0)
bool Result = false;
if (PortName != 0)
{
gs_const_string PortIdent = ConstString(PortName);
u32 IdentBegin = FindLast(PortIdent, '\\') + 1;
PortIdent = Substring(PortIdent, IdentBegin, PortIdent.Length);
gs_const_string_array PortsAvailable = Win32SerialPorts_List(Transient, Transient);
for (u64 i = 0; i < PortsAvailable.Count; i++)
{
gs_const_string PortIdent = ConstString(PortName);
u32 IdentBegin = FindLast(PortIdent, '\\') + 1;
PortIdent = Substring(PortIdent, IdentBegin, PortIdent.Length);
gs_const_string_array PortsAvailable = Win32SerialPorts_List(Transient, Transient);
for (u64 i = 0; i < PortsAvailable.Count; i++)
{
gs_const_string AvailablePortName = PortsAvailable.Strings[i];
if (StringsEqualUpToLength(AvailablePortName, PortIdent, PortIdent.Length))
{
Result = true;
break;
}
}
gs_const_string AvailablePortName = PortsAvailable.Strings[i];
if (StringsEqualUpToLength(AvailablePortName, PortIdent, PortIdent.Length))
{
Result = true;
break;
}
}
return Result;
}
return Result;
}
HANDLE
Win32SerialPort_Open(char* PortName, gs_memory_arena* Transient)
{
DEBUG_TRACK_FUNCTION;
HANDLE ComPortHandle = INVALID_HANDLE_VALUE;;
DEBUG_TRACK_FUNCTION;
HANDLE ComPortHandle = INVALID_HANDLE_VALUE;;
if (Win32SerialPort_Exists(PortName, Transient))
{
if (Win32SerialPort_Exists(PortName, Transient))
ComPortHandle = CreateFile(PortName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, // Default Security Attr
OPEN_EXISTING,
0, // Not overlapped I/O
NULL);
bool HasError = false;
if (ComPortHandle != INVALID_HANDLE_VALUE)
{
ComPortHandle = CreateFile(PortName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, // Default Security Attr
OPEN_EXISTING,
0, // Not overlapped I/O
NULL);
bool HasError = false;
if (ComPortHandle != INVALID_HANDLE_VALUE)
{
COMMTIMEOUTS Timeouts = { 0 };
Timeouts.ReadIntervalTimeout = 0; // in milliseconds
Timeouts.ReadTotalTimeoutConstant = 0; // in milliseconds
Timeouts.ReadTotalTimeoutMultiplier = 0; // in milliseconds
Timeouts.WriteTotalTimeoutConstant = 0; // in milliseconds
Timeouts.WriteTotalTimeoutMultiplier = 0; // in milliseconds
HasError = !SetCommTimeouts(ComPortHandle, &Timeouts);
}
else
{
HasError = true;
}
if (HasError)
{
// Error
s32 Error = GetLastError();
switch (Error)
{
case ERROR_INVALID_FUNCTION:
case ERROR_NO_SUCH_DEVICE:
case ERROR_FILE_NOT_FOUND:
{
// NOTE(PS): The outer scope should handle these cases
ComPortHandle = INVALID_HANDLE_VALUE;
}break;
InvalidDefaultCase;
}
}
COMMTIMEOUTS Timeouts = { 0 };
Timeouts.ReadIntervalTimeout = 0; // in milliseconds
Timeouts.ReadTotalTimeoutConstant = 0; // in milliseconds
Timeouts.ReadTotalTimeoutMultiplier = 0; // in milliseconds
Timeouts.WriteTotalTimeoutConstant = 0; // in milliseconds
Timeouts.WriteTotalTimeoutMultiplier = 0; // in milliseconds
HasError = !SetCommTimeouts(ComPortHandle, &Timeouts);
}
else
{
HasError = true;
}
return ComPortHandle;
if (HasError)
{
// Error
s32 Error = GetLastError();
switch (Error)
{
case ERROR_INVALID_FUNCTION:
case ERROR_NO_SUCH_DEVICE:
case ERROR_FILE_NOT_FOUND:
{
// NOTE(PS): The outer scope should handle these cases
ComPortHandle = INVALID_HANDLE_VALUE;
}break;
InvalidDefaultCase;
}
}
}
return ComPortHandle;
}
void
Win32SerialPort_Close(HANDLE PortHandle)
{
CloseHandle(PortHandle);
CloseHandle(PortHandle);
}
bool
Win32SerialPort_Write(HANDLE PortHandle, gs_data Buffer)
{
DEBUG_TRACK_FUNCTION;
Assert(PortHandle != INVALID_HANDLE_VALUE);
bool Success = false;
DWORD BytesWritten = 0;
if (WriteFile(PortHandle, Buffer.Memory, Buffer.Size, &BytesWritten, NULL))
DEBUG_TRACK_FUNCTION;
Assert(PortHandle != INVALID_HANDLE_VALUE);
bool Success = false;
DWORD BytesWritten = 0;
if (WriteFile(PortHandle, Buffer.Memory, Buffer.Size, &BytesWritten, NULL))
{
Success = (BytesWritten == Buffer.Size);
if (!Success)
{
Success = (BytesWritten == Buffer.Size);
if (!Success)
{
Log_Error(GlobalLogBuffer, "Error: Entire buffer not written.\n");
}
Log_Error(GlobalLogBuffer, "Error: Entire buffer not written.\n");
}
else
}
else
{
Log_Error(GlobalLogBuffer, "Error: Unable to write to port\n");
s32 Error = GetLastError();
switch (Error)
{
Log_Error(GlobalLogBuffer, "Error: Unable to write to port\n");
s32 Error = GetLastError();
switch (Error)
{
case ERROR_OPERATION_ABORTED:
case ERROR_GEN_FAILURE:
{
// NOTE(pjs): Probably means that the serial port became invalid
// ie. the usb stick was removed
}break;
case ERROR_ACCESS_DENIED:
{
// ??
}break;
case ERROR_NO_SUCH_DEVICE:
{
}break;
case ERROR_INVALID_HANDLE:
InvalidDefaultCase;
}
case ERROR_OPERATION_ABORTED:
case ERROR_GEN_FAILURE:
{
// NOTE(pjs): Probably means that the serial port became invalid
// ie. the usb stick was removed
}break;
case ERROR_ACCESS_DENIED:
{
// ??
}break;
case ERROR_NO_SUCH_DEVICE:
{
}break;
case ERROR_INVALID_HANDLE:
InvalidDefaultCase;
}
return Success;
}
return Success;
}
bool
Win32SerialPort_SetRead(HANDLE PortHandle)
{
bool Status = SetCommMask(PortHandle, EV_RXCHAR);
return Status;
bool Status = SetCommMask(PortHandle, EV_RXCHAR);
return Status;
}
u32
Win32SerialPort_ReadMessageWhenReady(HANDLE PortHandle, gs_data Data)
{
u32 ReadSize = 0;
DWORD EventMask = 0;
bool Status = WaitCommEvent(PortHandle, &EventMask, NULL);
if (Status)
u32 ReadSize = 0;
DWORD EventMask = 0;
bool Status = WaitCommEvent(PortHandle, &EventMask, NULL);
if (Status)
{
DWORD NoBytesRead = 0;
do
{
DWORD NoBytesRead = 0;
do
{
u8 Byte = 0;
Status = ReadFile(PortHandle, &Byte, sizeof(char), &NoBytesRead, NULL);
Data.Memory[ReadSize] = Byte;
ReadSize++;
}
while (NoBytesRead > 0 && ReadSize < Data.Size);
u8 Byte = 0;
Status = ReadFile(PortHandle, &Byte, sizeof(char), &NoBytesRead, NULL);
Data.Memory[ReadSize] = Byte;
ReadSize++;
}
//Read data and store in a buffer
return ReadSize;
while (NoBytesRead > 0 && ReadSize < Data.Size);
}
//Read data and store in a buffer
return ReadSize;
}
/////////////////////////
// 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);
u64 PortNameSize = 256;
u64 PortNameBufferSize = PortNameSize * Win32SerialHandlesCountMax;
char* PortNameBuffer = AllocatorAllocArray(Context.Allocator, char, PortNameBufferSize);
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
char* NameBase = PortNameBuffer + (PortNameSize * i);
Win32SerialPortNames[i] = MakeString(NameBase, 0, PortNameSize);
Win32SerialPortFilled[i] = 0;
}
DEBUG_TRACK_FUNCTION;
Win32SerialHandlesCountMax = 32;
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 = PushArray(A, char, PortNameBufferSize);
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
char* NameBase = PortNameBuffer + (PortNameSize * i);
Win32SerialPortNames[i] = MakeString(NameBase, 0, PortNameSize);
Win32SerialPortFilled[i] = 0;
}
}
void
Win32SerialArray_Push(HANDLE SerialHandle, gs_const_string PortName)
{
DEBUG_TRACK_FUNCTION;
bool Found = false;
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
DEBUG_TRACK_FUNCTION;
bool Found = false;
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
bool WasFilled = InterlockedCompareExchange((LONG volatile*)Win32SerialPortFilled + i, 1, 0);
if (!WasFilled)
{
bool WasFilled = InterlockedCompareExchange((LONG volatile*)Win32SerialPortFilled + i, 1, 0);
if (!WasFilled)
{
Win32SerialHandles[i] = SerialHandle;
PrintF(&Win32SerialPortNames[i], "%S", PortName);
Found = true;
break;
}
Win32SerialHandles[i] = SerialHandle;
PrintF(&Win32SerialPortNames[i], "%S", PortName);
Found = true;
break;
}
Assert(Found);
}
Assert(Found);
}
void
Win32SerialArray_Pop(u32 Index)
{
bool WasFilled = InterlockedCompareExchange((LONG volatile*)Win32SerialPortFilled + Index, 0, 1);
Assert(WasFilled);
Win32SerialPortFilled[Index] = false;
Win32SerialHandles[Index] = INVALID_HANDLE_VALUE;
bool WasFilled = InterlockedCompareExchange((LONG volatile*)Win32SerialPortFilled + Index, 0, 1);
Assert(WasFilled);
Win32SerialPortFilled[Index] = false;
Win32SerialHandles[Index] = INVALID_HANDLE_VALUE;
}
HANDLE
Win32SerialArray_Get(gs_const_string PortName)
{
DEBUG_TRACK_FUNCTION;
HANDLE PortHandle = INVALID_HANDLE_VALUE;
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
DEBUG_TRACK_FUNCTION;
HANDLE PortHandle = INVALID_HANDLE_VALUE;
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
if (Win32SerialPortFilled[i] &&
StringsEqual(Win32SerialPortNames[i].ConstString, PortName))
{
if (Win32SerialPortFilled[i] &&
StringsEqual(Win32SerialPortNames[i].ConstString, PortName))
{
PortHandle = Win32SerialHandles[i];
break;
}
PortHandle = Win32SerialHandles[i];
break;
}
return PortHandle;
}
return PortHandle;
}
HANDLE
Win32SerialArray_GetOrOpen(gs_const_string PortName, u32 BaudRate, u8 ByteSize, u8 Parity, u8 StopBits, gs_memory_arena* Transient)
{
DEBUG_TRACK_FUNCTION;
HANDLE PortHandle = Win32SerialArray_Get(PortName);
if (PortHandle == INVALID_HANDLE_VALUE)
DEBUG_TRACK_FUNCTION;
HANDLE PortHandle = Win32SerialArray_Get(PortName);
if (PortHandle == INVALID_HANDLE_VALUE)
{
Assert(IsNullTerminated(PortName));
PortHandle = Win32SerialPort_Open(PortName.Str, Transient);
if (PortHandle != INVALID_HANDLE_VALUE)
{
Assert(IsNullTerminated(PortName));
PortHandle = Win32SerialPort_Open(PortName.Str, Transient);
if (PortHandle != INVALID_HANDLE_VALUE)
{
Win32SerialPort_SetState(PortHandle, BaudRate, ByteSize, Parity, StopBits);
Win32SerialArray_Push(PortHandle, PortName);
}
Win32SerialPort_SetState(PortHandle, BaudRate, ByteSize, Parity, StopBits);
Win32SerialArray_Push(PortHandle, PortName);
}
return PortHandle;
}
return PortHandle;
}
void
Win32SerialArray_Close(gs_const_string PortName)
{
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
for (u32 i = 0; i < Win32SerialHandlesCountMax; i++)
{
if (Win32SerialPortFilled[i] && StringsEqual(Win32SerialPortNames[i].ConstString, PortName))
{
if (Win32SerialPortFilled[i] && StringsEqual(Win32SerialPortNames[i].ConstString, PortName))
{
Win32SerialPort_Close(Win32SerialHandles[i]);
Win32SerialArray_Pop(i);
break;
}
Win32SerialPort_Close(Win32SerialHandles[i]);
Win32SerialArray_Pop(i);
break;
}
}
}
#define WIN32_SERIAL_H

View File

@ -7,14 +7,14 @@
struct win32_socket
{
SOCKET Socket;
SOCKET Socket;
};
struct win32_socket_array
{
win32_socket* Values;
s32 CountMax;
s32 Count;
win32_socket* Values;
s32 CountMax;
s32 Count;
};
global WSADATA WSAData;
@ -27,28 +27,28 @@ global win32_socket_array Win32Sockets;
internal win32_socket_array
Win32SocketArray_Create(u32 CountMax, gs_memory_arena* Storage)
{
win32_socket_array Result = {};
Result.CountMax = CountMax;
Result.Values = PushArray(Storage, win32_socket, CountMax);
return Result;
win32_socket_array Result = {};
Result.CountMax = CountMax;
Result.Values = PushArray(Storage, win32_socket, CountMax);
return Result;
}
internal s32
Win32SocketArray_Take(win32_socket_array* Array)
{
Assert(Array->Count < Array->CountMax);
s32 Result = Array->Count++;
win32_socket* Socket = Array->Values + Result;
*Socket = {0};
return Result;
Assert(Array->Count < Array->CountMax);
s32 Result = Array->Count++;
win32_socket* Socket = Array->Values + Result;
*Socket = {0};
return Result;
}
internal win32_socket*
Win32SocketArray_Get(win32_socket_array Array, s32 Index)
{
Assert(Index < Array.Count);
win32_socket* Result = Array.Values + Index;
return Result;
Assert(Index < Array.Count);
win32_socket* Result = Array.Values + Index;
return Result;
}
//////////////////////
@ -58,259 +58,259 @@ Win32SocketArray_Get(win32_socket_array Array, s32 Index)
internal win32_socket
Win32Socket_Create(s32 AddressFamily, s32 Type, s32 Protocol)
{
win32_socket Result = {0};
Result.Socket = socket(AddressFamily, Type, Protocol);
if (Result.Socket == INVALID_SOCKET)
{
s32 Error = WSAGetLastError();
InvalidCodePath;
}
return Result;
win32_socket Result = {0};
Result.Socket = socket(AddressFamily, Type, Protocol);
if (Result.Socket == INVALID_SOCKET)
{
s32 Error = WSAGetLastError();
InvalidCodePath;
}
return Result;
}
internal void
Win32Socket_Bind(win32_socket* Socket, s32 AddressFamily, char* Address, s32 Port)
{
sockaddr_in Service = {0};
Service.sin_family = AddressFamily;
Service.sin_addr.s_addr = inet_addr(Address);
Service.sin_port = htons(Port);
s32 Result = bind(Socket->Socket, (SOCKADDR*)&Service, sizeof(Service));
if (Result == SOCKET_ERROR)
{
s32 Error = WSAGetLastError();
InvalidCodePath;
}
sockaddr_in Service = {0};
Service.sin_family = AddressFamily;
Service.sin_addr.s_addr = inet_addr(Address);
Service.sin_port = htons(Port);
s32 Result = bind(Socket->Socket, (SOCKADDR*)&Service, sizeof(Service));
if (Result == SOCKET_ERROR)
{
s32 Error = WSAGetLastError();
InvalidCodePath;
}
}
internal win32_socket
Win32Socket_ConnectToAddress(char* Address, char* DefaultPort)
{
win32_socket Result = {};
addrinfo Hints = {0};
Hints.ai_family = AF_UNSPEC;
Hints.ai_socktype = SOCK_STREAM;
Hints.ai_protocol = IPPROTO_TCP;
addrinfo* PotentialConnections;
s32 Error = getaddrinfo(Address, DefaultPort, &Hints, &PotentialConnections);
if (Error == 0)
{
for (addrinfo* InfoAt = PotentialConnections; InfoAt != NULL; InfoAt = InfoAt->ai_next)
{
win32_socket Socket = Win32Socket_Create(InfoAt->ai_family, InfoAt->ai_socktype, InfoAt->ai_protocol);
if (Socket.Socket == INVALID_SOCKET)
{
Error = WSAGetLastError();
InvalidCodePath;
}
Error = connect(Socket.Socket, InfoAt->ai_addr, (int)InfoAt->ai_addrlen);
if (Error == SOCKET_ERROR)
{
closesocket(Socket.Socket);
continue;
}
else
{
Result = Socket;
break;
}
}
}
else
win32_socket Result = {};
addrinfo Hints = {0};
Hints.ai_family = AF_UNSPEC;
Hints.ai_socktype = SOCK_STREAM;
Hints.ai_protocol = IPPROTO_TCP;
addrinfo* PotentialConnections;
s32 Error = getaddrinfo(Address, DefaultPort, &Hints, &PotentialConnections);
if (Error == 0)
{
for (addrinfo* InfoAt = PotentialConnections; InfoAt != NULL; InfoAt = InfoAt->ai_next)
{
win32_socket Socket = Win32Socket_Create(InfoAt->ai_family, InfoAt->ai_socktype, InfoAt->ai_protocol);
if (Socket.Socket == INVALID_SOCKET)
{
Error = WSAGetLastError();
InvalidCodePath;
}
Error = connect(Socket.Socket, InfoAt->ai_addr, (int)InfoAt->ai_addrlen);
if (Error == SOCKET_ERROR)
{
closesocket(Socket.Socket);
continue;
}
else
{
Result = Socket;
break;
}
}
freeaddrinfo(PotentialConnections);
return Result;
}
else
{
Error = WSAGetLastError();
InvalidCodePath;
}
freeaddrinfo(PotentialConnections);
return Result;
}
internal bool
Win32ConnectSocket(platform_socket_manager* Manager, platform_socket* Socket)
{
bool Result = false;
addrinfo Hints = {0};
Hints.ai_family = AF_UNSPEC;
Hints.ai_socktype = SOCK_STREAM;
Hints.ai_protocol = IPPROTO_TCP;
addrinfo* PotentialConnections;
s32 Error = getaddrinfo(Socket->Addr, Socket->Port, &Hints, &PotentialConnections);
if (Error == 0)
{
for (addrinfo* InfoAt = PotentialConnections; InfoAt != NULL; InfoAt = InfoAt->ai_next)
{
SOCKET SocketHandle = socket(InfoAt->ai_family, InfoAt->ai_socktype, InfoAt->ai_protocol);
if (SocketHandle == INVALID_SOCKET)
{
Error = WSAGetLastError();
InvalidCodePath;
}
// If iMode == 0, blocking is enabled
// if iMode != 0, non-blocking mode is enabled
u_long iMode = 0;
Error = ioctlsocket(SocketHandle, FIONBIO, &iMode);
if (Error != NO_ERROR)
{
InvalidCodePath;
}
Error = connect(SocketHandle, InfoAt->ai_addr, (int)InfoAt->ai_addrlen);
if (Error == SOCKET_ERROR)
{
u32 Status = WSAGetLastError();
if (Status == WSAEWOULDBLOCK)
{
// Non-blocking sockets
#if 0
TIMEVAL Timeout = { 0, 500 };
fd_set SocketSet = {};
FD_ZERO(&SocketSet);
FD_SET(SocketHandle, &SocketSet);
Assert(FD_ISSET(SocketHandle, &SocketSet));
Status = select(0, &SocketSet, 0, 0, (const TIMEVAL*)&Timeout);
if (Status == SOCKET_ERROR)
{
}
else if (Status == 0)
{
}
else
{
}
#endif
}
else
{
closesocket(SocketHandle);
continue;
}
}
Socket->PlatformHandle = (u8*)Win32Alloc(sizeof(SOCKET), 0);
*(SOCKET*)Socket->PlatformHandle = SocketHandle;
Result = true;
break;
}
}
else
bool Result = false;
addrinfo Hints = {0};
Hints.ai_family = AF_UNSPEC;
Hints.ai_socktype = SOCK_STREAM;
Hints.ai_protocol = IPPROTO_TCP;
addrinfo* PotentialConnections;
s32 Error = getaddrinfo(Socket->Addr, Socket->Port, &Hints, &PotentialConnections);
if (Error == 0)
{
for (addrinfo* InfoAt = PotentialConnections; InfoAt != NULL; InfoAt = InfoAt->ai_next)
{
SOCKET SocketHandle = socket(InfoAt->ai_family, InfoAt->ai_socktype, InfoAt->ai_protocol);
if (SocketHandle == INVALID_SOCKET)
{
Error = WSAGetLastError();
InvalidCodePath;
}
// If iMode == 0, blocking is enabled
// if iMode != 0, non-blocking mode is enabled
u_long iMode = 0;
Error = ioctlsocket(SocketHandle, FIONBIO, &iMode);
if (Error != NO_ERROR)
{
InvalidCodePath;
}
Error = connect(SocketHandle, InfoAt->ai_addr, (int)InfoAt->ai_addrlen);
if (Error == SOCKET_ERROR)
{
u32 Status = WSAGetLastError();
if (Status == WSAEWOULDBLOCK)
{
// Non-blocking sockets
#if 0
TIMEVAL Timeout = { 0, 500 };
fd_set SocketSet = {};
FD_ZERO(&SocketSet);
FD_SET(SocketHandle, &SocketSet);
Assert(FD_ISSET(SocketHandle, &SocketSet));
Status = select(0, &SocketSet, 0, 0, (const TIMEVAL*)&Timeout);
if (Status == SOCKET_ERROR)
{
}
else if (Status == 0)
{
}
else
{
}
#endif
}
else
{
closesocket(SocketHandle);
continue;
}
}
Socket->PlatformHandle = (u8*)Win32Alloc(sizeof(SOCKET), 0, 0);
*(SOCKET*)Socket->PlatformHandle = SocketHandle;
Result = true;
break;
}
if (!Result)
{
Assert(Socket->PlatformHandle == 0);
}
freeaddrinfo(PotentialConnections);
return Result;
}
else
{
Error = WSAGetLastError();
InvalidCodePath;
}
if (!Result)
{
Assert(Socket->PlatformHandle == 0);
}
freeaddrinfo(PotentialConnections);
return Result;
}
internal bool
Win32CloseSocket(platform_socket_manager* Manager, platform_socket* Socket)
{
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
closesocket(*Win32Sock);
Win32Free((u8*)Socket->PlatformHandle, sizeof(SOCKET));
*Socket = {};
return true;
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
closesocket(*Win32Sock);
Win32Free((u8*)Socket->PlatformHandle, sizeof(SOCKET), 0);
*Socket = {};
return true;
}
internal bool
Win32SocketQueryStatus(platform_socket_manager* Manager, platform_socket* Socket)
{
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
bool Result = (*Win32Sock != INVALID_SOCKET);
return Result;
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
bool Result = (*Win32Sock != INVALID_SOCKET);
return Result;
}
internal u32
Win32SocketPeek(platform_socket_manager* Manager, platform_socket* Socket)
{
u32 Result = 0;
s32 Flags = MSG_PEEK;
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
char Temp[4];
u32 TempSize = 4;
//Log_Message(GlobalLogBuffer, "Pre Peek...");
//s32 BytesQueued = recv(*Win32Sock, Temp, TempSize, Flags);
u_long BytesQueued = 0;
ioctlsocket(*Win32Sock, FIONREAD, &BytesQueued);
//Log_Message(GlobalLogBuffer, "Post Peek\n");
if (BytesQueued != SOCKET_ERROR)
u32 Result = 0;
s32 Flags = MSG_PEEK;
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
char Temp[4];
u32 TempSize = 4;
//Log_Message(GlobalLogBuffer, "Pre Peek...");
//s32 BytesQueued = recv(*Win32Sock, Temp, TempSize, Flags);
u_long BytesQueued = 0;
ioctlsocket(*Win32Sock, FIONREAD, &BytesQueued);
//Log_Message(GlobalLogBuffer, "Post Peek\n");
if (BytesQueued != SOCKET_ERROR)
{
Result = (u32)BytesQueued;
}
else
{
s32 Error = WSAGetLastError();
switch (Error)
{
Result = (u32)BytesQueued;
case WSAEWOULDBLOCK:
{
// NOTE(PS): This case covers non-blocking sockets
// if we peek and there's nothing there, it returns
// this error code. MSDN says its a non-fatal error
// and the operation should be retried later
Result = 0;
} break;
case WSAENOTCONN:
case WSAECONNRESET:
case WSAECONNABORTED:
{
CloseSocket(Manager, Socket);
}break;
InvalidDefaultCase;
}
else
{
s32 Error = WSAGetLastError();
switch (Error)
{
case WSAEWOULDBLOCK:
{
// NOTE(PS): This case covers non-blocking sockets
// if we peek and there's nothing there, it returns
// this error code. MSDN says its a non-fatal error
// and the operation should be retried later
Result = 0;
} break;
case WSAENOTCONN:
case WSAECONNRESET:
case WSAECONNABORTED:
{
CloseSocket(Manager, Socket);
}break;
InvalidDefaultCase;
}
}
return (s32)Result;
}
return (s32)Result;
}
internal gs_data
Win32SocketReceive(platform_socket_manager* Manager, platform_socket* Socket, gs_memory_arena* Storage)
{
// TODO(pjs): Test this first code path when you have data running - it should
// get the actual size of the data packet being sent
// TODO(pjs): Test this first code path when you have data running - it should
// get the actual size of the data packet being sent
#if 0
gs_data Result = {};
s32 BytesQueued = Win32Socket_PeekGetTotalSize(Socket);
if (BytesQueued > 0)
{
Result = PushSizeToData(Storage, BytesQueued);
s32 Flags = 0;
s32 BytesReceived = recv(Socket->Socket, (char*)Result.Memory, Result.Size, Flags);
Assert(BytesReceived == BytesQueued);
}
return Result;
#else
gs_data Result = PushSizeToData(Storage, 1024);
gs_data Result = {};
s32 BytesQueued = Win32Socket_PeekGetTotalSize(Socket);
if (BytesQueued > 0)
{
Result = PushSizeToData(Storage, BytesQueued);
s32 Flags = 0;
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
s32 BytesReceived = recv(*Win32Sock, (char*)Result.Memory, Result.Size, Flags);
if (BytesReceived == SOCKET_ERROR)
{
// TODO(pjs): Error logging
s32 Error = WSAGetLastError();
InvalidCodePath;
}
Result.Size = BytesReceived;
return Result;
s32 BytesReceived = recv(Socket->Socket, (char*)Result.Memory, Result.Size, Flags);
Assert(BytesReceived == BytesQueued);
}
return Result;
#else
gs_data Result = PushSize(Storage, 1024);
s32 Flags = 0;
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
s32 BytesReceived = recv(*Win32Sock, (char*)Result.Memory, Result.Size, Flags);
if (BytesReceived == SOCKET_ERROR)
{
// TODO(pjs): Error logging
s32 Error = WSAGetLastError();
InvalidCodePath;
}
Result.Size = BytesReceived;
return Result;
#endif
}
@ -318,193 +318,193 @@ Win32SocketReceive(platform_socket_manager* Manager, platform_socket* Socket, gs
internal s32
Win32SocketSend(platform_socket_manager* Manager, platform_socket* Socket, u32 Address, u32 Port, gs_data Data, s32 Flags)
{
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
sockaddr_in SockAddress = {};
SockAddress.sin_family = AF_INET;
SockAddress.sin_port = HostToNetU16(Port);
SockAddress.sin_addr.s_addr = HostToNetU32(Address);
s32 LengthSent = sendto(*Win32Sock, (char*)Data.Memory, Data.Size, Flags, (sockaddr*)&SockAddress, sizeof(sockaddr_in));
//Log_Message(GlobalLogBuffer, "Attempting To Send Network Data: ");
if (LengthSent == SOCKET_ERROR)
SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle;
sockaddr_in SockAddress = {};
SockAddress.sin_family = AF_INET;
SockAddress.sin_port = HostToNetU16(Port);
SockAddress.sin_addr.s_addr = HostToNetU32(Address);
s32 LengthSent = sendto(*Win32Sock, (char*)Data.Memory, Data.Size, Flags, (sockaddr*)&SockAddress, sizeof(sockaddr_in));
//Log_Message(GlobalLogBuffer, "Attempting To Send Network Data: ");
if (LengthSent == SOCKET_ERROR)
{
s32 Error = WSAGetLastError();
switch (Error)
{
s32 Error = WSAGetLastError();
switch (Error)
case WSAEWOULDBLOCK:
{
// NOTE(PS): This covers non-blocking sockets
// In this case the message should be tried again
LengthSent = 0;
//Log_Message(GlobalLogBuffer, "Not sent, buffered\n");
}break;
case WSAECONNABORTED:
case WSAENETUNREACH:
case WSAECONNRESET:
case WSAENOTCONN:
{
if (CloseSocket(Manager, Socket))
{
case WSAEWOULDBLOCK:
{
// NOTE(PS): This covers non-blocking sockets
// In this case the message should be tried again
LengthSent = 0;
//Log_Message(GlobalLogBuffer, "Not sent, buffered\n");
}break;
case WSAECONNABORTED:
case WSAENETUNREACH:
case WSAECONNRESET:
case WSAENOTCONN:
{
if (CloseSocket(Manager, Socket))
{
Log_Error(GlobalLogBuffer, "Error: %d\n", Error);
Error = 0;
}
}break;
InvalidDefaultCase;
Log_Error(GlobalLogBuffer, "Error: %d\n", Error);
Error = 0;
}
}break;
InvalidDefaultCase;
}
else
{
Log_Message(GlobalLogBuffer, "Sent\n");
}
return LengthSent;
}
else
{
Log_Message(GlobalLogBuffer, "Sent\n");
}
return LengthSent;
}
internal s32
Win32Socket_SetOption(win32_socket* Socket, s32 Level, s32 Option, const char* OptionValue, s32 OptionLength)
{
int Error = setsockopt(Socket->Socket, Level, Option, OptionValue, OptionLength);
if (Error == SOCKET_ERROR)
{
Error = WSAGetLastError();
// TODO(Peter): :ErrorLogging
}
return Error;
int Error = setsockopt(Socket->Socket, Level, Option, OptionValue, OptionLength);
if (Error == SOCKET_ERROR)
{
Error = WSAGetLastError();
// TODO(Peter): :ErrorLogging
}
return Error;
}
internal s32
Win32Socket_SetOption(platform_socket_handle SocketHandle, s32 Level, s32 Option, const char* OptionValue, s32 OptionLength)
{
win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, (s32)SocketHandle);
return Win32Socket_SetOption(Socket, Level, Option, OptionValue, OptionLength);
win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, (s32)SocketHandle);
return Win32Socket_SetOption(Socket, Level, Option, OptionValue, OptionLength);
}
internal s32
Win32Socket_SendTo(platform_socket_handle SocketHandle, u32 Address, u32 Port, const char* Buffer, s32 BufferLength, s32 Flags)
{
win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, (s32)SocketHandle);
sockaddr_in SockAddress = {};
SockAddress.sin_family = AF_INET;
SockAddress.sin_port = HostToNetU16(Port);
SockAddress.sin_addr.s_addr = HostToNetU32(Address);
s32 LengthSent = sendto(Socket->Socket, Buffer, BufferLength, Flags, (sockaddr*)&SockAddress, sizeof(sockaddr_in));
Log_Message(GlobalLogBuffer, "Attempting To Send Network Data: ");
if (LengthSent == SOCKET_ERROR)
win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, (s32)SocketHandle);
sockaddr_in SockAddress = {};
SockAddress.sin_family = AF_INET;
SockAddress.sin_port = HostToNetU16(Port);
SockAddress.sin_addr.s_addr = HostToNetU32(Address);
s32 LengthSent = sendto(Socket->Socket, Buffer, BufferLength, Flags, (sockaddr*)&SockAddress, sizeof(sockaddr_in));
Log_Message(GlobalLogBuffer, "Attempting To Send Network Data: ");
if (LengthSent == SOCKET_ERROR)
{
s32 Error = WSAGetLastError();
switch (Error)
{
s32 Error = WSAGetLastError();
switch (Error)
{
case WSAENETUNREACH:
{
Log_Message(GlobalLogBuffer,
"Non Critical Error: WSAENETUNREACH \n");
} break;
default:
{
Log_Error(GlobalLogBuffer, "Error: %d \n", Error);
InvalidCodePath;
} break;
}
case WSAENETUNREACH:
{
Log_Message(GlobalLogBuffer,
"Non Critical Error: WSAENETUNREACH \n");
} break;
default:
{
Log_Error(GlobalLogBuffer, "Error: %d \n", Error);
InvalidCodePath;
} break;
}
else
{
Log_Message(GlobalLogBuffer, "Sent\n");
}
return LengthSent;
}
else
{
Log_Message(GlobalLogBuffer, "Sent\n");
}
return LengthSent;
}
internal void
Win32Socket_SetListening(win32_socket* Socket)
{
if (listen(Socket->Socket, SOMAXCONN) == SOCKET_ERROR)
{
// TODO(pjs): Error logging
s32 Error = WSAGetLastError();
InvalidCodePath;
}
if (listen(Socket->Socket, SOMAXCONN) == SOCKET_ERROR)
{
// TODO(pjs): Error logging
s32 Error = WSAGetLastError();
InvalidCodePath;
}
}
internal s32
Win32Socket_PeekGetTotalSize(win32_socket* Socket)
{
s32 Flags = MSG_PEEK;
char Temp[4];
s32 BytesQueued = recv(Socket->Socket, Temp, 4, Flags);
if (BytesQueued == SOCKET_ERROR)
{
// TODO(pjs): Error logging
s32 Error = WSAGetLastError();
BytesQueued = 0;
}
return BytesQueued;
s32 Flags = MSG_PEEK;
char Temp[4];
s32 BytesQueued = recv(Socket->Socket, Temp, 4, Flags);
if (BytesQueued == SOCKET_ERROR)
{
// TODO(pjs): Error logging
s32 Error = WSAGetLastError();
BytesQueued = 0;
}
return BytesQueued;
}
internal gs_data
Win32Socket_Receive(win32_socket* Socket, gs_memory_arena* Storage)
{
#if 0
gs_data Result = {};
s32 BytesQueued = Win32Socket_PeekGetTotalSize(Socket);
if (BytesQueued > 0)
{
Result = PushSizeToData(Storage, BytesQueued);
s32 Flags = 0;
s32 BytesReceived = recv(Socket->Socket, (char*)Result.Memory, Result.Size, Flags);
Assert(BytesReceived == BytesQueued);
}
return Result;
#else
gs_data Result = PushSizeToData(Storage, 1024);
gs_data Result = {};
s32 BytesQueued = Win32Socket_PeekGetTotalSize(Socket);
if (BytesQueued > 0)
{
Result = PushSizeToData(Storage, BytesQueued);
s32 Flags = 0;
s32 BytesReceived = recv(Socket->Socket, (char*)Result.Memory, Result.Size, Flags);
if (BytesReceived == SOCKET_ERROR)
Assert(BytesReceived == BytesQueued);
}
return Result;
#else
gs_data Result = PushSize(Storage, 1024);
s32 Flags = 0;
s32 BytesReceived = recv(Socket->Socket, (char*)Result.Memory, Result.Size, Flags);
if (BytesReceived == SOCKET_ERROR)
{
// TODO(pjs): Error logging
s32 Error = WSAGetLastError();
switch (Error)
{
// TODO(pjs): Error logging
s32 Error = WSAGetLastError();
switch (Error)
{
case WSAECONNABORTED:
case WSANOTINITIALISED:
break;
case WSAENOTCONN:
{
}break;
InvalidDefaultCase;
}
case WSAECONNABORTED:
case WSANOTINITIALISED:
break;
case WSAENOTCONN:
{
}break;
InvalidDefaultCase;
}
Result.Size = BytesReceived;
return Result;
}
Result.Size = BytesReceived;
return Result;
#endif
}
internal void
Win32Socket_Close(win32_socket* Socket)
{
closesocket(Socket->Socket);
Socket->Socket = INVALID_SOCKET;
closesocket(Socket->Socket);
Socket->Socket = INVALID_SOCKET;
}
internal void
Win32Socket_CloseArray(win32_socket_array Array)
{
for (s32 i = 0; i < Array.Count; i++)
{
win32_socket* Socket = Array.Values + i;
Win32Socket_Close(Socket);
}
for (s32 i = 0; i < Array.Count; i++)
{
win32_socket* Socket = Array.Values + i;
Win32Socket_Close(Socket);
}
}
//////////////////////
@ -514,30 +514,30 @@ Win32Socket_CloseArray(win32_socket_array Array)
internal void
Win32SocketSystem_Init(gs_memory_arena* Arena)
{
WSAStartup(MAKEWORD(2, 2), &WSAData);
Win32Sockets = Win32SocketArray_Create(16, Arena);
WSAStartup(MAKEWORD(2, 2), &WSAData);
Win32Sockets = Win32SocketArray_Create(16, Arena);
}
internal void
Win32SocketSystem_Cleanup()
{
Win32Socket_CloseArray(Win32Sockets);
s32 CleanupResult = 0;
do {
CleanupResult = WSACleanup();
}while(CleanupResult == SOCKET_ERROR);
Win32Socket_CloseArray(Win32Sockets);
s32 CleanupResult = 0;
do {
CleanupResult = WSACleanup();
}while(CleanupResult == SOCKET_ERROR);
}
PLATFORM_GET_SOCKET_HANDLE(Win32GetSocketHandle)
{
s32 Result = Win32SocketArray_Take(&Win32Sockets);
s32 Error = 0;
win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, Result);
*Socket = Win32Socket_Create(AF_INET, SOCK_DGRAM, 0);
Error = Win32Socket_SetOption(Socket, IPPROTO_IP, IP_MULTICAST_TTL,
(const char*)(&Multicast_TimeToLive), sizeof(Multicast_TimeToLive));
return (platform_socket_handle)Result;
s32 Result = Win32SocketArray_Take(&Win32Sockets);
s32 Error = 0;
win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, Result);
*Socket = Win32Socket_Create(AF_INET, SOCK_DGRAM, 0);
Error = Win32Socket_SetOption(Socket, IPPROTO_IP, IP_MULTICAST_TTL,
(const char*)(&Multicast_TimeToLive), sizeof(Multicast_TimeToLive));
return (platform_socket_handle)Result;
}
#define WIN32_FOLDHAUS_SOCKET_H

View File

@ -7,22 +7,22 @@
struct worker_thread_entry
{
b32 IsValid;
u32 Index;
b32 IsValid;
u32 Index;
};
struct worker_thread_info
{
gs_thread_context ThreadContext;
HANDLE Handle;
gs_work_queue* Queue;
gs_thread_context ThreadContext;
HANDLE Handle;
gs_work_queue* Queue;
};
struct win32_work_queue
{
u32 ThreadCount;
worker_thread_info* Threads;
gs_work_queue WorkQueue;
u32 ThreadCount;
worker_thread_info* Threads;
gs_work_queue WorkQueue;
};
worker_thread_info* WorkerThreads;
@ -31,219 +31,219 @@ win32_work_queue Win32WorkQueue;
internal s32
Win32GetThreadId()
{
s32 Result = GetCurrentThreadId();
return Result;
s32 Result = GetCurrentThreadId();
return Result;
}
internal gs_thread_context
Win32CreateThreadContext(gs_memory_arena* Transient = 0)
{
gs_thread_context Result = {0};
Result.ThreadInfo.ThreadID = Win32GetThreadId();
Result.Allocator = CreateAllocator(Win32Alloc, Win32Free);
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.FileHandler = CreateFileHandler(Win32GetFileInfo,
Win32ReadEntireFile,
Win32WriteEntireFile,
Win32EnumerateDirectory,
Result.Transient);
Result.DebugOutput.Print = Win32DebugPrint;
return Result;
gs_thread_context Result = {0};
Result.ThreadInfo.ThreadID = Win32GetThreadId();
Result.Allocator = CreatePlatformAllocator();
if (Transient != 0)
{
Result.Transient = Transient;
}
else
{
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,
Win32WriteEntireFile,
Win32EnumerateDirectory,
Result.Transient);
Result.DebugOutput.Print = Win32DebugPrint;
return Result;
}
PUSH_WORK_ON_QUEUE(Win32PushWorkOnQueue)
{
#if DEBUG
// NOTE(Peter): Just prints out the names of all the pending jobs if we end up
// overflowing the buffer
if (Queue->JobsCount >= Queue->JobsMax)
// NOTE(Peter): Just prints out the names of all the pending jobs if we end up
// overflowing the buffer
if (Queue->JobsCount >= Queue->JobsMax)
{
gs_string DebugString = MakeString((char*)malloc(256), 256);
for (u32 i = 0; i < Queue->JobsCount; i++)
{
gs_string DebugString = MakeString((char*)malloc(256), 256);
for (u32 i = 0; i < Queue->JobsCount; i++)
{
Log_Message(GlobalLogBuffer, "%d %s \n", i, Queue->Jobs[i].JobName);
}
Log_Message(GlobalLogBuffer, "%d %s \n", i, Queue->Jobs[i].JobName);
}
}
#endif
Assert(Queue->JobsCount < Queue->JobsMax);
gs_threaded_job* Job = Queue->Jobs + Queue->JobsCount;
Job->WorkProc = WorkProc;
Job->Data = Data;
Assert(Queue->JobsCount < Queue->JobsMax);
gs_threaded_job* Job = Queue->Jobs + Queue->JobsCount;
Job->WorkProc = WorkProc;
Job->Data = Data;
#if DEBUG
Job->JobName = JobName;
Job->JobName = JobName;
#endif
// Complete Past Writes before Future Writes
_WriteBarrier();
_mm_sfence();
++Queue->JobsCount;
ReleaseSemaphore(Queue->SemaphoreHandle, 1, 0);
// Complete Past Writes before Future Writes
_WriteBarrier();
_mm_sfence();
++Queue->JobsCount;
ReleaseSemaphore(Queue->SemaphoreHandle, 1, 0);
}
internal worker_thread_entry
CompleteAndTakeNextJob(gs_work_queue* Queue, worker_thread_entry Completed, gs_thread_context Context)
{
if (Completed.IsValid)
if (Completed.IsValid)
{
InterlockedIncrement((LONG volatile*)&Queue->JobsCompleted);
}
worker_thread_entry Result = {};
Result.IsValid = false;
u32 OriginalNextJobIndex = Queue->NextJobIndex;
while (OriginalNextJobIndex < Queue->JobsCount)
{
u32 Index = InterlockedCompareExchange((LONG volatile*)&Queue->NextJobIndex,
OriginalNextJobIndex + 1,
OriginalNextJobIndex);
if (Index == OriginalNextJobIndex)
{
InterlockedIncrement((LONG volatile*)&Queue->JobsCompleted);
Result.Index = Index;
Result.IsValid = true;
break;
}
worker_thread_entry Result = {};
Result.IsValid = false;
u32 OriginalNextJobIndex = Queue->NextJobIndex;
while (OriginalNextJobIndex < Queue->JobsCount)
{
u32 Index = InterlockedCompareExchange((LONG volatile*)&Queue->NextJobIndex,
OriginalNextJobIndex + 1,
OriginalNextJobIndex);
if (Index == OriginalNextJobIndex)
{
Result.Index = Index;
Result.IsValid = true;
break;
}
OriginalNextJobIndex = Queue->NextJobIndex;
}
return Result;
OriginalNextJobIndex = Queue->NextJobIndex;
}
return Result;
}
COMPLETE_QUEUE_WORK(Win32DoQueueWorkUntilDone)
{
worker_thread_entry Entry = {};
Entry.IsValid = false;
while (Queue->JobsCompleted < Queue->JobsCount)
worker_thread_entry Entry = {};
Entry.IsValid = false;
while (Queue->JobsCompleted < Queue->JobsCount)
{
Entry = CompleteAndTakeNextJob(Queue, Entry, Context);
if (Entry.IsValid)
{
Entry = CompleteAndTakeNextJob(Queue, Entry, Context);
if (Entry.IsValid)
{
Queue->Jobs[Entry.Index].WorkProc(Context, Queue->Jobs[Entry.Index].Data);
}
Queue->Jobs[Entry.Index].WorkProc(Context, Queue->Jobs[Entry.Index].Data);
}
}
}
DWORD WINAPI
WorkerThreadProc (LPVOID InputThreadInfo)
{
worker_thread_info* ThreadInfo = (worker_thread_info*)InputThreadInfo;
ThreadInfo->ThreadContext = Win32CreateThreadContext();
worker_thread_entry Entry = {};
Entry.IsValid = false;
while (true)
worker_thread_info* ThreadInfo = (worker_thread_info*)InputThreadInfo;
ThreadInfo->ThreadContext = Win32CreateThreadContext();
worker_thread_entry Entry = {};
Entry.IsValid = false;
while (true)
{
MemoryArenaClear(ThreadInfo->ThreadContext.Transient);
Entry = CompleteAndTakeNextJob(ThreadInfo->Queue, Entry, ThreadInfo->ThreadContext);
if (Entry.IsValid)
{
ClearArena(ThreadInfo->ThreadContext.Transient);
Entry = CompleteAndTakeNextJob(ThreadInfo->Queue, Entry, ThreadInfo->ThreadContext);
if (Entry.IsValid)
{
ThreadInfo->Queue->Jobs[Entry.Index].WorkProc(ThreadInfo->ThreadContext,
ThreadInfo->Queue->Jobs[Entry.Index].Data);
}
else
{
WaitForSingleObjectEx(ThreadInfo->Queue->SemaphoreHandle, INFINITE, 0);
}
ThreadInfo->Queue->Jobs[Entry.Index].WorkProc(ThreadInfo->ThreadContext,
ThreadInfo->Queue->Jobs[Entry.Index].Data);
}
return 0;
else
{
WaitForSingleObjectEx(ThreadInfo->Queue->SemaphoreHandle, INFINITE, 0);
}
}
return 0;
}
DWORD WINAPI
Win32ThreadProcWrapper(LPVOID ThreadInfo)
{
platform_thread* Thread = (platform_thread*)ThreadInfo;
gs_thread_context Ctx = Win32CreateThreadContext();
Thread->Proc(&Ctx, Thread->UserData);
// TODO(pjs): Destroy Thread Context
// TODO(pjs): How do we notify the thread manager this thread belongs to that it is free?
// Probaby put a pointer to the thread manager in the platform_thread struct
// so we can update the tracking structure?
return 0;
platform_thread* Thread = (platform_thread*)ThreadInfo;
gs_thread_context Ctx = Win32CreateThreadContext();
Thread->Proc(&Ctx, Thread->UserData);
// TODO(pjs): Destroy Thread Context
// TODO(pjs): How do we notify the thread manager this thread belongs to that it is free?
// Probaby put a pointer to the thread manager in the platform_thread struct
// so we can update the tracking structure?
return 0;
}
CREATE_THREAD(Win32CreateThread)
{
Thread->Proc = Proc;
Thread->UserData = UserData;
// TODO(pjs): ugh, allocation out in the middle of nowhere
HANDLE* ThreadHandle = AllocatorAllocStruct(Ctx.Allocator, HANDLE);
*ThreadHandle = CreateThread(0, 0, Win32ThreadProcWrapper, (void*)Thread, 0, 0);
// TODO(pjs): Error checking on the created thread
Thread->PlatformHandle = (u8*)ThreadHandle;
return true;
Thread->Proc = Proc;
Thread->UserData = UserData;
// TODO(pjs): ugh, allocation out in the middle of nowhere
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
Thread->PlatformHandle = (u8*)ThreadHandle;
return true;
}
KILL_THREAD(Win32KillThread)
{
HANDLE* ThreadHandle = (HANDLE*)Thread->PlatformHandle;
TerminateThread(ThreadHandle, 0);
// TODO(pjs): see allocation out in the middle of nowhere in Win32CreateThread
Win32Free((void*)Thread->PlatformHandle, sizeof(HANDLE));
// TODO(pjs): Error checking
return true;
HANDLE* ThreadHandle = (HANDLE*)Thread->PlatformHandle;
TerminateThread(ThreadHandle, 0);
// TODO(pjs): see allocation out in the middle of nowhere in Win32CreateThread
Win32Free((void*)Thread->PlatformHandle, sizeof(HANDLE), 0);
// TODO(pjs): Error checking
return true;
}
internal void
Win32WorkQueue_Init(gs_memory_arena* Arena, u32 ThreadCount)
{
if (ThreadCount > 0)
{
Win32WorkQueue.ThreadCount = ThreadCount;
Win32WorkQueue.Threads = PushArray(Arena, worker_thread_info, ThreadCount);
}
gs_work_queue WQ = {};
WQ.SemaphoreHandle = CreateSemaphoreEx(0, 0, ThreadCount, 0, 0, SEMAPHORE_ALL_ACCESS);;
WQ.JobsMax = 512;
WQ.Jobs = PushArray(Arena, gs_threaded_job, WQ.JobsMax);
WQ.NextJobIndex = 0;
WQ.PushWorkOnQueue = Win32PushWorkOnQueue;
WQ.CompleteQueueWork = Win32DoQueueWorkUntilDone;
Win32WorkQueue.WorkQueue = WQ;
// ID = 0 is reserved for this thread
for (u32 i = 0; i < ThreadCount; i++)
{
worker_thread_info* T = Win32WorkQueue.Threads + i;
T->Queue = &Win32WorkQueue.WorkQueue;
T->Handle = CreateThread(0, 0, &WorkerThreadProc, (void*)T, 0, 0);
}
if (ThreadCount > 0)
{
Win32WorkQueue.ThreadCount = ThreadCount;
Win32WorkQueue.Threads = PushArray(Arena, worker_thread_info, ThreadCount);
}
gs_work_queue WQ = {};
WQ.SemaphoreHandle = CreateSemaphoreEx(0, 0, ThreadCount, 0, 0, SEMAPHORE_ALL_ACCESS);;
WQ.JobsMax = 512;
WQ.Jobs = PushArray(Arena, gs_threaded_job, WQ.JobsMax);
WQ.NextJobIndex = 0;
WQ.PushWorkOnQueue = Win32PushWorkOnQueue;
WQ.CompleteQueueWork = Win32DoQueueWorkUntilDone;
Win32WorkQueue.WorkQueue = WQ;
// ID = 0 is reserved for this thread
for (u32 i = 0; i < ThreadCount; i++)
{
worker_thread_info* T = Win32WorkQueue.Threads + i;
T->Queue = &Win32WorkQueue.WorkQueue;
T->Handle = CreateThread(0, 0, &WorkerThreadProc, (void*)T, 0, 0);
}
}
internal void
Win32WorkQueue_Cleanup()
{
u32 Error = 0;
for (u32 Thread = 0; Thread < Win32WorkQueue.ThreadCount; Thread++)
u32 Error = 0;
for (u32 Thread = 0; Thread < Win32WorkQueue.ThreadCount; Thread++)
{
u32 Success = TerminateThread(Win32WorkQueue.Threads[Thread].Handle, 0);
if (!Success)
{
u32 Success = TerminateThread(Win32WorkQueue.Threads[Thread].Handle, 0);
if (!Success)
{
Error = GetLastError();
InvalidCodePath;
}
Error = GetLastError();
InvalidCodePath;
}
}
}
#define WIN32_FOLDHAUS_WORK_QUEUE_H

File diff suppressed because it is too large Load Diff

View File

@ -2,79 +2,82 @@
internal void
MessageQueue_Init(blumen_network_msg_queue* Queue, gs_memory_arena* Arena)
{
for (u32 i = 0; i < BLUMEN_MESSAGE_QUEUE_COUNT; i++)
{
Queue->Buffers[i] = PushSizeToData(Arena, DEFAULT_QUEUE_ENTRY_SIZE);
}
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] = MemoryCursorPushSize(&C, DEFAULT_QUEUE_ENTRY_SIZE);
}
}
internal bool
MessageQueue_CanWrite(blumen_network_msg_queue Queue)
{
bool Result = ((Queue.WriteHead >= Queue.ReadHead) ||
(Queue.WriteHead < Queue.ReadHead));
return Result;
bool Result = ((Queue.WriteHead >= Queue.ReadHead) ||
(Queue.WriteHead < Queue.ReadHead));
return Result;
}
internal bool
MessageQueue_Write(blumen_network_msg_queue* Queue, gs_data Msg)
{
Assert(Msg.Size <= DEFAULT_QUEUE_ENTRY_SIZE);
u32 Index = Queue->WriteHead;
Assert(Index >= 0 &&
Index < BLUMEN_MESSAGE_QUEUE_COUNT);
gs_data* Dest = Queue->Buffers + Index;
CopyMemoryTo(Msg.Memory, Dest->Memory, Msg.Size);
Dest->Size = Msg.Size;
// NOTE(pjs): We increment write head at the end of writing so that
// a reader thread doesn't pull the message off before we've finished
// filling it out
Queue->WriteHead = (Queue->WriteHead + 1) % BLUMEN_MESSAGE_QUEUE_COUNT;
return true;
Assert(Msg.Size <= DEFAULT_QUEUE_ENTRY_SIZE);
u32 Index = Queue->WriteHead;
Assert(Index >= 0 &&
Index < BLUMEN_MESSAGE_QUEUE_COUNT);
gs_data* Dest = Queue->Buffers + Index;
CopyMemoryTo(Msg.Memory, Dest->Memory, Msg.Size);
Dest->Size = Msg.Size;
// NOTE(pjs): We increment write head at the end of writing so that
// a reader thread doesn't pull the message off before we've finished
// filling it out
Queue->WriteHead = (Queue->WriteHead + 1) % BLUMEN_MESSAGE_QUEUE_COUNT;
return true;
}
internal bool
MessageQueue_CanRead(blumen_network_msg_queue Queue)
{
bool Result = (Queue.ReadHead != Queue.WriteHead);
return Result;
bool Result = (Queue.ReadHead != Queue.WriteHead);
return Result;
}
internal gs_data
MessageQueue_Peek(blumen_network_msg_queue* Queue)
{
gs_data Result = {};
u32 ReadIndex = Queue->ReadHead;
if (ReadIndex >= BLUMEN_MESSAGE_QUEUE_COUNT)
{
ReadIndex = 0;
}
Result = Queue->Buffers[ReadIndex];
return Result;
gs_data Result = {};
u32 ReadIndex = Queue->ReadHead;
if (ReadIndex >= BLUMEN_MESSAGE_QUEUE_COUNT)
{
ReadIndex = 0;
}
Result = Queue->Buffers[ReadIndex];
return Result;
}
internal gs_data
MessageQueue_Read(blumen_network_msg_queue* Queue)
{
gs_data Result = {};
u32 ReadIndex = Queue->ReadHead++;
if (ReadIndex >= BLUMEN_MESSAGE_QUEUE_COUNT)
{
Queue->ReadHead = 0;
ReadIndex = 0;
}
Result = Queue->Buffers[ReadIndex];
return Result;
gs_data Result = {};
u32 ReadIndex = Queue->ReadHead++;
if (ReadIndex >= BLUMEN_MESSAGE_QUEUE_COUNT)
{
Queue->ReadHead = 0;
ReadIndex = 0;
}
Result = Queue->Buffers[ReadIndex];
return Result;
}
internal void
MessageQueue_Clear(blumen_network_msg_queue* Queue)
{
while (MessageQueue_CanRead(*Queue))
{
MessageQueue_Read(Queue);
}
while (MessageQueue_CanRead(*Queue))
{
MessageQueue_Read(Queue);
}
}

File diff suppressed because it is too large Load Diff

528
src/gs_libs/gs_memory.h Normal file
View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -22,141 +22,141 @@ global log_buffer* GlobalLogBuffer;
typedef struct
{
v3 CenterStart;
v3 CenterEnd;
r32 Radius;
u32 SegmentsCount;
u32 SubsegmentsCount;
u32 SubsegmentLeds;
// Only one of these two values is needed.
// If ChannelsArray != 0, then it will be used, and assumed to
// have SegmentsCount values
// Otherwise, each segment will increment from ChannelStart
u32 ChannelStart;
u32* ChannelsArray;
char* ComPort;
char* SectionTagValue;
char* FlowerTagValue;
v3 CenterStart;
v3 CenterEnd;
r32 Radius;
u32 SegmentsCount;
u32 SubsegmentsCount;
u32 SubsegmentLeds;
// Only one of these two values is needed.
// If ChannelsArray != 0, then it will be used, and assumed to
// have SegmentsCount values
// Otherwise, each segment will increment from ChannelStart
u32 ChannelStart;
u32* ChannelsArray;
char* ComPort;
char* SectionTagValue;
char* FlowerTagValue;
} loop_desc;
internal void
BuildLoop(gs_string* OutputBuffer, loop_desc Desc)
{
r32 SegmentsArc = TauR32 / Desc.SegmentsCount;
r32 SubsegmentsArc = SegmentsArc / Desc.SubsegmentsCount;
r32 SegmentsArc = TauR32 / Desc.SegmentsCount;
r32 SubsegmentsArc = SegmentsArc / Desc.SubsegmentsCount;
for (u32 i = 0; i < Desc.SegmentsCount; i++)
{
r32 ArcBase = SegmentsArc * i;
for (u32 i = 0; i < Desc.SegmentsCount; i++)
u32 Channel = 0;
if (Desc.ChannelsArray != 0)
{
r32 ArcBase = SegmentsArc * i;
u32 Channel = 0;
if (Desc.ChannelsArray != 0)
{
Channel = Desc.ChannelsArray[i];
}
else
{
Channel = Desc.ChannelStart + i;
}
WriteLedStripOpen(OutputBuffer, Channel, Desc.ComPort);
WriteSegmentSequenceOpen(OutputBuffer, Desc.SubsegmentsCount);
for (u32 j = 0; j < Desc.SubsegmentsCount; j++)
{
r32 Arc = ArcBase + (SubsegmentsArc * j);
v3 Offset = v3{ SinR32(Arc), 0, CosR32(Arc) } * Desc.Radius;
v3 P0 = Desc.CenterStart + Offset;
v3 P1 = Desc.CenterEnd + Offset;
// Swap directions on the middle strip
if (j%2 != 0)
{
v3 Temp = P0;
P0 = P1;
P1 = Temp;
}
WriteSegmentSequenceSegment(OutputBuffer, P0, P1, Desc.SubsegmentLeds);
}
WriteSegmentSequenceClose(OutputBuffer);
WriteSegmentTagsOpen(OutputBuffer, 2);
WriteSegmentTag(OutputBuffer, "section", Desc.SectionTagValue);
WriteSegmentTag(OutputBuffer, "flower", Desc.FlowerTagValue);
WriteSegmentTagsClose(OutputBuffer);
WriteLedStripClose(OutputBuffer);
Channel = Desc.ChannelsArray[i];
}
else
{
Channel = Desc.ChannelStart + i;
}
WriteLedStripOpen(OutputBuffer, Channel, Desc.ComPort);
WriteSegmentSequenceOpen(OutputBuffer, Desc.SubsegmentsCount);
for (u32 j = 0; j < Desc.SubsegmentsCount; j++)
{
r32 Arc = ArcBase + (SubsegmentsArc * j);
v3 Offset = v3{ SinR32(Arc), 0, CosR32(Arc) } * Desc.Radius;
v3 P0 = Desc.CenterStart + Offset;
v3 P1 = Desc.CenterEnd + Offset;
// Swap directions on the middle strip
if (j%2 != 0)
{
v3 Temp = P0;
P0 = P1;
P1 = Temp;
}
WriteSegmentSequenceSegment(OutputBuffer, P0, P1, Desc.SubsegmentLeds);
}
WriteSegmentSequenceClose(OutputBuffer);
WriteSegmentTagsOpen(OutputBuffer, 2);
WriteSegmentTag(OutputBuffer, "section", Desc.SectionTagValue);
WriteSegmentTag(OutputBuffer, "flower", Desc.FlowerTagValue);
WriteSegmentTagsClose(OutputBuffer);
WriteLedStripClose(OutputBuffer);
}
}
typedef struct
{
v3 Pos;
char* ComPort;
char* FlowerTagValue;
u32* StemChannels;
u32* BloomOuterChannels;
u32* BloomInnerChannels;
v3 Pos;
char* ComPort;
char* FlowerTagValue;
u32* StemChannels;
u32* BloomOuterChannels;
u32* BloomInnerChannels;
} flower_desc;
internal u32
BuildFlower(gs_string* OutputBuffer, flower_desc Desc)
{
#if 1
// the bloom stem inner
loop_desc BloomStemInner = {};
BloomStemInner.CenterStart = v3{0, 1.4f, 0};
BloomStemInner.CenterEnd = v3{0, .9f, 0};
BloomStemInner.Radius = .05f;
BloomStemInner.SegmentsCount = 6;
BloomStemInner.SubsegmentsCount = 3;
BloomStemInner.SubsegmentLeds = 35;
BloomStemInner.ChannelsArray = Desc.BloomInnerChannels;
BloomStemInner.ComPort = Desc.ComPort;
BloomStemInner.SectionTagValue = "inner_bloom";
BloomStemInner.FlowerTagValue = Desc.FlowerTagValue;
BuildLoop(OutputBuffer, BloomStemInner);
// the bloom stem outer
loop_desc BloomStemOuter = {};
BloomStemOuter.CenterStart = v3{0, .5f, 0};
BloomStemOuter.CenterEnd = v3{0, .9f, 0};
BloomStemOuter.Radius = .07f;
BloomStemOuter.SegmentsCount = 9;
BloomStemOuter.SubsegmentsCount = 3;
BloomStemOuter.SubsegmentLeds = 41;
BloomStemOuter.ChannelsArray = Desc.BloomOuterChannels;
BloomStemOuter.ComPort = Desc.ComPort;
BloomStemOuter.SectionTagValue = "outer_bloom";
BloomStemOuter.FlowerTagValue = Desc.FlowerTagValue;
BuildLoop(OutputBuffer, BloomStemOuter);
// the bloom stem inner
loop_desc BloomStemInner = {};
BloomStemInner.CenterStart = v3{0, 1.4f, 0};
BloomStemInner.CenterEnd = v3{0, .9f, 0};
BloomStemInner.Radius = .05f;
BloomStemInner.SegmentsCount = 6;
BloomStemInner.SubsegmentsCount = 3;
BloomStemInner.SubsegmentLeds = 35;
BloomStemInner.ChannelsArray = Desc.BloomInnerChannels;
BloomStemInner.ComPort = Desc.ComPort;
BloomStemInner.SectionTagValue = "inner_bloom";
BloomStemInner.FlowerTagValue = Desc.FlowerTagValue;
BuildLoop(OutputBuffer, BloomStemInner);
// the bloom stem outer
loop_desc BloomStemOuter = {};
BloomStemOuter.CenterStart = v3{0, .5f, 0};
BloomStemOuter.CenterEnd = v3{0, .9f, 0};
BloomStemOuter.Radius = .07f;
BloomStemOuter.SegmentsCount = 9;
BloomStemOuter.SubsegmentsCount = 3;
BloomStemOuter.SubsegmentLeds = 41;
BloomStemOuter.ChannelsArray = Desc.BloomOuterChannels;
BloomStemOuter.ComPort = Desc.ComPort;
BloomStemOuter.SectionTagValue = "outer_bloom";
BloomStemOuter.FlowerTagValue = Desc.FlowerTagValue;
BuildLoop(OutputBuffer, BloomStemOuter);
#endif
#if 1
// the flower stem
loop_desc FlowerStem = {};
FlowerStem.CenterStart = v3{0, -1.5f, 0};
FlowerStem.CenterEnd = v3{0, .5f, 0};
FlowerStem.Radius = .05f;
FlowerStem.SegmentsCount = 6;
FlowerStem.SubsegmentsCount = 1;
FlowerStem.SubsegmentLeds = 300;
FlowerStem.ChannelsArray = Desc.StemChannels;
FlowerStem.ComPort = Desc.ComPort;
FlowerStem.SectionTagValue = "stem";
FlowerStem.FlowerTagValue = Desc.FlowerTagValue;
BuildLoop(OutputBuffer, FlowerStem);
// the flower stem
loop_desc FlowerStem = {};
FlowerStem.CenterStart = v3{0, -1.5f, 0};
FlowerStem.CenterEnd = v3{0, .5f, 0};
FlowerStem.Radius = .05f;
FlowerStem.SegmentsCount = 6;
FlowerStem.SubsegmentsCount = 1;
FlowerStem.SubsegmentLeds = 300;
FlowerStem.ChannelsArray = Desc.StemChannels;
FlowerStem.ComPort = Desc.ComPort;
FlowerStem.SectionTagValue = "stem";
FlowerStem.FlowerTagValue = Desc.FlowerTagValue;
BuildLoop(OutputBuffer, FlowerStem);
#endif
u32 StripsCount = BloomStemInner.SegmentsCount;
StripsCount += BloomStemOuter.SegmentsCount;
StripsCount += FlowerStem.SegmentsCount;
return StripsCount;
u32 StripsCount = BloomStemInner.SegmentsCount;
StripsCount += BloomStemOuter.SegmentsCount;
StripsCount += FlowerStem.SegmentsCount;
return StripsCount;
}
// Just for brevity, no real function provided
@ -164,88 +164,88 @@ BuildFlower(gs_string* OutputBuffer, flower_desc Desc)
internal u8
FlowerStripToChannel(u8 Flower, u8 Channel)
{
Assert(Flower < 3);
Assert(Channel < 8);
u8 Result = 0;
Result |= (Flower & 0x03) << 3;
Result |= (Channel & 0x07);
return Result;
Assert(Flower < 3);
Assert(Channel < 8);
u8 Result = 0;
Result |= (Flower & 0x03) << 3;
Result |= (Channel & 0x07);
return Result;
}
int main(int ArgCount, char** Args)
{
gs_thread_context Ctx = Win32CreateThreadContext();
GlobalLogBuffer = AllocatorAllocStruct(Ctx.Allocator, log_buffer);
*GlobalLogBuffer = Log_Init(Ctx.Allocator, 32);
gs_string OutputBuffer0 = PushString(Ctx.Transient, MB(4));
gs_string OutputBuffer1 = PushString(Ctx.Transient, MB(4));
gs_string OutputBuffer2 = PushString(Ctx.Transient, MB(4));
WriteAssemblyUARTOpen(&OutputBuffer0,
"Blumen Lumen - Silver Spring - 00",
100,
v3{-1, 0, 0},
21,
"");
WriteAssemblyUARTOpen(&OutputBuffer1,
"Blumen Lumen - Silver Spring - 01",
100,
v3{0, 0, 0},
21,
"");
WriteAssemblyUARTOpen(&OutputBuffer2,
"Blumen Lumen - Silver Spring - 02",
100,
v3{1, 0, 0},
21,
"");
u32 StripCount = 0;
u32 StemChannels[] = { FSC(2, 1), FSC(2, 2), FSC(2, 3), FSC(2, 4), FSC(2, 5), FSC(2, 6) };
u32 BloomOuterChannels[] = { FSC(1, 0), FSC(1, 1), FSC(1, 2), FSC(1, 3), FSC(1, 4), FSC(1, 5), FSC(1, 6), FSC(1, 7), FSC(2, 0) };
u32 BloomInnerChannels[] = { FSC(0, 0), FSC(0, 1), FSC(0, 2), FSC(0, 3), FSC(0, 4), FSC(0, 5) };
flower_desc F0 = {};
F0.Pos = v3{0, 0, 0};
F0.ComPort = "\\\\.\\COM11";
F0.FlowerTagValue = "left";
F0.StemChannels = StemChannels;
F0.BloomOuterChannels = BloomOuterChannels;
F0.BloomInnerChannels = BloomInnerChannels;
StripCount += BuildFlower(&OutputBuffer0, F0);
flower_desc F1 = {};
F1.Pos = v3{0, 0, 0};
F1.ComPort = "\\\\.\\COM12";
F1.FlowerTagValue = "center";
F1.StemChannels = StemChannels;
F1.BloomInnerChannels = BloomInnerChannels;
F1.BloomOuterChannels = BloomOuterChannels;
StripCount += BuildFlower(&OutputBuffer1, F1);
flower_desc F2 = {};
F2.Pos = v3{0, 0, 0};
F2.ComPort = "\\\\.\\COM6";
F2.FlowerTagValue = "right";
F2.StemChannels = StemChannels;
F2.BloomInnerChannels = BloomInnerChannels;
F2.BloomOuterChannels = BloomOuterChannels;
StripCount += BuildFlower(&OutputBuffer2, F2);
WriteEntireFile(Ctx.FileHandler, ConstString("data/ss_blumen_one.fold"), StringToData(OutputBuffer0));
WriteEntireFile(Ctx.FileHandler, ConstString("data/ss_blumen_two.fold"), StringToData(OutputBuffer1));
WriteEntireFile(Ctx.FileHandler, ConstString("data/ss_blumen_three.fold"), StringToData(OutputBuffer2));
//printf("%.*s\n", (u32)OutputBuffer.Length, OutputBuffer.Str);
//printf("%d\n", StripCount);
return 0;
gs_thread_context Ctx = Win32CreateThreadContext();
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));
gs_string OutputBuffer2 = PushString(Ctx.Transient, MB(4));
WriteAssemblyUARTOpen(&OutputBuffer0,
"Blumen Lumen - Silver Spring - 00",
100,
v3{-1, 0, 0},
21,
"");
WriteAssemblyUARTOpen(&OutputBuffer1,
"Blumen Lumen - Silver Spring - 01",
100,
v3{0, 0, 0},
21,
"");
WriteAssemblyUARTOpen(&OutputBuffer2,
"Blumen Lumen - Silver Spring - 02",
100,
v3{1, 0, 0},
21,
"");
u32 StripCount = 0;
u32 StemChannels[] = { FSC(2, 1), FSC(2, 2), FSC(2, 3), FSC(2, 4), FSC(2, 5), FSC(2, 6) };
u32 BloomOuterChannels[] = { FSC(1, 0), FSC(1, 1), FSC(1, 2), FSC(1, 3), FSC(1, 4), FSC(1, 5), FSC(1, 6), FSC(1, 7), FSC(2, 0) };
u32 BloomInnerChannels[] = { FSC(0, 0), FSC(0, 1), FSC(0, 2), FSC(0, 3), FSC(0, 4), FSC(0, 5) };
flower_desc F0 = {};
F0.Pos = v3{0, 0, 0};
F0.ComPort = "\\\\.\\COM11";
F0.FlowerTagValue = "left";
F0.StemChannels = StemChannels;
F0.BloomOuterChannels = BloomOuterChannels;
F0.BloomInnerChannels = BloomInnerChannels;
StripCount += BuildFlower(&OutputBuffer0, F0);
flower_desc F1 = {};
F1.Pos = v3{0, 0, 0};
F1.ComPort = "\\\\.\\COM12";
F1.FlowerTagValue = "center";
F1.StemChannels = StemChannels;
F1.BloomInnerChannels = BloomInnerChannels;
F1.BloomOuterChannels = BloomOuterChannels;
StripCount += BuildFlower(&OutputBuffer1, F1);
flower_desc F2 = {};
F2.Pos = v3{0, 0, 0};
F2.ComPort = "\\\\.\\COM6";
F2.FlowerTagValue = "right";
F2.StemChannels = StemChannels;
F2.BloomInnerChannels = BloomInnerChannels;
F2.BloomOuterChannels = BloomOuterChannels;
StripCount += BuildFlower(&OutputBuffer2, F2);
WriteEntireFile(Ctx.FileHandler, ConstString("data/ss_blumen_one.fold"), StringToData(OutputBuffer0));
WriteEntireFile(Ctx.FileHandler, ConstString("data/ss_blumen_two.fold"), StringToData(OutputBuffer1));
WriteEntireFile(Ctx.FileHandler, ConstString("data/ss_blumen_three.fold"), StringToData(OutputBuffer2));
//printf("%.*s\n", (u32)OutputBuffer.Length, OutputBuffer.Str);
//printf("%d\n", StripCount);
return 0;
}

View File

@ -30,195 +30,195 @@ global log_buffer* GlobalLogBuffer;
u8*
FindNextHeader(gs_data Data, u8* StartAt)
{
u8* At = StartAt;
while (!(At[0] == 'U' &&
At[1] == 'P' &&
At[2] == 'X' &&
At[3] == 'L') &&
(u32)(At - Data.Memory) < Data.Size)
{
At++;
}
return At;
u8* At = StartAt;
while (!(At[0] == 'U' &&
At[1] == 'P' &&
At[2] == 'X' &&
At[3] == 'L') &&
(u32)(At - Data.Memory) < Data.Size)
{
At++;
}
return At;
}
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,
16, 17, 18, 19, 20, 21, 22, 23,
//40, 41, 42, 43, 44, 45, 46, 47,
};
u8* FirstHeaderAddr = 0;
for (u32 j = 0; j < sizeof(Channels) / sizeof(u32); j++)
{
u32 ChannelIndex = Channels[j];
uart_header* Header = MemoryCursorPushStruct(&WriteCursor, uart_header);
UART_FillHeader(Header, ChannelIndex, UART_SET_CHANNEL_WS2812);
u32 Channels[] = {
0, 1, 2, 3, 4, 5, 6, 7,
16, 17, 18, 19, 20, 21, 22, 23,
//40, 41, 42, 43, 44, 45, 46, 47,
};
u8* FirstHeaderAddr = 0;
for (u32 j = 0; j < sizeof(Channels) / sizeof(u32); j++)
if (FirstHeaderAddr == 0)
{
u32 ChannelIndex = Channels[j];
uart_header* Header = PushStructOnCursor(&WriteCursor, uart_header);
UART_FillHeader(Header, ChannelIndex, UART_SET_CHANNEL_WS2812);
if (FirstHeaderAddr == 0)
{
FirstHeaderAddr = (u8*)Header;
}
uart_channel* Channel = PushStructOnCursor(&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);
Pixel[0] = Count;
Pixel[1] = 0;
Pixel[2] = 255 - Count;
}
uart_footer* Footer = PushStructOnCursor(&WriteCursor, uart_footer);
Footer->CRC = UART_CalculateCRC((u8*)Header, (u8*)(Footer));
FirstHeaderAddr = (u8*)Header;
}
uart_header* DrawAllHeader = PushStructOnCursor(&WriteCursor, uart_header);
UART_FillHeader(DrawAllHeader, 255, UART_DRAW_ALL);
uart_footer* DrawAllFooter =
PushStructOnCursor(&WriteCursor, uart_footer);
DrawAllFooter->CRC = UART_CalculateCRC((u8*)DrawAllHeader, (u8*)(DrawAllFooter));
uart_channel* Channel = MemoryCursorPushStruct(&WriteCursor, uart_channel);
Channel->ElementsCount = 3;
Channel->ColorPackingOrder = 36; // 10010000
Channel->PixelsCount = 300;
Data->Size = ((u8*)DrawAllFooter - (u8*)FirstHeaderAddr) + sizeof(uart_footer);
for (u32 i = 0; i < Channel->PixelsCount; i++)
{
u8* Pixel = MemoryCursorPushArray(&WriteCursor, u8, 3);
Pixel[0] = Count;
Pixel[1] = 0;
Pixel[2] = 255 - Count;
}
uart_footer* Footer = MemoryCursorPushStruct(&WriteCursor, uart_footer);
Footer->CRC = UART_CalculateCRC((u8*)Header, (u8*)(Footer));
}
uart_header* DrawAllHeader = MemoryCursorPushStruct(&WriteCursor, uart_header);
UART_FillHeader(DrawAllHeader, 255, UART_DRAW_ALL);
uart_footer* DrawAllFooter =
MemoryCursorPushStruct(&WriteCursor, uart_footer);
DrawAllFooter->CRC = UART_CalculateCRC((u8*)DrawAllHeader, (u8*)(DrawAllFooter));
Data->Size = ((u8*)DrawAllFooter - (u8*)FirstHeaderAddr) + sizeof(uart_footer);
}
int main(int ArgCount, char** Args)
{
gs_thread_context Ctx = Win32CreateThreadContext();
GlobalLogBuffer = AllocatorAllocStruct(Ctx.Allocator, log_buffer);
*GlobalLogBuffer = Log_Init(Ctx.Allocator, 32);
gs_thread_context Ctx = Win32CreateThreadContext();
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);
gs_const_string OutFileName = ConstString("./serial_dump.data");
if (false)
{
Win32SerialPort_SetRead(SerialHandle);
HANDLE SerialHandle = Win32SerialPort_Open("\\\\.\\COM9", Ctx.Transient);
Win32SerialPort_SetState(SerialHandle, 2000000, 8, 0, 1);
gs_data Data = PushSize(Ctx.Transient, KB(32));
gs_const_string OutFileName = ConstString("./serial_dump.data");
Win32SerialPort_SetRead(SerialHandle);
u32 ReadSize = Win32SerialPort_ReadMessageWhenReady(SerialHandle, Data);
if (false)
u8* SetChannelHeaderAddr = 0;
uart_header* SetChannelHeader = 0;
uart_header* DrawAllHeader = 0;
u8* ScanAt = Data.Memory;
do
{
Win32SerialPort_SetRead(SerialHandle);
gs_data Data = PushSizeToData(Ctx.Transient, KB(32));
Win32SerialPort_SetRead(SerialHandle);
u32 ReadSize = Win32SerialPort_ReadMessageWhenReady(SerialHandle, Data);
u8* SetChannelHeaderAddr = 0;
uart_header* SetChannelHeader = 0;
uart_header* DrawAllHeader = 0;
u8* ScanAt = Data.Memory;
do
ScanAt = FindNextHeader(Data, ScanAt);
uart_header* Header = (uart_header*)ScanAt;
if (Header->RecordType == UART_SET_CHANNEL_WS2812)
{
printf("Set Channel:\n");
printf(" Channel: %d\n", Header->Channel);
printf(" Pixels: %d\n", ((uart_channel*)(Header + 1))->PixelsCount);
if (!SetChannelHeader)
{
ScanAt = FindNextHeader(Data, ScanAt);
uart_header* Header = (uart_header*)ScanAt;
if (Header->RecordType == UART_SET_CHANNEL_WS2812)
{
printf("Set Channel:\n");
printf(" Channel: %d\n", Header->Channel);
printf(" Pixels: %d\n", ((uart_channel*)(Header + 1))->PixelsCount);
if (!SetChannelHeader)
{
SetChannelHeaderAddr = (u8*)Header;
SetChannelHeader = Header;
}
}
if (Header->RecordType == UART_DRAW_ALL)
{
printf("Draw All:\n");
printf(" Channel: %d\n", Header->Channel);
if (!DrawAllHeader)
{
DrawAllHeader= Header;
}
}
ScanAt += sizeof(uart_header);
}while(((u32)(ScanAt - Data.Memory + sizeof(uart_header)) < Data.Size));
uart_channel* Channel = (uart_channel*)(SetChannelHeader + 1);
u8* DataStart = (u8*)(Channel + 1);
uart_footer* Footer = (uart_footer*)(DataStart + (Channel->ElementsCount * Channel->PixelsCount));
u32 TestCRC = UART_CalculateCRC((u8*)SetChannelHeader, (u8*)(Footer));
uart_footer* DrawAllFooter = (uart_footer*)(DrawAllHeader + 1);
u32 DrawwAllCRC = UART_CalculateCRC((u8*)DrawAllHeader, (u8*)(DrawAllFooter));
HANDLE FileHandle = CreateFileA(OutFileName.Str, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (FileHandle != INVALID_HANDLE_VALUE)
{
DWORD BytesWritten = 0;
if (!WriteFile(FileHandle, Data.Memory, Data.Size, &BytesWritten, NULL))
{
InvalidCodePath;
}
SetChannelHeaderAddr = (u8*)Header;
SetChannelHeader = Header;
}
CloseHandle(FileHandle);
Win32SerialPort_Close(SerialHandle);
}
else if (true)
{
gs_data Data = PushSizeToData(Ctx.Transient, KB(32));
u8 Count = 0;
while(true)
}
if (Header->RecordType == UART_DRAW_ALL)
{
printf("Draw All:\n");
printf(" Channel: %d\n", Header->Channel);
if (!DrawAllHeader)
{
CreateMessage(&Data, ++Count);
Win32SerialPort_Write(SerialHandle, Data);
Sleep(100);
DrawAllHeader= Header;
}
}
else if (false)
{
gs_data Data = PushSizeToData(Ctx.Transient, KB(32));
gs_file File = Win32ReadEntireFile(Ctx.FileHandler, OutFileName, Data);
gs_data Messages = {0};
u8* ScanAt = Data.Memory;
ScanAt = FindNextHeader(Data, ScanAt);
uart_header* FirstHeader = (uart_header*)ScanAt;
ScanAt += sizeof(uart_header);
uart_header* LastHeader = 0;
do
{
ScanAt = FindNextHeader(Data, ScanAt);
uart_header* Header = (uart_header*)ScanAt;
if (Header->RecordType == UART_DRAW_ALL)
{
LastHeader = Header;
}
ScanAt += sizeof(uart_header);
}while((u32)(ScanAt - Data.Memory) < Data.Size);
u8* OnePastLastByte = ((u8*)(LastHeader + 1)) + sizeof(uart_footer);
Messages.Memory = (u8*)FirstHeader;
Messages.Size = OnePastLastByte - Messages.Memory;
while (true)
{
Win32SerialPort_Write(SerialHandle, Messages);
Sleep(100);
}
}
}
ScanAt += sizeof(uart_header);
}while(((u32)(ScanAt - Data.Memory + sizeof(uart_header)) < Data.Size));
return 0;
uart_channel* Channel = (uart_channel*)(SetChannelHeader + 1);
u8* DataStart = (u8*)(Channel + 1);
uart_footer* Footer = (uart_footer*)(DataStart + (Channel->ElementsCount * Channel->PixelsCount));
u32 TestCRC = UART_CalculateCRC((u8*)SetChannelHeader, (u8*)(Footer));
uart_footer* DrawAllFooter = (uart_footer*)(DrawAllHeader + 1);
u32 DrawwAllCRC = UART_CalculateCRC((u8*)DrawAllHeader, (u8*)(DrawAllFooter));
HANDLE FileHandle = CreateFileA(OutFileName.Str, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (FileHandle != INVALID_HANDLE_VALUE)
{
DWORD BytesWritten = 0;
if (!WriteFile(FileHandle, Data.Memory, Data.Size, &BytesWritten, NULL))
{
InvalidCodePath;
}
}
CloseHandle(FileHandle);
Win32SerialPort_Close(SerialHandle);
}
else if (true)
{
gs_data Data = PushSize(Ctx.Transient, KB(32));
u8 Count = 0;
while(true)
{
CreateMessage(&Data, ++Count);
Win32SerialPort_Write(SerialHandle, Data);
Sleep(100);
}
}
else if (false)
{
gs_data Data = PushSize(Ctx.Transient, KB(32));
gs_file File = Win32ReadEntireFile(Ctx.FileHandler, OutFileName, Data);
gs_data Messages = {0};
u8* ScanAt = Data.Memory;
ScanAt = FindNextHeader(Data, ScanAt);
uart_header* FirstHeader = (uart_header*)ScanAt;
ScanAt += sizeof(uart_header);
uart_header* LastHeader = 0;
do
{
ScanAt = FindNextHeader(Data, ScanAt);
uart_header* Header = (uart_header*)ScanAt;
if (Header->RecordType == UART_DRAW_ALL)
{
LastHeader = Header;
}
ScanAt += sizeof(uart_header);
}while((u32)(ScanAt - Data.Memory) < Data.Size);
u8* OnePastLastByte = ((u8*)(LastHeader + 1)) + sizeof(uart_footer);
Messages.Memory = (u8*)FirstHeader;
Messages.Size = OnePastLastByte - Messages.Memory;
while (true)
{
Win32SerialPort_Write(SerialHandle, Messages);
Sleep(100);
}
}
return 0;
}

View File

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

View File

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