Application-shape conversions: opengl examples & tutorials, pathTracer viewers, hrtf, dasHV fixture - #3595
Merged
Merged
Conversation
… 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
Contributor
There was a problem hiding this comment.
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_heapplusmaybe_collect_gc()boundaries to OpenGL tutorial/example loops and dasHV server tick loops. - Refactor pathTracer OpenGL viewers and several OpenGL examples from monolithic
mainloops into exportedinit/update/shutdown+ standalonemaindrivers (with--max-frameswhere 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.
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
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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. Thedef update : boolcontract stays — it's a blessed stop-signal variant (the wasm host auto-drives the trio and never callsmain; the files already documented this correctly).Commit 3 — pathTracer GL viewers ×3 + hrtf. Monolith → trio + canonical main with a
--max-framesbound (the viewers'--frameslong flag renamed to--max-frames;-fkept; 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 ofinit()locals for module globals — required, those captures would dangle onceinitreturns. 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