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

File diff suppressed because it is too large Load Diff

View File

@ -7,42 +7,42 @@
enum file_view_mode enum file_view_mode
{ {
FileViewMode_Load, FileViewMode_Load,
FileViewMode_Save, FileViewMode_Save,
}; };
struct file_view_state struct file_view_state
{ {
file_view_mode Mode; file_view_mode Mode;
gs_string WorkingDirectory; gs_string WorkingDirectory;
gs_string DisplayDirectory; gs_string DisplayDirectory;
gs_memory_arena FileNamesArena; gs_memory_arena FileNamesArena;
gs_file_info_array FileNames; gs_file_info_array FileNames;
gs_file_info SelectedFile; gs_file_info SelectedFile;
}; };
internal void internal void
FileView_SetMode(panel* Panel, file_view_mode Mode) FileView_SetMode(panel* Panel, file_view_mode Mode)
{ {
file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state); file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state);
FileViewState->Mode = Mode; FileViewState->Mode = Mode;
} }
internal void internal void
FileView_Exit_(panel* FileViewPanel, app_state* State, context Context) FileView_Exit_(panel* FileViewPanel, app_state* State, context Context)
{ {
// TODO(pjs): Free State->FileNamesArena // TODO(pjs): Free State->FileNamesArena
Assert(FileViewPanel->IsModalOverrideFor != 0); Assert(FileViewPanel->IsModalOverrideFor != 0);
panel* ReturnTo = FileViewPanel->IsModalOverrideFor; panel* ReturnTo = FileViewPanel->IsModalOverrideFor;
if (ReturnTo->ModalOverrideCB) if (ReturnTo->ModalOverrideCB)
{ {
ReturnTo->ModalOverrideCB(FileViewPanel, State, Context); ReturnTo->ModalOverrideCB(FileViewPanel, State, Context);
} }
Panel_PopModalOverride(ReturnTo, &State->PanelSystem); Panel_PopModalOverride(ReturnTo, &State->PanelSystem);
} }
global input_command* FileView_Commands = 0; global input_command* FileView_Commands = 0;
@ -51,35 +51,35 @@ s32 FileView_CommandsCount = 0;
internal void internal void
FileView_UpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_state* State, context Context) 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 // NOTE(pjs): make sure we're only passing valid directory paths to the
// function // function
char LastChar = WorkingDirectory.Str[WorkingDirectory.Length - 1]; char LastChar = WorkingDirectory.Str[WorkingDirectory.Length - 1];
Assert(LastChar == '\\' || LastChar == '/'); Assert(LastChar == '\\' || LastChar == '/');
ClearArena(&State->FileNamesArena); MemoryArenaClear(&State->FileNamesArena);
gs_string SanitizedDir = PushString(Context.ThreadContext.Transient, WorkingDirectory.Length + 2); gs_string SanitizedDir = PushString(Context.ThreadContext.Transient, WorkingDirectory.Length + 2);
SanitizePath(WorkingDirectory, &SanitizedDir, Context.ThreadContext.Transient); SanitizePath(WorkingDirectory, &SanitizedDir, Context.ThreadContext.Transient);
if (SanitizedDir.Str[SanitizedDir.Length - 1] != '\\') if (SanitizedDir.Str[SanitizedDir.Length - 1] != '\\')
{ {
AppendPrintF(&SanitizedDir, "\\"); AppendPrintF(&SanitizedDir, "\\");
} }
gs_const_string SanitizedDisplayDir = SanitizedDir.ConstString; gs_const_string SanitizedDisplayDir = SanitizedDir.ConstString;
gs_file_info NewWorkingDir = GetFileInfo(Context.ThreadContext.FileHandler, SanitizedDir.ConstString); gs_file_info NewWorkingDir = GetFileInfo(Context.ThreadContext.FileHandler, SanitizedDir.ConstString);
if (NewWorkingDir.IsDirectory) if (NewWorkingDir.IsDirectory)
{ {
AppendPrintF(&SanitizedDir, "*"); AppendPrintF(&SanitizedDir, "*");
NullTerminate(&SanitizedDir); NullTerminate(&SanitizedDir);
State->FileNames = EnumerateDirectory(Context.ThreadContext.FileHandler, &State->FileNamesArena, SanitizedDir.ConstString, EnumerateDirectory_IncludeDirectories); State->FileNames = EnumerateDirectory(Context.ThreadContext.FileHandler, &State->FileNamesArena, SanitizedDir.ConstString, EnumerateDirectory_IncludeDirectories);
// NOTE(pjs): we might be printing from State->WorkingDirectory to State->WorkingDirectory // NOTE(pjs): we might be printing from State->WorkingDirectory to State->WorkingDirectory
// in some cases. Shouldn't be a problem but it is unnecessary // in some cases. Shouldn't be a problem but it is unnecessary
PrintF(&State->WorkingDirectory, "%S", SanitizedDir.ConstString); PrintF(&State->WorkingDirectory, "%S", SanitizedDir.ConstString);
PrintF(&State->DisplayDirectory, "%S", SanitizedDisplayDir); PrintF(&State->DisplayDirectory, "%S", SanitizedDisplayDir);
} }
} }
GSMetaTag(panel_init); GSMetaTag(panel_init);
@ -87,16 +87,16 @@ GSMetaTag(panel_type_file_view);
internal void internal void
FileView_Init(panel* Panel, app_state* State, context Context) FileView_Init(panel* Panel, app_state* State, context Context)
{ {
// TODO: :FreePanelMemory // TODO: :FreePanelMemory
file_view_state* FileViewState = PushStruct(&State->Permanent, file_view_state); file_view_state* FileViewState = PushStruct(&State->Permanent, file_view_state);
Panel->StateMemory = StructToData(FileViewState, file_view_state); Panel->StateMemory = StructToData(FileViewState, file_view_state);
FileViewState->FileNamesArena = CreateMemoryArena(Context.ThreadContext.Allocator, "File View - File Names Arena"); FileViewState->FileNamesArena = MemoryArenaCreate(MB(4), Bytes(8), Context.ThreadContext.Allocator, 0, 0, "File View - File Names Arena");
// TODO(pjs): this shouldn't be stored in permanent // TODO(pjs): this shouldn't be stored in permanent
FileViewState->DisplayDirectory = PushString(&State->Permanent, 1024); FileViewState->DisplayDirectory = PushString(&State->Permanent, 1024);
FileViewState->WorkingDirectory = PushString(&State->Permanent, 1024); FileViewState->WorkingDirectory = PushString(&State->Permanent, 1024);
FileView_UpdateWorkingDirectory(ConstString(".\\"), FileViewState, Context); FileView_UpdateWorkingDirectory(ConstString(".\\"), FileViewState, Context);
} }
GSMetaTag(panel_cleanup); GSMetaTag(panel_cleanup);
@ -112,87 +112,87 @@ GSMetaTag(panel_type_file_view);
internal void internal void
FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) 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); file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state);
ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("FileView Layout")); 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 (!FileViewState->SelectedFile.Path.Str)
{ {
if (ui_Button(&State->Interface, MakeString("Save"))) FileViewState->SelectedFile.Path = FileViewState->DisplayDirectory.ConstString;
{ }
if (!FileViewState->SelectedFile.Path.Str)
{
FileViewState->SelectedFile.Path = FileViewState->DisplayDirectory.ConstString;
}
FileView_Exit_(Panel, State, Context); FileView_Exit_(Panel, State, Context);
}
}
if (ui_Button(&State->Interface, MakeString("Exit")))
{
FileView_Exit_(Panel, State, Context);
}
} }
ui_EndRow(&State->Interface); }
// Header if (ui_Button(&State->Interface, MakeString("Exit")))
if (ui_TextEntry(&State->Interface, MakeString("pwd"), &FileViewState->DisplayDirectory)) {
{ FileView_Exit_(Panel, State, Context);
// 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")); 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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,97 +11,97 @@
enum data_buffer_address_type enum data_buffer_address_type
{ {
AddressType_NetworkIP, AddressType_NetworkIP,
AddressType_ComPort, AddressType_ComPort,
AddressType_Invalid, AddressType_Invalid,
}; };
struct addressed_data_buffer struct addressed_data_buffer
{ {
union union
{
struct
{ {
struct u8* Memory;
{ u32 MemorySize;
u8* Memory;
u32 MemorySize;
};
gs_data Data;
}; };
gs_data Data;
};
data_buffer_address_type AddressType; data_buffer_address_type AddressType;
// IP Address // IP Address
platform_socket_handle SendSocket; platform_socket_handle SendSocket;
u32 V4SendAddress; u32 V4SendAddress;
u32 SendPort; u32 SendPort;
// COM // COM
gs_const_string ComPort; gs_const_string ComPort;
addressed_data_buffer* Next; addressed_data_buffer* Next;
}; };
struct addressed_data_buffer_list struct addressed_data_buffer_list
{ {
gs_memory_arena* Arena; gs_memory_arena* Arena;
addressed_data_buffer* Root; addressed_data_buffer* Root;
addressed_data_buffer* Head; addressed_data_buffer* Head;
}; };
internal void internal void
AddressedDataBufferList_Clear(addressed_data_buffer_list* List) AddressedDataBufferList_Clear(addressed_data_buffer_list* List)
{ {
List->Root = 0; List->Root = 0;
List->Head = 0; List->Head = 0;
ClearArena(List->Arena); MemoryArenaClear(List->Arena);
} }
internal addressed_data_buffer* internal addressed_data_buffer*
AddressedDataBufferList_PushEmpty(addressed_data_buffer_list* List) AddressedDataBufferList_PushEmpty(addressed_data_buffer_list* List)
{ {
addressed_data_buffer* Result = PushStruct(List->Arena, addressed_data_buffer); addressed_data_buffer* Result = PushStruct(List->Arena, addressed_data_buffer);
*Result = {0}; *Result = {0};
Result->Next = 0; Result->Next = 0;
Result->MemorySize = 0; Result->MemorySize = 0;
Result->Memory = 0; Result->Memory = 0;
SLLPushOrInit(List->Root, List->Head, Result); SLLPushOrInit(List->Root, List->Head, Result);
return Result; return Result;
} }
internal addressed_data_buffer* internal addressed_data_buffer*
AddressedDataBufferList_Push(addressed_data_buffer_list* List, u32 BufferSize) AddressedDataBufferList_Push(addressed_data_buffer_list* List, u32 BufferSize)
{ {
addressed_data_buffer* Result = AddressedDataBufferList_PushEmpty(List); addressed_data_buffer* Result = AddressedDataBufferList_PushEmpty(List);
Result->MemorySize = BufferSize; Result->MemorySize = BufferSize;
Result->Memory = PushArray(List->Arena, u8, Result->MemorySize); Result->Memory = PushArray(List->Arena, u8, Result->MemorySize);
return Result; return Result;
} }
internal void internal void
AddressedDataBuffer_SetNetworkAddress(addressed_data_buffer* Buffer, platform_socket_handle SendSocket, u32 V4SendAddress, u32 SendPort) AddressedDataBuffer_SetNetworkAddress(addressed_data_buffer* Buffer, platform_socket_handle SendSocket, u32 V4SendAddress, u32 SendPort)
{ {
Buffer->AddressType = AddressType_NetworkIP; Buffer->AddressType = AddressType_NetworkIP;
Buffer->SendSocket = SendSocket; Buffer->SendSocket = SendSocket;
Buffer->V4SendAddress = V4SendAddress; Buffer->V4SendAddress = V4SendAddress;
Buffer->SendPort = SendPort; Buffer->SendPort = SendPort;
} }
internal void internal void
AddressedDataBuffer_SetCOMPort(addressed_data_buffer* Buffer, gs_const_string ComPort) AddressedDataBuffer_SetCOMPort(addressed_data_buffer* Buffer, gs_const_string ComPort)
{ {
Buffer->AddressType = AddressType_ComPort; Buffer->AddressType = AddressType_ComPort;
Buffer->ComPort = ComPort; Buffer->ComPort = ComPort;
} }
internal addressed_data_buffer_list internal addressed_data_buffer_list
AddressedDataBufferList_Create(gs_thread_context TC) AddressedDataBufferList_Create(gs_thread_context TC)
{ {
addressed_data_buffer_list Result = {}; addressed_data_buffer_list Result = {};
Result.Arena = AllocatorAllocStruct(TC.Allocator, gs_memory_arena); Result.Arena = AllocStruct(TC.Allocator, gs_memory_arena, "Addressed Data");
*Result.Arena = CreateMemoryArena(TC.Allocator, "Addressed Data Buffer List Arena"); *Result.Arena = MemoryArenaCreate(KB(256), Bytes(8), TC.Allocator, 0, 0, "Addressed Data Buffer List Arena");
return Result; return Result;
} }
#define FOLDHAUS_ADDRESSED_DATA_H #define FOLDHAUS_ADDRESSED_DATA_H

View File

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

View File

@ -9,163 +9,163 @@
internal void internal void
UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel ChannelSettings, v2_strip Strip, led_buffer LedBuffer) 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 // 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 // to catch the error where they are different
Assert(ChannelSettings.PixelsCount == Strip.LedCount); Assert(ChannelSettings.PixelsCount == Strip.LedCount);
uart_header* Header = PushStructOnCursor(WriteCursor, uart_header); uart_header* Header = MemoryCursorPushStruct(WriteCursor, uart_header);
UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812); UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812);
uart_channel* Channel = PushStructOnCursor(WriteCursor, uart_channel); uart_channel* Channel = MemoryCursorPushStruct(WriteCursor, uart_channel);
*Channel = ChannelSettings; *Channel = ChannelSettings;
for (u32 i = 0; i < Channel->PixelsCount; i++) for (u32 i = 0; i < Channel->PixelsCount; i++)
{ {
u32 LedIndex = Strip.LedLUT[i]; u32 LedIndex = Strip.LedLUT[i];
pixel Color = LedBuffer.Colors[LedIndex]; pixel Color = LedBuffer.Colors[LedIndex];
u8* OutputPixel = PushArrayOnCursor(WriteCursor, u8, 3); u8* OutputPixel = MemoryCursorPushArray(WriteCursor, u8, 3);
// TODO(pjs): Use the Output mask // TODO(pjs): Use the Output mask
#if 1 #if 1
OutputPixel[0] = Color.R; OutputPixel[0] = Color.R;
OutputPixel[1] = Color.G; OutputPixel[1] = Color.G;
OutputPixel[2] = Color.B; OutputPixel[2] = Color.B;
#else #else
OutputPixel[0] = 255; OutputPixel[0] = 255;
OutputPixel[1] = 255; OutputPixel[1] = 255;
OutputPixel[2] = 255; OutputPixel[2] = 255;
#endif #endif
if (Channel->ElementsCount == 4) if (Channel->ElementsCount == 4)
{ {
// TODO(pjs): Calculate white from the RGB components? // TODO(pjs): Calculate white from the RGB components?
// Generally we just need a good way to handle the white channel, // Generally we just need a good way to handle the white channel,
// both in the renderer and in output // both in the renderer and in output
//OutputPixel[Channel->WhiteIndex] = Color.W; //OutputPixel[Channel->WhiteIndex] = Color.W;
}
} }
}
uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer); uart_footer* Footer = MemoryCursorPushStruct(WriteCursor, uart_footer);
UART_FillFooter(Footer, (u8*)Header); UART_FillFooter(Footer, (u8*)Header);
} }
internal void internal void
UART_DrawAll_Create(gs_memory_cursor* WriteCursor) UART_DrawAll_Create(gs_memory_cursor* WriteCursor)
{ {
uart_header* Header = PushStructOnCursor(WriteCursor, uart_header); uart_header* Header = MemoryCursorPushStruct(WriteCursor, uart_header);
UART_FillHeader(Header, 1, UART_DRAW_ALL); UART_FillHeader(Header, 1, UART_DRAW_ALL);
uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer); uart_footer* Footer = MemoryCursorPushStruct(WriteCursor, uart_footer);
UART_FillFooter(Footer, (u8*)Header); UART_FillFooter(Footer, (u8*)Header);
} }
internal void internal void
UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem, gs_memory_arena* Transient) UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem, gs_memory_arena* Transient)
{ {
uart_channel ChannelSettings = {0}; uart_channel ChannelSettings = {0};
ChannelSettings.ElementsCount = 3; ChannelSettings.ElementsCount = 3;
ChannelSettings.ColorPackingOrder = 36; ChannelSettings.ColorPackingOrder = 36;
// NOTE(pjs): This is the minimum size of every UART message. SetChannelBuffer messages will // 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 // be bigger than this, but their size is based on the number of pixels in each channel
u32 MessageBaseSize = UART_MESSAGE_MIN_SIZE; u32 MessageBaseSize = UART_MESSAGE_MIN_SIZE;
for (u32 AssemblyIdx = 0; AssemblyIdx < Assemblies.Count; AssemblyIdx++) for (u32 AssemblyIdx = 0; AssemblyIdx < Assemblies.Count; AssemblyIdx++)
{
assembly Assembly = Assemblies.Values[AssemblyIdx];
led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
struct strips_to_data_buffer
{ {
assembly Assembly = Assemblies.Values[AssemblyIdx]; gs_const_string ComPort;
led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
struct strips_to_data_buffer 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; BufferSelected = At;
break;
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;
} }
}
for (strips_to_data_buffer* At = BuffersNeededHead; // if no existing buffer for this com port
At!= 0; // create a new one
At = At->Next) if (!BufferSelected)
{ {
u32 TotalBufferSize = MessageBaseSize * Assembly.StripCount; // SetChannelBuffer messages BufferSelected = PushStruct(Transient, strips_to_data_buffer);
TotalBufferSize += MessageBaseSize; // DrawAll message *BufferSelected = {};
TotalBufferSize += ChannelSettings.ElementsCount * At->LedCount; // pixels * channels per pixel 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;
At->ChannelsStart = PushArray(Transient, u8*, At->StripIndicesCount); SLLPushOrInit(BuffersNeededHead, BuffersNeededTail, BufferSelected);
BuffersNeededCount += 1;
}
addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, TotalBufferSize); Assert(BufferSelected->StripIndicesCount < BufferSelected->StripIndicesCountMax);
gs_const_string ComPort = At->ComPort; u32 Index = BufferSelected->StripIndicesCount++;
AddressedDataBuffer_SetCOMPort(Buffer, ComPort); BufferSelected->StripIndices[Index] = StripIdx;
BufferSelected->LedCount += StripAt.LedCount;
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);
}
} }
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,99 +10,99 @@
RELOAD_STATIC_DATA(ReloadStaticData) RELOAD_STATIC_DATA(ReloadStaticData)
{ {
GlobalDebugServices = DebugServices; GlobalDebugServices = DebugServices;
GlobalLogBuffer = LogBuffer; GlobalLogBuffer = LogBuffer;
if (AppReady) if (AppReady)
{ {
app_state* State = (app_state*)Context.MemoryBase; app_state* State = (app_state*)Context.MemoryBase;
State->PanelSystem.PanelDefs = GlobalPanelDefs; State->PanelSystem.PanelDefs = GlobalPanelDefs;
State->PanelSystem.PanelDefsCount = GlobalPanelDefsCount; State->PanelSystem.PanelDefsCount = GlobalPanelDefsCount;
gs_data UserData = State->UserSpaceDesc.UserData; gs_data UserData = State->UserSpaceDesc.UserData;
State->UserSpaceDesc = BlumenLumen_UserSpaceCreate(); State->UserSpaceDesc = BlumenLumen_UserSpaceCreate();
if (UserData.Memory && !State->UserSpaceDesc.UserData.Memory) if (UserData.Memory && !State->UserSpaceDesc.UserData.Memory)
{ {
State->UserSpaceDesc.UserData = UserData; State->UserSpaceDesc.UserData = UserData;
}
US_LoadPatterns(&State->UserSpaceDesc, State, Context);
} }
US_LoadPatterns(&State->UserSpaceDesc, State, Context);
}
} }
INITIALIZE_APPLICATION(InitializeApplication) INITIALIZE_APPLICATION(InitializeApplication)
{ {
Context->MemorySize = sizeof(app_state); Context->MemorySize = sizeof(app_state);
Context->MemoryBase = AllocatorAlloc(Context->ThreadContext.Allocator, Context->MemorySize).Memory; Context->MemoryBase = Alloc(Context->ThreadContext.Allocator, Context->MemorySize, "Memory Base");
app_state* State = (app_state*)Context->MemoryBase; app_state* State = (app_state*)Context->MemoryBase;
*State = {}; *State = {};
State->Permanent = CreateMemoryArena(Context->ThreadContext.Allocator, "Permanent"); State->Permanent = MemoryArenaCreate(MB(4), Bytes(8), Context->ThreadContext.Allocator,0, 0, "Permanent");
State->Transient = Context->ThreadContext.Transient; State->Transient = Context->ThreadContext.Transient;
State->Assemblies = AssemblyArray_Create(8, &State->Permanent); State->Assemblies = AssemblyArray_Create(8, &State->Permanent);
State->CommandQueue = CommandQueue_Create(&State->Permanent, 32); State->CommandQueue = CommandQueue_Create(&State->Permanent, 32);
animation_system_desc AnimSysDesc = {}; animation_system_desc AnimSysDesc = {};
AnimSysDesc.Storage = &State->Permanent; AnimSysDesc.Storage = &State->Permanent;
AnimSysDesc.AnimArrayCount = 32; AnimSysDesc.AnimArrayCount = 32;
AnimSysDesc.SecondsPerFrame = 1.0f / 24.0f; AnimSysDesc.SecondsPerFrame = 1.0f / 24.0f;
State->AnimationSystem = AnimationSystem_Init(AnimSysDesc); State->AnimationSystem = AnimationSystem_Init(AnimSysDesc);
if (!Context->Headless) if (!Context->Headless)
{ {
interface_config IConfig = {0}; interface_config IConfig = {0};
IConfig.FontSize = 14; IConfig.FontSize = 14;
IConfig.PanelBG = v4{ .3f, .3f, .3f, 1.f }; IConfig.PanelBG = v4{ .3f, .3f, .3f, 1.f };
IConfig.ButtonColor_Inactive = BlackV4; IConfig.ButtonColor_Inactive = BlackV4;
IConfig.ButtonColor_Active = v4{ .1f, .1f, .1f, 1.f }; IConfig.ButtonColor_Active = v4{ .1f, .1f, .1f, 1.f };
IConfig.ButtonColor_Selected = v4{ .3f, .3f, .3f, 1.f }; IConfig.ButtonColor_Selected = v4{ .3f, .3f, .3f, 1.f };
IConfig.TextColor = WhiteV4; IConfig.TextColor = WhiteV4;
IConfig.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f }; IConfig.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f };
IConfig.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f }; IConfig.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f };
IConfig.ListBGHover = v4{ .22f, .22f, .22f, 1.f }; IConfig.ListBGHover = v4{ .22f, .22f, .22f, 1.f };
IConfig.ListBGSelected = v4{ .44f, .44f, .44f, 1.f }; IConfig.ListBGSelected = v4{ .44f, .44f, .44f, 1.f };
IConfig.Margin = v2{5, 5}; IConfig.Margin = v2{5, 5};
State->Interface = ui_InterfaceCreate(*Context, IConfig, &State->Permanent); State->Interface = ui_InterfaceCreate(*Context, IConfig, &State->Permanent);
PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent); PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent);
} }
State->SACN = SACN_Initialize(*Context); State->SACN = SACN_Initialize(*Context);
State->LedSystem = LedSystem_Create(Context->ThreadContext.Allocator, 128); State->LedSystem = LedSystem_Create(Context->ThreadContext.Allocator, 128);
State->AssemblyDebugState = AssemblyDebug_Create(&State->Permanent); State->AssemblyDebugState = AssemblyDebug_Create(&State->Permanent);
State->AssemblyDebugState.Brightness = 255; State->AssemblyDebugState.Brightness = 255;
State->AssemblyDebugState.Override = ADS_Override_None; State->AssemblyDebugState.Override = ADS_Override_None;
State->Modes = OperationModeSystemInit(&State->Permanent, Context->ThreadContext); State->Modes = OperationModeSystemInit(&State->Permanent, Context->ThreadContext);
ReloadStaticData(*Context, GlobalDebugServices, GlobalLogBuffer, true); ReloadStaticData(*Context, GlobalDebugServices, GlobalLogBuffer, true);
US_CustomInit(&State->UserSpaceDesc, State, *Context); US_CustomInit(&State->UserSpaceDesc, State, *Context);
if (!Context->Headless) if (!Context->Headless)
{ {
// NOTE(pjs): This just sets up the default panel layout // NOTE(pjs): This just sets up the default panel layout
panel* RootPanel = PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, *Context); panel* RootPanel = PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, *Context);
SplitPanel(RootPanel, .25f, PanelSplit_Horizontal, &State->PanelSystem, State, *Context); SplitPanel(RootPanel, .25f, PanelSplit_Horizontal, &State->PanelSystem, State, *Context);
panel* AnimPanel = RootPanel->Bottom; panel* AnimPanel = RootPanel->Bottom;
Panel_SetType(AnimPanel, &State->PanelSystem, PanelType_AnimationTimeline, State, *Context); Panel_SetType(AnimPanel, &State->PanelSystem, PanelType_AnimationTimeline, State, *Context);
panel* TopPanel = RootPanel->Top; panel* TopPanel = RootPanel->Top;
SplitPanel(TopPanel, .5f, PanelSplit_Vertical, &State->PanelSystem, State, *Context); SplitPanel(TopPanel, .5f, PanelSplit_Vertical, &State->PanelSystem, State, *Context);
panel* LeftPanel = TopPanel->Left; panel* LeftPanel = TopPanel->Left;
SplitPanel(LeftPanel, .5f, PanelSplit_Vertical, &State->PanelSystem, State, *Context); SplitPanel(LeftPanel, .5f, PanelSplit_Vertical, &State->PanelSystem, State, *Context);
panel* Profiler = LeftPanel->Right; panel* Profiler = LeftPanel->Right;
Panel_SetType(Profiler, &State->PanelSystem, PanelType_MessageLog, State, *Context); Panel_SetType(Profiler, &State->PanelSystem, PanelType_MessageLog, State, *Context);
panel* Hierarchy = LeftPanel->Left; panel* Hierarchy = LeftPanel->Left;
Panel_SetType(Hierarchy, &State->PanelSystem, PanelType_AssemblyDebug, State, *Context); Panel_SetType(Hierarchy, &State->PanelSystem, PanelType_AssemblyDebug, State, *Context);
} }
State->RunEditor = !Context->Headless; State->RunEditor = !Context->Headless;
} }
internal void internal void
@ -111,89 +111,89 @@ BuildAssemblyData (app_state* State, context Context, addressed_data_buffer_list
#define SEND_DATA #define SEND_DATA
#ifdef SEND_DATA #ifdef SEND_DATA
// NOTE(pjs): Building data buffers to be sent out to the sculpture // 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 // 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 SACNAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaSACN, State->Transient);
assembly_array UARTAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaUART, State->Transient); assembly_array UARTAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaUART, State->Transient);
SACN_BuildOutputData(&State->SACN, OutputData, SACNAssemblies, &State->LedSystem); SACN_BuildOutputData(&State->SACN, OutputData, SACNAssemblies, &State->LedSystem);
UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem, State->Transient); UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem, State->Transient);
#endif #endif
} }
UPDATE_AND_RENDER(UpdateAndRender) UPDATE_AND_RENDER(UpdateAndRender)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
app_state* State = (app_state*)Context->MemoryBase; app_state* State = (app_state*)Context->MemoryBase;
// NOTE(Peter): We do this at the beginning because all the render commands are stored in Transient, // 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 // 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 // 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. // incorrect to clear the arena, and then access the memory later.
ClearArena(State->Transient); MemoryArenaClear(State->Transient);
Assert(State->UserSpaceDesc.UserData.Memory != 0);
if (State->RunEditor)
{
Editor_Update(State, Context, InputQueue);
}
AnimationSystem_Update(&State->AnimationSystem, Context->DeltaTime);
if (AnimationSystem_NeedsRender(State->AnimationSystem))
{
Assert(State->UserSpaceDesc.UserData.Memory != 0); Assert(State->UserSpaceDesc.UserData.Memory != 0);
AnimationSystem_RenderToLedBuffers(&State->AnimationSystem,
State->Assemblies,
&State->LedSystem,
State->Patterns,
State->Transient,
*Context,
State->UserSpaceDesc.UserData.Memory);
}
if (State->RunEditor) 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); ZeroMemoryBlock(At->Memory, At->MemorySize);
}
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);
}
} }
}
} }
CLEANUP_APPLICATION(CleanupApplication) CLEANUP_APPLICATION(CleanupApplication)
{ {
app_state* State = (app_state*)Context.MemoryBase; app_state* State = (app_state*)Context.MemoryBase;
for (u32 i = 0; i < State->Assemblies.Count; i++) for (u32 i = 0; i < State->Assemblies.Count; i++)
{ {
assembly Assembly = State->Assemblies.Values[i]; assembly Assembly = State->Assemblies.Values[i];
led_buffer LedBuffer = State->LedSystem.Buffers[Assembly.LedBufferIndex]; led_buffer LedBuffer = State->LedSystem.Buffers[Assembly.LedBufferIndex];
AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0}); AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0});
} }
BuildAssemblyData(State, Context, OutputData); BuildAssemblyData(State, Context, OutputData);
US_CustomCleanup(&State->UserSpaceDesc, State, Context); US_CustomCleanup(&State->UserSpaceDesc, State, Context);
SACN_Cleanup(&State->SACN, Context); SACN_Cleanup(&State->SACN, Context);
} }
#define FOLDHAUS_APP_CPP #define FOLDHAUS_APP_CPP

