summaryrefslogtreecommitdiffhomepage
path: root/.rules/plan/phase-08-zero-copy.md
blob: 56f99c39c2e57f1d4f49c4f79e6310be6ddd5996 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Phase 8 — GLX Texture-from-Pixmap (Zero-Copy Upgrade)

---

## Step 8.1 — Replace XGetImage with GLX_EXT_texture_from_pixmap

This is the performance upgrade. Instead of reading pixels through the
CPU, bind the X pixmap directly as an OpenGL texture:

1. Find an FBConfig that supports `GLX_BIND_TO_TEXTURE_RGBA_EXT`.
2. Create a `GLXPixmap` from the X `Pixmap`.
3. Call `glXBindTexImageEXT()` to bind it as a GL texture.
4. Wrap the GL texture ID in a raylib `Texture2D` struct (set `.id`
   directly, since raylib textures are just GL texture handles with
   width/height/format metadata).

On damage: `glXReleaseTexImageEXT` then `glXBindTexImageEXT` to refresh.
On resize: destroy and recreate the GLX pixmap.

Handle `GLX_Y_INVERTED_EXT` — if the pixmap is Y-inverted, flip the
texture coordinates when drawing (use `DrawTexturePro` with a negative
source height, or flip in a shader).

**Verify:** Same visual result as Step 3.4 but with dramatically less
CPU usage. Confirm with `top` or `perf` that `XGetImage` is no longer
called. `xeyes` still tracks the mouse smoothly. Resizing windows
works without artifacts.

**Note:** This step may not work inside Xephyr (which uses software
rendering). If `GLX_EXT_texture_from_pixmap` is not available in Xephyr,
keep the CPU-copy path as a fallback and test zero-copy on a real X
session or VM with GPU passthrough. Implement runtime detection:

```c
const char *glx_exts = glXQueryExtensionsString(dpy, screen);
bool has_tfp = strstr(glx_exts, "GLX_EXT_texture_from_pixmap") != NULL;
```

Use `has_tfp` to pick the code path.