Metal: make display sync configurable (mtl-vsync)
With vsync on (default) presents wait for the panel refresh: redisplay self-caps at the display rate, which is also a power win (the stock backend happily renders hundreds of invisible frames per second under sustained scroll). Disabling it trades that cap for NS-like latency on machine-paced workloads.
This commit is contained in:
parent
d9948f18dd
commit
11afaa1eb4
3 changed files with 29 additions and 0 deletions
22
src/mtlfns.m
22
src/mtlfns.m
|
|
@ -606,6 +606,27 @@ frame. Returns t while animations are enabled, nil otherwise. */)
|
|||
return Qt;
|
||||
}
|
||||
|
||||
DEFUN ("mtl-vsync", Fmtl_vsync, Smtl_vsync, 1, 2, 0,
|
||||
doc: /* Enable (non-nil) or disable display sync for FRAME's GPU layer.
|
||||
With vsync on (default) presents wait for the display refresh: redisplay
|
||||
is capped at the panel rate, which keeps CPU/GPU use minimal. With it
|
||||
off, presents return immediately (lower latency, uncapped, more power).
|
||||
FRAME defaults to the selected frame. */)
|
||||
(Lisp_Object enable, Lisp_Object frame)
|
||||
{
|
||||
if (NILP (frame)) frame = Fselected_frame ();
|
||||
CHECK_LIVE_FRAME (frame);
|
||||
g_mtl_vsync_enabled = !NILP (enable);
|
||||
MtlFrameData *fd = mtl_get_frame_data (XFRAME (frame));
|
||||
if (fd && fd.metalLayer)
|
||||
{
|
||||
block_input ();
|
||||
fd.metalLayer.displaySyncEnabled = g_mtl_vsync_enabled;
|
||||
unblock_input ();
|
||||
}
|
||||
return enable;
|
||||
}
|
||||
|
||||
void
|
||||
syms_of_mtlfns (void)
|
||||
{
|
||||
|
|
@ -632,6 +653,7 @@ syms_of_mtlfns (void)
|
|||
defsubr (&Smtl_video_move);
|
||||
defsubr (&Smtl_video_tick);
|
||||
defsubr (&Smtl_anim_tick);
|
||||
defsubr (&Smtl_vsync);
|
||||
}
|
||||
|
||||
#endif /* HAVE_MTL */
|
||||
|
|
|
|||
|
|
@ -293,6 +293,7 @@ extern MtlScrollEasing g_mtl_scroll_easing;
|
|||
extern float g_mtl_scroll_duration; /* seconds, default 0.15 */
|
||||
extern NSUInteger g_mtl_trail_len; /* default 20 */
|
||||
extern BOOL g_mtl_animations_enabled; /* default NO (animations are opt-in) */
|
||||
extern BOOL g_mtl_vsync_enabled; /* default YES (60fps power cap) */
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
Global Metal display list
|
||||
|
|
|
|||
|
|
@ -262,6 +262,11 @@ MtlScrollEasing g_mtl_scroll_easing = MTL_EASE_OUT_QUAD;
|
|||
float g_mtl_scroll_duration = 0.15f;
|
||||
NSUInteger g_mtl_trail_len = 20;
|
||||
|
||||
/* When false, presents do not wait for the display refresh
|
||||
(CAMetalLayer.displaySyncEnabled): redisplay never blocks on a
|
||||
drawable, trading the 60 fps power cap for NS-like latency. */
|
||||
BOOL g_mtl_vsync_enabled = YES;
|
||||
|
||||
/* Master switch for the GPU animation layer (cursor effects, particles,
|
||||
CADisplayLink @60fps). OFF by default: the goal is pixel-correct parity
|
||||
with the NS backend first. When off, the cursor is drawn directly into the
|
||||
|
|
@ -781,6 +786,7 @@ mtl_setup_frame (struct frame *f)
|
|||
layer.device = g_device;
|
||||
layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
layer.framebufferOnly = YES;
|
||||
layer.displaySyncEnabled = g_mtl_vsync_enabled;
|
||||
layer.frame = view.bounds;
|
||||
layer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue