Skip to content

Application-shape conversions: opengl examples & tutorials, pathTracer viewers, hrtf, dasHV fixture - #3595

Merged
borisbat merged 6 commits into
masterfrom
bbatkin/app-shape-conversions
Jul 30, 2026
Merged

Application-shape conversions: opengl examples & tutorials, pathTracer viewers, hrtf, dasHV fixture#3595
borisbat merged 6 commits into
masterfrom
bbatkin/app-shape-conversions

Conversation

@borisbat

Copy link
Copy Markdown
Collaborator

Application-shape conversions: opengl examples & tutorials, pathTracer viewers, hrtf, dasHV fixture

The remaining slices of the canonical-shape audit (#3593 landed the mechanical sweep; this converts what needed real restructuring). One PR, four bisectable commits — each chunk independently run-proven.

Commit 1 — dasHV tutorials (fixture fix, not conversions). The shared server fixture's threaded tick loop ran with zero collect points; a thread context collects its own heap when the program declares options gc (probe-verified — all 8 tutorial roots already carried gc+persistent_heap as dead flags). maybe_collect_gc() now sits between ticks at all 7 loop sites, and the fixture header states what it is: test scaffolding so the client script can run in-process, not an app skeleton — real servers use the canonical shape (examples/hv/ws_chat_server.das). Tutorials 03/05/06/07 run end-to-end.

Commit 2 — tutorials/opengl ×12. Pure mechanics: options gc+persistent_heap, require live/live_gc, collect call in the desktop loop. The def update : bool contract stays — it's a blessed stop-signal variant (the wasm host auto-drives the trio and never calls main; the files already documented this correctly).

Commit 3 — pathTracer GL viewers ×3 + hrtf. Monolith → trio + canonical main with a --max-frames bound (the viewers' --frames long flag renamed to --max-frames; -f kept; no callers existed). hrtf's audio callback/mixer untouched; teardown order preserved exactly. All four run-proven windowed, 60-frame bounded, exit 0.

Commit 4 — examples/opengl ×10. Same conversion; frame bodies verbatim, defers → shutdown() in LIFO order. 09/10/11's GLFW callbacks drop by-ref captures of init() locals for module globals — required, those captures would dangle once init returns. All 10 run-proven windowed, exit 0.

Every converted file is now live-reloadable and web-drivable (the trio is the contract both hosts consume). Node-editor deliberately parked (legacy imgui_app() host — a port, not a patch).

Validation: lint + dasfmt green across all 33 touched files (pre-existing long-function warnings nolinted at 9 sites); 17 windowed run proofs + 4 dasHV end-to-end runs; CPU pathTracer + _profile still compile; preflight fast tier green.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NcrnLGE9AEh8EAND3xYCRC

borisbat added 4 commits July 30, 2026 04:28
… as test scaffolding

The fixture's threaded tick loop ran with zero collect points -- and a thread context can collect its own heap when the program declares options gc (probe-verified; all 8 tutorial roots already carried gc+persistent_heap as dead flags). maybe_collect_gc() now sits between ticks in all 7 loop sites. The fixture header states what it is: test scaffolding so the client script can run in-process, NOT an app skeleton -- real servers use the canonical shape (examples/hv/ws_chat_server.das). Run-proven: tutorials 03/05/06/07 end-to-end, exit 0; lint 7 files clean; format-verified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01NcrnLGE9AEh8EAND3xYCRC
Each tutorial gains options gc + persistent_heap (nothing in their require chain cascades either), require live/live_gc, and maybe_collect_gc() inside main's while (update()) loop. The bool-returning update stays -- it is a blessed stop-signal variant, not a web contract (the wasm host auto-drives the trio and never calls main; the files' own comments already said so correctly). Pre-existing long-function warnings nolinted at 4 sites. Lint 12 files clean, dasfmt verified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01NcrnLGE9AEh8EAND3xYCRC
The three pathTracer viewers and the HRTF demo split their monolithic mains into the exported trio + a canonical main (update + maybe_collect_gc per frame, --max-frames bound; the viewers' --frames long flag renamed to --max-frames, -f kept, no callers existed). Frame bodies moved verbatim; hrtf's audio callback/mixer path untouched, teardown order preserved exactly (finalize then LIFO defers). All four run-proven windowed: 60-frame bounded runs exit 0 (hrtf plays and finalizes its mixer cleanly). CPU toy_path_tracer + _profile still compile.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01NcrnLGE9AEh8EAND3xYCRC
Each monolithic main splits into the exported trio + canonical main (update + maybe_collect_gc per frame, arcanoid-pattern --max-frames bound); frame bodies verbatim, defers become shutdown() in LIFO order, needed locals hoisted to module globals. 09/10/11's GLFW callbacks drop their by-ref captures of init() locals for globals -- required, not stylistic: those captures would dangle once init returns. Wasm host note added per file (the trio makes these web-drivable; main is desktop-only). All 10 run-proven windowed: 60-frame bounded runs exit 0. Lint + dasfmt clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01NcrnLGE9AEh8EAND3xYCRC
Copilot AI review requested due to automatic review settings July 30, 2026 11:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR continues the repo-wide “canonical application shape” adoption by converting remaining OpenGL tutorials/examples and the pathTracer viewers to the exported init/update/shutdown lifecycle, and by inserting explicit GC boundaries (options gc + maybe_collect_gc()) into long-running loops (including threaded dasHV tutorial fixtures). It also updates the HRTF demo to the same lifecycle while keeping the audio callback/mixer behavior intact.

Changes:

  • Add options gc / options persistent_heap plus maybe_collect_gc() boundaries to OpenGL tutorial/example loops and dasHV server tick loops.
  • Refactor pathTracer OpenGL viewers and several OpenGL examples from monolithic main loops into exported init/update/shutdown + standalone main drivers (with --max-frames where applicable).
  • Restructure the HRTF demo into the same exported lifecycle and add GC boundaries in the main loop.

Reviewed changes

Copilot reviewed 33 out of 33 changed files in this pull request and generated 17 comments.

Show a summary per file
File Description
tutorials/opengl/12_gltf/12_gltf.das Adds gc+persistent_heap, imports live GC helper, inserts GC boundary in loop.
tutorials/opengl/11_hdr/11_hdr.das Adds gc+persistent_heap, imports live GC helper, inserts GC boundary in loop.
tutorials/opengl/10_deferred/10_deferred.das Adds gc+persistent_heap, imports live GC helper, inserts GC boundary in loop.
tutorials/opengl/09_msaa/09_msaa.das Adds gc+persistent_heap, imports live GC helper, inserts GC boundary in loop.
tutorials/opengl/08_shadow/08_shadow.das Adds gc+persistent_heap, imports live GC helper, inserts GC boundary in loop.
tutorials/opengl/07_particles/07_particles.das Adds gc+persistent_heap, imports live GC helper, inserts GC boundary in loop.
tutorials/opengl/06_skybox/06_skybox.das Adds gc+persistent_heap, imports live GC helper, inserts GC boundary in loop.
tutorials/opengl/05_instancing/05_instancing.das Adds gc+persistent_heap, imports live GC helper, inserts GC boundary in loop.
tutorials/opengl/04_cube/04_cube.das Adds gc+persistent_heap, imports live GC helper, inserts GC boundary in loop.
tutorials/opengl/03_sdf/03_sdf.das Adds gc+persistent_heap, imports live GC helper, inserts GC boundary in loop.
tutorials/opengl/02_mandelbrot/02_mandelbrot.das Adds gc+persistent_heap, imports live GC helper, inserts GC boundary in loop.
tutorials/opengl/01_triangle/01_triangle.das Adds gc+persistent_heap, imports live GC helper, inserts GC boundary in loop.
tutorials/dasHV/tutorial_server.das Adds per-tick GC boundary inside threaded fixture loop; clarifies fixture intent in comments.
tutorials/dasHV/08_https_wss.das Adds live GC helper + live_host and per-tick GC boundary in threaded loop.
tutorials/dasHV/07_sse_and_streaming.das Adds live GC helper + live_host and per-tick GC boundary; small callback parameter rename.
tutorials/dasHV/06_websockets.das Adds live GC helper + live_host and per-tick GC boundary; marks main as linear tutorial flow.
tutorials/dasHV/05_cookies_and_forms.das Adds live GC helper + live_host and per-tick GC boundary in threaded loop.
tutorials/dasHV/04_http_server_advanced.das Adds live GC helper + live_host and per-tick GC boundary; marks main as linear tutorial flow.
tutorials/dasHV/03_http_server.das Adds live GC helper + live_host and per-tick GC boundary; marks init/main as linear tutorial flow.
examples/pathTracer/toy_pathtracer_opengl_basic.das Refactors into init/update/shutdown, adds live GC boundary in loop, updates CLI naming.
examples/pathTracer/toy_path_tracer_opengl.das Refactors into init/update/shutdown, adds live GC boundary in loop, updates CLI naming.
examples/pathTracer/toy_path_tracer_opengl_hdr.das Refactors into init/update/shutdown, adds live GC boundary in loop, updates CLI naming.
examples/opengl/11_hello_gltf_animation.das Converts to canonical lifecycle + standalone driver with GC boundary and --max-frames.
examples/opengl/10_hello_gltf.das Converts to canonical lifecycle + standalone driver with GC boundary and --max-frames.
examples/opengl/09_hello_mesh.das Converts to canonical lifecycle + standalone driver with GC boundary and --max-frames.
examples/opengl/07_hello_gen.das Converts to canonical lifecycle + standalone driver with GC boundary and --max-frames.
examples/opengl/06_hello_ttf.das Converts to canonical lifecycle + standalone driver with GC boundary and --max-frames.
examples/opengl/05_hello_compute.das Converts to canonical lifecycle + standalone driver with GC boundary and --max-frames.
examples/opengl/04_hello_render_to_texture.das Converts to canonical lifecycle + standalone driver with GC boundary and --max-frames.
examples/opengl/03_hello_cube.das Converts to canonical lifecycle + standalone driver with GC boundary and --max-frames.
examples/opengl/02_hello_image.das Converts to canonical lifecycle + standalone driver with GC boundary and --max-frames.
examples/opengl/01_hello_triangle.das Converts to canonical lifecycle + standalone driver with GC boundary and --max-frames.
examples/audio/hrtf/main.das Converts to canonical lifecycle, adds GC boundary in loop, keeps audio system finalize in shutdown.
Comments suppressed due to low confidence (1)

examples/opengl/02_hello_image.das:118

  • shutdown() passes a nullable GLFWwindow? to glfwDestroyWindow. The GLFW binding does not guard against null; guard and clear the window handle before terminating (see modules/dasGlfw/dasglfw/glfw_live.das:86-93).
[export]
def shutdown() {
    glfwDestroyWindow(window)
    glfwTerminate()
}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread examples/opengl/01_hello_triangle.das
Comment thread examples/opengl/04_hello_render_to_texture.das
Comment thread examples/opengl/03_hello_cube.das
Comment thread examples/opengl/05_hello_compute.das
Comment thread examples/opengl/06_hello_ttf.das
Comment thread examples/audio/hrtf/main.das
Comment thread examples/pathTracer/toy_path_tracer_opengl.das Outdated
Comment thread examples/pathTracer/toy_path_tracer_opengl_hdr.das Outdated
Comment thread examples/opengl/05_hello_compute.das Outdated
Comment thread examples/opengl/02_hello_image.das Outdated
Copilot findings: shutdown() passed a nullable GLFWwindow? straight to
glfwDestroyWindow. Guard + clear the handle (glfw_live.das
live_destroy_window pattern) in all 14 converted files so shutdown is
safe after partial init; hrtf's stats_box lock-box removal gets the same
guard. glfwTerminate stays unconditional (documented safe pre-init).
Also 4 comment typos.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcrnLGE9AEh8EAND3xYCRC
Copilot AI review requested due to automatic review settings July 30, 2026 12:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 33 out of 33 changed files in this pull request and generated no new comments.

libImguiApp & co. take GLFW_INCLUDE_DIR (the GLFW3 ExternalProject's
$<CONFIG>/include install tree) but had no dependency edge on it, so
Ninja could compile module_imgui_app.cpp before the 3.4 headers were
staged and fall back to the system GLFW 3.3 (no GLFWallocator) - hit on
the linux Debug lane. Same ADD_DEPENDENCIES edge dasGlfw's own libs and
the imguiApp shared twin already carry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcrnLGE9AEh8EAND3xYCRC
Copilot AI review requested due to automatic review settings July 30, 2026 12:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 34 out of 34 changed files in this pull request and generated no new comments.

@borisbat
borisbat merged commit 8975d77 into master Jul 30, 2026
36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants