Replaced old memory arena with a new, better one, which also has a test suite
This commit is contained in:
parent
baf4c5d5a6
commit
f261cbd55a
|
@ -6,7 +6,7 @@ SET MyPath=%MyPath:~0,-1%
|
||||||
call %MyPath%\_prebuild_win32.bat app debug msvc
|
call %MyPath%\_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%
|
||||||
|
|
||||||
|
|
|
@ -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
|
@ -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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
@ -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
|
@ -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
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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")
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue