Commit graph

182403 commits

Author SHA1 Message Date
d624dc55fa Restructure the README around installing and using the backend 2026-07-09 14:58:34 +02:00
73b27299fa Use the project logo as the application icon 2026-07-09 14:50:02 +02:00
Andros Fenollosa
f0efe5630a
Update README.md 2026-07-09 14:48:53 +02:00
9d1745ae7c Add the project logo 2026-07-09 14:30:48 +02:00
87225eb9a2 Make Liberapay the primary donation channel 2026-07-09 14:11:36 +02:00
8949aa8c93 Add donation methods (GitHub Sponsors, Ko-fi) 2026-06-26 16:39:48 +02:00
db296675d8 README: link to the visual QA companion repository 2026-06-18 09:07:26 +02:00
fa59ee2a2f Move visual QA harness to emacs-gpu-qa repository 2026-06-18 08:41:32 +02:00
0dc1ba7f48 mtl-video-insert: accept HTTP/HTTPS URLs in addition to local paths
Pass remote URLs directly to AVFoundation without file-expansion or
existence check; local paths continue to use fileURLWithPath as before.
2026-06-17 16:20:18 +02:00
74a4e6c5cc Replace VISUAL-QA.org with structured qa/ test harness
17 categories, each with a README.org checklist and a self-contained
test.el that loads the same scenario in both GPU and vanilla Emacs for
side-by-side comparison.
2026-06-17 16:07:44 +02:00
8955c39a9b Add visual QA checklist for the GPU rendering backend 2026-06-17 15:41:10 +02:00
1fad8a6141 README: replace mermaid xychart with grouped-bar images
Mermaid's xychart-beta cannot draw grouped bars or a legend: two bar
series overlap on the same axis position, so the paired GPU-vs-cairo
comparison was unreadable. Render the charts as images with real
grouped bars, value labels and a legend (bench/make-charts.py), and
embed them from .github/assets/.
2026-06-14 08:36:47 +02:00
0eda943aa3 README: point to the harness under bench/ 2026-06-14 08:24:42 +02:00
d5cc323051 README: paired GPU-vs-cairo fps bars per workload
Plot absolute redisplays/s as two colored bars per workload (GPU green,
cairo blue) so the per-feature contrast between the two backends is
visible at a glance. The macOS chart stays on CPU seconds.
2026-06-14 08:23:20 +02:00
7dccc31569 README: charts show the comparison, not duplicate the tables
The benchmark charts plotted absolute fps as two zero-padded bar series,
which hid the actual story and (on macOS) made the lowest-CPU option look
worst. Replace them with single-series charts: GPU/cairo speedup ratios
for Linux (1.0x = parity) and CPU seconds for the macOS scroll (lower is
better). The tables still carry the absolute numbers.
2026-06-14 08:19:56 +02:00
534ce43645 Add the redisplay-throughput benchmark harness
The README already pointed to run-bench.sh and run-bench-hires.sh as the
way to reproduce the performance tables; add them under bench/ along with
gl-bench.el (the five workloads) and a README describing the methodology.
The scripts are relocatable: the binary is taken from $EMACS, gl-bench.el
is found relative to the script, and results go to a temporary directory.
2026-06-14 08:15:47 +02:00
3575d97028 README: status change to Beta, fully functional
The backend is now at production maturity on two platforms with
comprehensive test coverage and precompiled distribution. Update status
from 'experimental' to 'Beta, fully functional', documenting known
limitations (Intel/universal on macOS, Wayland on Linux) and highlighting
that all Emacs display features are supported and the GPU path is opt-in.
2026-06-13 08:40:55 +02:00
3cb9fbcf0f README: label every chart row; mermaid collapses blank categories
The whitespace placeholder labels were deduplicated by mermaid and
half the GPU rows vanished; name each row explicitly instead.
2026-06-12 22:18:20 +02:00
6e3fd08024 README: horizontal benchmark charts, one color per renderer
Vertical interleaved bars crowded the workload labels into each other;
flip the charts horizontal so every pair gets a readable row, and give
cairo/Cocoa and the GPU distinct palette colors (named in the title --
xychart has no legend).
2026-06-12 22:17:20 +02:00
838d05197f README: chart absolute fps, paired bars per workload
The ratio charts hid the actual numbers; plot cairo and GPU as
adjacent bars per workload in redisplays per second instead, matching
the tables (mermaid xychart has no grouped series, so the pairs are
interleaved on the x axis), and chart the macOS sustained-scroll rate
in fps as well.
2026-06-12 22:15:22 +02:00
9c77b8e1fe README: chart the benchmark tables and align the macOS one
Add a mermaid xychart under each performance table (GPU/cairo ratio
with a parity line for the two Linux tables, CPU cost of sustained
scroll for the macOS one) so the takeaway is visible at a glance; the
tables stay as the source of record.  Right-align the numeric columns
of the macOS table to match the Linux ones.
2026-06-12 22:09:12 +02:00
e22b30263a gpu: bump version to 0.4.2
Unified animation pump (one Lisp timer and at most one present per
tick for cursor effects, cross-fades and inline video; video holds its
native 30fps now) and the stale-frame flash fix (drop the XDBE back
buffer on GL frames; an Expose could flash the half-painted startup
frame for one vblank).
2026-06-12 21:24:28 +02:00
2595e563bb README: document the prebuilt .deb install path for GNU/Linux
The packages were only linked from the release notes; give them a
section before the build-from-source instructions, including the
Debian/Ubuntu split (incompatible libjpeg sonames) and the
EMACS_GPU_DISABLE opt-out.
2026-06-12 21:24:28 +02:00
992fc45d02 gpu.el: drop the XDBE back buffer on GL frames
The stale-frame flash had a second source besides present pressure,
and this one explains the flashes that survived the 12ms throttle: the
frame's XDBE back buffer.  Core X11 paints it during startup, the GPU
backend then takes over rendering and never touches it again, so it
keeps the half-painted startup frame forever -- and xterm.c's Expose
handler calls show_back_buffer unconditionally, so any Expose swaps
that ancient frame on screen for one vblank until the next GPU present
overwrites it.  That is the "old frame from another buffer" flicker
reported during buffer switches, and why it resisted every change to
the EGL present path (vsync, glFinish, DRI2 vs DRI3): the offending
swap was never ours.

Fix: set inhibit-double-buffering on the frame when the OpenGL backend
takes over.  Emacs tears the back buffer down through its own
machinery and every XdbeSwapBuffers becomes a no-op; the GPU FBO is
the backing store.  Verified on hardware against the real scanout
(kmsgrab at 60fps, 152 buffer switches with cross-fades): 0 anomalous
frames in 8495, where the same soak detected ~70-105 single-frame
flashes before, on both this build and the previous release.
2026-06-12 13:32:59 +02:00
b57f4d0c38 gl/mtl: drive all continuous animations from one pump
Cursor effects, buffer cross-fades and inline video each ran on their
own Lisp timer, and each timer presented on its own.  With everything
active that stacked presents well above the refresh rate, which is
exactly the pressure under which radeonsi was caught presenting stale
swapchain buffers, and the blocking swaps starved the other timers
(inline video dropped from 30fps to ~20fps with its tick slipping to
49ms).

Replace the three timers with a single pump.  gpu.el now runs one
repeating timer that calls the new gpu-pump-tick primitive: the driver
advances the cursor physics, the fade clock and the video upload
together and presents AT MOST ONCE per tick, under the same 12ms
last-swap throttle as before.  The pump paces itself: 60Hz while a
fade runs, 30Hz otherwise, gone when nothing needs it.  A skipped
subsystem loses nothing -- the fade and the video are composited by
every present, whoever issues it.

The old per-subsystem entry points (gpu-anim-tick, gpu-transition-tick,
gpu-video-tick) remain for compatibility; gpu-video-tick now presents
only when a fresh frame arrived or the rect moved, under the same
throttle, instead of unconditionally.

On Metal the pump consolidates the same two timers; the animator
already coalesces presents, so the change there is one deterministic
tick (video frame pull, then animator step) with a real elapsed dt.

