VNCCanvas: fix faint ghost edges left by a moving cursor - #303
Open
michael-adler wants to merge 1 commit into
Open
VNCCanvas: fix faint ghost edges left by a moving cursor#303michael-adler wants to merge 1 commit into
michael-adler wants to merge 1 commit into
Conversation
Solid-color content (e.g. a block text cursor) advancing across the screen left faint stale borders behind at its previous positions, worst in 1:1 view and still present when scaled. Not a compression artifact -- reproduced regardless of encoding/quality settings. Two separate bugs were stacked here: 1. onPaint drew each dirty rect as its own small, independently composited bitmap. Every such tile leaves a visible seam at its own boundary (blending of a scaled edge, or HiDPI content-scale interpolation even at 1:1). Fix: composite a single whole-canvas bitmap in onPaint instead of many per-rect tiles, removing any internal edge that could leave a seam. 2. Even after (1), stale content remained in some spots, and a full forced repaint (e.g. from a resize) always cleared it -- meaning the pixel data was correct, but some Refresh(false, &rect) calls for just the changed sub-rect just never resulted in that area being repainted on this wx port. Tried coalescing all of a tick's changes into one bounding-box Refresh() call instead of one call per rect, in case it was multiple overlapping calls confusing the OS's dirty tracking -- still lost updates. So partial-rect invalidation itself isn't reliable here, not just how it's split into calls. Fix: always invalidate the whole canvas on any change, removing the dependency on that tracking entirely. Invalidating and redrawing everything on every update would normally be wasteful, so VNCCanvas now keeps its own native-resolution copy of the framebuffer (fb_cache), updated incrementally: only the changed rect is re-fetched from the connection (the expensive per-pixel copy, unchanged in cost from before this fix), while onPaint just blits the already-current cache in one cheap, GPU-composited call. The always-redraw-everything requirement from (2) ends up nearly free. Root cause of the wx-level partial-invalidation unreliability itself is still unknown. Signed-off-by: Michael Adler <madler@tapil.com>
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.
Solid-color content (e.g. a block text cursor) advancing across the screen left faint stale borders behind at its previous positions, worst in 1:1 view and still present when scaled. Not a compression artifact -- reproduced regardless of encoding/quality settings.
Tested on MacOS.
Two separate bugs were stacked here:
onPaint drew each dirty rect as its own small, independently composited bitmap. Every such tile leaves a visible seam at its own boundary (blending of a scaled edge, or HiDPI content-scale interpolation even at 1:1). Fix: composite a single whole-canvas bitmap in onPaint instead of many per-rect tiles, removing any internal edge that could leave a seam.
Even after (1), stale content remained in some spots, and a full forced repaint (e.g. from a resize) always cleared it -- meaning the pixel data was correct, but some Refresh(false, &rect) calls for just the changed sub-rect just never resulted in that area being repainted on this wx port. Tried coalescing all of a tick's changes into one bounding-box Refresh() call instead of one call per rect, in case it was multiple overlapping calls confusing the OS's dirty tracking -- still lost updates. So partial-rect invalidation itself isn't reliable here, not just how it's split into calls. Fix: always invalidate the whole canvas on any change, removing the dependency on that tracking entirely.
Invalidating and redrawing everything on every update would normally be wasteful, so VNCCanvas now keeps its own native-resolution copy of the framebuffer (fb_cache), updated incrementally: only the changed rect is re-fetched from the connection (the expensive per-pixel copy, unchanged in cost from before this fix), while onPaint just blits the already-current cache in one cheap, GPU-composited call. The always-redraw-everything requirement from (2) ends up nearly free.
Root cause of the wx-level partial-invalidation unreliability itself is still unknown.