fix(milkdrop): each block keeps MilkDrop 2's own variables - #620
Merged
Merged
Conversation
ns-eel2 keeps reg00..reg99 in one process-wide array (nseel_globalregs): per-frame, per-pixel, every wave and shape and both presets of a transition see the same hundred values, and nothing resets them. With fidelity on the engine now does the same; with it off each pool keeps its own registers. The switch is read at run time, so flipping fidelity moves the storage in the same frame, and Preset.get/set follow it. The common idiom is init writing random values to reg01..reg03 and shapes reading them; the shapes saw 0 and piled their instances on one point. 192 corpus presets use registers. resetGlobals() clears gmegabuf and the registers. MilkDrop never does; thumbnails call it before each render, so a thumbnail depends on its key and not on the preset drawn before it, and tests use it for isolation. Refs #580, #560
…op 2 MilkDrop runs per-pixel code in a VM of its own (state.cpp m_pv_eel). It does not see per-frame's variables; it gets time, fps, frame, progress, the six audio values, the mesh and pixel sizes and the aspect once a frame before per-frame runs, q1..q32 after it, and zoom..sy per vertex from what per-frame left. Its own variables and megabuf persist across vertices and frames, and what it writes never reaches per-frame or the drawing. With fidelity on the engine now does the same; with it off per-pixel shares the main pool as before. Per-pixel code is compiled twice, once per pool, because closures bind the pool at compile time and fidelity can flip at run time. The old zoom_base escape is legacy only (no corpus use). Preset construction costs about 0.03 ms more; a 1,728-vertex frame costs the same. A static scan finds 696 presets whose per-pixel code reads or writes something per-frame also uses: per-pixel reading a per-frame variable (453), writing one per-frame reads (285), writing per-frame-only names such as decay or wave_r (91), writing q (146), megabuf in both (10). Per-frame code that keeps its own x or y was also overwritten by the last vertex. Refs #580, #560
…ilkDrop 2 Each custom wave has two VMs in MilkDrop (state.cpp m_pf_eel and m_pp_eel). Per-point code does not see the wave's per-frame variables; it gets time, fps, frame, progress and the six audio values before the wave's per-frame code runs, q1..q32 and t1..t8 after it, and sample, value1, value2, x, y and the colour per point. Its own variables and megabuf persist across points and frames; t1..t8 it writes last only until the next frame. With fidelity on the engine now does the same; with it off per-point shares the wave's pool as before. Two wave tests read a per-frame counter from per-point; they now pass it through t1 and t2, the way a MilkDrop preset has to. Refs #580, #560
…changes them MilkDrop loads time, fps, frame, progress and the six audio values into each wave and shape from its own sources (LoadCustomWavePerFrameEvallibVars, LoadCustomShapePerFrameEvallibVars), not from the main per-frame VM. The engine copied them from the main pool after per-frame ran, so a preset that rewrites bass or time in per-frame changed what its waves and shapes saw. With fidelity on they now read the values from before per-frame, the snapshot per-pixel already takes; three corpus presets are affected. With fidelity off nothing changes. Refs #580, #560
ns-eel2 caps each loop and while call at 1,048,576 turns (NSEEL_LOOPFUNC_SUPPORT_MAXLEN) and has no budget per block. The engine has a budget per run so that a preset cannot freeze the app; with fidelity on each call is now capped like MilkDrop's and the budget is wider where MilkDrop allows it: 4,194,304 for init code and 1,048,576 for per-frame code of the preset, its waves and its shapes. Per-pixel and per-point keep 1,024 a vertex, where MilkDrop's cap would freeze the app. A shape runs its per-frame code once per instance, so one shape may spend at most 4,194,304 turns a frame over all instances. Five corpus presets need about 1.07 million turns in init and ran out at 1,048,576; one shape needs 103,424 in a frame and ran out at 65,536. While also stopped one turn early under the new cap, found by a test. With fidelity off nothing changes. Refs #580, #560
ROADMAP (#580) describes the variable scope with its sources, the measurements per step and the 900-preset sample, and moves scope and the loop cap out of the not-done list. Division by zero and the guarded functions stay there with the corpus count and the reason; 16-character variable names are left out with the reason. Both READMEs gain a bullet. Refs #580, #560
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.
With fidelity on, every expression block now has MilkDrop 2's own variables. MilkDrop runs each block in a virtual machine of its own (state.cpp:213-225); the engine used one pool for init, per-frame and per-pixel, and one per wave for per-frame and per-point. With fidelity off nothing changes — every measured group is byte-identical.
Source checked in Nullsoft's ns-eel2 (BeatDrop 53d83ee): variables live in each VM's own table (
ctx->varTable); onlyreg00..reg99(nseel_globalregs[100]) andgmegabufare shared.Commits
reg00..reg99are one array for every block, wave, shape and both presets of a transition;Preset.get/setfollow;resetGlobals()clears registers andgmegabufmegabuf; nothing leaks back to per-frame or drawingmegabufloop/whilestop at 1,048,576 turns a call; budgets widened where MilkDrop allows (init 4,194,304, per-frame 1,048,576, one shape ≤ 4,194,304 a frame over its instances); per-pixel/per-point keep 1,024 a vertexPer-pixel and per-point code is compiled twice (one per pool) so fidelity can still flip at run time. Thumbnails now call
resetGlobals()before each render, so a thumbnail depends only on its key; video export already opens a fresh page per job.Measured
Against the previous commit, last 10 of 60 frames, each preset in a fresh page (no carry-over of registers,
gmegabufor feedback):reg01..03 = rand(..), shapes read them; before, shapes saw 0 and stacked all instances on one point (Martin – Pixies Party, city lights).x/y, which the last vertex used to overwrite.x/yin per-frame and hands them to per-pixel as the zoom centre; the last vertex used to overwrite them every frame. Alone in a fresh page it differs by 61% and is not blown (brightness 0.62), so its class there also depends on run order.Thumbnails and exports of register, per-pixel and per-point presets change as expected; existing thumbnails regenerate because the engine files change.
Tests
24 new in
tests/milkdrop-md2-scope.test.js; thumbnail page test checks the reset; two wave tests pass a per-frame counter through t1/t2 as a MilkDrop preset must; compile guard counts 13 calls. 2251/2251 pass. 51 of 52 mutations caught (the one left caps loops with fidelity off too — equivalent, since that budget never exceeds the cap). Awhileoff-by-one under the new cap was found by a test and fixed.npm run smoke: only a context-loss phase fails, the same environmental failuremain(47935d2) and 7050cc9 show on this machine today (throttled frames); the MilkDrop compile line is unchanged (5,25,5,7,1,8,0) and userData checksums are unchanged.Not done (documented in ROADMAP)
log(≤0),pow/exp/tanoverflow → 0;asin/acosclamp).NSEEL_MAX_VARIABLE_NAMELEN): 24 corpus presets use names that long, none collide.Refs #580, #560