fix(graphics): scope image store keys per terminal#1752
Open
cantona wants to merge 1 commit into
Open
Conversation
The window-level image stores (Sugarloaf::image_data and the renderer's
per-image GPU texture cache) were keyed by a bare numeric id: kitty
images by their protocol id verbatim, atlas graphics (sixel/iTerm2) by
their GraphicId shifted above the u32 range. One window hosts many
terminals (tabs and splits) that all share these stores, but both id
spaces restart per terminal -- a kitty client in each tab numbers its
images from 1, and each terminal's atlas GraphicIds start over too. So
two tabs displaying images collided: tab B's image id 1 overwrote tab
A's, and removals could free the wrong tab's texture.
Replace the flat u64 key with ImageKey { owner, source, id }, where
owner is the originating route id and source distinguishes the atlas
and kitty id spaces. Disjointness now comes from the source
discriminant rather than a numeric shift, so atlas keys carry the raw
GraphicId. The removal queue changes from Vec<u64> to
Vec<GraphicRemoval> (Atlas(GraphicId) | Kitty(u32)) so the frontend,
which owns the route id, builds the matching key; removals are applied
before inserts so an evict-then-retransmit of the same id in one batch
keeps the fresh pixels.
This was referenced Jul 23, 2026
cantona
force-pushed
the
fix/multi-tab-image-key
branch
from
July 23, 2026 09:05
9358a0d to
5674f6c
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.
fix(graphics): scope image store keys per terminal
Problem
The window-level image stores —
Sugarloaf::image_data(CPU pixels) andthe renderer's per-image GPU texture cache — are keyed by a bare numeric
id:
image_idverbatim (kitty_image_key)GraphicIdshifted above theu32 range (
atlas_image_key)But one window hosts many terminals (tabs and splits) that all share
these stores, and both id spaces restart per terminal: a kitty
client in each tab numbers its images from 1, and each terminal's atlas
GraphicIds start over too.So two tabs displaying images collide:
the shared store. Switch back to Tab A and its image is now B's.
under some numbering, since the "disjoint namespace" was only a
numeric shift.
To reproduce: open two tabs,
icat/imgcata different image in each,then switch between them — the images bleed across tabs.
Fix
Replace the flat
u64key with a composite key:ownerscopes every entry to the terminal that produced it, so tabsno longer share id space.
sourcedistinguishes the atlas and kitty id spaces, so disjointnesscomes from the discriminant rather than a numeric shift — atlas keys
now carry the raw
GraphicIdwith no1 << 32offset.The backend removal queue changes from
Vec<u64>toVec<GraphicRemoval>(Atlas(GraphicId)|Kitty(u32)), because thebackend has no notion of the frontend's route id. The frontend, which
owns the route id, builds the matching
ImageKeywhen draining thequeue.
Removals are now applied before inserts in the frontend handler, so
an evict-then-retransmit of the same id landing in one batch keeps the
freshly transmitted pixels instead of dropping them.
Scope
Pure re-keying of the shared image stores and the removal queue. No
change to byte accounting, eviction policy, or the render loop.
Testing
cargo fmt --all -- --check— cleancargo clippy -p rioterm --all-features— no new warningscargo test --features wgpu— all suites pass (0 failed)image_keys_discriminate_source_and_ownerpins that thesame protocol id from two owners / two sources maps to distinct keys,
and that identity holds within one owner+source.