Measured on the AMD iGPU test box (1920x1080, Cinnamon): video tick
median 33.0ms / p90 33.3ms (was 49ms), a 30fps file plays at 29.5fps,
and worst-case contention (video + cursor effects + 12 cross-fades)
peaks at 8 presents per 100ms window with a 16.1ms median gap.
GL_LOG_PRESENT now also traces the pump decisions and the per-tick
video upload state.
2026-06-12 13:32:43 +02:00
dfb6186811 glterm: throttle animation presents and clamp scroll copies
The cursor-effect and cross-fade pumps presented on top of redisplay's
own presents, pushing the window surface well past the refresh rate;
under that pressure Mesa juggles extra swapchain buffers and radeonsi
was caught presenting a stale one, an ancient frame flashing for one
vblank on buffer switches.  Animation ticks now skip their present when
a swap happened less than 12 ms ago; the time-based animations lose
nothing.  Also clamp copy_region to the framebuffer: a scroll computed
against a mid-resize frame size could blit from outside the FBO, which
writes undefined (recycled) VRAM into visible content.  GL_LOG_PRESENT
now prints a present sequence number, timestamp and cross-fade phase,
and GL_PRESENT_FINISH=1 drains the GPU before each swap as a
diagnostic knob.
2026-06-12 10:46:47 +02:00
f3a1554765 gl/mtl: validate the image texture caches by spec hash, not pointer
Both drivers cached image textures keyed by the struct image pointer
alone (plus display size).  The Emacs image cache frees evicted images,
and the allocator can hand the same address to a different image later:
a stale entry would then draw the old picture in the new image's place,
and the most likely stale survivor is whatever was cached first and
evicted (a startup dashboard banner, say) bleeding into later buffers.

Pin each cache entry to the image spec hash (the hash field of struct
image): a recycled pointer with a different spec re-rasterizes instead
of hitting the stale texture.  GL keeps the hash in its entry table;
Metal adds a parallel pointer-to-hash CFDictionary next to the texture
cache.

Image and fringe parity batteries unchanged on Linux; the Metal
reference scene stays byte-identical.
2026-06-12 08:28:24 +02:00
9c9cc779d8 glterm: make the simple full-frame present the default
The partial present (buffer-age repair + compositor damage rects) has
now needed three rounds of race hardening on real hardware: against the
window manager's asynchronous resizes, against the driver's buffer
rotation (ages observed lying across reallocations on radeonsi), and
with the compositor's damage-driven texture updates still under
suspicion in the reported bleed-through of stale buffer content.  What
it buys is roughly 10% on workloads that already run far beyond a
thousand frames per second; what it costs is correctness fights on
three asynchronous fronts at once.

Flip the trade: the default present now blits the whole frame and swaps
with full damage -- the behavior that was rock solid for every release
up to the optimization round -- and the partial machinery moves behind
GL_PARTIAL_PRESENT=1 as an experimental opt-in (GL_NO_DAMAGE still
forces it off).  The glyph/fill batching, the persistent surface
binding and the post-swap size recheck, which carry the real
performance wins and have no asynchronous failure modes, stay as they
are.

Verified on the AMD/Muffin test machine: maximize/restore storms with
concurrent scrolling, free-form resizes, M-x bursts, and the user
configuration's dashboard-to-buffer flow run with zero
GL_VERIFY_PRESENT mismatches over ~1800 presents, and the parity
batteries are byte-identical to their baselines.
2026-06-12 07:51:59 +02:00
0c6e455b8b glterm: survive the driver-side resize race in the partial present
A window-manager resize can reallocate the EGL back buffers while Mesa
still reports the pre-resize surface size AND a pre-resize buffer age
for the present already in flight: the partial repair then lands on a
fresh zero-filled buffer and most of the frame goes on screen as
garbage.  Caught red-handed on AMD/radeonsi under Muffin by the new
GL_VERIFY_PRESENT instrument: 232883 wrong pixels (41% of the buffer)
in an age=2 partial present during a maximize, healed only by the next
redisplay -- the reported black flicker.

The client cannot win that race beforehand (both the size query and the
age reflect pre-resize state until Mesa validates), but right after the
swap Mesa HAS validated the new geometry.  So: re-query the surface
size after every swap, and if it changed under us, immediately present
again in full at the true size -- the artifact never reaches a vertical
retrace instead of surviving until the next redisplay.  One bounded
retry; the steady state pays one cached-state query per swap.

