fix(sdl2): content-hash attributes in line fingerprint to fix text ghosting#2219
Merged
theangelperalta merged 2 commits intoJun 4, 2026
Conversation
Contributor
|
✅ Code Contractor Validation: PASSED ℹ️ 1 violation(s) dismissed 📚 About Code ContractorDeclarative Code Standards That Learn and Improve Define domain-specific validation rules in YAML. Want this for your repo? |
All violations have been dismissed.
The SDL2 frontend composites persistent per-view GPU textures and only re-renders lines the per-window line-fingerprint cache marks as changed. That fingerprint folded each item through sxhash, but in SBCL sxhash on a standard-object (attribute) and structure-object (color) is identity-based, not content-based. Attributes can be mutated in place -- e.g. vi-mode and skk-mode recolor the shared cursor attribute via set-attribute. After such a mutation the object identity is unchanged, so sxhash is unchanged, the fingerprint is unchanged, and the line is skipped on redraw -- leaving the previous frame's glyphs on the persistent texture (ghosting). M-x redraw-display cleared the cache and masked the bug. Add item-content-hash, used by djb2, which folds attribute content (foreground/background/reverse/bold/underline) and color components, and recurses through cons spines so attributes nested in the (start end attribute) entries of logical-line-attributes are content-hashed. This makes the fingerprint consistent with attribute-equal and the rest of the pipeline. Genuinely unchanged lines still hash identically and are still skipped. Add test-fingerprint-detects-attribute-mutation covering in-place mutation through both logical-line-attributes and end-of-line-cursor-attribute.
…l access Address Code Contractor internal_symbol_rule: switch the mutation test to the exported `make-attribute`/`set-attribute` (via the package's :use of :lem-core) instead of `lem-core::`, and document why the remaining `make-logical-line`/`compute-line-fingerprint` internals are accessed (white-box unit test of the display layer's fingerprint cache).
602c507 to
145214a
Compare
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.
Summary
The SDL2 frontend composites persistent per-view GPU textures and only re-renders lines the core display layer marks as changed. That decision is made by a per-window line-fingerprint cache in
src/display/physical-line.lisp: each frame every screen line is hashed, and if the hash matches the cached one the line is skipped.The fingerprint folded each item through
sxhash. In SBCL,sxhashon astandard-object(theattributeclass) and on astructure-object(thecolorstruct) is identity-based, not content-based. Attributes can be mutated in place — e.g. vi-mode and skk-mode recolor the sharedcursorattribute viaset-attribute. After such a mutation the object identity is unchanged, sosxhashis unchanged, so the fingerprint is unchanged, so the line is skipped on redraw — leaving the previous frame's glyphs on the persistent texture. That is the ghosting.M-x redraw-displaycleared the fingerprint cache and repainted every line, which is why a forced redraw made the ghost disappear.This makes the fingerprint hash attribute/color content, consistent with how the rest of the pipeline compares attributes (
attribute-equal,drawing-object-equal, the SDL2text-surface-cache).Changes
src/display/physical-line.lispitem-content-hash, a content-based hash used bydjb2:attribute→ foldsforeground,background,reverse,bold,underline.color→ folds thered/green/bluecomponents.cons→ recurses through the spine (tolerant of dotted tails) so attributes nested inside the(start end attribute)entries oflogical-line-attributesare content-hashed, not caught by the identity-basedsxhashof the surrounding sublist.sxhash(unchanged behavior).djb2now callsitem-content-hashinstead ofsxhash.The performance optimization is preserved: genuinely unchanged lines still hash identically and are still skipped; only in-place attribute mutation now correctly invalidates the line.
tests/display-cache.lisptest-fingerprint-detects-attribute-mutation, asserting the line fingerprint changes after an in-placeset-attributemutation, covering both an attribute referenced throughlogical-line-attributesand one referenced throughend-of-line-cursor-attribute(the literal cursor case).Notes
contract.ymlstyle rules (colon-prefixedloopkeywords, kebab-case naming, docstring on the new function).