Skip to content
Tech News
← Back to articles

I built a GPU back end for Emacs

read original get Emacs GPU Acceleration Plugin → more articles
Why This Matters

This project demonstrates how leveraging GPU acceleration in Emacs can significantly enhance its performance and visual capabilities, challenging long-standing limitations rooted in its CPU-centric design. It highlights the potential for modernizing legacy software to better utilize current hardware, benefiting both developers and users seeking richer, more interactive experiences.

Key Takeaways

A few months ago I became obsessed with a silly question: why does my Emacs, on a laptop with a perfectly capable GPU, draw all of its text using the CPU? And that led to others: why can't I play a video inside a buffer? Why can't I have animated cursor effects? Why can't I cross-fade between buffers? I needed to satisfy my curiosity, so I started digging.

I started reading the code, with an AI as my companion. I discovered that every glyph, every underline, every scroll is recomputed and repainted by the processor. Emacs's redisplay engine ( xdisp.c ) was born in an era when there was no other option, and it is tuned to the millimeter for exactly that. And nobody had managed to slip a GPU underneath without rewriting half of Emacs... until recently.

So I decided to try. What began as a weekend experiment ended up being a complete display backend for macOS with Metal, a second backend for GNU/Linux with OpenGL, a video player inside the buffer, shader-based cursor effects, and a debate of more than a hundred messages on the Emacs developers' mailing list that ranged from cairo's performance to software freedom and the ethics of artificial intelligence.

This article exists because I feel like telling the story, and it might be useful for future implementations. At the end I leave the lessons I take away and a conclusion that is not the one I expected when I started.

A note of honesty up front: I built this project with the help of an LLM as a copilot, from start to finish. I say it here just as I said it in public when I was asked. I will come back to it, because it turned out to be the most important plot twist of the whole journey.

Phase 1: the architecture decision

Anyone's first instinct would be to open the macOS code, the Cocoa backend ( nsterm.m ), and start replacing CoreGraphics calls with Metal calls. It is the most direct path. And it is exactly what I decided not to do.

The problem with that approach is that it ties you to one platform. If I write "Emacs with Metal", I have an Emacs for Mac and nothing else. I needed to write a display-backend abstraction that would let me have one driver per platform. So I sketched a three-layer architecture on a Post-it:

flowchart TD X["Redisplay engine

(xdisp.c, untouched)"]:::core --> P["src/gfxterm.c

... continue reading