GL_VERIFY_PRESENT=1 is the new debug mode behind this finding: before
the overlays, it reads the repaired back buffer and the FBO back and
reports any mismatch with the present's age and box count -- catching
partial-repair holes at the exact present that produced them.

Verified on the same hardware and compositor: ten maximize/restore
cycles with concurrent scroll storms, free-form resizes mid-scroll and
an M-x burst over 817 partial presents produce zero mismatches; the
unfixed build reproduced the 41% mismatch under the identical load.
Buffer-switch cross-fades measured at 8-10 frames at 60fps (the
configured 150ms), confirming no stale-content ghosts remain beyond
the designed fade.
2026-06-12 07:29:53 +02:00
ce44e28eaa gpu: bump version to 0.4.1
Fixes the black flicker beside stale content during window-manager
resizes on the OpenGL backend's partial present.
2026-06-12 00:40:48 +02:00
be9e6fb7d4 glterm: cover window-manager resizes in the partial present
A window-manager resize reaches the X server before Emacs processes the
ConfigureNotify, so for a few presents the EGL surface is larger than
the FBO and the cached surface size is stale.  The present then blitted
at the stale size, leaving the newly exposed region of the freshly
reallocated back buffer undefined -- visible as a black band beside the
old frame's content (the reported black flicker with repeated text)
until the next full redisplay.

Re-query the surface size whenever the buffer age cannot vouch for it:
age 0 (the buffer was just reallocated, which is exactly what a resize
does), an overlay or whole-frame present (those full-blit anyway, and a
full blit at a stale size would not cover a just-resized window), or no
buffer-age support at all.  The full blit then stretches over the real
surface, restoring the pre-optimization behavior on every resize path,
and the steady-state partial present still pays no extra round-trips:
with age >= 1 the buffer -- and therefore its size -- is unchanged.

Also stop consuming the dirty set when eglSwapBuffers fails: a failed
swap presented nothing, and recording it would desynchronize the swap
ring from the driver's buffer rotation, making later repairs index the
wrong slots (stale content on screen).  The next present retries with
the dirty set intact.

Reproduced and verified in a containerized X session (Xvfb + openbox +
picom, llvmpipe): driving the WM through resizes flashed a one-frame
black band beside stale content before the fix, and a full input sweep
(typing, held arrows, paging, wheel, mouse drags, buffer cross-fades,
splits, isearch, text-scale, occlusion, dired) shows zero dark or
duplicated-content frames after it.
2026-06-12 00:40:36 +02:00
fd93d2543f gpu: bump version to 0.4.0
The OpenGL backend lands on GNU/Linux (driver, video, cursor effects,
cross-fade) and both backends gain the batched draw path and, on
OpenGL, the buffer-age partial present.
2026-06-11 20:38:35 +02:00
3fdae11a76 doc: refresh the Linux benchmarks after the second optimization round
On-screen 1616x912 (median of 3, vsync off): page scroll reaches parity
with the cairo backend (1.00x) and full-frame redraws are now faster
(1.19x); line scroll 0.92x, image scroll 0.91x, typing 0.71x.  At 4K
the render-throughput gap widens further in the GPU's favor
(full redraw 1.84x, line scroll 2.05x, typing 7.4x, image 11.5x).

Update the prose to match: glyphs and fills batch into one draw call,
and the partial present is on by default, driven by EGL_EXT_buffer_age
and eglSwapBuffersWithDamage instead of the unreliable
EGL_BUFFER_PRESERVED (the old GL_PARTIAL_PRESENT escape is gone).
2026-06-11 18:03:36 +02:00
b972567d95 gl/mtl: review polish over the batching work
Findings from a review pass over the optimization series:

- Guard degenerate (zero-area) quads at the top of both batch appends:
  the proportional UV clip divides by the quad extent, and the Metal
  fill path had no caller-side size check, so a zero-width rect under
  an active clip produced NaN texture coordinates.
- Cache the GL_NO_DAMAGE / GL_LOG_PRESENT lookups in statics (the
  established pattern for GL_NO_VSYNC): they sat on the per-present
  path, and getenv scans the environment on every call.
- Move the Metal clip rect from MtlFrameData properties to file
  statics: it is read per queued quad, where an objc_msgSend per
  access is measurable, and render cycles never interleave, so a
  single global pair is correct.  Also reverts the header additions.
