Skip to content

Release v0.4.3

Choose a tag to compare

@github-actions github-actions released this 22 Jun 22:50

Patinae v0.4.3

When I started this project, I was frustrated with PyMOL on Apple Silicon Mac. I tried Chimera, MolStar, and a few other tools, but I never found a molecular visualizer that felt both convenient for my own daily work and hackable enough for the experiments I wanted to run. So I decided to write my own, and the first version was naturally tuned around the machine I had in front of me: a MacBook Pro M4 Max with 128 GB of unified memory.

Patinae now runs on a much wider range of hardware than that one configuration, and some of the most useful issues have come from setups very different from my original one: lower-VRAM GPUs, integrated and shared-memory adapters, Windows bundles, and devices with tighter WebGPU limits. This release is about treating all of those as first-class targets rather than edge cases.

Patinae 0.4.3 turns renderer memory from an implicit assumption into an explicit resource. The renderer now has memory profiles, GPU-memory accounting, budget-aware representation planning, SceneStore compaction, OOM recovery, startup/web/benchmark profile overrides, registered memory settings, and a much clearer performance HUD. The goal is not to pretend that every enormous molecular scene now fits on every GPU. The goal is better: use the headroom when it's there, scale down deliberately when it isn't, and tell the user what changed instead of failing mysteriously.


Highlights

Renderer memory profiles

Patinae now has renderer memory profiles:

  • performance: the full native path for machines with generous GPU headroom.
  • balanced: lower scratch-target and capacity pressure while preserving normal interaction.
  • lite: a constrained profile that gates or disables allocation-heavy optional features.
  • manual:<MiB>: the constrained policy with an explicit memory budget.

When no override is provided, Patinae selects a policy from adapter facts, backend, platform, and GPU limits. Requested WGPU limits are clamped to the selected adapter before device creation, so Patinae no longer requests limits that a smaller adapter cannot satisfy.

Memory profiles are selected when the renderer is created. Changing the active profile means restarting the desktop app, recreating the web viewer, or rerunning the benchmark process.

Desktop startup can force a profile with PATINAE_RENDER_MEMORY_PROFILE:

PATINAE_RENDER_MEMORY_PROFILE=balanced patinae protein.pdb
PATINAE_RENDER_MEMORY_PROFILE=lite patinae protein.pdb
PATINAE_RENDER_MEMORY_PROFILE=manual:1024 patinae protein.pdb

The render_loop benchmark accepts the same profile syntax through BENCH_MEMORY_PROFILE.

The regular command/settings registry also understands the memory knobs:

set render_memory_profile, balanced
set render_memory_profile, lite
set render_memory_profile, manual
set render_memory_budget, 1024
unset render_memory_profile
unset render_memory_budget

Those settings go through the normal set/get/unset path and are useful for command/session consistency, but they do not hot-swap an already-created renderer in this release.

For web embeds, ViewerOptions.memoryProfile and the <patinae-viewer memory-profile="..."> attribute can force auto, performance, balanced, lite, or manual:<MiB> at initialization.

Representation builds now respect memory budgets

Large representation builds are now planned before the renderer allocates GPU buffers.

The renderer estimates memory for built-in representations, checks the active policy, and can downgrade or skip expensive work under constrained profiles. Sticks, cartoons, surfaces, silhouettes, AO, picking, overlays, postprocess scratch targets, shadows, atlases, and native handoff buffers all participate in the policy instead of blindly taking the largest path first.

When Patinae has to degrade, it can emit renderer warnings through the native warning bus and the web command-output/REPL path. Scenes that exceed the active budget should now fail smaller and more honestly: fewer surprise OOMs, more visible explanations.

Selections also remain visible in low-memory cases through lightweight selected-atom dots, even when full overlay targets are denied.

SceneStore compaction and OOM recovery

SceneStore now tracks live, allocated, orphaned, slack, and reclaimed bytes. After load/replace/remove churn, it can compact stale ranges, rewrite CPU staging buffers, discard old GPU buffers, and let the next flush allocate dense buffers again.

On confirmed WGPU or surface out-of-memory failures, Patinae now tries a recovery ladder: force SceneStore compaction, retry once, and temporarily lower the effective memory profile from the captured baseline. Validation errors, device loss, and ordinary surface churn stay out of that ladder, so the fallback path is reserved for real memory pressure.

Memory diagnostics you can actually read

PATINAE_PERF=1 now shows a sectioned telemetry HUD:

  • live FPS;
  • average, 1% low, and 0.1% low frame times;
  • memory profile badge;
  • memory total/live numbers;
  • budget usage bar for explicitly budgeted profiles;
  • per-pass GPU timings.

The same renderer memory snapshots also flow into timing logs, render-loop benchmark output, web performance snapshots, and SceneStore churn diagnostics.

The numbers behind the profile work

On the validation machine (Apple M4 Max, Metal, 1024x1024 benchmark viewport), constrained profiles reduced estimated renderer memory substantially:

  • 1fsd classic_large: lite reduced the snapshot from 38.3 MiB to 20.0 MiB.
  • 3J3Q sticks_heavy: performance was 1701.6 MiB, balanced was 1424.0 MiB, and lite was 565.2 MiB.
  • 3J3Q surface_cartoon_large: performance was 11555.4 MiB, balanced was 1355.9 MiB, and lite was 565.2 MiB.
  • 3J3Q skripkin_silhouettes: performance was 2577.5 MiB, balanced was 1403.9 MiB, and lite was 598.2 MiB.

These are renderer estimates from the local smoke matrix, not a universal hardware promise. They are useful because they prove the new policy stack is not cosmetic: it changes what Patinae allocates before the driver has to say no.

Windows startup is less opaque

Windows startup now uses Slint's automatic WGPU path with DX12 as the default backend, prepares bundled Python runtime paths before plugin loading, and logs device limits and uncaptured WGPU errors more usefully.

If Patinae cannot find a hardware-accelerated WGPU adapter, it no longer disappears behind a silent startup failure or continues into a CPU/WARP/llvmpipe software path that cannot support the interactive viewport. It shows a startup error window through Slint's software renderer and exits with a clear message that software WGPU rendering is disabled for the main renderer.


New features

  • Renderer memory profiles: automatic, performance, balanced, lite, and explicit manual:<MiB> policies for renderer construction.
  • GPU memory ledger: deterministic accounting for renderer-owned buffers, textures, frame targets, representation buffers, picking resources, SceneStore capacity, and desktop handoff textures.
  • Budget-aware representation planning: large built-in representations are estimated before allocation and can be downgraded, skipped, or warned under constrained profiles.
  • SceneStore compaction: live render objects can be retained while stale ranges are compacted and GPU buffers are rebuilt densely after churn.
  • OOM recovery ladder: confirmed allocation pressure can trigger compaction, retry, and temporary profile lowering instead of immediate redraw failure.
  • Startup, web, and benchmark memory overrides: desktop, web, and render-loop benchmark hosts can force a renderer memory policy at initialization.
  • Registered memory settings: render_memory_profile and render_memory_budget now use the regular command/settings path for set/get/unset and session consistency.
  • Web memory profile controls: TypeScript viewer options and the custom element memory-profile attribute can select the renderer memory policy at initialization.
  • PATINAE_PERF memory HUD: the performance overlay now includes a readable memory section with profile, live usage, total estimate, and budget fill when a budget exists.
  • Renderer memory warnings: native and web hosts can surface renderer degradation decisions through normal warning/output channels.
  • Selected-atom dots fallback: low-memory scenes can keep selection feedback visible without full overlay targets.
  • Expanded benchmark coverage: render-loop scenarios now cover profile comparisons, churn diagnostics, Skripkin silhouettes, warnings, and memory snapshots.

Bug fixes and improvements

  • Lower-limit GPU startup: WGPU required limits are clamped to adapter capabilities, reducing startup failures on smaller or integrated adapters.
  • Optional viewport allocation gates: SSAO, FXAA scratch, picking resources, selection overlays, shadows, atlases, native handoff buffers, and postprocess targets now respect memory policy.
  • Representation capacity caps: constrained profiles can reduce stick/sphere/cartoon/surface capacity before allocating the expensive path.
  • Picking under pressure: hit-test resources are allocated lazily from current headroom and can be disabled when the budget does not fit.
  • Memory warning dedupe: repeated non-build representation decisions avoid spamming the same warning.
  • GPU OOM classification: real out-of-memory and surface OOM errors are separated from validation errors, device loss, and ordinary surface churn.
  • Theme consistency: dark-mode menu colors now follow the same theme mode as the rest of the app.
  • Chain palette consistency: light theme chain B/C colors now match the dark theme ordering instead of swapping green and blue.
  • Windows bundle startup: bundled Python dependency paths are prepared before plugin DLL loading, including the venv Scripts directory.
  • Windows diagnostics cleanup: selected-GPU logging warnings are silenced where Windows uses Slint's automatic WGPU path.
  • Viewport GPU copy cleanup: viewport GPU image copy/readback helpers moved into patinae-render, keeping the Slint viewport layer thinner.
  • Version tooling: scripts/version.sh now keeps the README version badge in sync during version bumps.

Downloads

Bundles (recommended)

Self-contained packages with the app, plugins, and runtime pieces. Unzip or mount and run.

Platform Architecture Download
macOS Apple Silicon Patinae.dmg
Windows x86_64 patinae-bundle-windows-x86_64.zip
Windows ARM64 patinae-bundle-windows-arm64.zip

Standalone executables

Bare binaries for advanced users. Plugins can be installed separately.

Platform Architecture Executable Plugins
macOS Apple Silicon patinae-macos-arm64.tar.gz patinae-plugins-macos-arm64.tar.gz
Windows x86_64 patinae-windows-x86_64.zip patinae-plugins-windows-x86_64.zip
Windows ARM64 patinae-windows-arm64.zip patinae-plugins-windows-arm64.zip
Linux x86_64 patinae-linux-x86_64.tar.gz patinae-plugins-linux-x86_64.tar.gz
Linux ARM64 patinae-linux-arm64.tar.gz patinae-plugins-linux-arm64.tar.gz

Python and web

Package Download
Python wheels pip install patinae or see release assets below
Web viewer (WASM + JS) patinae-web.tar.gz

Release scale

Compared with v0.4.2, this release touches 96 files, with 9,290 insertions and 1,365 deletions. Most of the work is concentrated in renderer memory policy, representation budgeting, SceneStore compaction, OOM recovery, desktop/web renderer hosts, the performance HUD, and Windows startup behavior.


Full Changelog: v0.4.2...v0.4.3