No description
Find a file
2026-06-04 22:46:36 +02:00
.github/assets README: add the buffer cross-fade demo 2026-06-04 22:14:21 +02:00
admin Merge from origin/emacs-31 2026-05-29 11:01:25 +01:00
build-aux Update from Gnulib by running admin/merge-gnulib 2026-05-26 21:57:20 -07:00
cross ; Add 2026 to copyright years. 2026-01-01 12:54:34 +00:00
doc Disable markdown-ts-mode & markdown-ts-view-mode for Emacs 31 2026-06-01 19:11:46 +01:00
etc Support Ansible messages in compilation-mode 2026-06-02 12:43:08 +02:00
exec Fix the Android build again 2026-05-28 11:31:16 +08:00
java Bump master Emacs version to 32.0.50 2026-05-07 17:46:43 +01:00
leim ; Add 2026 to copyright years. 2026-01-01 12:54:34 +00:00
lib Also copy lib/mini-gmp-gnulib.c from Gnulib 2026-05-26 22:21:08 -07:00
lib-src Ignore SO_RCVTIMEO errors in emacsclient 2026-05-31 12:48:42 -07:00
lisp Rename the user-facing Lisp API from mtl- to gpu- 2026-06-04 22:20:20 +02:00
lwlib ARRAYELTS → countof 2026-05-26 21:57:20 -07:00
m4 ; * m4/texinfo.m4 (gl_SET_MAKEINFO): Fix introductory comment. 2026-05-31 14:22:33 +02:00
modules ; Add 2026 to copyright years. 2026-01-01 12:54:34 +00:00
msdos Fix the MSDOS build 2026-05-28 12:59:55 +08:00
nextstep ; Add 2026 to copyright years. 2026-01-01 12:54:34 +00:00
nt Bump master Emacs version to 32.0.50 2026-05-07 17:46:43 +01:00
oldXMenu ; Add 2026 to copyright years. 2026-01-01 12:54:34 +00:00
src Rename the user-facing Lisp API from mtl- to gpu- 2026-06-04 22:20:20 +02:00
test Support Ansible messages in compilation-mode 2026-06-02 12:43:08 +02:00
.clang-format
.clangd Tweak .clangd to work with gcc-compiled Emacs (bug#78367) 2025-05-11 11:14:32 +01:00
.dir-locals.el Review some attribute macro usage 2026-03-14 15:08:15 +01:00
.gitattributes Merge branch 'main' into icalendar 2026-02-08 16:05:31 -05:00
.gitignore README: add GPU demos (inline video, animated GIF, cursor effects) 2026-06-04 09:50:51 +02:00
.gitlab-ci.yml ; Add 2026 to copyright years. 2026-01-01 12:54:34 +00:00
.mailmap ; * .mailmap: Add email alias 2026-01-18 21:59:38 +01:00
autogen.sh ; Add 2026 to copyright years. 2026-01-01 12:54:34 +00:00
BUGS * BUGS: Minor copy edit. 2024-09-21 13:29:36 +02:00
ChangeLog.1 ; Add 2026 to copyright years. 2026-01-01 12:54:34 +00:00
ChangeLog.2 ; Add 2026 to copyright years. 2026-01-01 12:54:34 +00:00
ChangeLog.3 ; Update exported ChangeLog files and etc/AUTHORS 2026-05-07 20:08:43 +01:00
ChangeLog.4 ; Spelling fixes. 2026-04-29 22:45:51 -07:00
ChangeLog.5 ; * ChangeLog.5: Some fixes and tidying up. 2026-05-07 20:14:12 +01:00
ChangeLog.android ; Add 2026 to copyright years. 2026-01-01 12:54:34 +00:00
config.bat Fix the MSDOS build 2026-05-28 12:59:55 +08:00
configure.ac Fase I: split the GPU backend into neutral policy + driver vtable 2026-06-04 08:54:03 +02:00
CONTRIBUTE ; Add 2026 to copyright years. 2026-01-01 12:54:34 +00:00
COPYING
GNUmakefile ; Add 2026 to copyright years. 2026-01-01 12:54:34 +00:00
INSTALL ; Add 2026 to copyright years. 2026-01-01 12:54:34 +00:00
INSTALL.REPO ; Add 2026 to copyright years. 2026-01-01 12:54:34 +00:00
make-dist ; Add 2026 to copyright years. 2026-01-01 12:54:34 +00:00
Makefile.in Restore runtime dependencies to documentation files 2026-06-01 12:15:04 +08:00
README Bump master Emacs version to 32.0.50 2026-05-07 17:46:43 +01:00
README.md README: Homebrew cask installation 2026-06-04 22:46:36 +02:00

emacs-gpu

GNU Emacs with a GPU-accelerated display backend.

On macOS it renders with native Apple Metal: text goes through a GPU glyph atlas, images and inline video are textures, and the whole frame is composited by the GPU instead of CoreGraphics. The output is pixel-accurate against the stock Cocoa backend.

OpenGL support for GNU/Linux and Windows is planned but not implemented yet. The drawing logic is already platform-neutral (src/gfxterm.c) behind a small driver interface (src/gfxdrv.h); an OpenGL driver only needs to implement that interface (src/glterm.c is the documented skeleton). Contributions welcome.

Why a GPU backend?

Beyond raw rendering, it enables things the stock backend cannot do:

  • Inline video playback: AVFoundation decodes straight into Metal textures (zero copies) and the frames are composited inside the buffer, following scrolling and clipped to the window. No xwidgets, no embedded browser.
  • GPU cursor effects (opt-in): expanding rings, comet trails and friends are drawn as a compositor overlay, without ever touching the buffer content underneath.
  • A path to cheap visual effects: buffer transitions, smooth scrolling or any future eye candy is one more shader pass over the composited frame, not a rewrite of the display engine.

Text is rasterized once into a GPU glyph atlas and drawn as textured quads; scrolling moves already-rendered pixels with a texture blit.

Performance

Measured on an Apple M1 Pro (Emacs 32 development build, 120x45 frame, font-locked xdisp.c, same binary with and without the GPU backend; /usr/bin/time -l over scripted workloads):

Workload Stock (Cocoa) GPU, vsync on (default) GPU, vsync off
Sustained scroll, redisplays/s 481 324 475
CPU for 15 s of that scroll 16.0 s 10.5 s 15.5 s
Typing throughput (chars/s, machine-paced) 108 52 106
Idle (8 s) CPU 1.21 s 1.19 s same
Peak RSS ~140 MB ~144 MB same

Honest reading:

  • Machine-paced throughput and CPU cost match the stock backend (vsync off). There is no GPU tax.
  • With vsync on (the default), presents wait for the display refresh: the screen shows the same 60 fps either way, but Emacs burns ~35% less CPU under flat-out scrolling because it stops rendering frames nobody can see. Human-paced input is unaffected (the cap is ~52 machine-paced updates/s; keyboard auto-repeat tops out well below that). (gpu-vsync nil) switches to uncapped, stock-like behavior.
  • Idle cost is identical and the GPU resources add ~4 MB of RSS.

Status: experimental, under active development.

Note: I am not answering issues for now. Feel free to open them as a public record (they will be read eventually), but do not expect a reply at this stage.

Demos

Inline video playing inside a buffer, decoded by AVFoundation straight into Metal textures (gpu-video-insert):

Inline video

An animated GIF playing next to font-locked code scrolling, all composited by the GPU:

Animated GIF and code

GPU cursor effects (gpu-animations), here the sonicboom mode:

Sonicboom cursor

Buffer switches cross-fade on the GPU (on by default, configurable):

Buffer cross-fade

Installing

With Homebrew (Apple Silicon, macOS 26+):

brew install --cask tanrax/tap/emacs-gpu

Or grab the signed, self-contained Emacs.app from the releases.

Building on macOS

Requires Xcode (or the Command Line Tools) and the usual Emacs build dependencies (brew install autoconf automake gnutls texinfo pkg-config).

./autogen.sh

SDK=$(xcrun --sdk macosx --show-sdk-path)
CC="xcrun clang" OBJC="xcrun clang" \
CFLAGS="-isysroot $SDK" CPPFLAGS="-isysroot $SDK" OBJCFLAGS="-isysroot $SDK" \
./configure --with-ns --with-mtl

make -j$(sysctl -n hw.ncpu)

The binary is src/emacs (or install the app bundle from nextstep/).

Enabling the GPU backend

The release app bundle enables it automatically (set the environment variable EMACS_GPU_DISABLE=1 to start with the stock Cocoa backend instead). In a source build, switch a frame to Metal with:

(add-to-list 'load-path "/path/to/emacs-gpu/lisp")
(require 'gpu)
(gpu-enable)

Commands and options

Command What it does
M-x gpu-status Show backend state: GPU device, animations, cursor mode
M-: (gpu-draw-stats) Renderer counters; glyphs-drawn growing proves the GPU is painting
M-x gpu-toggle-animations Toggle GPU cursor effects (on by default)
M-x gpu-set-cursor Pick the cursor effect: sonicboom (default), torpedo (comet trail), spring, ripple, pixiedust, hollow, beam, block
M-: (gpu-vsync nil) Uncap presents from the display refresh (lower latency, more power)
M-: (gpu-video-insert "clip.mp4" 480 270 t) Play a video inline at point; follows scrolling
M-x gpu-video-stop Stop the inline video

Cursor effects trigger on cursor jumps (M-<, M->, isearch hits), not on single-character movement.

Buffer switches cross-fade by default; tune or disable with:

(setq gpu-buffer-transition-duration 0.15) ; seconds
(setq gpu-buffer-transitions nil)          ; turn it off

How it works

redisplay engine (xdisp.c, untouched)
        ↓
src/gfxterm.c   platform-neutral drawing policy
        ↓
src/gfxdrv.h    driver interface (~25 ops)
        ↓
src/mtlterm.m   Metal driver: glyph atlas (CoreText → R8 texture),
                render cycle on a persistent texture, AVFoundation
                video through CVMetalTextureCache

License

GNU General Public License v3 or later, same as GNU Emacs.