Metal: coalesce immediate-draw presents to stop mouse-face hover flicker
Mouse-face highlight (note_mouse_highlight -> show_mouse_face) draws outside the update_begin/end cycle. Presenting on every immediate draw_glyph_string flickered: one mouse move runs clear_mouse_face + show_mouse_face, several draws, each flashing the intermediate (un-highlighted) state. Each immediate draw now commits to the static texture but defers the on-screen present (endFramePresent:NO sets needsPresent); flush_display and update_begin present once, showing the whole clear+redraw sequence in a single composite. This keeps the pipeline clean (no encoder left open between draws) while removing the flicker. Verified: hover highlight still applies (gamma 168 vs 179 inactive), AE vs NS unchanged at 0.88%.
This commit is contained in:
parent
47aeb064a1
commit
d91a6dc02b
2 changed files with 43 additions and 12 deletions
|
|
@ -169,6 +169,11 @@ typedef struct mtl_spring {
|
|||
the start of the next frame, when a render encoder is active. */
|
||||
@property (nonatomic, strong) NSMutableArray *pendingClears;
|
||||
|
||||
/* F1: immediate draws (mouse-face highlight, etc.) commit to the static texture
|
||||
but defer presenting; this flag tells flush_display a present is pending so
|
||||
the whole clear+redraw sequence is shown in one go (no flicker). */
|
||||
@property (nonatomic, assign) BOOL needsPresent;
|
||||
|
||||
/* Main Emacs render cycle (renders to staticTexture) */
|
||||
- (void)beginFrame;
|
||||
- (void)endFrame;
|
||||
|
|
|
|||
|
|
@ -1277,16 +1277,26 @@ easing_apply (MtlScrollEasing mode, float t)
|
|||
}
|
||||
|
||||
- (void)endFrame
|
||||
{
|
||||
[self endFramePresent:YES];
|
||||
}
|
||||
|
||||
/* Commit the static-texture draws. When PRESENT is NO, only the static texture
|
||||
is updated and the on-screen present is deferred (needsPresent), so a sequence
|
||||
of immediate draws (clear_mouse_face + show_mouse_face) is shown in a single
|
||||
composite by flush_display instead of flickering through each step. */
|
||||
- (void)endFramePresent:(BOOL)present
|
||||
{
|
||||
if (!self.encoder) return;
|
||||
[self.encoder endEncoding];
|
||||
[self.cmdBuf commit];
|
||||
/* Do NOT present here — compositor presents via compositeToScreen */
|
||||
self.encoder = nil;
|
||||
self.cmdBuf = nil;
|
||||
self.drawable = nil;
|
||||
/* Immediately composite so Emacs redisplay is visible */
|
||||
[self compositeToScreen];
|
||||
if (present)
|
||||
[self compositeToScreen];
|
||||
else
|
||||
self.needsPresent = YES;
|
||||
}
|
||||
|
||||
- (void)compositeToScreen
|
||||
|
|
@ -1296,6 +1306,8 @@ easing_apply (MtlScrollEasing mode, float t)
|
|||
id<CAMetalDrawable> drawable = [self.metalLayer nextDrawable];
|
||||
if (!drawable) return;
|
||||
|
||||
self.needsPresent = NO; /* about to present whatever is in the static texture */
|
||||
|
||||
NSSize sz = self.metalLayer.frame.size;
|
||||
MtlAnimator *anim = self.animator;
|
||||
|
||||
|
|
@ -2128,17 +2140,25 @@ mtl_draw_glyph_string (struct glyph_string *s)
|
|||
MtlFrameData *fd = mtl_get_frame_data (s->f);
|
||||
if (!fd) return;
|
||||
|
||||
BOOL opened_here = NO;
|
||||
if (!fd.encoder)
|
||||
/* If we are outside the normal update_begin/end cycle (mouse-face highlight
|
||||
and other immediate draws), wrap this one string in its own frame: open,
|
||||
draw, and COMMIT to the static texture, but DEFER the on-screen present.
|
||||
Presenting on every immediate draw flickered (a mouse move runs
|
||||
clear_mouse_face + show_mouse_face = several draws, each flashing the
|
||||
intermediate state); leaving the encoder open across draws instead made the
|
||||
state leak into the next click/redisplay. Committing per draw keeps the
|
||||
pipeline clean, and deferring the present lets mtl_flush_display show the
|
||||
whole sequence in one composite. */
|
||||
if (fd.encoder)
|
||||
{
|
||||
mtl_draw_glyph_string_impl (s);
|
||||
}
|
||||
else
|
||||
{
|
||||
[fd beginFrame];
|
||||
opened_here = YES;
|
||||
mtl_draw_glyph_string_impl (s);
|
||||
[fd endFramePresent:NO];
|
||||
}
|
||||
|
||||
mtl_draw_glyph_string_impl (s);
|
||||
|
||||
if (opened_here)
|
||||
[fd endFrame];
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -2231,7 +2251,13 @@ mtl_flush_display (struct frame *f)
|
|||
The bug in Phase 2 was calling beginFrame here, which left an orphaned
|
||||
encoder that never got endEncoding, causing an assertion failure. */
|
||||
MtlFrameData *fd = mtl_get_frame_data (f);
|
||||
if (fd && fd.encoder) [fd endFrame];
|
||||
if (!fd) return;
|
||||
if (fd.encoder)
|
||||
[fd endFrame];
|
||||
else if (fd.needsPresent)
|
||||
/* Present the deferred immediate draws (mouse-face highlight, etc.) that
|
||||
were committed to the static texture without presenting. */
|
||||
[fd compositeToScreen];
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue