dankamongmen / notcurses

blingful character graphics/TUI library. definitely not curses.
https://nick-black.com/dankwiki/index.php/Notcurses
Other
3.45k stars 112 forks source link

changing piles needs to kill old graphics #2318

Open dankamongmen opened 2 years ago

dankamongmen commented 2 years ago

Run [xray] in kitty, and see that we have two graphics visible at any given time. This is because when one pile replaces another, we don't kill the old graphics ([xray] happens to work with sixel because we scrub the entire affected area, but the problem exists there, too). We somehow need to kill these. See #1948 for background information.

My first thought is that all current sprixels need be duplicated (not the graphic itself, just the metadata) post-render onto a new list kept in the notcurses object. Then, if we get a new pile, we throw these copies into our sprixelcache (or just special-case them, probably easier) and they are hidden. Each raster, this list is killed off (yeah, definitely easier to special-case).

That might work?

dankamongmen commented 2 years ago

So I think the plan above will work well enough for Kitty graphics, but it's more difficult to make it work for Sixel, since we have to scrub underneath it....

so let's keep a list in the renderstate struct. when we render and the previous pile is equal to the current pile, we can blow this list away (we might reuse it, but conceptually we can blow it away). when the previous pile is not equal to the current pile, we must act on it...actually, consider this: a bitmap plane might be moved into our pile from the pile that was just rendered. so in that case, we wouldn't want to erase it, despite a different pile having been last. so we'll operate on a per-sprixel basis. that means we'll need to use the id field to correlate them (remember, we can't touch the actual sprixel, due to threading guarantees).

this could eliminate the HIDE state, and it almost needs to, since otherwise when the pile came back, we'd try to erase the graphic a second time. no, you wouldn't eliminate the state, but you'd change the handler code -- if we were the last pile, erase. otherwise, just free the sprixel. yes.

dankamongmen commented 2 years ago

we also need to handle the case where cell-pixel geometry changes. so:

so the only hitch i see is that if we kill the image, and then come back to our pile without having hidden it, we need to redraw it. that's fine with sixel and with old Kitty, but in modern kitty, we don't keep a copy of the image. if we delete with a lowercase directive, our image ought be left in cache, and thus can be summoned up with a presentation action....

but we would need to know to do that. so that's presumably another state?

dankamongmen commented 2 years ago

track_sprixel_metadata() now creates sprixel_metadata objects and enqueues them into the rstate.

dankamongmen commented 2 years ago

i don't think we can use last_pile as a quick litmus. consider the [xray] case: we only ever render one pile. we render to a new pile, then reparent that plane to the standard pile, which is rendered (after killing the previous plane). the alternate pile exists only as a scratch ground. so here we're always rendering the same pile....oh nevermind, we'll have the sprixel in SPRIXEL_HIDE state in the pile, and thus find it. ok, all good.

in any case, it turns out i can eliminate the double-draw in [xray] without all this by simply making lplane shared between the two threads, and killing it every cycle (previously, it was alive for two). unfortunately, it turns out this saves no time -- kitty wasn't slowed by having two on-screen, and we're smart enough not to be redrawing etc. we still need this for general correctness, but it's not going to speed up anything of ours. c'est la vie!

dankamongmen commented 2 years ago

well man, that sucks a lot of the impetus out of implementing this =]. master now has an [xray] clear of residue.

dankamongmen commented 2 years ago

this is a grody solution whichever way you cut it, and like so many other things, mosaics would render it meaningless. i'm tempted to boot it past 3.0.0, and let mosaics take care of things naturally...