View File

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

View File

@ -8,190 +8,190 @@
internal render_command_buffer internal render_command_buffer
AllocateRenderCommandBuffer (u8* Memory, s32 Size, gs_thread_context Ctx) AllocateRenderCommandBuffer (u8* Memory, s32 Size, gs_thread_context Ctx)
{ {
render_command_buffer Result = {}; render_command_buffer Result = {};
Result.CommandMemory = Memory; Result.CommandMemory = Memory;
Result.CommandMemorySize = Size; Result.CommandMemorySize = Size;
Result.CommandMemoryUsed = 0; Result.CommandMemoryUsed = 0;
Result.Ctx = Ctx; Result.Ctx = Ctx;
return Result; return Result;
} }
internal render_command_buffer internal render_command_buffer
AllocateRenderCommandBuffer(u32 MemorySize, AllocateRenderCommandBuffer(u32 MemorySize,
gs_memory_arena* Arena, gs_memory_arena* Arena,
gs_thread_context Ctx) gs_thread_context Ctx)
{ {
u8* Memory = PushSize(Arena, MemorySize); u8* Memory = PushSize(Arena, MemorySize).Memory;
return AllocateRenderCommandBuffer(Memory, MemorySize, Ctx); return AllocateRenderCommandBuffer(Memory, MemorySize, Ctx);
} }
internal void internal void
Render3DQuadBatch (u8* CommandData, s32 TriCount) Render3DQuadBatch (u8* CommandData, s32 TriCount)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
v4* Vertecies = (v4*)(CommandData + BATCH_3D_VERTECIES_OFFSET(TriCount)); v4* Vertecies = (v4*)(CommandData + BATCH_3D_VERTECIES_OFFSET(TriCount));
v2* UVs = (v2*)(CommandData + BATCH_3D_UVS_OFFSET(TriCount)); v2* UVs = (v2*)(CommandData + BATCH_3D_UVS_OFFSET(TriCount));
v4* Colors = (v4*)(CommandData + BATCH_3D_COLORS_OFFSET(TriCount)); v4* Colors = (v4*)(CommandData + BATCH_3D_COLORS_OFFSET(TriCount));
#if IMMEDIATE_MODE_RENDERING #if IMMEDIATE_MODE_RENDERING
for (s32 Tri = 0; Tri < TriCount; Tri++) for (s32 Tri = 0; Tri < TriCount; Tri++)
{ {
v4 P0 = Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 0)]; v4 P0 = Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 0)];
v4 P1 = Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 1)]; v4 P1 = Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 1)];
v4 P2 = Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 2)]; v4 P2 = Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 2)];
v2 UV0 = UVs[BATCH_3D_UV_INDEX(Tri, 0)]; v2 UV0 = UVs[BATCH_3D_UV_INDEX(Tri, 0)];
v2 UV1 = UVs[BATCH_3D_UV_INDEX(Tri, 1)]; v2 UV1 = UVs[BATCH_3D_UV_INDEX(Tri, 1)];
v2 UV2 = UVs[BATCH_3D_UV_INDEX(Tri, 2)]; v2 UV2 = UVs[BATCH_3D_UV_INDEX(Tri, 2)];
v4 C0 = Colors[BATCH_3D_COLOR_INDEX(Tri, 0)]; v4 C0 = Colors[BATCH_3D_COLOR_INDEX(Tri, 0)];
v4 C1 = Colors[BATCH_3D_COLOR_INDEX(Tri, 1)]; v4 C1 = Colors[BATCH_3D_COLOR_INDEX(Tri, 1)];
v4 C2 = Colors[BATCH_3D_COLOR_INDEX(Tri, 2)]; 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 #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 #endif
} }
internal void internal void
Render2DQuadBatch (u8* CommandData, s32 QuadCount) Render2DQuadBatch (u8* CommandData, s32 QuadCount)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
v2* Vertecies = (v2*)(CommandData + BATCH_2D_VERTECIES_OFFSET(QuadCount)); v2* Vertecies = (v2*)(CommandData + BATCH_2D_VERTECIES_OFFSET(QuadCount));
v2* UVs = (v2*)(CommandData + BATCH_2D_UVS_OFFSET(QuadCount)); v2* UVs = (v2*)(CommandData + BATCH_2D_UVS_OFFSET(QuadCount));
v4* Colors = (v4*)(CommandData + BATCH_2D_COLORS_OFFSET(QuadCount)); v4* Colors = (v4*)(CommandData + BATCH_2D_COLORS_OFFSET(QuadCount));
#if IMMEDIATE_MODE_RENDERING #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 P0 = Vertecies[BATCH_2D_VERTEX_INDEX(Quad, Tri, 0)]; v2 P2 = Vertecies[BATCH_2D_VERTEX_INDEX(Quad, Tri, 2)];
v2 P1 = Vertecies[BATCH_2D_VERTEX_INDEX(Quad, Tri, 1)]; v2 UV0 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 0)];
v2 P2 = Vertecies[BATCH_2D_VERTEX_INDEX(Quad, Tri, 2)]; v2 UV1 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 1)];
v2 UV0 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 0)]; v2 UV2 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 2)];
v2 UV1 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 1)]; v4 C0 = Colors[BATCH_2D_COLOR_INDEX(Quad, Tri, 0)];
v2 UV2 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 2)]; v4 C1 = Colors[BATCH_2D_COLOR_INDEX(Quad, Tri, 1)];
v4 C0 = Colors[BATCH_2D_COLOR_INDEX(Quad, Tri, 0)]; v4 C2 = Colors[BATCH_2D_COLOR_INDEX(Quad, Tri, 2)];
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); OpenGLDraw2DTri(P0, P1, P2, UV0, UV1, UV2, C0, C1, C2);
}
} }
}
#else #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 #endif
} }
internal void internal void
RenderCommandBuffer (render_command_buffer CommandBuffer) RenderCommandBuffer (render_command_buffer CommandBuffer)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
glMatrixMode(GL_TEXTURE_2D); glMatrixMode(GL_TEXTURE_2D);
glLoadIdentity(); glLoadIdentity();
glClearColor(0.1f, 0.1f, 0.1f, 1); glClearColor(0.1f, 0.1f, 0.1f, 1);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
b32 GLTextureEnabled = false; b32 GLTextureEnabled = false;
u8* CurrentPosition = CommandBuffer.CommandMemory; u8* CurrentPosition = CommandBuffer.CommandMemory;
while(CurrentPosition < CommandBuffer.CommandMemory + CommandBuffer.CommandMemoryUsed) 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; case RenderCommand_render_command_set_render_mode:
CurrentPosition += sizeof(render_command_header); {
switch (CommandHeader->Type) 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: glEnable(GL_DEPTH_TEST);
{ glDepthFunc(GL_LESS);
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;
} }
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 internal void
ClearRenderBuffer (render_command_buffer* Buffer) ClearRenderBuffer (render_command_buffer* Buffer)
{ {
Buffer->CommandMemoryUsed = 0; Buffer->CommandMemoryUsed = 0;
} }
#define FOLDHAUS_RENDERER_CPP #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 // DLL
struct win32_dll_refresh struct win32_dll_refresh
{ {
FILETIME LastWriteTime; FILETIME LastWriteTime;
HMODULE DLL; HMODULE DLL;
bool IsValid; bool IsValid;
char SourceDLLPath[MAX_PATH]; char SourceDLLPath[MAX_PATH];
char WorkingDLLPath[MAX_PATH]; char WorkingDLLPath[MAX_PATH];
char LockFilePath[MAX_PATH]; char LockFilePath[MAX_PATH];
}; };
internal int internal int
Win32DLLgs_stringLength(char* gs_string) Win32DLLgs_stringLength(char* gs_string)
{ {
char* At = gs_string; char* At = gs_string;
while (*At) { At++; }; while (*At) { At++; };
return At - gs_string; return At - gs_string;
} }
internal int internal int
Win32DLLConcatgs_strings(int ALength, char* A, int BLength, char* B, int DestLength, char* Dest) Win32DLLConcatgs_strings(int ALength, char* A, int BLength, char* B, int DestLength, char* Dest)
{ {
char* Dst = Dest; char* Dst = Dest;
char* AAt = A; char* AAt = A;
int ALengthToCopy = ALength < DestLength ? ALength : DestLength; int ALengthToCopy = ALength < DestLength ? ALength : DestLength;
for (s32 a = 0; a < ALength; a++) for (s32 a = 0; a < ALength; a++)
{ {
*Dst++ = *AAt++; *Dst++ = *AAt++;
} }
char* BAt = B; char* BAt = B;
int DestLengthRemaining = DestLength - (Dst - Dest); int DestLengthRemaining = DestLength - (Dst - Dest);
int BLengthToCopy = BLength < DestLengthRemaining ? BLength : DestLength; int BLengthToCopy = BLength < DestLengthRemaining ? BLength : DestLength;
for (s32 b = 0; b < BLengthToCopy; b++) for (s32 b = 0; b < BLengthToCopy; b++)
{ {
*Dst++ = *BAt++; *Dst++ = *BAt++;
} }
int DestLengthOut = Dst - Dest; int DestLengthOut = Dst - Dest;
int NullTermIndex = DestLengthOut < DestLength ? DestLengthOut : DestLength; int NullTermIndex = DestLengthOut < DestLength ? DestLengthOut : DestLength;
Dest[NullTermIndex] = 0; Dest[NullTermIndex] = 0;
return DestLengthOut; return DestLengthOut;
} }
internal void internal void
GetApplicationPath(system_path* Result) GetApplicationPath(system_path* Result)
{ {
Assert(Result->Path); Assert(Result->Path);
Result->PathLength = GetModuleFileNameA(0, Result->Path, Result->PathLength); Result->PathLength = GetModuleFileNameA(0, Result->Path, Result->PathLength);
u32 CharactersScanned = 0; u32 CharactersScanned = 0;
u32 IndexOfLastSlash = 0; u32 IndexOfLastSlash = 0;
char *Scan = Result->Path; char *Scan = Result->Path;
while(*Scan) while(*Scan)
{
if (*Scan == '\\')
{ {
if (*Scan == '\\') Result->IndexOfLastSlash = CharactersScanned + 1;
{
Result->IndexOfLastSlash = CharactersScanned + 1;
}
Scan++;
CharactersScanned++;
} }
Scan++;
CharactersScanned++;
}
} }
internal b32 internal b32
LoadApplicationDLL(char* DLLName, win32_dll_refresh* DLLResult) LoadApplicationDLL(char* DLLName, win32_dll_refresh* DLLResult)
{ {
b32 Success = false; b32 Success = false;
Assert(DLLResult->DLL == 0); Assert(DLLResult->DLL == 0);
DLLResult->DLL = LoadLibraryA(DLLName); DLLResult->DLL = LoadLibraryA(DLLName);
if (DLLResult->DLL) if (DLLResult->DLL)
{ {
Success = true; Success = true;
DLLResult->IsValid = true; DLLResult->IsValid = true;
} }
return Success; return Success;
} }
internal void internal void
UnloadApplicationDLL(win32_dll_refresh* DLL) UnloadApplicationDLL(win32_dll_refresh* DLL)
{ {
if (DLL->DLL) if (DLL->DLL)
{ {
FreeLibrary(DLL->DLL); FreeLibrary(DLL->DLL);
} }
DLL->DLL = 0; DLL->DLL = 0;
DLL->IsValid = false; DLL->IsValid = false;
} }
internal win32_dll_refresh internal win32_dll_refresh
@ -104,57 +104,57 @@ InitializeDLLHotReloading(char* SourceDLLName,
char* WorkingDLLFileName, char* WorkingDLLFileName,
char* LockFileName) char* LockFileName)
{ {
win32_dll_refresh Result = {}; win32_dll_refresh Result = {};
Result.IsValid = false; Result.IsValid = false;
system_path ExePath = {}; system_path ExePath = {};
ExePath.PathLength = MAX_PATH; ExePath.PathLength = MAX_PATH;
ExePath.Path = (char*)VirtualAlloc(NULL, ExePath.PathLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); ExePath.Path = (char*)VirtualAlloc(NULL, ExePath.PathLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
GetApplicationPath(&ExePath); GetApplicationPath(&ExePath);
Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path, Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path,
Win32DLLgs_stringLength(SourceDLLName), SourceDLLName, Win32DLLgs_stringLength(SourceDLLName), SourceDLLName,
MAX_PATH, Result.SourceDLLPath); MAX_PATH, Result.SourceDLLPath);
Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path, Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path,
Win32DLLgs_stringLength(WorkingDLLFileName), WorkingDLLFileName, Win32DLLgs_stringLength(WorkingDLLFileName), WorkingDLLFileName,
MAX_PATH, Result.WorkingDLLPath); MAX_PATH, Result.WorkingDLLPath);
Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path, Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path,
Win32DLLgs_stringLength(LockFileName), LockFileName, Win32DLLgs_stringLength(LockFileName), LockFileName,
MAX_PATH, Result.LockFilePath); MAX_PATH, Result.LockFilePath);
Win32Free((u8*)ExePath.Path, ExePath.PathLength); Win32Free((u8*)ExePath.Path, ExePath.PathLength, 0);
return Result; return Result;
} }
internal b32 internal b32
HotLoadDLL(win32_dll_refresh* DLL) HotLoadDLL(win32_dll_refresh* DLL)
{ {
b32 DidReload = false; b32 DidReload = false;
FILETIME UpdatedLastWriteTime = {}; FILETIME UpdatedLastWriteTime = {};
WIN32_FIND_DATA FindData = {}; WIN32_FIND_DATA FindData = {};
HANDLE FileHandle = FindFirstFileA(DLL->SourceDLLPath, &FindData); HANDLE FileHandle = FindFirstFileA(DLL->SourceDLLPath, &FindData);
if (FileHandle != INVALID_HANDLE_VALUE) 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; UnloadApplicationDLL(DLL);
FindClose(FileHandle); CopyFileA(DLL->SourceDLLPath, DLL->WorkingDLLPath, FALSE);
LoadApplicationDLL(DLL->WorkingDLLPath, DLL);
DLL->LastWriteTime = UpdatedLastWriteTime;
DidReload = true;
} }
}
if (CompareFileTime(&UpdatedLastWriteTime, &DLL->LastWriteTime)) return DidReload;
{
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;
} }

