Created basic scope list view
This commit is contained in:
parent
59cac0f435
commit
dba7b1a250
|
@ -219,7 +219,10 @@ DrawLEDsInBufferRangeJob (s32 ThreadID, void* JobData)
|
|||
|
||||
draw_leds_job_data* Data = (draw_leds_job_data*)JobData;
|
||||
|
||||
s32 DrawCommandsCount = Data->OnePastLastIndex - Data->StartIndex;
|
||||
s32 LEDCount = Data->OnePastLastIndex - Data->StartIndex;
|
||||
|
||||
quad_batch_constructor_reserved_range BatchReservedRange = ThreadSafeReserveRangeInQuadConstructor(Data->Batch, LEDCount * 2);
|
||||
s32 TrisUsed = 0;
|
||||
|
||||
r32 HalfWidth = Data->LEDHalfWidth;
|
||||
|
||||
|
@ -235,7 +238,7 @@ DrawLEDsInBufferRangeJob (s32 ThreadID, void* JobData)
|
|||
|
||||
led* LED = Data->LEDs + Data->StartIndex;
|
||||
for (s32 LEDIdx = 0;
|
||||
LEDIdx < DrawCommandsCount;
|
||||
LEDIdx < LEDCount;
|
||||
LEDIdx++)
|
||||
{
|
||||
sacn_pixel SACNColor = Data->Colors[LED->Index];
|
||||
|
@ -248,9 +251,10 @@ DrawLEDsInBufferRangeJob (s32 ThreadID, void* JobData)
|
|||
v4 P2 = P2_In + V4Position;
|
||||
v4 P3 = P3_In + V4Position;
|
||||
|
||||
DEBUG_TRACK_SCOPE(PushLEDTris);
|
||||
PushTri3DOnBatch(Data->Batch, P0, P1, P2, UV0, UV1, UV2, Color, Color, Color);
|
||||
PushTri3DOnBatch(Data->Batch, P0, P2, P3, UV0, UV2, UV3, Color, Color, Color);
|
||||
SetTri3DInBatch(Data->Batch, BatchReservedRange.Start + TrisUsed++,
|
||||
P0, P1, P2, UV0, UV1, UV2, Color, Color, Color);
|
||||
SetTri3DInBatch(Data->Batch, BatchReservedRange.Start + TrisUsed++,
|
||||
P0, P2, P3, UV0, UV2, UV3, Color, Color, Color);
|
||||
|
||||
LED++;
|
||||
}
|
||||
|
@ -476,8 +480,53 @@ INITIALIZE_APPLICATION(InitializeApplication)
|
|||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
HandleInput (app_state* State, input_queue InputQueue, mouse_state Mouse)
|
||||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
|
||||
input_command_registry ActiveCommands = State->DefaultInputCommandRegistry;
|
||||
if (State->Modes.ActiveModesCount > 0)
|
||||
{
|
||||
ActiveCommands = State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].Commands;
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++)
|
||||
{
|
||||
input_entry Event = InputQueue.Entries[EventIdx];
|
||||
|
||||
// NOTE(Peter): These are in the order Down, Up, Held because we want to privalege
|
||||
// Down and Up over Held. In other words, we don't want to call a Held command on the
|
||||
// frame when the button was released, even if the command is registered to both events
|
||||
if (KeyTransitionedDown(Event))
|
||||
{
|
||||
FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue);
|
||||
}
|
||||
else if (KeyTransitionedUp(Event))
|
||||
{
|
||||
FindAndPushExistingCommand(ActiveCommands, Event, Command_Ended, &State->CommandQueue);
|
||||
}
|
||||
else if (KeyHeldDown(Event))
|
||||
{
|
||||
FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute all commands in CommandQueue
|
||||
for (s32 CommandIdx = State->CommandQueue.Used - 1; CommandIdx >= 0; CommandIdx--)
|
||||
{
|
||||
command_queue_entry* Entry = &State->CommandQueue.Commands[CommandIdx];
|
||||
Entry->Command.Proc(State, Entry->Event, Mouse);
|
||||
}
|
||||
|
||||
ClearCommandQueue(&State->CommandQueue);
|
||||
}
|
||||
|
||||
UPDATE_AND_RENDER(UpdateAndRender)
|
||||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
app_state* State = (app_state*)Context.MemoryBase;
|
||||
|
||||
// NOTE(Peter): We do this at the beginning because all the render commands are stored in Transient,
|
||||
|
@ -486,59 +535,7 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
|||
// incorrect to clear the arena, and then access the memory later.
|
||||
ClearArena(State->Transient);
|
||||
|
||||
{
|
||||
input_command_registry ActiveCommands = State->DefaultInputCommandRegistry;
|
||||
if (State->Modes.ActiveModesCount > 0)
|
||||
{
|
||||
ActiveCommands = State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].Commands;
|
||||
}
|
||||
|
||||
for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++)
|
||||
{
|
||||
input_entry Event = InputQueue.Entries[EventIdx];
|
||||
|
||||
// NOTE(Peter): These are in the order Down, Up, Held because we want to privalege
|
||||
// Down and Up over Held. In other words, we don't want to call a Held command on the
|
||||
// frame when the button was released, even if the command is registered to both events
|
||||
if (KeyTransitionedDown(Event))
|
||||
{
|
||||
FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue);
|
||||
}
|
||||
else if (KeyTransitionedUp(Event))
|
||||
{
|
||||
FindAndPushExistingCommand(ActiveCommands, Event, Command_Ended, &State->CommandQueue);
|
||||
}
|
||||
else if (KeyHeldDown(Event))
|
||||
{
|
||||
FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue);
|
||||
}
|
||||
|
||||
if (Event.Key == KeyCode_MouseLeftButton)
|
||||
{
|
||||
Mouse.LeftButtonTransitionedDown = KeyTransitionedDown(Event);
|
||||
Mouse.LeftButtonTransitionedUp = KeyTransitionedUp(Event);
|
||||
}
|
||||
else if (Event.Key == KeyCode_MouseMiddleButton)
|
||||
{
|
||||
Mouse.MiddleButtonTransitionedDown = KeyTransitionedDown(Event);
|
||||
Mouse.MiddleButtonTransitionedUp = KeyTransitionedUp(Event);
|
||||
}
|
||||
else if (Event.Key == KeyCode_MouseRightButton)
|
||||
{
|
||||
Mouse.RightButtonTransitionedDown = KeyTransitionedDown(Event);
|
||||
Mouse.RightButtonTransitionedUp = KeyTransitionedUp(Event);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute all commands in CommandQueue
|
||||
for (s32 CommandIdx = State->CommandQueue.Used - 1; CommandIdx >= 0; CommandIdx--)
|
||||
{
|
||||
command_queue_entry* Entry = &State->CommandQueue.Commands[CommandIdx];
|
||||
Entry->Command.Proc(State, Entry->Event, Mouse);
|
||||
}
|
||||
|
||||
ClearCommandQueue(&State->CommandQueue);
|
||||
}
|
||||
HandleInput(State, InputQueue, Mouse);
|
||||
|
||||
if (State->LEDBufferList)
|
||||
{
|
||||
|
@ -625,6 +622,7 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
|||
|
||||
DEBUG_IF(GlobalDebugServices->Interface.RenderSculpture) // DebugServices RenderSculpture Toggle
|
||||
{
|
||||
DEBUG_TRACK_SCOPE(RenderSculpture);
|
||||
s32 JobsNeeded = PLATFORM_THREAD_COUNT;
|
||||
s32 LEDBufferSize = IntegerDivideRoundUp(State->TotalLEDsCount, JobsNeeded);
|
||||
|
||||
|
@ -738,8 +736,6 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
|||
State->Interface, Context.WindowWidth, Context.WindowHeight - TopBarHeight,
|
||||
Context.DeltaTime, State, State->Camera, Mouse, State->Transient);
|
||||
}
|
||||
|
||||
EndDebugFrame(GlobalDebugServices);
|
||||
}
|
||||
|
||||
CLEANUP_APPLICATION(CleanupApplication)
|
||||
|
|
|
@ -1,21 +1,75 @@
|
|||
#define SCOPE_NAME_LENGTH 256
|
||||
struct scope_time_record
|
||||
struct scope_record
|
||||
{
|
||||
char ScopeName_[SCOPE_NAME_LENGTH];
|
||||
string ScopeName;
|
||||
|
||||
u32 Duration_Cycles;
|
||||
u32 NameHash;
|
||||
s64 StartCycles;
|
||||
s64 EndCycles;
|
||||
s32 CallDepth;
|
||||
};
|
||||
|
||||
struct collated_scope_record
|
||||
{
|
||||
u32 NameHash;
|
||||
s64 TotalCycles;
|
||||
s32 CallCount;
|
||||
|
||||
r32 PercentFrameTime;
|
||||
r32 TotalSeconds;
|
||||
|
||||
r32 AverageSecondsPerCall;
|
||||
};
|
||||
|
||||
#define SCOPE_NAME_BUFFER_LENGTH 128
|
||||
struct scope_name
|
||||
{
|
||||
u32 Hash;
|
||||
string Name;
|
||||
char Buffer[SCOPE_NAME_BUFFER_LENGTH];
|
||||
};
|
||||
|
||||
struct debug_scope_record_list
|
||||
{
|
||||
s32 ThreadId;
|
||||
s32 Max;
|
||||
s32 Count;
|
||||
scope_record* Calls;
|
||||
|
||||
s32 CurrentScopeCallDepth;
|
||||
};
|
||||
|
||||
#define DEBUG_FRAME_GROW_SIZE 8102
|
||||
struct debug_frame
|
||||
{
|
||||
s64 FrameStartCycles;
|
||||
s64 FrameEndCycles;
|
||||
|
||||
s32 ScopeNamesMax;
|
||||
scope_name* ScopeNamesHash;
|
||||
|
||||
s32 ThreadCount;
|
||||
debug_scope_record_list* ThreadCalls;
|
||||
|
||||
s32 CollatedScopesMax;
|
||||
collated_scope_record* CollatedScopes;
|
||||
};
|
||||
|
||||
#define FRAME_VIEW_PROFILER 0
|
||||
#define FRAME_VIEW_SCOPE_LIST 1
|
||||
|
||||
struct debug_interface
|
||||
{
|
||||
b32 ShowCameraMouse;
|
||||
b32 ShowTrackedScopes;
|
||||
b32 RenderSculpture;
|
||||
b32 SendSACNData;
|
||||
|
||||
s32 FrameView;
|
||||
};
|
||||
|
||||
typedef s32 debug_get_thread_id();
|
||||
typedef s64 debug_timing_proc();
|
||||
typedef u8* debug_alloc(s32 ElementSize, s32 ElementCount);
|
||||
typedef u8* debug_realloc(u8* Memory, s32 OldSize, s32 NewSize);
|
||||
|
||||
#define HISTOGRAM_DEPTH 10
|
||||
struct debug_histogram_entry
|
||||
|
@ -34,34 +88,101 @@ struct debug_histogram_entry
|
|||
u32 Total_CallCount;
|
||||
};
|
||||
|
||||
#define SCOPE_HISTOGRAM_SIZE 512
|
||||
#define DEBUG_FRAME_COUNT 128
|
||||
struct debug_services
|
||||
{
|
||||
s32 TrackedScopesCount;
|
||||
s32 TrackedScopesMax;
|
||||
scope_time_record* TrackedScopes;
|
||||
|
||||
s64 PerformanceCountFrequency;
|
||||
memory_arena DebugStorage;
|
||||
|
||||
b32 RecordFrames;
|
||||
s32 CurrentDebugFrame;
|
||||
debug_frame Frames[DEBUG_FRAME_COUNT];
|
||||
|
||||
debug_interface Interface;
|
||||
|
||||
debug_get_thread_id* GetThreadId;
|
||||
debug_timing_proc* GetWallClock;
|
||||
|
||||
debug_histogram_entry* ScopeHistogramUnsorted;
|
||||
debug_histogram_entry* ScopeHistogramSorted;
|
||||
|
||||
s32 ScopeHistogramUsed;
|
||||
debug_alloc* Alloc;
|
||||
debug_realloc* Realloc;
|
||||
};
|
||||
|
||||
internal void
|
||||
InitDebugServices (debug_services* Services, u8* Memory, s32 MemorySize, s32 TrackedScopesMax, s64 PerformanceCountFrequency)
|
||||
InitializeDebugFrame (debug_frame* Frame, s32 NameHashMax, s32 ThreadCount, s32 ScopeCallsMax, debug_services* Services)
|
||||
{
|
||||
InitMemoryArena(&Services->DebugStorage, Memory, MemorySize, 0);
|
||||
Frame->ScopeNamesMax = NameHashMax;
|
||||
Frame->ScopeNamesHash = (scope_name*)Services->Alloc(sizeof(scope_name), NameHashMax);
|
||||
|
||||
Services->TrackedScopesCount = 0;
|
||||
Services->TrackedScopesMax = TrackedScopesMax;
|
||||
Services->TrackedScopes = PushArray(&Services->DebugStorage, scope_time_record, TrackedScopesMax);
|
||||
// NOTE(Peter): We use the same size as scope names because we're only storing a single instance
|
||||
// per scope. If ScopeNamesMax can't hold all the scopes, this will never get filled and
|
||||
// we should assert and recompile with a resized NameHashMax
|
||||
Frame->CollatedScopesMax = NameHashMax;
|
||||
Frame->CollatedScopes = (collated_scope_record*)Services->Alloc(sizeof(collated_scope_record), NameHashMax);
|
||||
|
||||
for (s32 i = 0; i < Frame->ScopeNamesMax; i++)
|
||||
{
|
||||
scope_name* Entry = Frame->ScopeNamesHash + i;
|
||||
Entry->Name = MakeString(Entry->Buffer, 0, SCOPE_NAME_BUFFER_LENGTH);
|
||||
}
|
||||
|
||||
Frame->ThreadCount = ThreadCount;
|
||||
Frame->ThreadCalls = (debug_scope_record_list*)Services->Alloc(sizeof(debug_scope_record_list),
|
||||
ThreadCount);
|
||||
|
||||
for (s32 i = 0; i < ThreadCount; i++)
|
||||
{
|
||||
Frame->ThreadCalls[i].Max = ScopeCallsMax;
|
||||
Frame->ThreadCalls[i].Count = 0;
|
||||
Frame->ThreadCalls[i].Calls = (scope_record*)Services->Alloc(sizeof(scope_record), ScopeCallsMax);
|
||||
Frame->ThreadCalls[i].CurrentScopeCallDepth = 0;
|
||||
Frame->ThreadCalls[i].ThreadId = 0;
|
||||
}
|
||||
|
||||
for (s32 c = 0; c < Frame->CollatedScopesMax; c++)
|
||||
{
|
||||
Frame->CollatedScopes[c].NameHash = 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
StartDebugFrame(debug_frame* Frame, debug_services* Services)
|
||||
{
|
||||
Frame->FrameStartCycles = Services->GetWallClock();
|
||||
for (s32 i = 0; i < Frame->ThreadCount; i++)
|
||||
{
|
||||
Frame->ThreadCalls[i].Count = 0;
|
||||
Frame->ThreadCalls[i].CurrentScopeCallDepth = 0;
|
||||
}
|
||||
|
||||
for (s32 c = 0; c < Frame->CollatedScopesMax; c++)
|
||||
{
|
||||
s32 Hash = Frame->CollatedScopes[c].NameHash;
|
||||
Frame->CollatedScopes[c] = {};
|
||||
Frame->CollatedScopes[c].NameHash = Hash;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
InitDebugServices (debug_services* Services,
|
||||
s64 PerformanceCountFrequency,
|
||||
debug_alloc* Alloc,
|
||||
debug_realloc* Realloc,
|
||||
debug_timing_proc* GetWallClock,
|
||||
debug_get_thread_id* GetThreadId,
|
||||
s32 ThreadCount)
|
||||
{
|
||||
Services->Alloc = Alloc;
|
||||
Services->Realloc = Realloc;
|
||||
Services->GetWallClock = GetWallClock;
|
||||
Services->GetThreadId = GetThreadId;
|
||||
|
||||
Services->RecordFrames = true;
|
||||
|
||||
Services->CurrentDebugFrame = 0;
|
||||
s32 NameHashMax = 4096;
|
||||
s32 ScopeCallsMax = 4096;
|
||||
for (s32 i = 0; i < DEBUG_FRAME_COUNT; i++)
|
||||
{
|
||||
InitializeDebugFrame(&Services->Frames[i], NameHashMax, ThreadCount, ScopeCallsMax, Services);
|
||||
}
|
||||
|
||||
Services->Interface.RenderSculpture = true;
|
||||
|
||||
|
@ -71,182 +192,197 @@ InitDebugServices (debug_services* Services, u8* Memory, s32 MemorySize, s32 Tra
|
|||
Services->Interface.ShowTrackedScopes = false;
|
||||
Services->Interface.RenderSculpture = true;
|
||||
Services->Interface.SendSACNData = false;
|
||||
|
||||
Services->ScopeHistogramUnsorted = PushArray(&Services->DebugStorage, debug_histogram_entry, SCOPE_HISTOGRAM_SIZE);
|
||||
Services->ScopeHistogramSorted = PushArray(&Services->DebugStorage, debug_histogram_entry, SCOPE_HISTOGRAM_SIZE);
|
||||
|
||||
Services->ScopeHistogramUsed = 0;
|
||||
}
|
||||
|
||||
internal debug_frame*
|
||||
GetCurrentDebugFrame (debug_services* Services)
|
||||
{
|
||||
debug_frame* Result = Services->Frames + Services->CurrentDebugFrame;
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal debug_frame*
|
||||
GetLastDebugFrame(debug_services* Services)
|
||||
{
|
||||
s32 Index = (Services->CurrentDebugFrame - 1);
|
||||
if (Index < 0) { Index += DEBUG_FRAME_COUNT; }
|
||||
debug_frame* Result = Services->Frames + Index;
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal s32
|
||||
DEBUGFindScopeHistogram (debug_services* Services, string Name)
|
||||
GetIndexForNameHash(debug_frame* Frame, u32 NameHash)
|
||||
{
|
||||
s32 Result = -1;
|
||||
for (s32 i = 0; i < SCOPE_HISTOGRAM_SIZE; i++)
|
||||
|
||||
for (s32 Offset = 0; Offset < Frame->ScopeNamesMax; Offset++)
|
||||
{
|
||||
if (StringsEqual(Services->ScopeHistogramUnsorted[i].ScopeName, Name))
|
||||
u32 Index = (NameHash + Offset) % Frame->ScopeNamesMax;
|
||||
if ((Frame->ScopeNamesHash[Index].Hash == NameHash))
|
||||
{
|
||||
Result = i;
|
||||
Result = Index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(Peter): Its not technically wrong to return a -1 here, just means we didn't find it.
|
||||
// At the time of writing however, this function is only being called in contexts where we
|
||||
// know there should be an entry in the Name table, so a -1 actually indicates a problem.
|
||||
Assert(Result >= 0);
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal s32
|
||||
DEBUGAddScopeHistogram (debug_services* Services, scope_time_record Record)
|
||||
internal debug_scope_record_list*
|
||||
GetScopeListForThreadInFrame(debug_services* Services, debug_frame* Frame)
|
||||
{
|
||||
Assert(Services->ScopeHistogramUsed < SCOPE_HISTOGRAM_SIZE);
|
||||
debug_scope_record_list* List = 0;
|
||||
|
||||
s32 Result = Services->ScopeHistogramUsed++;
|
||||
|
||||
debug_histogram_entry* Entry = Services->ScopeHistogramUnsorted + Result;
|
||||
Entry->ScopeName = MakeString(Entry->ScopeName_, 256);
|
||||
|
||||
Entry->CurrentFrame = 0;
|
||||
Entry->Average_Cycles = 0;
|
||||
Entry->Average_CallCount = 0;
|
||||
Entry->Total_Cycles = 0;
|
||||
Entry->Total_CallCount = 0;
|
||||
|
||||
CopyStringTo(Record.ScopeName, &Entry->ScopeName);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal void
|
||||
DEBUGRecordScopeInHistogram (debug_services* Services, s32 Index, scope_time_record Record)
|
||||
{
|
||||
debug_histogram_entry* Entry = Services->ScopeHistogramUnsorted + Index;
|
||||
s32 FrameIndex = Entry->CurrentFrame;
|
||||
if (FrameIndex >= 0 && FrameIndex < HISTOGRAM_DEPTH)
|
||||
s32 CurrentThreadId = Services->GetThreadId();
|
||||
for (s32 Offset = 0; Offset < Frame->ThreadCount; Offset++)
|
||||
{
|
||||
Entry->PerFrame_Cycles[FrameIndex] += Record.Duration_Cycles;
|
||||
Entry->PerFrame_CallCount[FrameIndex]++;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
DEBUGCacheScopeHistogramValues (debug_histogram_entry* Histogram)
|
||||
{
|
||||
Histogram->Total_Cycles = 0;
|
||||
Histogram->Total_CallCount = 0;
|
||||
|
||||
// TODO(Peter): This doesn't account for the first frames when the histogram isn't full
|
||||
for (s32 i = 0; i < HISTOGRAM_DEPTH; i++)
|
||||
{
|
||||
Histogram->Total_Cycles += Histogram->PerFrame_Cycles[i];
|
||||
Histogram->Total_CallCount += Histogram->PerFrame_CallCount[i];
|
||||
}
|
||||
|
||||
Histogram->Average_Cycles = (Histogram->Total_Cycles / HISTOGRAM_DEPTH);
|
||||
Histogram->Average_CallCount = (Histogram->Total_CallCount / HISTOGRAM_DEPTH);
|
||||
}
|
||||
|
||||
internal void
|
||||
DEBUGSortedHistogramInsert(debug_histogram_entry Source, debug_histogram_entry* DestList, s32 DestCount, s32 Max)
|
||||
{
|
||||
s32 CurrentFrame0 = Source.CurrentFrame;
|
||||
s32 V0 = Source.Average_Cycles; //PerFrame_Cycles[CurrentFrame0];
|
||||
if (DestCount > 0)
|
||||
{
|
||||
for (s32 i = DestCount - 1; i >= 0; i--)
|
||||
s32 Index = (CurrentThreadId + Offset) % Frame->ThreadCount;
|
||||
if (Frame->ThreadCalls[Index].ThreadId == CurrentThreadId)
|
||||
{
|
||||
s32 CurrentFrame1 = DestList[i].CurrentFrame;
|
||||
s32 V1 = DestList[i].Average_Cycles; //PerFrame_Cycles[CurrentFrame1];
|
||||
if (V0 < V1)
|
||||
{
|
||||
DestList[i + 1] = Source;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
DestList[i + 1] = DestList[i];
|
||||
}
|
||||
List = Frame->ThreadCalls + Index;
|
||||
break;
|
||||
}
|
||||
else if (Frame->ThreadCalls[Index].ThreadId == 0)
|
||||
{
|
||||
Frame->ThreadCalls[Index].ThreadId = CurrentThreadId;
|
||||
List = Frame->ThreadCalls + Index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DestList[0] = Source;
|
||||
}
|
||||
|
||||
Assert(List);
|
||||
return List;
|
||||
}
|
||||
|
||||
internal void
|
||||
DEBUGSortHistogram(debug_histogram_entry* Source, debug_histogram_entry* Dest, s32 Count, s32 Max)
|
||||
CollateThreadScopeCalls (debug_scope_record_list* ThreadRecords, debug_frame* Frame)
|
||||
{
|
||||
for (s32 i = 0; i < Count; i++)
|
||||
for (s32 i = 0; i < ThreadRecords->Count; i++)
|
||||
{
|
||||
DEBUGSortedHistogramInsert(Source[i], Dest, i, Max);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
DEBUGCollateScopeRecords (debug_services* Services)
|
||||
{
|
||||
for (s32 i = 0; i < Services->TrackedScopesCount; i++)
|
||||
{
|
||||
scope_time_record Record = Services->TrackedScopes[i];
|
||||
s32 Index = DEBUGFindScopeHistogram(Services, Record.ScopeName);
|
||||
if (Index < 0)
|
||||
scope_record Record = ThreadRecords->Calls[i];
|
||||
s32 Index = GetIndexForNameHash (Frame, Record.NameHash);
|
||||
collated_scope_record* CollatedRecord = Frame->CollatedScopes + Index;
|
||||
|
||||
if (CollatedRecord->NameHash != Record.NameHash)
|
||||
{
|
||||
Index = DEBUGAddScopeHistogram(Services, Record);
|
||||
CollatedRecord->NameHash = Record.NameHash;
|
||||
CollatedRecord->TotalCycles = 0;
|
||||
CollatedRecord->CallCount = 0;
|
||||
}
|
||||
|
||||
DEBUGRecordScopeInHistogram(Services, Index, Record);
|
||||
CollatedRecord->TotalCycles += Record.EndCycles - Record.StartCycles;
|
||||
CollatedRecord->CallCount += 1;
|
||||
}
|
||||
|
||||
for (s32 h = 0; h < Services->ScopeHistogramUsed; h++)
|
||||
{
|
||||
DEBUGCacheScopeHistogramValues(Services->ScopeHistogramUnsorted + h);
|
||||
}
|
||||
|
||||
DEBUGSortHistogram(Services->ScopeHistogramUnsorted,
|
||||
Services->ScopeHistogramSorted,
|
||||
Services->ScopeHistogramUsed,
|
||||
SCOPE_HISTOGRAM_SIZE);
|
||||
}
|
||||
|
||||
internal void
|
||||
EndDebugFrame (debug_services* Services)
|
||||
{
|
||||
DEBUGCollateScopeRecords(Services);
|
||||
debug_frame* ClosingFrame = GetCurrentDebugFrame(Services);
|
||||
ClosingFrame->FrameEndCycles = Services->GetWallClock();
|
||||
|
||||
GSZeroMemory((u8*)Services->TrackedScopes, sizeof(scope_time_record) * Services->TrackedScopesMax);
|
||||
Services->TrackedScopesCount = 0;
|
||||
s64 FrameTotalCycles = ClosingFrame->FrameEndCycles - ClosingFrame->FrameStartCycles;
|
||||
|
||||
for (s32 i = 0; i < Services->ScopeHistogramUsed; i++)
|
||||
for (s32 t = 0; t < ClosingFrame->ThreadCount; t++)
|
||||
{
|
||||
s32 NewFrame = Services->ScopeHistogramUnsorted[i].CurrentFrame + 1;
|
||||
if (NewFrame >= HISTOGRAM_DEPTH)
|
||||
{
|
||||
NewFrame = 0;
|
||||
}
|
||||
Services->ScopeHistogramUnsorted[i].CurrentFrame = NewFrame;
|
||||
Services->ScopeHistogramUnsorted[i].PerFrame_Cycles[NewFrame] = 0;
|
||||
Services->ScopeHistogramUnsorted[i].PerFrame_CallCount[NewFrame] = 0;
|
||||
CollateThreadScopeCalls(ClosingFrame->ThreadCalls + t, ClosingFrame);
|
||||
}
|
||||
|
||||
for (s32 n = 0; n < ClosingFrame->ScopeNamesMax; n++)
|
||||
{
|
||||
if (ClosingFrame->ScopeNamesHash[n].Hash != 0)
|
||||
{
|
||||
collated_scope_record* CollatedRecord = ClosingFrame->CollatedScopes + n;
|
||||
CollatedRecord->TotalSeconds = (r32)CollatedRecord->TotalCycles / (r32)Services->PerformanceCountFrequency;
|
||||
CollatedRecord->PercentFrameTime = (r32)CollatedRecord->TotalCycles / (r32)FrameTotalCycles;
|
||||
CollatedRecord->AverageSecondsPerCall = CollatedRecord->TotalSeconds / CollatedRecord->CallCount;
|
||||
}
|
||||
}
|
||||
|
||||
Services->CurrentDebugFrame = (Services->CurrentDebugFrame + 1) % DEBUG_FRAME_COUNT;
|
||||
StartDebugFrame(&Services->Frames[Services->CurrentDebugFrame], Services);
|
||||
}
|
||||
|
||||
internal scope_time_record*
|
||||
PushScopeRecord(string ScopeName, debug_services* Services)
|
||||
internal u32
|
||||
HashScopeName (char* ScopeName)
|
||||
{
|
||||
scope_time_record* Result = 0;
|
||||
// djb2 hash
|
||||
u32 Hash = 5381;
|
||||
char* C = ScopeName;
|
||||
while(*C)
|
||||
{
|
||||
Hash = ((Hash << 5) + Hash) + *C;
|
||||
C++;
|
||||
}
|
||||
return Hash;
|
||||
}
|
||||
|
||||
internal scope_name*
|
||||
GetOrAddNameHashEntry(debug_frame* Frame, u32 NameHash)
|
||||
{
|
||||
scope_name* Result = 0;
|
||||
|
||||
s32 OnePastIndex = InterlockedIncrement((long*)&Services->TrackedScopesCount);
|
||||
Assert(OnePastIndex <= Services->TrackedScopesMax);
|
||||
Result = Services->TrackedScopes + OnePastIndex - 1;
|
||||
|
||||
Result->ScopeName = MakeString(Result->ScopeName_, SCOPE_NAME_LENGTH);
|
||||
CopyStringTo(ScopeName, &Result->ScopeName);
|
||||
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))
|
||||
{
|
||||
Result = Frame->ScopeNamesHash + Index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal void
|
||||
LogScopeTime (debug_services* Services, string ScopeName, u64 CyclesElapsed)
|
||||
internal u32
|
||||
BeginTrackingScopeAndGetNameHash (debug_services* Services, char* ScopeName)
|
||||
{
|
||||
scope_time_record* Record = PushScopeRecord(ScopeName, Services);
|
||||
Record->Duration_Cycles = CyclesElapsed;
|
||||
debug_frame* CurrentFrame = GetCurrentDebugFrame(Services);
|
||||
debug_scope_record_list* ThreadList = GetScopeListForThreadInFrame(Services, CurrentFrame);
|
||||
|
||||
ThreadList->CurrentScopeCallDepth++;
|
||||
|
||||
u32 NameHash = HashScopeName(ScopeName);
|
||||
scope_name* Entry = GetOrAddNameHashEntry(CurrentFrame, NameHash);
|
||||
if (Entry->Hash == 0) // If its new
|
||||
{
|
||||
Entry->Hash = NameHash;
|
||||
// TODO(Peter): need to initialize all entry name strings to point at the buffer
|
||||
// This will break eventually. when it does, do this ^^^^ when on startup
|
||||
CopyCharArrayToString(ScopeName, &Entry->Name);
|
||||
}
|
||||
|
||||
return NameHash;
|
||||
}
|
||||
|
||||
internal void
|
||||
PushScopeTimeOnFrame (debug_services* Services, s32 NameHash, u64 StartCycles, u64 EndCycles)
|
||||
{
|
||||
debug_frame* CurrentFrame = GetCurrentDebugFrame(Services);
|
||||
debug_scope_record_list* ThreadList = GetScopeListForThreadInFrame(Services, CurrentFrame);
|
||||
|
||||
if (ThreadList->Count >= ThreadList->Max)
|
||||
{
|
||||
s32 CurrentSize = ThreadList->Max * sizeof(scope_record);
|
||||
s32 NewMax = (ThreadList->Max + DEBUG_FRAME_GROW_SIZE);
|
||||
s32 NewSize = NewMax * sizeof(scope_record);
|
||||
ThreadList->Calls = (scope_record*)Services->Realloc((u8*)ThreadList->Calls, CurrentSize, NewSize);
|
||||
ThreadList->Max = NewMax;
|
||||
}
|
||||
|
||||
Assert(ThreadList->Count < ThreadList->Max);
|
||||
|
||||
s32 EntryIndex = ThreadList->Count++;
|
||||
scope_record* Record = ThreadList->Calls + EntryIndex;
|
||||
Record->NameHash = NameHash;
|
||||
Record->StartCycles = StartCycles;
|
||||
Record->EndCycles = EndCycles;
|
||||
Record->CallDepth = --ThreadList->CurrentScopeCallDepth;
|
||||
}
|
||||
|
||||
internal r32 DEBUGGetSecondsElapsed (s64 Start, s64 End, r32 PerformanceCountFrequency)
|
||||
|
@ -255,7 +391,7 @@ internal r32 DEBUGGetSecondsElapsed (s64 Start, s64 End, r32 PerformanceCountFre
|
|||
return Result;
|
||||
}
|
||||
|
||||
#if 1
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_TRACK_FUNCTION scope_tracker ScopeTracker (__FUNCTION__, GlobalDebugServices)
|
||||
#define DEBUG_TRACK_SCOPE(name) scope_tracker ScopeTracker_##name (#name, GlobalDebugServices)
|
||||
#else
|
||||
|
@ -265,27 +401,29 @@ internal r32 DEBUGGetSecondsElapsed (s64 Start, s64 End, r32 PerformanceCountFre
|
|||
struct scope_tracker
|
||||
{
|
||||
s64 ScopeStart;
|
||||
|
||||
char ScopeName_[SCOPE_NAME_LENGTH];
|
||||
string ScopeName;
|
||||
|
||||
u32 ScopeNameHash;
|
||||
debug_services* DebugServices;
|
||||
|
||||
scope_tracker(char* ScopeName, debug_services* DebugServices)
|
||||
{
|
||||
this->ScopeName = MakeString(this->ScopeName_, SCOPE_NAME_LENGTH);
|
||||
CopyCharArrayToString(ScopeName, &this->ScopeName);
|
||||
this->ScopeStart = DebugServices->GetWallClock();
|
||||
this->DebugServices = DebugServices;
|
||||
if (DebugServices->RecordFrames)
|
||||
{
|
||||
this->ScopeNameHash = BeginTrackingScopeAndGetNameHash(DebugServices, ScopeName);
|
||||
this->ScopeStart = DebugServices->GetWallClock();
|
||||
this->DebugServices = DebugServices;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->DebugServices = 0;
|
||||
}
|
||||
}
|
||||
|
||||
~scope_tracker()
|
||||
{
|
||||
s64 ScopeEnd = DebugServices->GetWallClock();
|
||||
u32 CyclesElapsed = (u32)(ScopeEnd - this->ScopeStart);
|
||||
#if 0
|
||||
r32 SecondsElapsed = DEBUGGetSecondsElapsed(this->ScopeStart, ScopeEnd, DebugServices->PerformanceCountFrequency);
|
||||
#endif
|
||||
LogScopeTime(DebugServices, ScopeName, CyclesElapsed);
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,3 +1,194 @@
|
|||
|
||||
internal void
|
||||
RenderProfiler_ScopeVisualization(render_command_buffer* RenderBuffer,
|
||||
interface_config Interface, mouse_state Mouse,
|
||||
v2 Min, v2 Max,
|
||||
debug_frame* VisibleFrame, memory_arena* Memory)
|
||||
{
|
||||
v4 ThreadColors[] = {
|
||||
v4{.73f, .33f, .83f, 1},
|
||||
v4{0, .50f, .50f, 1},
|
||||
v4{.83f, 0, 0, 1},
|
||||
v4{.33f, .49f, .83f, 1},
|
||||
v4{.74f, .40f, .25f, 1},
|
||||
};
|
||||
|
||||
r32 Width = Max.x - Min.x;
|
||||
r32 DepthHeight = 64;
|
||||
|
||||
s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
|
||||
s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles;
|
||||
|
||||
debug_scope_record_list* ThreadScopeCalls = GetScopeListForThreadInFrame(GlobalDebugServices,
|
||||
VisibleFrame);
|
||||
|
||||
MakeStringBuffer(String, 256);
|
||||
for (s32 i = 0; i < ThreadScopeCalls->Count; i++)
|
||||
{
|
||||
scope_record* Record = ThreadScopeCalls->Calls + i;
|
||||
scope_name* Name = GetOrAddNameHashEntry(VisibleFrame, Record->NameHash);
|
||||
r32 PercentStart = (r32)(Record->StartCycles - FrameStartCycles) / (r32)FrameTotalCycles;
|
||||
r32 PercentEnd = (r32)(Record->EndCycles - FrameStartCycles) / (r32)FrameTotalCycles;
|
||||
|
||||
v2 ScopeMin = v2{Min.x + (Width * PercentStart), Max.y - ((Record->CallDepth + 1) * DepthHeight)};
|
||||
v2 ScopeMax = v2{Min.x + (Width * PercentEnd), ScopeMin.y + (DepthHeight - 4)};
|
||||
|
||||
if ((ScopeMax.x - ScopeMin.x) >= 1)
|
||||
{
|
||||
v4 Color = ThreadColors[0];
|
||||
if (PointIsInRange(Mouse.Pos, ScopeMin, ScopeMax))
|
||||
{
|
||||
Color = GreenV4;
|
||||
}
|
||||
|
||||
PushRenderQuad2D(RenderBuffer, ScopeMin, ScopeMax, Color);
|
||||
PushRenderBoundingBox2D(RenderBuffer, ScopeMin, ScopeMax, 1, BlackV4);
|
||||
|
||||
if (PointIsInRange(Mouse.Pos, ScopeMin, ScopeMax))
|
||||
{
|
||||
PushRenderQuad2D(RenderBuffer, Mouse.Pos, Mouse.Pos + v2{256, 32}, BlackV4);
|
||||
PrintF(&String, "%.*s : %d - %d", Name->Name.Length, Name->Name.Memory, Record->StartCycles, Record->EndCycles);
|
||||
DrawString(RenderBuffer, String, Interface.Font, Mouse.Pos, WhiteV4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
RenderProfiler_ListVisualization(render_command_buffer* RenderBuffer,
|
||||
interface_config Interface, mouse_state Mouse,
|
||||
v2 Min, v2 Max,
|
||||
debug_frame* VisibleFrame, memory_arena* Memory)
|
||||
{
|
||||
MakeStringBuffer(String, 256);
|
||||
|
||||
r32 YAt = Max.y - Interface.Font->PixelHeight;
|
||||
r32 Column0X = Min.x;
|
||||
r32 Column1X = Column0X + 256;
|
||||
r32 Column2X = Column1X + 128;
|
||||
r32 Column3X = Column2X + 128;
|
||||
r32 Column4X = Column3X + 100;
|
||||
|
||||
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.Length, NameEntry.Name.Memory);
|
||||
DrawString(RenderBuffer, String, Interface.Font, v2{Column0X, YAt}, WhiteV4);
|
||||
|
||||
PrintF(&String, "%f", CollatedRecord->PercentFrameTime);
|
||||
DrawString(RenderBuffer, String, Interface.Font, v2{Column1X, YAt}, WhiteV4);
|
||||
|
||||
PrintF(&String, "%fs", CollatedRecord->TotalSeconds);
|
||||
DrawString(RenderBuffer, String, Interface.Font, v2{Column2X, YAt}, WhiteV4);
|
||||
|
||||
PrintF(&String, "%dcy", CollatedRecord->TotalCycles);
|
||||
DrawString(RenderBuffer, String, Interface.Font, v2{Column3X, YAt}, WhiteV4);
|
||||
|
||||
PrintF(&String, "%d calls", CollatedRecord->CallCount);
|
||||
DrawString(RenderBuffer, String, Interface.Font, v2{Column4X, YAt}, WhiteV4);
|
||||
|
||||
YAt -= Interface.Font->PixelHeight + 4;
|
||||
|
||||
if (YAt < Min.y) { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
DrawDebugFrameList (render_command_buffer* RenderBuffer, interface_config Interface, mouse_state Mouse, v2 BoundsMin, v2 BoundsMax, memory_arena* Memory)
|
||||
{
|
||||
string String = InitializeEmptyString(PushArray(Memory, char, 256), 256);
|
||||
|
||||
v4 FrameColors[] = { GreenV4, YellowV4, RedV4, WhiteV4 };
|
||||
|
||||
r32 FrameListHeight = 64;
|
||||
v2 FrameListMin = v2{BoundsMin.x + 16, BoundsMax.y - (16 + FrameListHeight)};
|
||||
v2 FrameListMax = v2{BoundsMax.x - 16, BoundsMax.y - 16};
|
||||
|
||||
r32 FrameListPadding = 4;
|
||||
r32 FrameListInnerWidth = (FrameListMax.x - FrameListMin.x) - (FrameListPadding * 2);
|
||||
|
||||
r32 SingleFrameStep = FrameListInnerWidth / DEBUG_FRAME_COUNT;
|
||||
r32 SingleFrameWidth = (r32)((s32)SingleFrameStep - 2);
|
||||
|
||||
PushRenderBoundingBox2D(RenderBuffer, FrameListMin, FrameListMax, 2, WhiteV4);
|
||||
|
||||
if (PointIsInRange(Mouse.Pos, FrameListMin, FrameListMax) &&
|
||||
MouseButtonHeldDown(Mouse.LeftButtonState))
|
||||
{
|
||||
r32 LocalMouseX = (Mouse.Pos.x - FrameListMin.x) + FrameListPadding;
|
||||
s32 ClosestFrameIndex = (LocalMouseX / SingleFrameStep);
|
||||
|
||||
if (ClosestFrameIndex >= 0 && ClosestFrameIndex < DEBUG_FRAME_COUNT)
|
||||
{
|
||||
GlobalDebugServices->RecordFrames = false;
|
||||
GlobalDebugServices->CurrentDebugFrame = ClosestFrameIndex;
|
||||
}
|
||||
}
|
||||
|
||||
for (s32 F = 0; F < DEBUG_FRAME_COUNT; F++)
|
||||
{
|
||||
v2 Min = v2{FrameListMin.x + FrameListPadding + (F * SingleFrameStep), FrameListMin.y + 4};
|
||||
v2 Max = v2{Min.x + SingleFrameWidth, FrameListMax.y - 4};
|
||||
|
||||
s32 FramesAgo = (GlobalDebugServices->CurrentDebugFrame - F);
|
||||
if (FramesAgo < 0) { FramesAgo += DEBUG_FRAME_COUNT; }
|
||||
v4 Color = FrameColors[GSClamp(0, FramesAgo, 3)];
|
||||
PushRenderQuad2D(RenderBuffer, Min, Max, Color);
|
||||
}
|
||||
|
||||
debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices);
|
||||
s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
|
||||
s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles;
|
||||
|
||||
PrintF(&String, "Frame %d - Total Cycles: %lld",
|
||||
GlobalDebugServices->CurrentDebugFrame - 1,
|
||||
FrameTotalCycles);
|
||||
DrawString(RenderBuffer, String, Interface.Font, FrameListMin - v2{0, 32}, WhiteV4);
|
||||
|
||||
v2 ButtonMin = v2{FrameListMax.x - 128, FrameListMin.y - 32};
|
||||
v2 ButtonMax = ButtonMin + v2{128, 28};
|
||||
button_result ShouldResumeRecording = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax,
|
||||
MakeString("Resume Recording"), Interface, Mouse);
|
||||
if (ShouldResumeRecording.Pressed)
|
||||
{
|
||||
GlobalDebugServices->RecordFrames = true;
|
||||
}
|
||||
|
||||
ButtonMin = v2{FrameListMin.x, FrameListMin.y - 60};
|
||||
ButtonMax = v2{FrameListMin.x + 128, FrameListMin.y - 42};
|
||||
button_result ActivateScopeView = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax,
|
||||
MakeString("Scope View"), Interface, Mouse);
|
||||
|
||||
ButtonMin.x += 152;
|
||||
ButtonMax.x += 152;
|
||||
button_result ActivateListView = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax,
|
||||
MakeString("List View"), Interface, Mouse);
|
||||
|
||||
if (ActivateScopeView.Pressed) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_PROFILER; }
|
||||
if (ActivateListView.Pressed) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_SCOPE_LIST; }
|
||||
|
||||
v2 ViewModeMin = v2{FrameListMin.x, BoundsMin.y};
|
||||
v2 ViewModeMax = v2{FrameListMax.x, FrameListMin.y - 96};
|
||||
|
||||
if (GlobalDebugServices->Interface.FrameView == FRAME_VIEW_PROFILER)
|
||||
{
|
||||
RenderProfiler_ScopeVisualization(RenderBuffer, Interface, Mouse,
|
||||
ViewModeMin, ViewModeMax,
|
||||
VisibleFrame, Memory);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderProfiler_ListVisualization(RenderBuffer, Interface, Mouse,
|
||||
ViewModeMin, ViewModeMax,
|
||||
VisibleFrame, Memory);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_config Interface, r32 WindowWidth, r32 WindowHeight, r32 DeltaTime, app_state* State, camera Camera, mouse_state Mouse, memory_arena* Transient)
|
||||
{
|
||||
|
@ -10,7 +201,7 @@ DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_c
|
|||
|
||||
string DebugString = InitializeEmptyString(PushArray(Transient, char, 256), 256);
|
||||
|
||||
if (GlobalDebugServices->Interface.ShowCameraMouse || GlobalDebugServices->Interface.ShowTrackedScopes)
|
||||
if (GlobalDebugServices->Interface.ShowCameraMouse)
|
||||
{
|
||||
PushRenderQuad2D(RenderBuffer,
|
||||
v2{TopOfDebugView.x, TopOfDebugView.y - 500},
|
||||
|
@ -100,12 +291,17 @@ DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_c
|
|||
DrawString(RenderBuffer, DebugString, Interface.Font, TopOfScreenLinePos, v4{1.0f, 1.0f, 1.0f, 1.0f});
|
||||
TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font);
|
||||
|
||||
b32 LeftButtonIsDown = (Mouse.LeftButtonState & KeyState_IsDown) > 0;
|
||||
b32 LeftButtonWasDown = (Mouse.LeftButtonState & KeyState_WasDown) > 0;
|
||||
|
||||
s32 MousePrecision = 0;
|
||||
PrintF(&DebugString, "Mouse Pos: (%.*f, %.*f) Down: (%.*f, %.*f)",
|
||||
PrintF(&DebugString, "Mouse Pos: (%.*f, %.*f) Down: (%.*f, %.*f) State: %s %s",
|
||||
MousePrecision, Mouse.Pos.x,
|
||||
MousePrecision, Mouse.Pos.y,
|
||||
MousePrecision, Mouse.DownPos.x,
|
||||
MousePrecision, Mouse.DownPos.y);
|
||||
MousePrecision, Mouse.DownPos.y,
|
||||
(LeftButtonIsDown ? "Is Down" : "Is Not Down"),
|
||||
(LeftButtonWasDown ? "Was Down" : "Was Not Down"));
|
||||
DrawString(RenderBuffer, DebugString, Interface.Font,
|
||||
TopOfScreenLinePos, WhiteV4);
|
||||
TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font);
|
||||
|
@ -116,12 +312,24 @@ DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_c
|
|||
DrawString(RenderBuffer, DebugString, Interface.Font,
|
||||
TopOfScreenLinePos, WhiteV4);
|
||||
TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font);
|
||||
|
||||
PrintF(&DebugString, "Render Buffer: %d / %d (at this point)",
|
||||
RenderBuffer->CommandMemoryUsed,
|
||||
RenderBuffer->CommandMemorySize);
|
||||
DrawString(RenderBuffer, DebugString, Interface.Font,
|
||||
TopOfScreenLinePos, WhiteV4);
|
||||
TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font);
|
||||
}
|
||||
|
||||
if (GlobalDebugServices->Interface.ShowTrackedScopes)
|
||||
{
|
||||
r32 ColumnsStartX = TopOfScreenLinePos.x;
|
||||
v2 ProfilerMin = v2{TopOfDebugView.x, TopOfDebugView.y - 500};
|
||||
v2 ProfilerMax = v2{TopOfDebugView.x + 700, TopOfDebugView.y - 64};
|
||||
PushRenderQuad2D(RenderBuffer, ProfilerMin, ProfilerMax, v4{0, 0, 0, .8f});
|
||||
DrawDebugFrameList(RenderBuffer, Interface, Mouse, ProfilerMin, ProfilerMax, Transient);
|
||||
|
||||
#if 0
|
||||
r32 ColumnsStartX = TopOfScreenLinePos.x;
|
||||
for (s32 i = 0; i < GlobalDebugServices->ScopeHistogramUsed; i++)
|
||||
{
|
||||
v2 Register = v2{ColumnsStartX, TopOfScreenLinePos.y};
|
||||
|
@ -161,6 +369,7 @@ DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_c
|
|||
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ZeroArenaToSnapshot(Transient, StartTempMemory);
|
||||
|
|
|
@ -520,10 +520,11 @@ ConnectNodes(node_list* NodeList,
|
|||
s32 UpstreamNodeHandle, s32 UpstreamNodePort,
|
||||
s32 DownstreamNodeHandle, s32 DownstreamNodePort)
|
||||
{
|
||||
interface_node* UpstreamNode = 0;
|
||||
interface_node* DownstreamNode = GetNodeWithHandle(NodeList, DownstreamNodeHandle);
|
||||
if (!CheckForRecursionWithHandle(NodeList, UpstreamNodeHandle, DownstreamNode))
|
||||
{
|
||||
interface_node* UpstreamNode = GetNodeWithHandle(NodeList, UpstreamNodeHandle);
|
||||
UpstreamNode = GetNodeWithHandle(NodeList, UpstreamNodeHandle);
|
||||
if (PortTypesMatch(UpstreamNode, UpstreamNodePort,
|
||||
DownstreamNode, DownstreamNodePort))
|
||||
{
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
internal render_command_buffer
|
||||
AllocateRenderCommandBuffer (u8* Memory, s32 Size)
|
||||
AllocateRenderCommandBuffer (u8* Memory, s32 Size, renderer_realloc* Realloc)
|
||||
{
|
||||
render_command_buffer Result = {};
|
||||
Result.CommandMemory = Memory;
|
||||
Result.CommandMemoryUsed = 0;
|
||||
Result.CommandMemorySize = Size;
|
||||
Result.CommandMemoryUsed = 0;
|
||||
Result.Realloc = Realloc;
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
@ -95,6 +96,8 @@ RenderCommandBuffer (render_command_buffer CommandBuffer)
|
|||
{
|
||||
case RenderCommand_render_command_set_render_mode:
|
||||
{
|
||||
DEBUG_TRACK_SCOPE(SetRenderMode);
|
||||
|
||||
render_command_set_render_mode* Command = (render_command_set_render_mode*)(CommandHeader + 1);
|
||||
|
||||
glViewport(Command->ViewOffsetX, Command->ViewOffsetY,
|
||||
|
@ -118,6 +121,8 @@ RenderCommandBuffer (render_command_buffer CommandBuffer)
|
|||
|
||||
case RenderCommand_render_command_clear_screen:
|
||||
{
|
||||
DEBUG_TRACK_SCOPE(RendererClearScreen);
|
||||
|
||||
render_command_clear_screen* Command = (render_command_clear_screen*)(CommandHeader + 1);
|
||||
|
||||
ClearRenderBuffer();
|
||||
|
|
|
@ -186,12 +186,18 @@ struct render_command_set_render_mode
|
|||
b32 UseDepthBuffer;
|
||||
};
|
||||
|
||||
typedef u8* renderer_realloc(u8* Base, s32 CurrentSize, s32 NewSize);
|
||||
|
||||
#define COMMAND_BUFFER_MIN_GROW_SIZE Megabytes(2)
|
||||
|
||||
struct render_command_buffer
|
||||
{
|
||||
u8* CommandMemory;
|
||||
s32 CommandMemoryUsed;
|
||||
s32 CommandMemorySize;
|
||||
|
||||
renderer_realloc* Realloc;
|
||||
|
||||
s32 ViewWidth;
|
||||
s32 ViewHeight;
|
||||
};
|
||||
|
@ -230,15 +236,29 @@ PackColorStructR32 (r32 In_R, r32 In_G, r32 In_B, r32 In_A)
|
|||
return Result;
|
||||
}
|
||||
|
||||
internal void
|
||||
ResizeBufferIfNecessary(render_command_buffer* Buffer, s32 DataSize)
|
||||
{
|
||||
if (Buffer->CommandMemoryUsed + DataSize > Buffer->CommandMemorySize)
|
||||
{
|
||||
// NOTE(Peter): If this becomes a problem just go back to the original solution of
|
||||
// NewSize = Buffer->CommandMemorySize + (2 * DataSize);
|
||||
s32 SpaceAvailable = Buffer->CommandMemorySize - Buffer->CommandMemoryUsed;
|
||||
s32 SpaceNeeded = DataSize - SpaceAvailable; // This is known to be positive at this point
|
||||
s32 AdditionSize = GSMax(SpaceNeeded, COMMAND_BUFFER_MIN_GROW_SIZE);
|
||||
s32 NewSize = Buffer->CommandMemorySize + AdditionSize;
|
||||
Buffer->CommandMemory = Buffer->Realloc(Buffer->CommandMemory,
|
||||
Buffer->CommandMemorySize,
|
||||
NewSize);
|
||||
Buffer->CommandMemorySize = NewSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Batch
|
||||
|
||||
internal s32
|
||||
PushQuad3DBatch (render_command_buffer* Buffer, render_quad_batch_constructor* Constructor, s32 QuadCount, u8* MemStart, b32 UseIntegerColor = false)
|
||||
PushQuad3DBatch (render_command_buffer* Buffer, render_quad_batch_constructor* Constructor, u8* MemStart, s32 TriCount, s32 DataSize, b32 UseIntegerColor = false)
|
||||
{
|
||||
s32 TriCount = QuadCount * 2;
|
||||
s32 DataSize = BATCH_3D_SIZE(TriCount);
|
||||
Assert(Buffer->CommandMemoryUsed + DataSize <= Buffer->CommandMemorySize);
|
||||
|
||||
Constructor->Max = TriCount;
|
||||
Constructor->Count = 0;
|
||||
|
||||
|
@ -251,15 +271,13 @@ PushQuad3DBatch (render_command_buffer* Buffer, render_quad_batch_constructor* C
|
|||
}
|
||||
|
||||
internal s32
|
||||
PushQuad2DBatch (render_command_buffer* Buffer, render_quad_batch_constructor* Constructor, s32 QuadCount, u8* MemStart)
|
||||
PushQuad2DBatch (render_command_buffer* Buffer, render_quad_batch_constructor* Constructor, s32 QuadCount, s32 DataSize, u8* MemStart)
|
||||
{
|
||||
s32 DataSize = BATCH_2D_SIZE(QuadCount);
|
||||
Assert(Buffer->CommandMemoryUsed + DataSize <= Buffer->CommandMemorySize);
|
||||
|
||||
GSZeroMemory(MemStart, DataSize);
|
||||
|
||||
Constructor->Max = QuadCount;
|
||||
Constructor->Count = 0;
|
||||
|
||||
Constructor->Vertecies = (v4*)(MemStart + BATCH_2D_VERTECIES_OFFSET(QuadCount));
|
||||
Constructor->UVs = (v2*)(MemStart + BATCH_2D_UVS_OFFSET(QuadCount));
|
||||
Constructor->ColorsV = (v4*)(MemStart + BATCH_2D_COLORS_OFFSET(QuadCount));
|
||||
|
@ -280,31 +298,58 @@ ThreadSafeIncrementQuadConstructorCount (render_quad_batch_constructor* Construc
|
|||
return Result;
|
||||
}
|
||||
|
||||
struct quad_batch_constructor_reserved_range
|
||||
{
|
||||
s32 Start;
|
||||
s32 OnePastLast;
|
||||
};
|
||||
|
||||
internal quad_batch_constructor_reserved_range
|
||||
ThreadSafeReserveRangeInQuadConstructor(render_quad_batch_constructor* Constructor, s32 TrisNeeded)
|
||||
{
|
||||
quad_batch_constructor_reserved_range Result = {};
|
||||
Result.OnePastLast = InterlockedAdd((long*)&Constructor->Count, TrisNeeded);
|
||||
Result.Start = Result.OnePastLast - TrisNeeded;
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline void
|
||||
SetTri3DInBatch (render_quad_batch_constructor* Constructor, s32 TriIndex,
|
||||
v4 P0, v4 P1, v4 P2,
|
||||
v2 UV0, v2 UV1, v2 UV2,
|
||||
v4 C0, v4 C1, v4 C2)
|
||||
{
|
||||
// Vertecies
|
||||
Constructor->Vertecies[BATCH_3D_VERTEX_INDEX(TriIndex, 0)] = P0;
|
||||
Constructor->Vertecies[BATCH_3D_VERTEX_INDEX(TriIndex, 1)] = P1;
|
||||
Constructor->Vertecies[BATCH_3D_VERTEX_INDEX(TriIndex, 2)] = P2;
|
||||
|
||||
// UVs
|
||||
Constructor->UVs[BATCH_3D_UV_INDEX(TriIndex, 0)] = UV0;
|
||||
Constructor->UVs[BATCH_3D_UV_INDEX(TriIndex, 1)] = UV1;
|
||||
Constructor->UVs[BATCH_3D_UV_INDEX(TriIndex, 2)] = UV1;
|
||||
|
||||
// Color V0
|
||||
Constructor->ColorsV[BATCH_3D_COLOR_INDEX(TriIndex, 0)] = C0;
|
||||
Constructor->ColorsV[BATCH_3D_COLOR_INDEX(TriIndex, 1)] = C1;
|
||||
Constructor->ColorsV[BATCH_3D_COLOR_INDEX(TriIndex, 2)] = C2;
|
||||
}
|
||||
|
||||
inline void
|
||||
PushTri3DOnBatch (render_quad_batch_constructor* Constructor,
|
||||
v4 P0, v4 P1, v4 P2,
|
||||
v2 UV0, v2 UV1, v2 UV2,
|
||||
v4 C0, v4 C1, v4 C2)
|
||||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
s32 Tri = ThreadSafeIncrementQuadConstructorCount(Constructor);
|
||||
// Vertecies
|
||||
Constructor->Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 0)] = P0;
|
||||
Constructor->Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 1)] = P1;
|
||||
Constructor->Vertecies[BATCH_3D_VERTEX_INDEX(Tri, 2)] = P2;
|
||||
// UVs
|
||||
Constructor->UVs[BATCH_3D_UV_INDEX(Tri, 0)] = UV0;
|
||||
Constructor->UVs[BATCH_3D_UV_INDEX(Tri, 1)] = UV1;
|
||||
Constructor->UVs[BATCH_3D_UV_INDEX(Tri, 2)] = UV1;
|
||||
// Color V0
|
||||
Constructor->ColorsV[BATCH_3D_COLOR_INDEX(Tri, 0)] = C0;
|
||||
Constructor->ColorsV[BATCH_3D_COLOR_INDEX(Tri, 1)] = C1;
|
||||
Constructor->ColorsV[BATCH_3D_COLOR_INDEX(Tri, 2)] = C2;
|
||||
SetTri3DInBatch(Constructor, Tri, P0, P1, P2, UV0, UV1, UV2, C0, C1, C2);
|
||||
};
|
||||
|
||||
internal void
|
||||
PushQuad3DOnBatch (render_quad_batch_constructor* Constructor, v4 P0, v4 P1, v4 P2, v4 P3, v2 UVMin, v2 UVMax, v4 Color)
|
||||
{
|
||||
Assert(Constructor->Count < Constructor->Max);
|
||||
Assert(Constructor->Count + 2 < Constructor->Max);
|
||||
PushTri3DOnBatch(Constructor, P0, P1, P2, UVMin, v2{UVMax.x, UVMin.y}, UVMax, Color, Color, Color);
|
||||
PushTri3DOnBatch(Constructor, P0, P2, P3, UVMin, UVMax, v2{UVMin.x, UVMax.y}, Color, Color, Color);
|
||||
}
|
||||
|
@ -332,6 +377,8 @@ PushQuad2DOnBatch (render_quad_batch_constructor* Constructor,
|
|||
v2 UV0, v2 UV1, v2 UV2, v2 UV3,
|
||||
v4 C0, v4 C1, v4 C2, v4 C3)
|
||||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
|
||||
s32 Quad = ThreadSafeIncrementQuadConstructorCount(Constructor);
|
||||
v2* Vertecies = (v2*)Constructor->Vertecies;
|
||||
|
||||
|
@ -367,6 +414,8 @@ PushQuad2DOnBatch (render_quad_batch_constructor* Constructor,
|
|||
internal void
|
||||
PushQuad2DOnBatch (render_quad_batch_constructor* Constructor, v2 P0, v2 P1, v2 P2, v2 P3, v2 UVMin, v2 UVMax, v4 Color)
|
||||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
|
||||
s32 Quad = ThreadSafeIncrementQuadConstructorCount(Constructor);
|
||||
v2* Vertecies = (v2*)Constructor->Vertecies;
|
||||
|
||||
|
@ -422,6 +471,7 @@ PushLine2DOnBatch (render_quad_batch_constructor* Constructor, v2 P0, v2 P1, r32
|
|||
internal u8*
|
||||
PushRenderCommand_ (render_command_buffer* CommandBuffer, render_command_type CommandType, s32 CommandSize)
|
||||
{
|
||||
ResizeBufferIfNecessary(CommandBuffer, CommandSize);
|
||||
Assert(CommandBuffer->CommandMemoryUsed + CommandSize <= CommandBuffer->CommandMemorySize);
|
||||
|
||||
render_command_header* Header = (render_command_header*)(CommandBuffer->CommandMemory + CommandBuffer->CommandMemoryUsed);
|
||||
|
@ -488,11 +538,15 @@ PushRenderClearScreen (render_command_buffer* Buffer)
|
|||
internal render_quad_batch_constructor
|
||||
PushRenderQuad2DBatch(render_command_buffer* Buffer, s32 QuadCount)
|
||||
{
|
||||
s32 DataSize = BATCH_2D_SIZE(QuadCount);
|
||||
ResizeBufferIfNecessary(Buffer, DataSize + sizeof(render_batch_command_quad_2d));
|
||||
Assert(Buffer->CommandMemoryUsed + DataSize <= Buffer->CommandMemorySize);
|
||||
|
||||
render_quad_batch_constructor Result = {};
|
||||
|
||||
render_batch_command_quad_2d* Command = PushRenderCommand(Buffer, render_batch_command_quad_2d);
|
||||
Command->QuadCount = QuadCount;
|
||||
Command->DataSize = PushQuad2DBatch(Buffer, &Result, QuadCount, (u8*)(Command + 1));
|
||||
Command->DataSize = PushQuad2DBatch(Buffer, &Result, QuadCount, DataSize, (u8*)(Command + 1));
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
@ -515,11 +569,16 @@ PushRenderLine2D (render_command_buffer* Buffer, v2 P0, v2 P1, r32 Thickness, v4
|
|||
internal render_quad_batch_constructor
|
||||
PushRenderQuad3DBatch(render_command_buffer* Buffer, s32 QuadCount)
|
||||
{
|
||||
s32 TriCount = QuadCount * 2;
|
||||
s32 DataSize = BATCH_3D_SIZE(TriCount);
|
||||
ResizeBufferIfNecessary(Buffer, DataSize + sizeof(render_batch_command_quad_3d));
|
||||
Assert(Buffer->CommandMemoryUsed + DataSize <= Buffer->CommandMemorySize);
|
||||
|
||||
render_quad_batch_constructor Result = {};
|
||||
|
||||
render_batch_command_quad_3d* Command = PushRenderCommand(Buffer, render_batch_command_quad_3d);
|
||||
Command->QuadCount = QuadCount;
|
||||
Command->DataSize = PushQuad3DBatch(Buffer, &Result, QuadCount, (u8*)(Command + 1));
|
||||
Command->DataSize = PushQuad3DBatch(Buffer, &Result, (u8*)(Command + 1), TriCount, DataSize);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
@ -547,11 +606,15 @@ internal render_quad_batch_constructor
|
|||
PushRenderTexture2DBatch(render_command_buffer* Buffer, s32 QuadCount,
|
||||
render_texture Texture)
|
||||
{
|
||||
s32 DataSize = BATCH_2D_SIZE(QuadCount);
|
||||
ResizeBufferIfNecessary(Buffer, DataSize);
|
||||
Assert(Buffer->CommandMemoryUsed + DataSize <= Buffer->CommandMemorySize);
|
||||
|
||||
render_quad_batch_constructor Result = {};
|
||||
|
||||
render_batch_command_texture_2d* Command = PushRenderCommand(Buffer, render_batch_command_texture_2d);
|
||||
Command->QuadCount = QuadCount;
|
||||
Command->DataSize = PushQuad2DBatch(Buffer, &Result, QuadCount, (u8*)(Command + 1));
|
||||
Command->DataSize = PushQuad2DBatch(Buffer, &Result, QuadCount, DataSize, (u8*)(Command + 1));
|
||||
Command->Texture = Texture;
|
||||
|
||||
return Result;
|
||||
|
|
|
@ -11,7 +11,6 @@ NodeType_SwdColorProc,
|
|||
NodeType_SolidColorProc,
|
||||
NodeType_VerticalColorFadeProc,
|
||||
NodeType_RevolvingDiscs,
|
||||
NodeType_MichelleColorProc,
|
||||
NodeType_Count,
|
||||
};
|
||||
|
||||
|
@ -61,7 +60,7 @@ node_struct_member MemberList_swd_color_data[] = {
|
|||
|
||||
node_struct_member MemberList_solid_color_data[] = {
|
||||
{ MemberType_v4, "Color", (u64)&((solid_color_data*)0)->Color, IsInputMember },
|
||||
{ MemberType_NODE_COLOR_BUFFER, "LEDs", (u64)&((solid_color_data*)0)->LEDs, IsInputMember | IsOutputMember},
|
||||
{ MemberType_NODE_COLOR_BUFFER, "ResultLEDs", (u64)&((solid_color_data*)0)->ResultLEDs, IsOutputMember},
|
||||
};
|
||||
|
||||
node_struct_member MemberList_vertical_color_fade_data[] = {
|
||||
|
@ -82,11 +81,6 @@ node_struct_member MemberList_revolving_discs_data[] = {
|
|||
{ MemberType_NODE_COLOR_BUFFER, "ResultLEDs", (u64)&((revolving_discs_data*)0)->ResultLEDs, IsOutputMember},
|
||||
};
|
||||
|
||||
node_struct_member MemberList_michelle_data[] = {
|
||||
{ MemberType_v4, "Color", (u64)&((michelle_data*)0)->Color, IsInputMember },
|
||||
{ MemberType_NODE_COLOR_BUFFER, "LEDs", (u64)&((michelle_data*)0)->LEDs, IsInputMember | IsOutputMember},
|
||||
};
|
||||
|
||||
node_specification NodeSpecifications[] = {
|
||||
{ NodeType_FloatValue, "FloatValue", 10, MemberList_float_value_data, 8, 2, false},
|
||||
{ NodeType_VectorValue, "VectorValue", 11, MemberList_vector_data, 32, 5, false},
|
||||
|
@ -98,9 +92,8 @@ node_specification NodeSpecifications[] = {
|
|||
{ NodeType_SolidColorProc, "SolidColorProc", 14, MemberList_solid_color_data, 36, 2, false},
|
||||
{ NodeType_VerticalColorFadeProc, "VerticalColorFadeProc", 21, MemberList_vertical_color_fade_data, 44, 4, false},
|
||||
{ NodeType_RevolvingDiscs, "RevolvingDiscs", 14, MemberList_revolving_discs_data, 60, 8, false},
|
||||
{ NodeType_MichelleColorProc, "MichelleColorProc", 17, MemberList_michelle_data, 36, 2, false},
|
||||
};
|
||||
s32 NodeSpecificationsCount = 11;
|
||||
s32 NodeSpecificationsCount = 10;
|
||||
|
||||
internal void CallNodeProc(interface_node* Node, u8* Data, led* LEDs, s32 LEDsCount, r32 DeltaTime)
|
||||
{
|
||||
|
@ -116,6 +109,5 @@ case NodeType_SwdColorProc: { SwdColorProc((swd_color_data*)Data, DeltaTime); }
|
|||
case NodeType_SolidColorProc: { SolidColorProc((solid_color_data*)Data, DeltaTime); } break;
|
||||
case NodeType_VerticalColorFadeProc: { VerticalColorFadeProc((vertical_color_fade_data*)Data, DeltaTime); } break;
|
||||
case NodeType_RevolvingDiscs: { RevolvingDiscs((revolving_discs_data*)Data, DeltaTime); } break;
|
||||
case NodeType_MichelleColorProc: { MichelleColorProc((michelle_data*)Data, DeltaTime); } break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ enum key_state_flags
|
|||
KeyState_IsDown = 1 << 1,
|
||||
};
|
||||
|
||||
#define KeyWasDown(event) ((event.State & KeyState_WasDown) > 0)
|
||||
#define KeyIsDown(event) ((event.State & KeyState_IsDown) > 0)
|
||||
#define KeyWasDown(event) ((event & KeyState_WasDown) > 0)
|
||||
#define KeyIsDown(event) ((event & KeyState_IsDown) > 0)
|
||||
|
||||
struct input_entry
|
||||
{
|
||||
|
@ -30,12 +30,9 @@ struct mouse_state
|
|||
v2 DeltaPos;
|
||||
v2 DownPos;
|
||||
|
||||
b32 LeftButtonTransitionedDown;
|
||||
b32 LeftButtonTransitionedUp;
|
||||
b32 MiddleButtonTransitionedDown;
|
||||
b32 MiddleButtonTransitionedUp;
|
||||
b32 RightButtonTransitionedDown;
|
||||
b32 RightButtonTransitionedUp;
|
||||
b32 LeftButtonState;
|
||||
b32 MiddleButtonState;
|
||||
b32 RightButtonState;
|
||||
};
|
||||
|
||||
internal input_queue
|
||||
|
@ -78,17 +75,35 @@ AddInputEventEntry (input_queue* Queue, key_code Key,
|
|||
internal b32
|
||||
KeyTransitionedDown (input_entry Entry)
|
||||
{
|
||||
return (!KeyWasDown(Entry) && KeyIsDown(Entry));
|
||||
return (!KeyWasDown(Entry.State) && KeyIsDown(Entry.State));
|
||||
}
|
||||
|
||||
internal b32
|
||||
KeyTransitionedUp (input_entry Entry)
|
||||
{
|
||||
return (KeyWasDown(Entry) && !KeyIsDown(Entry));
|
||||
return (KeyWasDown(Entry.State) && !KeyIsDown(Entry.State));
|
||||
}
|
||||
|
||||
internal b32
|
||||
KeyHeldDown (input_entry Entry)
|
||||
{
|
||||
return (KeyWasDown(Entry) && KeyIsDown(Entry));
|
||||
return (KeyWasDown(Entry.State) && KeyIsDown(Entry.State));
|
||||
}
|
||||
|
||||
internal b32
|
||||
MouseButtonTransitionedDown (b32 MouseButtonState)
|
||||
{
|
||||
return (!KeyWasDown(MouseButtonState) && KeyIsDown(MouseButtonState));
|
||||
}
|
||||
|
||||
internal b32
|
||||
MouseButtonTransitionedUp (b32 MouseButtonState)
|
||||
{
|
||||
return (KeyWasDown(MouseButtonState) && !KeyIsDown(MouseButtonState));
|
||||
}
|
||||
|
||||
internal b32
|
||||
MouseButtonHeldDown (b32 MouseButtonState)
|
||||
{
|
||||
return (KeyWasDown(MouseButtonState) && KeyIsDown(MouseButtonState));
|
||||
}
|
|
@ -624,6 +624,21 @@ v2 _Min, v2 _Max
|
|||
_P.y >= _Min.y && _P.y <= _Max.y);
|
||||
}
|
||||
|
||||
static bool
|
||||
PointIsInRangeSafe (
|
||||
v2 _P,
|
||||
v2 _Min, v2 _Max
|
||||
)
|
||||
{
|
||||
s32 MinX = GSMin(_Min.x, _Max.x);
|
||||
s32 MinY = GSMin(_Min.y, _Max.y);
|
||||
s32 MaxX = GSMax(_Min.x, _Max.x);
|
||||
s32 MaxY = GSMax(_Min.y, _Max.y);
|
||||
|
||||
return (_P.x >= MinX && _P.x <= MaxX &&
|
||||
_P.y >= MinY && _P.y <= MaxY);
|
||||
}
|
||||
|
||||
inline v2
|
||||
PointToPercentRange (v2 P, v2 Min, v2 Max)
|
||||
{
|
||||
|
|
|
@ -871,6 +871,10 @@ GetPerformanceFrequency ()
|
|||
internal s64
|
||||
GetWallClock ()
|
||||
{
|
||||
#if 0
|
||||
s64 Result = __rdtsc();
|
||||
return Result;
|
||||
#else
|
||||
LARGE_INTEGER Time;
|
||||
if (!QueryPerformanceCounter(&Time))
|
||||
{
|
||||
|
@ -878,6 +882,7 @@ GetWallClock ()
|
|||
InvalidCodePath;
|
||||
}
|
||||
return (s64)Time.QuadPart;
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
|
|
@ -207,7 +207,7 @@ EvaluateButton (render_command_buffer* RenderBuffer,
|
|||
|
||||
if (PointIsInRange(Mouse.Pos, Min, Max))
|
||||
{
|
||||
if (Mouse.LeftButtonTransitionedDown)
|
||||
if (MouseButtonTransitionedDown(Mouse.LeftButtonState))
|
||||
{
|
||||
Result.Pressed = true;
|
||||
}
|
||||
|
@ -350,7 +350,7 @@ EvaluateSlider (render_command_buffer* RenderBuffer, v2 Min, v2 Max, string Labe
|
|||
BGColor = Config.ButtonColor_Active;
|
||||
}
|
||||
|
||||
if (Mouse.LeftButtonTransitionedDown)
|
||||
if (MouseButtonTransitionedDown(Mouse.LeftButtonState))
|
||||
{
|
||||
if (PointIsInRange(Mouse.DownPos, Min, Max))
|
||||
{
|
||||
|
@ -581,7 +581,7 @@ EvaluateColorChannelSlider (render_command_buffer* RenderBuffer, v4 ChannelMask,
|
|||
v2{0, 0}, v2{1, 0}, v2{1, 1}, v2{0, 1},
|
||||
LeftColor, RightColor, RightColor, LeftColor);
|
||||
|
||||
if (Mouse.LeftButtonTransitionedDown)
|
||||
if (MouseButtonTransitionedDown(Mouse.LeftButtonState))
|
||||
{
|
||||
if (PointIsInRange(Mouse.DownPos, Min, Max))
|
||||
{
|
||||
|
@ -605,7 +605,7 @@ EvaluateColorPicker (render_command_buffer* RenderBuffer, v4* Value, v2 PanelMin
|
|||
b32 ShouldClose = false;
|
||||
|
||||
v2 PanelMax = v2{400, 500};
|
||||
if (Mouse.LeftButtonTransitionedDown && !PointIsInRange(Mouse.Pos, PanelMin, PanelMax))
|
||||
if (MouseButtonTransitionedDown(Mouse.LeftButtonState) && !PointIsInRange(Mouse.Pos, PanelMin, PanelMax))
|
||||
{
|
||||
ShouldClose = true;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
NODE_STRUCT(solid_color_data)
|
||||
{
|
||||
NODE_IN(v4, Color);
|
||||
NODE_COLOR_BUFFER_INOUT;
|
||||
NODE_COLOR_BUFFER_OUT(Result);
|
||||
};
|
||||
|
||||
NODE_PROC(SolidColorProc, solid_color_data)
|
||||
|
@ -11,14 +11,14 @@ NODE_PROC(SolidColorProc, solid_color_data)
|
|||
u8 G = (u8)GSClamp(0.f, (Data->Color.g * 255), 255.f);
|
||||
u8 B = (u8)GSClamp(0.f, (Data->Color.b * 255), 255.f);
|
||||
|
||||
led* LED = Data->LEDs;
|
||||
for (s32 l = 0; l < Data->LEDCount; l++)
|
||||
led* LED = Data->ResultLEDs;
|
||||
for (s32 l = 0; l < Data->ResultLEDCount; l++)
|
||||
{
|
||||
Assert(LED->Index >= 0 && LED->Index < Data->LEDCount);
|
||||
Assert(LED->Index >= 0 && LED->Index < Data->ResultLEDCount);
|
||||
|
||||
Data->Colors[LED->Index].R = R;
|
||||
Data->Colors[LED->Index].G = G;
|
||||
Data->Colors[LED->Index].B = B;
|
||||
Data->ResultColors[LED->Index].R = R;
|
||||
Data->ResultColors[LED->Index].G = G;
|
||||
Data->ResultColors[LED->Index].B = B;
|
||||
LED++;
|
||||
}
|
||||
}
|
||||
|
@ -69,23 +69,27 @@ NODE_STRUCT(revolving_discs_data)
|
|||
|
||||
NODE_PROC(RevolvingDiscs, revolving_discs_data)
|
||||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
|
||||
sacn_pixel Color = PackFloatsToSACNPixel(Data->Color.r, Data->Color.g, Data->Color.b);
|
||||
|
||||
v4 Center = v4{0, 0, 0, 1};
|
||||
v4 Normal = v4{GSCos(Data->ThetaZ), 0, GSSin(Data->ThetaZ), 0}; // NOTE(Peter): dont' need to normalize. Should always be 1
|
||||
v4 Right = Cross(Normal, v4{0, 1, 0, 0});
|
||||
//Normal = RotateAround(Data->ThetaY, Right);
|
||||
|
||||
v4 FrontCenter = Center + (Normal * Data->DiscWidth);
|
||||
v4 BackCenter = Center - (Normal * Data->DiscWidth);
|
||||
|
||||
r32 OuterRadiusSquared = Data->OuterRadius * Data->OuterRadius;
|
||||
r32 InnerRadiusSquared = Data->InnerRadius * Data->InnerRadius;
|
||||
|
||||
led* LED = Data->ResultLEDs;
|
||||
for (s32 l = 0; l < Data->ResultLEDCount; l++)
|
||||
{
|
||||
v4 Position = LED->Position;
|
||||
|
||||
v4 ToFront = Normalize(Position + FrontCenter);
|
||||
v4 ToBack = Normalize(Position + BackCenter);
|
||||
v4 ToFront = Position + FrontCenter;
|
||||
v4 ToBack = Position + BackCenter;
|
||||
|
||||
r32 ToFrontDotNormal = Dot(ToFront, Normal);
|
||||
r32 ToBackDotNormal = Dot(ToBack, Normal);
|
||||
|
@ -93,8 +97,8 @@ NODE_PROC(RevolvingDiscs, revolving_discs_data)
|
|||
ToFrontDotNormal = GSClamp01(ToFrontDotNormal * 1000);
|
||||
ToBackDotNormal = GSClamp01(ToBackDotNormal * 1000);
|
||||
|
||||
r32 DistToCenter = Mag(Position);
|
||||
if (DistToCenter < Data->OuterRadius && DistToCenter > Data->InnerRadius)
|
||||
r32 SqDistToCenter = MagSqr(Position);
|
||||
if (SqDistToCenter < OuterRadiusSquared && SqDistToCenter > InnerRadiusSquared)
|
||||
{
|
||||
if (XOR(ToFrontDotNormal > 0, ToBackDotNormal > 0))
|
||||
{
|
||||
|
@ -103,28 +107,4 @@ NODE_PROC(RevolvingDiscs, revolving_discs_data)
|
|||
}
|
||||
LED++;
|
||||
}
|
||||
}
|
||||
|
||||
NODE_STRUCT(michelle_data)
|
||||
{
|
||||
NODE_IN(v4, Color);
|
||||
NODE_COLOR_BUFFER_INOUT;
|
||||
};
|
||||
|
||||
NODE_PROC(MichelleColorProc, michelle_data)
|
||||
{
|
||||
u8 R = (u8)GSClamp(0.f, (Data->Color.r * 255), 255.f);
|
||||
u8 G = (u8)GSClamp(0.f, (Data->Color.g * 255), 255.f);
|
||||
u8 B = (u8)GSClamp(0.f, (Data->Color.b * 255), 255.f);
|
||||
|
||||
led* LED = Data->LEDs;
|
||||
for (s32 l = 0; l < Data->LEDCount; l++)
|
||||
{
|
||||
Assert(LED->Index >= 0 && LED->Index < Data->LEDCount);
|
||||
|
||||
Data->Colors[LED->Index].R = R;
|
||||
Data->Colors[LED->Index].G = G;
|
||||
Data->Colors[LED->Index].B = B;
|
||||
LED++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -380,6 +380,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse
|
|||
AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, false, true,
|
||||
ShiftDown, AltDown, CtrlDown, false);
|
||||
|
||||
Mouse->LeftButtonState = KeyState_IsDown & ~KeyState_WasDown;
|
||||
Mouse->DownPos = Mouse->Pos;
|
||||
}break;
|
||||
|
||||
|
@ -391,6 +392,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse
|
|||
|
||||
AddInputEventEntry(InputQueue, KeyCode_MouseMiddleButton, false, true,
|
||||
ShiftDown, AltDown, CtrlDown, false);
|
||||
Mouse->MiddleButtonState = KeyState_IsDown & ~KeyState_WasDown;
|
||||
}break;
|
||||
|
||||
case WM_RBUTTONDOWN:
|
||||
|
@ -401,6 +403,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse
|
|||
|
||||
AddInputEventEntry(InputQueue, KeyCode_MouseRightButton, false, true,
|
||||
ShiftDown, AltDown, CtrlDown, false);
|
||||
Mouse->RightButtonState = KeyState_IsDown & ~KeyState_WasDown;
|
||||
}break;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
|
@ -411,6 +414,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse
|
|||
|
||||
AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, true, false,
|
||||
ShiftDown, AltDown, CtrlDown, false);
|
||||
Mouse->LeftButtonState = ~KeyState_IsDown & KeyState_WasDown;
|
||||
}break;
|
||||
|
||||
case WM_MBUTTONUP:
|
||||
|
@ -421,6 +425,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse
|
|||
|
||||
AddInputEventEntry(InputQueue, KeyCode_MouseMiddleButton, true, false,
|
||||
ShiftDown, AltDown, CtrlDown, false);
|
||||
Mouse->MiddleButtonState = ~KeyState_IsDown & KeyState_WasDown;
|
||||
}break;
|
||||
|
||||
case WM_RBUTTONUP:
|
||||
|
@ -431,6 +436,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse
|
|||
|
||||
AddInputEventEntry(InputQueue, KeyCode_MouseRightButton, true, false,
|
||||
ShiftDown, AltDown, CtrlDown, false);
|
||||
Mouse->RightButtonState = ~KeyState_IsDown & KeyState_WasDown;
|
||||
}break;
|
||||
|
||||
case WM_SYSKEYDOWN:
|
||||
|
@ -493,6 +499,27 @@ SetApplicationLinks (context* Context, win32_dll_refresh DLL, work_queue* WorkQu
|
|||
}
|
||||
}
|
||||
|
||||
internal u8*
|
||||
DEBUGAlloc(s32 ElementSize, s32 ElementCount)
|
||||
{
|
||||
return Win32BasicAlloc(ElementSize * ElementCount);
|
||||
}
|
||||
|
||||
internal u8*
|
||||
Win32Realloc(u8* Buf, s32 OldSize, s32 NewSize)
|
||||
{
|
||||
u8* NewMemory = Win32BasicAlloc(NewSize);
|
||||
GSMemCopy(Buf, NewMemory, OldSize);
|
||||
return NewMemory;
|
||||
}
|
||||
|
||||
internal s32
|
||||
Win32GetThreadId()
|
||||
{
|
||||
s32 Result = GetCurrentThreadId();
|
||||
return Result;
|
||||
}
|
||||
|
||||
int WINAPI
|
||||
WinMain (
|
||||
HINSTANCE HInstance,
|
||||
|
@ -516,8 +543,14 @@ INT NCmdShow
|
|||
r32 LastFrameSecondsElapsed = 0.0f;
|
||||
|
||||
GlobalDebugServices = (debug_services*)malloc(sizeof(debug_services));
|
||||
InitDebugServices(GlobalDebugServices, (u8*)malloc(Megabytes(8)), Megabytes(16), 32000, PerformanceCountFrequency);
|
||||
GlobalDebugServices->GetWallClock = GetWallClock;
|
||||
s32 DebugThreadCount = PLATFORM_THREAD_COUNT + 1;
|
||||
InitDebugServices(GlobalDebugServices,
|
||||
PerformanceCountFrequency,
|
||||
DEBUGAlloc,
|
||||
Win32Realloc,
|
||||
GetWallClock,
|
||||
Win32GetThreadId,
|
||||
DebugThreadCount);
|
||||
|
||||
mouse_state Mouse;
|
||||
input_queue InputQueue;
|
||||
|
@ -592,8 +625,8 @@ INT NCmdShow
|
|||
WSADATA WSAData;
|
||||
WSAStartup(MAKEWORD(2, 2), &WSAData);
|
||||
|
||||
platform_memory_result RenderMemory = Win32Alloc(Megabytes(32));
|
||||
render_command_buffer RenderBuffer = AllocateRenderCommandBuffer(RenderMemory.Base, RenderMemory.Size);
|
||||
platform_memory_result RenderMemory = Win32Alloc(Megabytes(12));
|
||||
render_command_buffer RenderBuffer = AllocateRenderCommandBuffer(RenderMemory.Base, RenderMemory.Size, Win32Realloc);
|
||||
|
||||
Context.InitializeApplication(Context);
|
||||
|
||||
|
@ -601,6 +634,10 @@ INT NCmdShow
|
|||
Context.WindowIsVisible = true;
|
||||
while (Running)
|
||||
{
|
||||
if (GlobalDebugServices->RecordFrames)
|
||||
{
|
||||
EndDebugFrame(GlobalDebugServices);
|
||||
}
|
||||
DEBUG_TRACK_SCOPE(MainLoop);
|
||||
|
||||
ResetInputQueue(&InputQueue);
|
||||
|
@ -624,6 +661,7 @@ INT NCmdShow
|
|||
MSG Message;
|
||||
while (PeekMessageA(&Message, MainWindow.Handle, 0, 0, PM_REMOVE))
|
||||
{
|
||||
DEBUG_TRACK_SCOPE(PeekWindowsMessages);
|
||||
HandleWindowMessage(Message, &MainWindow, &InputQueue, &Mouse);
|
||||
}
|
||||
|
||||
|
@ -641,6 +679,35 @@ INT NCmdShow
|
|||
RenderCommandBuffer(RenderBuffer);
|
||||
ClearRenderBuffer(&RenderBuffer);
|
||||
|
||||
|
||||
if (Mouse.LeftButtonState & KeyState_WasDown &&
|
||||
!((Mouse.LeftButtonState & KeyState_IsDown) > 0))
|
||||
{
|
||||
Mouse.LeftButtonState = 0;
|
||||
} else if (Mouse.LeftButtonState & KeyState_IsDown)
|
||||
{
|
||||
Mouse.LeftButtonState |= KeyState_WasDown;
|
||||
}
|
||||
|
||||
if (Mouse.MiddleButtonState & KeyState_WasDown &&
|
||||
!((Mouse.LeftButtonState & KeyState_IsDown) > 0))
|
||||
{
|
||||
Mouse.MiddleButtonState = 0;
|
||||
} else if (Mouse.MiddleButtonState & KeyState_IsDown)
|
||||
{
|
||||
Mouse.MiddleButtonState |= KeyState_WasDown;
|
||||
}
|
||||
|
||||
if (Mouse.RightButtonState & KeyState_WasDown &&
|
||||
!((Mouse.LeftButtonState & KeyState_IsDown) > 0))
|
||||
{
|
||||
Mouse.RightButtonState = 0;
|
||||
} else if (Mouse.RightButtonState & KeyState_IsDown)
|
||||
{
|
||||
Mouse.RightButtonState |= KeyState_WasDown;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////
|
||||
// Finish Up
|
||||
//////////////////////////////////
|
||||
|
@ -654,6 +721,7 @@ INT NCmdShow
|
|||
|
||||
while (SecondsElapsed < TargetSecondsPerFrame)
|
||||
{
|
||||
DEBUG_TRACK_SCOPE(UnusedTime);
|
||||
u32 SleepTime = 1000.0f * (TargetSecondsPerFrame - SecondsElapsed);
|
||||
Sleep(SleepTime);
|
||||
SecondsElapsed = GetSecondsElapsed(LastFrameEnd, GetWallClock(), PerformanceCountFrequency);
|
||||
|
|
8
todo.txt
8
todo.txt
|
@ -1,5 +1,10 @@
|
|||
TODO FOLDHAUS
|
||||
|
||||
YOU WERE IN THE MIDDLE OF
|
||||
You just got the profiler view rudimentarily working and were about to start to reimplement the
|
||||
scope list view. You need to start tracking debug interface state somehow, and it would be good
|
||||
to separate that out from global debug state
|
||||
|
||||
|
||||
BUGS
|
||||
- Typing a period into a float value doesn't register. Problem here is that we arent' translating key presses into characters at the win32 layer. Need to do that.
|
||||
|
@ -56,6 +61,7 @@ Structure
|
|||
- motion
|
||||
|
||||
Renderer
|
||||
- Render layers
|
||||
- Mouse Picking - point at a led and see info about it
|
||||
- Camera: pan
|
||||
- Camera: zoom
|
||||
|
@ -78,6 +84,8 @@ Command Line
|
|||
- select a channel/pattern
|
||||
|
||||
Optimization
|
||||
- investigate the memory access pattern of the SACN / LED systems. Guessing they are very slow
|
||||
- look into why debug logging functions seems to incur a large hit on framrate
|
||||
- patterns are asking to be multithreaded
|
||||
- probably want to convert as much color functions to use u32 Packed Colors
|
||||
- - Probably want to think about this more. What about supporting different color depths
|
||||
|
|
Loading…
Reference in New Issue