Downstream fixes: dynamic-flags ABI semantics, per-object dirty skipping (-79% csmUpdateModel), dirty-detection precision (rebased onto 1.1.0) - #4
Open
970205011 wants to merge 5 commits into
Conversation
…ore semantics The official core's reset only re-baselines the internal diff state; the flag array keeps showing the current frame's DidChange bits until the next csmUpdateModel overwrites them. Host apps (Cubism Framework) call csmUpdateModel -> csmResetDrawableDynamicFlags back to back and read the flags later while drawing, so clearing the array in place erased the current frame's bits before any read (csmVertexPositionsDidChange was always 0, silently disabling the mask/clipping pipeline and leaving uninitialized buffer indexes to be read). Update the regress_flag_reset scenario to assert the aligned semantics.
Skip deformers/art meshes/offscreens/glues whose blend key index/weight are unchanged with no dirty blend-shape target, no enable flip, and no recomputed parent deformer. Hidden nodes (enable=false/opacity=0) and their children are skipped entirely. Steady-state csmUpdateModel drops 5.88ms to 1.27ms (-79%/4.9x, -O3); mask steady state 9/64 unchanged, no crash over 4h+ run.
…lidation psm__update_flags set csmVertexPositionsDidChange for every enabled drawable each frame (Normal dirty branch). In steady state with dirty skipping most enabled meshes are not recomputed, so their vertex buffers are already current and do not need re-upload / mask re-draw. Gate the flag on m->mesh_changed[i] (set in psm__process_art_meshes, which runs before psm__update_flags) so only genuinely recomputed meshes report a vertex change. This makes the framework skip the mask atlas pass on most frames (Draw ~17ms -> ~7ms) while keeping clipping correct.
The dirty-update skip rule assumed a mesh's parent-part contribution only changes when the part chain's enable state flips (caught by en_flip). But the part's effective opacity also changes at runtime when the user adjusts a part opacity via the UI (csmSetPartOpacity -> input_opacity), without any enable flip. Clean meshes then kept their stale final opacity until they happened to be recomputed for another reason, so part opacity edits did not take effect. Track per-part effective-opacity changes: add part_opa_dirty / part_opa_prev arrays, set part_opa_dirty[i] in psm__apply_part_opacity when the recomputed effective opacity differs from the previous frame, and treat a changed parent part as a recompute reason in psm__process_art_meshes.
psm__apply_glues 对 glue 两个端点 mesh 做 stateful 位置混合。旧 psm__glue_mesh_dirty 只在 glue 自身脏时标记两端;若仅一端因动画 self_dirty 而重算,另一端保持 clean,则 clean 端仍保存上一帧 post-glue 的最终位置,重应用 glue 时出现 double-counting,且该端 mesh_changed=0 导致 reverse_y 遗漏、VERTEX_CHANGED 缺失 -> mask atlas 不重绘 -> 手臂闪烁。 新逻辑:先按 self_dirty/blend/enable-flip/parent/part-opa 计算 base_dirty;再对 glue 做固定点传播(glue 自身脏或任一端 base_dirty 则两端都标记 glue_mesh_dirty=1);调用点移到 process_art_meshes 前,确保 enable/deformer/part 状态就绪。
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.
PurismCore is used as a drop-in
Live2DCubismCore.dllreplacement under the official CubismFramework (Qt6 desktop app, production model: 3713 drawables / 823 params / 705 parts / 314 mask clips). These five fixes were developed and validated against v1.0.1 and are now rebased onto master (1.1.0) as part of the sync. Details in #3.1.
csmResetDrawableDynamicFlagssemantics (ABI fix)The official Core's reset only re-baselines the internal diff state; it does not clear the change bits in place. The previous in-place clear erased the current frame's
csmVertexPositionsDidChangebits before the framework'scsmGetDrawableDynamicFlagsreads them, silently disabling the VERTEX_CHANGED-driven mask/clipping pipeline. With this fix, flag sampling matches the official DLL frame-for-frame (64/64 first frame, steady state 9/64 on our model).2. Per-object dirty skipping in
csmUpdateModel(+79%)The official Core skips per-drawable work when inputs are unchanged. Per-object dirty checks (skip deformer/art-mesh/offscreen work when blend-key indices/weights are unchanged; skip disabled nodes and opacity-0 subtrees) bring steady-state
csmUpdateModelfrom 5.88ms to 1.27ms (-79%, 4.9x) on our model, while remaining bit-identical to the non-dirty path when everything changes.3. Dirty-detection precision
VERTEX_CHANGEDis set only for meshes actually recomputed this frame (gated onmesh_changed), matching official sparsity and avoiding needless vertex re-uploads/mask passes.Validation
-O3(shared library,PURISM_CORE_DLL), 0 errors.