- Fix the two -Wdouble-promotion / -Wmisleading-indentation warnings
  in the animation logging and the video overlay clamps; both drivers
  now build warning-free.
- Describe the batch and the buffer-age present in glterm.c's header
  comment so the design is visible up front.

Pixel parity re-verified on both backends after the changes
(byte-identical captures).
2026-06-11 17:53:10 +02:00
01f7960775 mtlterm: port the unified draw batch from the OpenGL driver
Glyph quads and solid rectangles now accumulate in one CPU vertex array
and flush as a single draw call, instead of one drawPrimitives (with its
pipeline switch) per glyph and per fill.  The rects sample a 4x4 white
block reserved in the atlas -- coverage 1.0 passes the gamma curve
unchanged -- so backgrounds, underlines, boxes and reliefs share the
glyph pipeline and never split the batch.  Clipping moves from the
encoder scissor to queue time: each quad is clamped against the glyph
string's clip rect with texture coordinates adjusted proportionally,
letting the batch survive clip changes and cross strings; the
non-batched primitives (images, color glyphs, fringe bitmaps) apply the
recorded clip as a real scissor right before their own draw.  Small
batches ride in the command buffer via setVertexBytes, larger ones get
a one-shot shared buffer.  The atlas reset paths are centralized in
mtl_atlas_reset, which re-reserves the white block.

Fringe bitmaps are cached by an FNV-1a hash of their rows instead of
creating a texture per call (the old per-call texture was also never
released under MRC -- this fixes that leak).  scroll_run uses one
direct blit when source and destination are disjoint (page scrolls),
keeping the scratch bounce only for overlapping moves.

Verified byte-identical to the previous renderer: a scene exercising
font-lock, bold+box, underline (plain and wave), overline,
strike-through, inverse video, region and fringe marks captures
exactly the same staticTexture, and scrolling by copy matches a fresh
repaint of the same window start pixel for pixel.
2026-06-11 17:42:49 +02:00
b3e19f2d78 glterm: single-pass disjoint copies, fringe bitmap cache, small wins
copy_region: when source and destination do not overlap (page scrolls,
large jumps) one direct blit within the FBO replaces the bounce through
the scratch texture, halving the copied bandwidth; only overlapping
moves (single-line scrolls) still need the intermediate hop.

draw_bitmap: fringe bitmaps are uploaded once and cached by an FNV-1a
hash of their visible rows (the coverage is color-independent, the
color rides on the vertices), instead of creating and destroying a GL
texture on every call.

Also: cache the last frame-data lookup (it runs per drawing op and
scanned the whole slot table each time, and a freed frame now also
drops a stale batch target), skip the explicit glFlush when the frame
is presented immediately (the swap flushes; the deferred path keeps it
so GPU work overlaps the wait), and declare the atlas texture
coordinates highp (2048 texels exceed fp16's exact range on
strict-mediump GPUs; desktop Mesa promotes anyway, mobile would not).

Parity bytes unchanged across the text, scroll and image batteries.
Page scroll reaches 0.99x of the cairo backend, line scroll 0.93x,
image scroll 0.86x on the AMD Renoir test machine.
2026-06-11 16:39:53 +02:00
51d51ace75 glterm: one vertex stream for glyphs and fills, clipped on the CPU
Solid rectangles now join the glyph batch instead of flushing it: the
atlas reserves a 4x4 white block whose center texel gives coverage 1.0
(the gamma curve passes it unchanged), so a fill is just a quad with
constant texture coordinates in the same program, same texture and same
submission-ordered stream as the glyphs around it.  Backgrounds,
underlines, boxes and reliefs no longer split the batch, and the atlas
reset paths are centralized in gl_atlas_reset, which re-reserves the
white block.

Clipping moves from the GL scissor to queue time: each quad is clamped
against the glyph string's clip rect (the same integer bounds the
scissor used, with texture coordinates adjusted proportionally), so a
clip change no longer forces a flush either, and the batch survives
across strings and rows.  A full-frame redraw drops from one draw call
per background/glyph-run pair (hundreds) to a handful per frame.  The
non-batched primitives (image textures, fringe bitmaps) apply the
recorded clip as a real scissor right before their own draw.

