Skip to content

Latest commit

 

History

History
115 lines (94 loc) · 6.56 KB

File metadata and controls

115 lines (94 loc) · 6.56 KB

Splot Architecture

System Overview

┌─────────────────────────────────────────────────────────┐
│  Application (PlotJuggler, standalone, WASM)            │
├─────────────────────────────────────────────────────────┤
│  High-Level API: Plot                                   │
│  (owns axes, grid, renderers, interaction handlers)     │
├─────────────────────────────────────────────────────────┤
│  Components                                             │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
│  │PlotCurve │ │PlotAxis  │ │PlotGrid  │ │PlotLegend │ │
│  │PlotMarker│ │PlotZoomer│ │PlotPanner│ │PlotMagnif.│ │
│  └──────────┘ └──────────┘ └──────────┘ └───────────┘ │
├─────────────────────────────────────────────────────────┤
│  Core Services                                          │
│  ┌────────────┐ ┌────────────┐ ┌──────────────────┐    │
│  │LineRenderer│ │MarkerRender│ │TextRenderer      │    │
│  │(AA quads)  │ │(SDF shapes)│ │(fontstash)       │    │
│  └────────────┘ └────────────┘ └──────────────────┘    │
│  ┌────────────┐ ┌────────────┐ ┌──────────────────┐    │
│  │PlotArea    │ │ScaleMap    │ │M4Decimation      │    │
│  │(layout)    │ │(transforms)│ │(MinMaxTree)      │    │
│  └────────────┘ └────────────┘ └──────────────────┘    │
├─────────────────────────────────────────────────────────┤
│  Renderer (Sokol GFX wrapper)                           │
├─────────────────────────────────────────────────────────┤
│  Sokol: sokol_gfx.h | sokol_app.h | sokol_fontstash.h  │
│  Backends: OpenGL 3.3 | Metal | D3D11 | WebGL2         │
└─────────────────────────────────────────────────────────┘

Technology Decisions

Component Choice Rationale
GPU abstraction Sokol WASM-first, minimal footprint, single-header, zlib license
Text rendering sokol_fontstash + stb_truetype No external font deps, works in WASM
Math cglm Lightweight, C-compatible
Testing GoogleTest Standard, FetchContent integration
Rejected NanoVG, Skia, ImPlot, bgfx See docs/research.md for full analysis

Key Design Patterns

PIMPL: Public API classes (Plot, Renderer, PlotCurve) hide Sokol/GPU types from headers.

Attach/Detach: PlotCurves are externally owned; attached to Plot via non-owning pointers. Curves can move between plots.

Event Abstraction: Backend-agnostic POD event structs (ScrollEvent, MouseButtonEvent, etc.) with adapters for Sokol and Qt.

M4 Decimation: Per pixel column, stores 4 values (first/min/max/last Y) for visually-lossless rendering of millions of points as ~2000 segments.

Fragment Shader AA: Lines rendered as GPU-expanded quads; antialiasing via distance-function in fragment shader (no MSAA needed).

Component Relationships

Plot (high-level, user-facing)

  • Owns: PlotArea, LineRenderer, MarkerRenderer, TextRenderer, PlotAxis (left+bottom), PlotGrid, PlotMagnifier, PlotPanner, PlotZoomer
  • Holds: non-owning pointers to attached PlotCurves
  • Auto-scales to data bounds by default

PlotCurve

  • Owns: PlotSeriesData (data container with MinMaxTree)
  • References: CurveAttributes (color, width, style)
  • Renders via: render(PlotArea&, LineRenderer&, MarkerRenderer&)
  • Supports: 6 styles (Lines, Dots, LinesAndDots, Steps, StepsInverted, Sticks)

PlotArea (layout manager)

  • Owns: x/y ScaleMap instances
  • Manages: margins, canvas-to-plot-area coordinate mapping
  • Provides: data-to-pixel and pixel-to-NDC transforms

Renderers

  • LineRenderer: Batched AA line segments (GPU quads, max 100K segments/batch)
  • MarkerRenderer: SDF-based point markers (instanced quads)
  • TextRenderer: Font atlas text (fontstash integration)

Data Pipeline

User data (doubles) → PlotSeriesData → MinMaxTree (built on set/append)
                                            ↓
Render frame: M4Decimation queries MinMaxTree for visible range
                                            ↓
~2000 segments → LineRenderer batch → GPU draw call

File Map

Directory Contents
include/splot/ Public headers (PIMPL forward-decl only)
src/ Implementations + Sokol shaders
examples/ Numbered demo apps (Sokol + Qt)
tests/ Unit tests (tests/unit/) and visual regression (tests/visual/)
benchmarks/ Performance benchmarks
third_party/ Sokol headers, stb, fontstash
docs/ Architecture, rendering, coordinates, testing docs

Performance Architecture

Technique Where Effect
M4 Decimation PlotCurve::render 1M points → ~2000 segments
MinMaxTree PlotSeriesData O(log n) range queries
Fragment shader AA LineRenderer 100x faster than MSAA
Batch rendering LineRenderer One draw call per curve
Dirty tracking StreamingBuffer Only upload changed bytes
Scissor clipping Plot::render GPU clips to PlotArea region

Measured results (RelWithDebInfo, 10M points):

  • Frame time: ~2ms (target <20ms)
  • Streaming rate: 88.6M pts/sec (target 100K pts/sec)
  • Query latency: <1ms