src/renderer/atlas/README.md
graph TD
Renderer["Renderer (base/renderer.cpp)
<small>breaks the text buffer down into GDI-oriented graphics
primitives (#quot;change brush to color X#quot;, #quot;draw string Y#quot;, ...)</small>"]
RenderEngineBase[/"RenderEngineBase
(base/RenderEngineBase.cpp)
<small>abstracts 24 LOC 👻</small>"\]
GdiEngine["GdiEngine (gdi/...)"]
subgraph AtlasEngine["AtlasEngine (atlas/...)"]
AtlasEngine.cpp["AtlasEngine.cpp
<small>Implements IRenderEngine text rendering API
breaks GDI graphics primitives down into DWRITE_GLYPH_RUNs</small>"]
AtlasEngine.api.cpp["AtlasEngine.api.cpp
<small>Implements the parts run inside the console
lock (many IRenderEngine setters)<small>"]
AtlasEngine.r.cpp["AtlasEngine.r.cpp
<small>Implements the parts run
outside of the console lock<small>"]
Backend.cpp["Backend.cpp
<small>Implements common functionality/helpers</small>"]
BackendD2D.cpp["BackendD2D.cpp
<small>Pure Direct2D text renderer (for low latency
remote desktop and older/no GPUs)</small>"]
BackendD3D.cpp["BackendD3D.cpp
<small>Custom, performant text renderer
with our own glyph cache</small>"]
end
Renderer -.-> RenderEngineBase
%% Mermaid.js has no support for backwards arrow at the moment
RenderEngineBase <-.->|extends| GdiEngine
Renderer ----> AtlasEngine
AtlasEngine.cpp <--> AtlasEngine.api.cpp
AtlasEngine.cpp <--> AtlasEngine.r.cpp
AtlasEngine.r.cpp --> BackendD2D.cpp
AtlasEngine.r.cpp --> BackendD3D.cpp
BackendD2D.cpp -.- Backend.cpp
BackendD3D.cpp -.- Backend.cpp
As you can see, breaking the text buffer down into GDI-style primitives just to rebuild them into DirectWrite ones, is pretty wasteful. It's also incredibly bug prone. It would be beneficial if the TextBuffer and rendering settings were given directly to AtlasEngine so it can do its own bidding.
The primary entrypoint for rendering is IBackend::Render and BackendD3D implements it via the following functions, by calling them one by one in the order listed here.
_handleSettingsUpdategraph TD
Render --> _handleSettingsUpdate
_handleSettingsUpdate -->|font changes| _updateFontDependents --> _d2dRenderTargetUpdateFontSettings
_handleSettingsUpdate -->|misc changes| _recreateCustomShader
_handleSettingsUpdate --->|misc changes| _recreateCustomRenderTargetView
_handleSettingsUpdate ---->|size changes| _recreateBackgroundColorBitmap
_handleSettingsUpdate -----> _recreateConstBuffer
_handleSettingsUpdate ------> _setupDeviceContextState
_drawBackgroundgraph TD
Render --> _drawBackground
_drawBackground --> _uploadBackgroundBitmap
_drawCursorPart1 / _drawCursorPart2graph TD
Render --> _drawCursorPart1["_drawCursorPart1
runs before _drawText
draws cursors that are behind the text"]
Render --> _drawCursorPart2["_drawCursorPart2
runs after _drawText
draws inverted cursors"]
_drawCursorPart1 -.->|_cursorRects| _drawCursorPart2
_drawTextgraph TD
Render --> _drawText
_drawText --> foreachRow(("for each row"))
foreachRow --> foreachRow
foreachRow --> foreachFont(("for each font face"))
foreachFont --> foreachFont
foreachFont --> foreachGlyph(("for each glyph"))
foreachGlyph --> foreachGlyph
foreachGlyph --> _glyphAtlasMap[("font/glyph-pair lookup in
glyph cache hashmap")]
_glyphAtlasMap --> drawGlyph
drawGlyph --> _appendQuad["_appendQuad
<small>stages the glyph for later drawing</small>"]
_glyphAtlasMap --> _appendQuad
subgraph drawGlyph["if glyph is missing"]
_drawGlyph["_drawGlyph
<small>(defers to _drawSoftFontGlyph for soft fonts)</small>"]
_drawGlyph -.->|if glpyh cache is full| _drawGlyphPrepareRetry
_drawGlyphPrepareRetry --> _flushQuads["_flushQuads
<small>draws the current state
into the render target</small>"]
_flushQuads --> _recreateInstanceBuffers["_recreateInstanceBuffers
<small>allocates a GPU buffer
for our glyph instances</small>"]
_drawGlyphPrepareRetry --> _resetGlyphAtlas["_resetGlyphAtlas
<small>clears the glyph texture</small>"]
_resetGlyphAtlas --> _resizeGlyphAtlas["_resizeGlyphAtlas
<small>resizes the glyph texture if it's still small</small>"]
_drawGlyph -.->|if it's a DECDHL glyph| _splitDoubleHeightGlyph["_splitDoubleHeightGlyph
<small>DECDHL glyphs are split up into their
top/bottom halves to emulate clip rects</small>"]
end
foreachGlyph -.-> _drawTextOverlapSplit["_drawTextOverlapSplit
<small>splits overly wide glyphs up into smaller chunks to support
foreground color changes within the ligature</small>"]
foreachRow -.->|if gridlines exist| _drawGridlineRow["_drawGridlineRow
<small>draws underlines, etc.</small>"]
_drawSelectiongraph TD
Render --> _drawSelection
_handleSettingsUpdategraph TD
Render --> _executeCustomShader