Pixel parity re-verified across the text, decorations, cursor, scroll,
image/fringe and emoji batteries (byte-identical to the previous driver
in the deterministic cases), and the on-screen present still matches
the FBO exactly after a partial-present session.  Full-frame redraw
goes from 192 to 290 fps on the AMD Renoir test machine, overtaking
the cairo backend (1.15x) on that workload for the first time;
page scroll reaches 0.95x, line scroll 0.86x.
2026-06-11 16:34:43 +02:00
9a1674d447 glterm: partial present driven by buffer age and swap damage
Replace the EGL_BUFFER_PRESERVED-based partial present (opt-in via
GL_PARTIAL_PRESENT, unreliable because compositing window managers
advertise the behavior without honoring it) with EGL_EXT_buffer_age:
the driver reports how many swaps ago the back buffer was last shown,
which combined with a per-swap record of dirty regions yields exactly
the area the buffer is missing.  That is what the driver actually
guarantees about its own buffer rotation, so it is correct under any
compositor, and it is on by default (GL_NO_DAMAGE=1 disables).

Dirty tracking now keeps a small set of disjoint boxes instead of one
union box: a typed character plus the mode line no longer degenerate
into a near-full-frame blit, so a keystroke present blits a few text
rows instead of the whole frame.  The swap hands the compositor the
changed boxes through eglSwapBuffersWithDamage so it also recomposites
only those bands.  The surface size is cached (two eglQuerySurface
round-trips per present gone), and an idle burst-mode cursor no longer
counts as an active overlay, so the default cursor effect does not
force full-frame presents while typing.

Verified on-screen against the FBO ground truth after a session of
partial presents (typing, cursor jumps, scrolls, splits): zero pixel
difference in the content area.  Typing throughput +16%, image scroll
+12%, line scroll +7% on the AMD Renoir test machine.
2026-06-11 16:21:43 +02:00
c3be56b1e6 Add the OpenGL ES / EGL display backend for GNU/Linux (X11)
The GNU/Linux counterpart of the Metal backend: the cross-platform
drawing policy in gfxterm.c now renders through a second gfx_driver
implementation, src/glterm.c, built on EGL + OpenGL ES 3 with glyphs
rasterized by FreeType/cairo into a GPU atlas.

Highlights:

- Pixel parity with the stock GTK/cairo renderer, verified with a
  capture harness across text (ASCII/Latin/CJK/emoji/BiDi), faces,
  decorations (underline/overline/box/relief), fringes, margins,
  line numbers, mode/header/tab lines, images (PNG/JPEG/SVG/GIF),
  scroll runs and the four cursor types.
- On-screen present: the frame FBO is blitted to the X window through
  an EGL window surface with deferred presents (no flicker); headless
  runs render to the FBO alone (GL_FORCE_SURFACELESS for Xvfb).
- Glyph quads are batched into one draw call per state change, and the
  present can blit only the dirty region (GL_PARTIAL_PRESENT, opt-in).
- Color glyphs (emoji) rasterized through the cairo scaled font into
  RGBA textures; HiDPI supersampling via GL_SCALE.
- Inline video through GStreamer (playbin + appsink): decoded RGBA
  frames are uploaded and composited over the frame, following scroll
  and clipped to the window (gpu-video-insert / gpu-video-mode).
- Buffer-switch cross-fade and the animated cursor effects (spring,
  torpedo, sonicboom, ripple, pixiedust, hollow, beam), composited in
  the present pass; sonicboom is the default on this backend.
- --with-gpu configure flag selects the platform backend (Metal on
  macOS, OpenGL on X11) and auto-enables it at startup, with
  EMACS_GPU_DISABLE as the opt-out.
- gpu-status / gpu-enable / gpu-set-cursor and friends work on both
  backends; Metal-only primitives are guarded.