View File

@ -1,36 +1,26 @@
// /* date = May 10th 2021 11:48 pm */
// 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
ALLOCATOR_ALLOC(Win32Alloc) #ifndef GS_MEMORY_WIN32_H
#define GS_MEMORY_WIN32_H
PLATFORM_ALLOC(Win32Alloc)
{ {
u8* Result = (u8*)VirtualAlloc(NULL, Size, u8* Result = (u8*)VirtualAlloc(NULL, Size,
MEM_COMMIT | MEM_RESERVE, MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE); PAGE_EXECUTE_READWRITE);
if (ResultSize != 0) if (ResultSize) *ResultSize = Size;
{ return Result;
*ResultSize = Size;
}
return Result;
} }
ALLOCATOR_FREE(Win32Free) PLATFORM_FREE(Win32Free)
{ {
b32 Result = VirtualFree(Ptr, 0, MEM_RELEASE); VirtualFree(Base, 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;
}
} }
#define WIN32_FOLDHAUS_MEMORY_H internal gs_allocator
#endif // WIN32_FOLDHAUS_MEMORY_H CreatePlatformAllocator()
{
return AllocatorCreate(Win32Alloc, Win32Free, 0);
}
#endif //GS_MEMORY_WIN32_H

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -2,79 +2,82 @@
internal void internal void
MessageQueue_Init(blumen_network_msg_queue* Queue, gs_memory_arena* Arena) MessageQueue_Init(blumen_network_msg_queue* Queue, gs_memory_arena* Arena)
{ {
for (u32 i = 0; i < BLUMEN_MESSAGE_QUEUE_COUNT; i++) gs_data MessageQueueData = PushSize(Arena, DEFAULT_QUEUE_ENTRY_SIZE * BLUMEN_MESSAGE_QUEUE_COUNT);
{ gs_memory_cursor C = MemoryCursorCreateFromData(MessageQueueData);
Queue->Buffers[i] = PushSizeToData(Arena, DEFAULT_QUEUE_ENTRY_SIZE);
} for (u32 i = 0; i < BLUMEN_MESSAGE_QUEUE_COUNT; i++)
{
Queue->Buffers[i] = MemoryCursorPushSize(&C, DEFAULT_QUEUE_ENTRY_SIZE);
}
} }
internal bool internal bool
MessageQueue_CanWrite(blumen_network_msg_queue Queue) MessageQueue_CanWrite(blumen_network_msg_queue Queue)
{ {
bool Result = ((Queue.WriteHead >= Queue.ReadHead) || bool Result = ((Queue.WriteHead >= Queue.ReadHead) ||
(Queue.WriteHead < Queue.ReadHead)); (Queue.WriteHead < Queue.ReadHead));
return Result; return Result;
} }
internal bool internal bool
MessageQueue_Write(blumen_network_msg_queue* Queue, gs_data Msg) MessageQueue_Write(blumen_network_msg_queue* Queue, gs_data Msg)
{ {
Assert(Msg.Size <= DEFAULT_QUEUE_ENTRY_SIZE); Assert(Msg.Size <= DEFAULT_QUEUE_ENTRY_SIZE);
u32 Index = Queue->WriteHead; u32 Index = Queue->WriteHead;
Assert(Index >= 0 && Assert(Index >= 0 &&
Index < BLUMEN_MESSAGE_QUEUE_COUNT); Index < BLUMEN_MESSAGE_QUEUE_COUNT);
gs_data* Dest = Queue->Buffers + Index; gs_data* Dest = Queue->Buffers + Index;
CopyMemoryTo(Msg.Memory, Dest->Memory, Msg.Size); CopyMemoryTo(Msg.Memory, Dest->Memory, Msg.Size);
Dest->Size = Msg.Size; Dest->Size = Msg.Size;
// NOTE(pjs): We increment write head at the end of writing so that // 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 // a reader thread doesn't pull the message off before we've finished
// filling it out // filling it out
Queue->WriteHead = (Queue->WriteHead + 1) % BLUMEN_MESSAGE_QUEUE_COUNT; Queue->WriteHead = (Queue->WriteHead + 1) % BLUMEN_MESSAGE_QUEUE_COUNT;
return true; return true;
} }
internal bool internal bool
MessageQueue_CanRead(blumen_network_msg_queue Queue) MessageQueue_CanRead(blumen_network_msg_queue Queue)
{ {
bool Result = (Queue.ReadHead != Queue.WriteHead); bool Result = (Queue.ReadHead != Queue.WriteHead);
return Result; return Result;
} }
internal gs_data internal gs_data
MessageQueue_Peek(blumen_network_msg_queue* Queue) MessageQueue_Peek(blumen_network_msg_queue* Queue)
{ {
gs_data Result = {}; gs_data Result = {};
u32 ReadIndex = Queue->ReadHead; u32 ReadIndex = Queue->ReadHead;
if (ReadIndex >= BLUMEN_MESSAGE_QUEUE_COUNT) if (ReadIndex >= BLUMEN_MESSAGE_QUEUE_COUNT)
{ {
ReadIndex = 0; ReadIndex = 0;
} }
Result = Queue->Buffers[ReadIndex]; Result = Queue->Buffers[ReadIndex];
return Result; return Result;
} }
internal gs_data internal gs_data
MessageQueue_Read(blumen_network_msg_queue* Queue) MessageQueue_Read(blumen_network_msg_queue* Queue)
{ {
gs_data Result = {}; gs_data Result = {};
u32 ReadIndex = Queue->ReadHead++; u32 ReadIndex = Queue->ReadHead++;
if (ReadIndex >= BLUMEN_MESSAGE_QUEUE_COUNT) if (ReadIndex >= BLUMEN_MESSAGE_QUEUE_COUNT)
{ {
Queue->ReadHead = 0; Queue->ReadHead = 0;
ReadIndex = 0; ReadIndex = 0;
} }
Result = Queue->Buffers[ReadIndex]; Result = Queue->Buffers[ReadIndex];
return Result; return Result;
} }
internal void internal void
MessageQueue_Clear(blumen_network_msg_queue* Queue) MessageQueue_Clear(blumen_network_msg_queue* Queue)
{ {
while (MessageQueue_CanRead(*Queue)) while (MessageQueue_CanRead(*Queue))
{ {
MessageQueue_Read(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,84 +22,84 @@ global log_buffer* GlobalLogBuffer;
typedef struct typedef struct
{ {
v3 CenterStart; v3 CenterStart;
v3 CenterEnd; v3 CenterEnd;
r32 Radius; r32 Radius;
u32 SegmentsCount; u32 SegmentsCount;
u32 SubsegmentsCount; u32 SubsegmentsCount;
u32 SubsegmentLeds; u32 SubsegmentLeds;
// Only one of these two values is needed. // Only one of these two values is needed.
// If ChannelsArray != 0, then it will be used, and assumed to // If ChannelsArray != 0, then it will be used, and assumed to
// have SegmentsCount values // have SegmentsCount values
// Otherwise, each segment will increment from ChannelStart // Otherwise, each segment will increment from ChannelStart
u32 ChannelStart; u32 ChannelStart;
u32* ChannelsArray; u32* ChannelsArray;
char* ComPort; char* ComPort;
char* SectionTagValue; char* SectionTagValue;
char* FlowerTagValue; char* FlowerTagValue;
} loop_desc; } loop_desc;
internal void internal void
BuildLoop(gs_string* OutputBuffer, loop_desc Desc) BuildLoop(gs_string* OutputBuffer, loop_desc Desc)
{ {
r32 SegmentsArc = TauR32 / Desc.SegmentsCount; r32 SegmentsArc = TauR32 / Desc.SegmentsCount;
r32 SubsegmentsArc = SegmentsArc / Desc.SubsegmentsCount; r32 SubsegmentsArc = SegmentsArc / Desc.SubsegmentsCount;
for (u32 i = 0; i < Desc.SegmentsCount; i++) for (u32 i = 0; i < Desc.SegmentsCount; i++)
{
r32 ArcBase = SegmentsArc * i;
u32 Channel = 0;
if (Desc.ChannelsArray != 0)
{ {
r32 ArcBase = SegmentsArc * i; Channel = Desc.ChannelsArray[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);
} }
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 typedef struct
{ {
v3 Pos; v3 Pos;
char* ComPort; char* ComPort;
char* FlowerTagValue; char* FlowerTagValue;
u32* StemChannels; u32* StemChannels;
u32* BloomOuterChannels; u32* BloomOuterChannels;
u32* BloomInnerChannels; u32* BloomInnerChannels;
} flower_desc; } flower_desc;
internal u32 internal u32
@ -107,56 +107,56 @@ BuildFlower(gs_string* OutputBuffer, flower_desc Desc)
{ {
#if 1 #if 1
// the bloom stem inner // the bloom stem inner
loop_desc BloomStemInner = {}; loop_desc BloomStemInner = {};
BloomStemInner.CenterStart = v3{0, 1.4f, 0}; BloomStemInner.CenterStart = v3{0, 1.4f, 0};
BloomStemInner.CenterEnd = v3{0, .9f, 0}; BloomStemInner.CenterEnd = v3{0, .9f, 0};
BloomStemInner.Radius = .05f; BloomStemInner.Radius = .05f;
BloomStemInner.SegmentsCount = 6; BloomStemInner.SegmentsCount = 6;
BloomStemInner.SubsegmentsCount = 3; BloomStemInner.SubsegmentsCount = 3;
BloomStemInner.SubsegmentLeds = 35; BloomStemInner.SubsegmentLeds = 35;
BloomStemInner.ChannelsArray = Desc.BloomInnerChannels; BloomStemInner.ChannelsArray = Desc.BloomInnerChannels;
BloomStemInner.ComPort = Desc.ComPort; BloomStemInner.ComPort = Desc.ComPort;
BloomStemInner.SectionTagValue = "inner_bloom"; BloomStemInner.SectionTagValue = "inner_bloom";
BloomStemInner.FlowerTagValue = Desc.FlowerTagValue; BloomStemInner.FlowerTagValue = Desc.FlowerTagValue;
BuildLoop(OutputBuffer, BloomStemInner); BuildLoop(OutputBuffer, BloomStemInner);
// the bloom stem outer // the bloom stem outer
loop_desc BloomStemOuter = {}; loop_desc BloomStemOuter = {};
BloomStemOuter.CenterStart = v3{0, .5f, 0}; BloomStemOuter.CenterStart = v3{0, .5f, 0};
BloomStemOuter.CenterEnd = v3{0, .9f, 0}; BloomStemOuter.CenterEnd = v3{0, .9f, 0};
BloomStemOuter.Radius = .07f; BloomStemOuter.Radius = .07f;
BloomStemOuter.SegmentsCount = 9; BloomStemOuter.SegmentsCount = 9;
BloomStemOuter.SubsegmentsCount = 3; BloomStemOuter.SubsegmentsCount = 3;
BloomStemOuter.SubsegmentLeds = 41; BloomStemOuter.SubsegmentLeds = 41;
BloomStemOuter.ChannelsArray = Desc.BloomOuterChannels; BloomStemOuter.ChannelsArray = Desc.BloomOuterChannels;
BloomStemOuter.ComPort = Desc.ComPort; BloomStemOuter.ComPort = Desc.ComPort;
BloomStemOuter.SectionTagValue = "outer_bloom"; BloomStemOuter.SectionTagValue = "outer_bloom";
BloomStemOuter.FlowerTagValue = Desc.FlowerTagValue; BloomStemOuter.FlowerTagValue = Desc.FlowerTagValue;
BuildLoop(OutputBuffer, BloomStemOuter); BuildLoop(OutputBuffer, BloomStemOuter);
#endif #endif
#if 1 #if 1
// the flower stem // the flower stem
loop_desc FlowerStem = {}; loop_desc FlowerStem = {};
FlowerStem.CenterStart = v3{0, -1.5f, 0}; FlowerStem.CenterStart = v3{0, -1.5f, 0};
FlowerStem.CenterEnd = v3{0, .5f, 0}; FlowerStem.CenterEnd = v3{0, .5f, 0};
FlowerStem.Radius = .05f; FlowerStem.Radius = .05f;
FlowerStem.SegmentsCount = 6; FlowerStem.SegmentsCount = 6;
FlowerStem.SubsegmentsCount = 1; FlowerStem.SubsegmentsCount = 1;
FlowerStem.SubsegmentLeds = 300; FlowerStem.SubsegmentLeds = 300;
FlowerStem.ChannelsArray = Desc.StemChannels; FlowerStem.ChannelsArray = Desc.StemChannels;
FlowerStem.ComPort = Desc.ComPort; FlowerStem.ComPort = Desc.ComPort;
FlowerStem.SectionTagValue = "stem"; FlowerStem.SectionTagValue = "stem";
FlowerStem.FlowerTagValue = Desc.FlowerTagValue; FlowerStem.FlowerTagValue = Desc.FlowerTagValue;
BuildLoop(OutputBuffer, FlowerStem); BuildLoop(OutputBuffer, FlowerStem);
#endif #endif
u32 StripsCount = BloomStemInner.SegmentsCount; u32 StripsCount = BloomStemInner.SegmentsCount;
StripsCount += BloomStemOuter.SegmentsCount; StripsCount += BloomStemOuter.SegmentsCount;
StripsCount += FlowerStem.SegmentsCount; StripsCount += FlowerStem.SegmentsCount;
return StripsCount; return StripsCount;
} }
// Just for brevity, no real function provided // Just for brevity, no real function provided
@ -164,88 +164,88 @@ BuildFlower(gs_string* OutputBuffer, flower_desc Desc)
internal u8 internal u8
FlowerStripToChannel(u8 Flower, u8 Channel) FlowerStripToChannel(u8 Flower, u8 Channel)
{ {
Assert(Flower < 3); Assert(Flower < 3);
Assert(Channel < 8); Assert(Channel < 8);
u8 Result = 0; u8 Result = 0;
Result |= (Flower & 0x03) << 3; Result |= (Flower & 0x03) << 3;
Result |= (Channel & 0x07); Result |= (Channel & 0x07);
return Result; return Result;
} }
int main(int ArgCount, char** Args) int main(int ArgCount, char** Args)
{ {
gs_thread_context Ctx = Win32CreateThreadContext(); gs_thread_context Ctx = Win32CreateThreadContext();
GlobalLogBuffer = AllocatorAllocStruct(Ctx.Allocator, log_buffer); GlobalLogBuffer = PushStruct(Ctx.Transient, log_buffer);
*GlobalLogBuffer = Log_Init(Ctx.Allocator, 32); *GlobalLogBuffer = Log_Init(Ctx.Transient, 32);
gs_string OutputBuffer0 = PushString(Ctx.Transient, MB(4)); gs_string OutputBuffer0 = PushString(Ctx.Transient, MB(4));
gs_string OutputBuffer1 = PushString(Ctx.Transient, MB(4)); gs_string OutputBuffer1 = PushString(Ctx.Transient, MB(4));
gs_string OutputBuffer2 = PushString(Ctx.Transient, MB(4)); gs_string OutputBuffer2 = PushString(Ctx.Transient, MB(4));
WriteAssemblyUARTOpen(&OutputBuffer0, WriteAssemblyUARTOpen(&OutputBuffer0,
"Blumen Lumen - Silver Spring - 00", "Blumen Lumen - Silver Spring - 00",
100, 100,
v3{-1, 0, 0}, v3{-1, 0, 0},
21, 21,
""); "");
WriteAssemblyUARTOpen(&OutputBuffer1, WriteAssemblyUARTOpen(&OutputBuffer1,
"Blumen Lumen - Silver Spring - 01", "Blumen Lumen - Silver Spring - 01",
100, 100,
v3{0, 0, 0}, v3{0, 0, 0},
21, 21,
""); "");
WriteAssemblyUARTOpen(&OutputBuffer2, WriteAssemblyUARTOpen(&OutputBuffer2,
"Blumen Lumen - Silver Spring - 02", "Blumen Lumen - Silver Spring - 02",
100, 100,
v3{1, 0, 0}, v3{1, 0, 0},
21, 21,
""); "");
u32 StripCount = 0; u32 StripCount = 0;
u32 StemChannels[] = { FSC(2, 1), FSC(2, 2), FSC(2, 3), FSC(2, 4), FSC(2, 5), FSC(2, 6) }; 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 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) }; u32 BloomInnerChannels[] = { FSC(0, 0), FSC(0, 1), FSC(0, 2), FSC(0, 3), FSC(0, 4), FSC(0, 5) };
flower_desc F0 = {}; flower_desc F0 = {};
F0.Pos = v3{0, 0, 0}; F0.Pos = v3{0, 0, 0};
F0.ComPort = "\\\\.\\COM11"; F0.ComPort = "\\\\.\\COM11";
F0.FlowerTagValue = "left"; F0.FlowerTagValue = "left";
F0.StemChannels = StemChannels; F0.StemChannels = StemChannels;
F0.BloomOuterChannels = BloomOuterChannels; F0.BloomOuterChannels = BloomOuterChannels;
F0.BloomInnerChannels = BloomInnerChannels; F0.BloomInnerChannels = BloomInnerChannels;
StripCount += BuildFlower(&OutputBuffer0, F0); StripCount += BuildFlower(&OutputBuffer0, F0);
flower_desc F1 = {}; flower_desc F1 = {};
F1.Pos = v3{0, 0, 0}; F1.Pos = v3{0, 0, 0};
F1.ComPort = "\\\\.\\COM12"; F1.ComPort = "\\\\.\\COM12";
F1.FlowerTagValue = "center"; F1.FlowerTagValue = "center";
F1.StemChannels = StemChannels; F1.StemChannels = StemChannels;
F1.BloomInnerChannels = BloomInnerChannels; F1.BloomInnerChannels = BloomInnerChannels;
F1.BloomOuterChannels = BloomOuterChannels; F1.BloomOuterChannels = BloomOuterChannels;
StripCount += BuildFlower(&OutputBuffer1, F1); StripCount += BuildFlower(&OutputBuffer1, F1);
flower_desc F2 = {}; flower_desc F2 = {};
F2.Pos = v3{0, 0, 0}; F2.Pos = v3{0, 0, 0};
F2.ComPort = "\\\\.\\COM6"; F2.ComPort = "\\\\.\\COM6";
F2.FlowerTagValue = "right"; F2.FlowerTagValue = "right";
F2.StemChannels = StemChannels; F2.StemChannels = StemChannels;
F2.BloomInnerChannels = BloomInnerChannels; F2.BloomInnerChannels = BloomInnerChannels;
F2.BloomOuterChannels = BloomOuterChannels; F2.BloomOuterChannels = BloomOuterChannels;
StripCount += BuildFlower(&OutputBuffer2, F2); StripCount += BuildFlower(&OutputBuffer2, F2);
WriteEntireFile(Ctx.FileHandler, ConstString("data/ss_blumen_one.fold"), StringToData(OutputBuffer0)); 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_two.fold"), StringToData(OutputBuffer1));
WriteEntireFile(Ctx.FileHandler, ConstString("data/ss_blumen_three.fold"), StringToData(OutputBuffer2)); WriteEntireFile(Ctx.FileHandler, ConstString("data/ss_blumen_three.fold"), StringToData(OutputBuffer2));
//printf("%.*s\n", (u32)OutputBuffer.Length, OutputBuffer.Str); //printf("%.*s\n", (u32)OutputBuffer.Length, OutputBuffer.Str);
//printf("%d\n", StripCount); //printf("%d\n", StripCount);
return 0; return 0;
} }

View File

@ -30,195 +30,195 @@ global log_buffer* GlobalLogBuffer;
u8* u8*
FindNextHeader(gs_data Data, u8* StartAt) FindNextHeader(gs_data Data, u8* StartAt)
{ {
u8* At = StartAt; u8* At = StartAt;
while (!(At[0] == 'U' && while (!(At[0] == 'U' &&
At[1] == 'P' && At[1] == 'P' &&
At[2] == 'X' && At[2] == 'X' &&
At[3] == 'L') && At[3] == 'L') &&
(u32)(At - Data.Memory) < Data.Size) (u32)(At - Data.Memory) < Data.Size)
{ {
At++; At++;
} }
return At; return At;
} }
void void
CreateMessage(gs_data* Data, u8 Count) CreateMessage(gs_data* Data, u8 Count)
{ {
gs_memory_cursor WriteCursor = CreateMemoryCursor(*Data); gs_memory_cursor WriteCursor = MemoryCursorCreateFromData(*Data);
u32 Channels[] = { u32 Channels[] = {
0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
16, 17, 18, 19, 20, 21, 22, 23, 16, 17, 18, 19, 20, 21, 22, 23,
//40, 41, 42, 43, 44, 45, 46, 47, //40, 41, 42, 43, 44, 45, 46, 47,
}; };
u8* FirstHeaderAddr = 0; u8* FirstHeaderAddr = 0;
for (u32 j = 0; j < sizeof(Channels) / sizeof(u32); j++) 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);
if (FirstHeaderAddr == 0)
{ {
u32 ChannelIndex = Channels[j]; FirstHeaderAddr = (u8*)Header;
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));
} }
uart_header* DrawAllHeader = PushStructOnCursor(&WriteCursor, uart_header); uart_channel* Channel = MemoryCursorPushStruct(&WriteCursor, uart_channel);
UART_FillHeader(DrawAllHeader, 255, UART_DRAW_ALL); Channel->ElementsCount = 3;
uart_footer* DrawAllFooter = Channel->ColorPackingOrder = 36; // 10010000
PushStructOnCursor(&WriteCursor, uart_footer); Channel->PixelsCount = 300;
DrawAllFooter->CRC = UART_CalculateCRC((u8*)DrawAllHeader, (u8*)(DrawAllFooter));
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) int main(int ArgCount, char** Args)
{ {
gs_thread_context Ctx = Win32CreateThreadContext(); gs_thread_context Ctx = Win32CreateThreadContext();
GlobalLogBuffer = AllocatorAllocStruct(Ctx.Allocator, log_buffer); GlobalLogBuffer = PushStruct(Ctx.Transient, log_buffer);
*GlobalLogBuffer = Log_Init(Ctx.Allocator, 32); *GlobalLogBuffer = Log_Init(Ctx.Transient, 32);
HANDLE SerialHandle = Win32SerialPort_Open("\\\\.\\COM9", Ctx.Transient); HANDLE SerialHandle = Win32SerialPort_Open("\\\\.\\COM9", Ctx.Transient);
Win32SerialPort_SetState(SerialHandle, 2000000, 8, 0, 1); Win32SerialPort_SetState(SerialHandle, 2000000, 8, 0, 1);
gs_const_string OutFileName = ConstString("./serial_dump.data"); gs_const_string OutFileName = ConstString("./serial_dump.data");
if (false) if (false)
{
Win32SerialPort_SetRead(SerialHandle);
gs_data Data = PushSize(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
{ {
Win32SerialPort_SetRead(SerialHandle); ScanAt = FindNextHeader(Data, ScanAt);
uart_header* Header = (uart_header*)ScanAt;
gs_data Data = PushSizeToData(Ctx.Transient, KB(32)); if (Header->RecordType == UART_SET_CHANNEL_WS2812)
{
Win32SerialPort_SetRead(SerialHandle); printf("Set Channel:\n");
u32 ReadSize = Win32SerialPort_ReadMessageWhenReady(SerialHandle, Data); printf(" Channel: %d\n", Header->Channel);
printf(" Pixels: %d\n", ((uart_channel*)(Header + 1))->PixelsCount);
u8* SetChannelHeaderAddr = 0; if (!SetChannelHeader)
uart_header* SetChannelHeader = 0;
uart_header* DrawAllHeader = 0;
u8* ScanAt = Data.Memory;
do
{ {
ScanAt = FindNextHeader(Data, ScanAt); SetChannelHeaderAddr = (u8*)Header;
uart_header* Header = (uart_header*)ScanAt; SetChannelHeader = Header;
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;
}
} }
CloseHandle(FileHandle); }
Win32SerialPort_Close(SerialHandle);
} if (Header->RecordType == UART_DRAW_ALL)
else if (true) {
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)
{ {
gs_data Data = PushSizeToData(Ctx.Transient, KB(32)); DWORD BytesWritten = 0;
if (!WriteFile(FileHandle, Data.Memory, Data.Size, &BytesWritten, NULL))
u8 Count = 0; {
while(true) InvalidCodePath;
{ }
CreateMessage(&Data, ++Count);
Win32SerialPort_Write(SerialHandle, Data);
Sleep(100);
}
} }
else if (false) CloseHandle(FileHandle);
Win32SerialPort_Close(SerialHandle);
}
else if (true)
{
gs_data Data = PushSize(Ctx.Transient, KB(32));
u8 Count = 0;
while(true)
{ {
gs_data Data = PushSizeToData(Ctx.Transient, KB(32)); CreateMessage(&Data, ++Count);
gs_file File = Win32ReadEntireFile(Ctx.FileHandler, OutFileName, Data); Win32SerialPort_Write(SerialHandle, Data);
Sleep(100);
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);
}
} }
}
else if (false)
{
gs_data Data = PushSize(Ctx.Transient, KB(32));
gs_file File = Win32ReadEntireFile(Ctx.FileHandler, OutFileName, Data);
return 0; 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 internal u32
TESTNextRandom(u32* LastRandomValue) NextRandom(u32* LastRandomValue)
{ {
u32 Result = *LastRandomValue; u32 Result = *LastRandomValue;
Result ^= Result << 13; Result ^= Result << 13;
@ -11,64 +9,63 @@ TESTNextRandom(u32* LastRandomValue)
return Result; return Result;
} }
internal void void
MemoryArenaTests() MemoryArenaTests()
{ {
Test("Allocator") 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); for (int i = 0; i < 4096; i++) Data[i] = (i % MaxU8);
bool Success = true; 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); TestResult(Success);
AllocatorFreeArray(Allocator, Data, u8, 4096); FreeArray(A, Data, u8, 4096);
// idk how to test free TestResult(true); // TODO(PS): How do we test free?
} }
Test("Memory Cursor") Test("Memory Cursor")
{ {
gs_allocator A = CreateAllocator(Win32Alloc, Win32Free); gs_allocator A = CreatePlatformAllocator();
u64 Size = 4096; u64 Size = 4096;
gs_data D = AllocatorAlloc(A, Size); gs_data D = AllocData(A, Size, "root");
gs_memory_cursor C = CreateMemoryCursor(D); gs_memory_cursor C = MemoryCursorCreate(D.Memory, D.Size);
u64 RoomLeft = CursorRoomLeft(C); u64 RoomLeft = MemoryCursorRoomLeft(C);
TestResult(RoomLeft == Size); TestResult(RoomLeft == Size);
TestResult(MemoryCursorHasRoom(C));
TestResult(CursorHasRoom(C, 2048)); TestResult(MemoryCursorCanPush(C, 2048));
TestResult(CursorHasRoom(C, Size)); TestResult(MemoryCursorCanPush(C, Size));
TestResult(!CursorHasRoom(C, Size + 1)); TestResult(!MemoryCursorCanPush(C, Size + 1));
for (u64 i = 0; i < 2048; i++) for (u64 i = 0; i < 2048; i++)
{ {
u8* Byte = PushSizeOnCursor(&C, 1).Memory; u8* Byte = MemoryCursorPushSize(&C, 1).Memory;
*Byte = (u8)(i % 256); *Byte = (u8)(i % 256);
} }
RoomLeft = CursorRoomLeft(C); RoomLeft = MemoryCursorRoomLeft(C);
TestResult(RoomLeft == (Size - 2048)); TestResult(RoomLeft == (Size - 2048));
PopSizeOnCursor(&C, 2048); MemoryCursorPopSize(&C, 2048);
TestResult(C.Position == 0); TestResult(C.Position == 0);
bool Success = true; bool Success = true;
for (u64 i = 0; i < 2048; i++) for (u64 i = 0; i < 2048; i++)
{ {
u8* Byte = PushSizeOnCursor(&C, 1).Memory; u8* Byte = MemoryCursorPushSize(&C, 1).Memory;
Success &= *Byte == (u8)(i % 256); Success &= *Byte == (u8)(i % 256);
} }
TestResult(Success); TestResult(Success);
AllocatorFree(A, D.Memory, D.Size);
} }
Test("Memory Arena") Test("Memory Arena")
{ {
gs_allocator Al = CreateAllocator(Win32Alloc, Win32Free); gs_allocator Al = CreatePlatformAllocator();
gs_memory_arena A = CreateMemoryArena(Al, "test", 128, 4); gs_memory_arena A = MemoryArenaCreate(128, 4, Al, 0, 0, "Test");
// NOTE(PS): We loop through this block 3 times // NOTE(PS): We loop through this block 3 times
// 1. Make sure the arena works out of the box // 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 // 3. Make sure the arena works the same way after freeing
for (int i = 0; i < 3; i++) 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); TestResult(D0.Size == 32);
// NOTE(PS): This should still result in 32 bytes // NOTE(PS): This should still result in 32 bytes
// because its going to align the Cursor after // because its going to align the Cursor after
// it allocates to a multiple of 4 bytes // 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); TestResult(D1.Size == 32);
// NOTE(PS): Allocating bigger than the size remaining // NOTE(PS): Allocating bigger than the size remaining
// in the current cursor // in the current cursor
gs_data D2 = PushSize_(&A, 128, FileNameAndLineNumberString); gs_data D2 = PushSize_(&A, 128, DEBUG_LOC);
TestResult(D2.Size == 128); TestResult(D2.Size == 128);
TestResult(A.CursorsCount != 1); TestResult(A.CursorsRoot != A.CursorsHead);
// NOTE(PS): Because there is still room in cursor // NOTE(PS): Because there is still room in cursor
// 0, the head of this gs_data should be one byte // 0, the head of this gs_data should be one byte
// past the end of D1 // 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); TestResult(D3.Memory == D1.Memory + D1.Size);
if (i == 0) if (i == 0)
{ {
ClearArena(&A); MemoryArenaClear(&A);
} else if (i == 1) { } 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_allocator Al = CreatePlatformAllocator();
gs_memory_arena A = CreateMemoryArena(Al, "test", 128, 4); gs_memory_arena A = MemoryArenaCreate(128, 8, Al, 0, 0, "Test");
// NOTE(PS): This makes sure that the Arena is moving its next allocation // NOTE(PS): This makes sure that the Arena is moving its next allocation
// pointer forward the appropriate amount after each allocation. If it isnt' // pointer forward the appropriate amount after each allocation. If it isnt'
@ -133,16 +128,21 @@ MemoryArenaTests()
} }
TestResult(Success); TestResult(Success);
FreeArena(&A);
} }
int FreeCount = 0; int FreeCount = 0;
int ClearCount = 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); // NOTE(PS): We're going to create thousands of allocations
gs_memory_arena A = CreateMemoryArena(Al, "test", 128, 4); // 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 // NOTE(PS): This is an array of allocation sizes
// As we repeat the loop we will get values out of this array // As we repeat the loop we will get values out of this array
@ -157,19 +157,19 @@ MemoryArenaTests()
u32 RandomSeed = 1923; u32 RandomSeed = 1923;
for (u64 i = 0; i < (4096 * 14); i++) for (u64 i = 0; i < (4096 * 14); i++)
{ {
TESTNextRandom(&RandomSeed); NextRandom(&RandomSeed);
u32 SizeIndex = RandomSeed % RandomSizesCount; u32 SizeIndex = RandomSeed % RandomSizesCount;
u64 RandomSize = RandomSizes[SizeIndex]; u64 RandomSize = RandomSizes[SizeIndex];
if (RandomSize == 0) if (RandomSize == 0)
{ {
ClearArena(&A); MemoryArenaClear(&A);
ClearCount++; ClearCount++;
} else if (RandomSize == 2) { } else if (RandomSize == 2) {
FreeArena(&A); MemoryArenaFree(&A);
FreeCount++; FreeCount++;
} else { } 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 // NOTE(PS): This check has to be >= because the arena
// might have adjusted to maintain alignment on this // might have adjusted to maintain alignment on this
// allocation. // allocation.
@ -179,6 +179,24 @@ MemoryArenaTests()
TestResult(Success); 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_path.h"
#include "../gs_libs/gs_csv.h" #include "../gs_libs/gs_csv.h"
#include "../app/platform_win32/win32_foldhaus_memory.h"
#include "./memory_arena_tests.cpp" #include "./memory_arena_tests.cpp"
gs_memory_arena Scratch = {}; 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) 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 B 123 344 32 foo, bar, blah, baz, whatever
Flower C 55 32 128 foo, bar, blah, baz, whatever)FOO"; 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) 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") Test("gs_string")
{ {