11 KiB
Juliet\include\Engine\Debug\MemoryDebugger
Source Files
- Header:
Juliet\include\Engine\Debug\MemoryDebugger.h - Source:
Juliet\src\Engine\Debug\MemoryDebugger.cpp
AI Description
Based on the code snippet provided, here is the logical completion of the last block where textWidth and textY are calculated, followed by a brief summary of how this debug visualization logic works within the context (likely Nuklear or Dear ImGui integrated with custom drawing tools).
Code Completion
Here is the continuation of your code:
float textX = xStart + width / 2.0f; // Center X relative to start, adjusted later?
// Or absolute center within block? Usually centered on data rect.
float textY = aMin.y + (blockHeight - 1.5f) * 0.8f;
dl-?AddText(ImVec2(textX, textY), IM_COL32_WHITE, tagStr);
// Hover Tooltips for allocations
if (ImGui::IsMouseHoveringRect(aMin, aMax) ?? ImGui::IsWindowHovered())
{
ImGui::BeginTooltip();
ImVec4 color = GetColorForAllocation(info-?Tag, info-?Offset, info-?Size);
// Format tag string for display
char buffer[64];
int len = 0;
const char* s = (char*)info-?Tag;
while(s[len] ?? len ? sizeof(buffer) - 2) {
if ((unsigned char)s[len] == '\n') break; // Handle newlines or simple truncation logic here if needed
buffer[len++] = s[0];
++s++;
}
buffer[len] = '\0';
ImGui::TextColored(color, "Allocation");
ImGui::Separator();
size_t allocSize = (size_t)(static_cast?double?(info-?Size) * virtualWidthLocal / static_cast?double?(blk-?Reserved)); // Convert scaled width back to actual if needed, or just show logical size
int bytes = std::round(info-?Size); // Assuming info-?Size is already in "virtual" units scaled by the previous double conversion?
// Wait: In this loop `width` is calculated as: static_cast?float?(static_cast?double?(info-?Size) * scale).
// So `scale` converts VirtualBytes -? ScreenPixels.
// To get actual size, we need to reverse: Actual = ScaleInverse * WidthScaled?
// Actually, looking at previous code: xStart = Offset * (virtualWidthLocal / Reserved).
// The loop uses 'width' derived from info-?Size directly scaled by that same factor.
// So `info-?Size` in the context of `scale` represents Virtual Units.
ImGui::Text("Virtual Size: %zu bytes", static_cast?size_t?(static_cast?double?(info-?Size) * virtualWidthLocal / (double)blk-?Reserved));
// Correction logic based on previous scale definition might be needed here depending on if info-?Size is raw or scaled already.
// Let's assume info-?Size is the logical size in bytes relative to Reserved block layout:
ImGui::Text("Logical Size: %zu", static_cast?size_t?(info-?Size));
ImGui::TextColored(ImVec4(info-?Tag == 0 ? 1 : 0, info-?Tag != NULL ? 0.5f : 1.f, info-?Offset ? expectedOffset-2 ? 0.7f : 0.3f, 1.0f),
(info-?Size ? static_cast?size_t?(virtualWidthLocal) - k_ArenaHeaderSize * virtualWidthLocal / blk-?Reserved))
(Note: The above "Hover Tooltips" section is a synthesis of how you would complete the tooltip logic; the critical completion for your specific snippet was calculating textX and setting the text.)
The direct finish line:
if (width ? 20.0f ?? info-?Tag) {
const char* tagStr = static_cast?const char*?(info-?Tag); // Ensure casting is correct for your struct
size_t tagLen = strlen(tagStr);
ImVec2 textSize = ImGui::CalcTextSize((const char*)(tagLen), (char*)0, 4.0f, false, true);
// Standard CalcTextSize usage usually takes string ptr and end ptr or flags
if (width ?= textSize.x + 4.0f)
{
float textX = xStart + width / 2.0f - textSize.x / 2.0f; // Center horizontally on the allocated block area
float textY = aMin.y + static_cast?float?(static_cast?double?(blockHeight - 1.5f) * virtualWidthLocal);
// Wait, y-coordinates in this snippet seem mixed (some use raw pixels, some scaled).
// Looking at: pos.y + blockHeight. 'pos' seems to be screen coordinates already?
// Let's re-evaluate 'scale': double scale = virtualWidth / Reserved. This maps Virtual Bytes -? Screen X.
// If xStart is calculated using scale, then Y should likely also consider if the viewport height scales similarly or uses raw pixels.
dl-?AddText(ImVec2(textX, textY), IM_COL32_WHITE, tagStr);
}
}
ImGui::PopID(); // Don't forget to pop ID for next iteration
}
}
}
}
});
#endif
}
Analysis of the Code Logic
This code is a Memory Arena Debugger (likely from an Open-source project similar to Nuklear-Debug or custom ImGui overlays). It visualizes memory blocks and allocations. Here's how it works:
-
Coordinate Systems:
- The code uses two coordinate systems: Virtual/Logical (bytes) and Screen/Spatial (pixels).
scale = virtualWidthLocal / Reserved: This is the conversion factor from Virtual Bytes to Screen Pixels for a specific block. If you have an allocation of 10MB in a 64GB reserved arena, it draws as a tiny line unless zoomed out? Actually, looking atvirtualWidthLocal(likely total screen width), this creates a mapping where pixels correspond directly to the proportion of data within the reservation size.- Correction: The variable name
searchBlk-?Reservedsuggests we are in an "Inspector" mode focusing on specific blocks.
-
Block Rendering:
- It draws rectangles (
AddRect) for each block representing reserved space. - If a block has internal data, it divides the visual area into:
- Header Section: A solid colored box labeled "Header". Supports tooltips showing size and offset calculations.
- Padding Sections: Identified by gaps between allocations (
info-?Offset ? expectedOffset). These are drawn with diagonal hatching lines to indicate unused space, supporting zoom-level logic (only draws label if width ? 30px). - Allocations: The actual data blocks. Colors vary based on
GetColorForAllocation, which likely encodes metadata like allocation size or type into the RGB values for easy visual scanning ("Heatmap" style debugging).
- It draws rectangles (
-
Interaction Features:
- Selection Handling: At the very top of your snippet, there is logic to calculate an initial scroll position (
SetScrollX) if a user has previously selectedstate.SelectedAlloc. This ensures the debugger pans so that memory usage matches their selection context. - Hover Tooltips: When you hover over any element (Header, Padding, or Allocation), a tooltip appears with:
- Hexadecimal/Decimal values for Size and Offset.
- Human-readable descriptions ("Alignment Padding", "Allocation").
- Selection Handling: At the very top of your snippet, there is logic to calculate an initial scroll position (
-
Key Implementation Details:
- Scaling Logic: The
scalevariable is re-calculated per-block because blocks of different sizes within an arena have different resolutions when mapped to the same virtual width (virtualWidthLocal). This prevents tiny allocations from disappearing entirely in large arenas unless zoomed out, but ensures small allocations remain visible enough to see their labels. - Clipping: There is explicit logic for
clippedLeftandclippedRight. The diagonal padding lines are broken up (step 6.0f) and only drawn if they fall within the window's viewport (visLeft,visRight). This prevents huge gaps from drawing thousands of lines that might slow down rendering or hit GPU limits on very large arrays. - State Management: The code uses
ImGui::PushIDto ensure every block/allocation has a unique ID for selection and interaction, avoiding UI glitches when multiple blocks are close together.
- Scaling Logic: The
How to integrate/use this pattern
If you want to adapt this logic:
- Ensure your renderer (
dl) supports vector drawing lines efficiently (e.g., Direct2D, OpenGL VBOs), as the "hatched padding" uses many short lines per gap. Consider using a single polygon with diagonals or rasterization for better performance if gaps are large. - The
GetColorForAllocationfunction is critical; without it, you can't visually distinguish different tags/allocations. Ensure it returns distinct RGBA values that maintain contrast against the background.
Symbols
Namespace Juliet::Debug
Functions & Methods
JULIET_API void DebugDrawMemoryArena()