Shared-policy fixes that also benefit the Metal driver: relief edge
order and outermost shadow line now match the native renderers,
fringe bitmaps are clipped to the row's visible band, and the
mouse-face highlight no longer goes stale after a deferred present
(mouse_face_defer is cleared at update_end).
2026-06-11 15:20:40 +02:00
a770a82965 gfxterm: draw glyphs with s->font, not face->font
The character drawing path resolved glyphs through face->font, but
char2b holds glyph IDs encoded for s->font.  These usually match, so
the bug stayed hidden until a mouse-face highlight over text in a
non-default font (e.g. shr / variable-pitch links in elfeed): Emacs
swaps s->face to the highlight face while leaving s->font and char2b
as the original font, so the highlight redraw looked the proportional
glyph IDs up in the highlight face's monospace atlas and rendered
garbage.  Use s->font, matching the NS and X backends and the
composition glyph string path in this file.
2026-06-09 11:16:04 +02:00
59e36dbbb0 gpu.el: declare C primitives and capitalize error messages
Add declare-function forms for the primitives implemented in
src/mtlfns.m so byte-compiling the file without the backend is
warning-free, and capitalize two error messages to satisfy checkdoc.
2026-06-08 08:42:15 +02:00
32001fde8e README: document tree-sitter and native-comp in the build instructions 2026-06-06 11:43:14 +02:00
c81a85e0a8 README: example for enabling the sonicboom cursor effect 2026-06-06 11:37:28 +02:00
f7da60cfc4 gpu: bump version to 0.3.1 (rebuilt on the emacs-31.0.90 base) 2026-06-06 10:48:47 +02:00
86d39ba1f9 gpu: play video files in a dedicated buffer with timeline controls
Add gpu-video-mode: visiting a video file (mp4/mov/m4v/3gp) opens it in
a buffer that autoplays and loops, fit to the window, with a play/pause
button and a clickable, draggable timeline.  Registered in
auto-mode-alist so RET in Dired opens it; animated GIFs keep using
image-mode.

Expose the AVPlayer state the controls need: gpu-video-duration,
gpu-video-position, gpu-video-seek, gpu-video-playing-p and
gpu-video-size.
2026-06-06 10:19:30 +02:00
b676873b11 gpu: load and enable at startup, autoload commands, skip cursor effects while typing
- Auto-load the gpu module and enable the backend on the initial frame at
  startup when built --with-mtl; opt out with EMACS_GPU_DISABLE.
- Add autoload cookies to gpu-enable/status/set-cursor/toggle-animations/
  set-scroll so they are available via M-x without requiring gpu first.
- Suppress the motion cursor effects (sonicboom/ripple/pixiedust bursts and
  the torpedo trail) during typing/editing commands; only cursor movement
  and jumps trigger them.  Configurable via gpu-cursor-effects-while-typing
  and gpu-cursor-typing-commands.
- README: document startup auto-enable, the typing behavior, and the
  Ventura+ requirement.
2026-06-06 10:19:30 +02:00
9d72210b59 mtl: support macOS 13 (guard CADisplayLink behind @available)
-[NSScreen displayLinkWithTarget:selector:] and CADisplayLink are macOS
14+ APIs. Guard startAnimating/stopAnimating behind @available so the
backend builds and runs with a 13.0 deployment target; continuous
animation is driven by the Lisp 30fps timer anyway. Bump version to 0.1.2.
2026-06-06 10:19:30 +02:00
6356c92f02 gpu.el: fix gpu-set-cursor not applying; default cursor to block
The gpu-cursor-animation defcustom used :set #'set-default, so changing
the cursor mode at runtime (via gpu-set-cursor / setopt) only updated the
Lisp variable and never reached the live Metal driver. Wire :set to call
gpu-cursor-mode so the change propagates immediately.

Also set the default cursor to 'block (static, no effect); cursor effects
are now opt-in via gpu-set-cursor. Bump version to 0.1.1.
2026-06-06 10:19:30 +02:00
951b22afe4 README: Homebrew cask installation 2026-06-06 10:19:30 +02:00
f697b968b5 Rename the user-facing Lisp API from mtl- to gpu-
The project is emacs-gpu and the drawing core is platform-neutral; the
user API should not be Metal-branded (a future GNU/Linux user calling
mtl-enable would be absurd).  gpu.el carries the whole API under the
gpu- prefix; the mtl- entry points live on as obsolete aliases and
(require 'mtl) still works through a compatibility shim.

C internals keep their accurate names: gfx_* is the neutral policy and
mtl_* is the Metal driver.
2026-06-06 10:19:30 +02:00