From 50602cd46e975efba29ee869988586ad4b216ca9 Mon Sep 17 00:00:00 2001 From: Lipeng Guo Date: Sun, 8 Feb 2026 22:23:04 +0800 Subject: [PATCH 1/2] docs: add DMABUF shared memory guide for zero-copy GPU rendering Add comprehensive documentation on DMABUF/Browser Shared Memory for Linux, explaining zero-copy GPU memory sharing between Rust backend and WebKitGTK frontend. Includes architecture diagrams, implementation options, current limitations, and reference documentation links. Co-Authored-By: Claude Sonnet 4.5 --- docs/dmabuf-shared-memory.md | 321 +++++++++++++++++++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 docs/dmabuf-shared-memory.md diff --git a/docs/dmabuf-shared-memory.md b/docs/dmabuf-shared-memory.md new file mode 100644 index 0000000..c6dac6b --- /dev/null +++ b/docs/dmabuf-shared-memory.md @@ -0,0 +1,321 @@ +# DMABUF/Browser Shared Memory for Zero-Copy GPU Rendering + +## Overview + +DMABUF (Direct Memory Access Buffer) is a Linux kernel mechanism for sharing buffers between devices (GPU, camera, video encoder, etc.) without CPU copies. For Tauri on Linux, this enables zero-copy GPU memory sharing between Rust native rendering and the WebKitGTK webview. + +## Why DMABUF? + +### Traditional Approach (CPU Copy) +``` +Rust GPU → glReadPixels → CPU RAM → IPC → Browser → Upload to GPU +``` +- **Slow**: CPU copy bottleneck +- **High latency**: ~10-30ms for 1080p +- **High power**: Memory bandwidth intensive + +### DMABUF Approach (Zero-Copy) +``` +Rust GPU → DMABUF Handle → Browser → Direct GPU Access +``` +- **Fast**: No CPU copies +- **Low latency**: ~1-3ms +- **Efficient**: Minimal power consumption + +## Requirements + +### System Requirements +- Linux kernel 4.4+ (DMABUF support) +- GPU drivers supporting DMA-BUF export: + - Intel Mesa (i915) + - AMD Radeon (amdgpu/radeonsi) + - NVIDIA (proprietary driver 515+ with GBM backend) +- Compositor supporting DMA-BUF (Wayland: Weston, KWin, Mutter; X11: limited) + +### Browser/WebKitGTK Requirements +- WebKitGTK 2.40+ with DMA-BUF import support +- EGL 1.5+ with `EGL_EXT_image_dma_buf_import` extension +- Check support: + ```bash + # Check EGL extensions + eglinfo | grep dma_buf + + # Check WebKitGTK version + pkg-config --modversion webkit2gtk-4.1 + ``` + +## Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Tauri App │ +├─────────────────────────────────────────────────────────────┤ +│ ┌─────────────────┐ ┌─────────────────────────┐ │ +│ │ Rust Backend │ │ WebKitGTK Frontend │ │ +│ │ │ │ │ │ +│ │ ┌───────────┐ │ │ ┌───────────────────┐ │ │ +│ │ │ OpenGL │ │ │ │ │ │ │ +│ │ │ Render │ │ │ │ WebGL Context │ │ │ +│ │ └─────┬─────┘ │ │ └─────────┬─────────┘ │ │ +│ │ │ │ │ │ │ │ +│ │ ┌─────▼─────┐ │ DMABUF │ ┌─────────▼─────────┐ │ │ +│ │ │ EGL/G BM │──┼─────────┼─▶│ WebGL Texture │ │ │ +│ │ │ Export │ │ FD │ │ Import │ │ │ +│ │ └──────────┘ │ │ └───────────────────┘ │ │ +│ └─────────────────┘ └─────────────────────────┘ │ +└─────────────────────────────────────────────────────────────┘ + │ │ + ▼ ▼ + GPU Memory (Shared) GPU Memory +``` + +## Implementation Options + +### Option 1: WebGL VideoTexture (MediaSource) + +Use WebCodecs API with VideoFrame containing DMABUF: + +```rust +// Rust - Export DMABUF +use drm::buffer::DrmBuffer; +use egl::EGLDisplay; + +let dmabuf_fd = export_gl_buffer_to_dmabuf(gl_texture); +// Send fd via IPC (SCM_RIGHTS) +``` + +```javascript +// Frontend - Import as VideoFrame +const videoFrame = new VideoFrame(dmabuf_handle, { + timestamp: 0, + codedWidth: 1920, + codedHeight: 1080 +}); +// Render to canvas +ctx.drawImage(videoFrame, 0, 0); +``` + +**Pros:** +- Standard web API +- Hardware video decoder integration + +**Cons:** +- Browser support varies (Chrome/Chromium better) +- Limited to video-like formats + +### Option 2: WebGL Texture with EGL Extension (Advanced) + +Direct EGL texture sharing: + +```rust +// Rust backend +use egl::{EGLDisplay, EGLImage}; +use gbm::{BufferObject, Format}; + +// Create GBM buffer +let gbm_device = gbm::Device::open("/dev/dri/renderD128").unwrap(); +let gbm_bo = gbm_device.create_buffer::( + 1920, 1080, + gbm::Format::Argb8888, + gbm::BufferObjectFlags::RENDERING +).unwrap(); + +// Export to DMABUF +let dmabuf_fd = gbm_bo.export_fd().unwrap(); + +// Create EGLImage from DMABUF +let egl_image = egl.create_image( + egl::NO_CONTEXT, + EGL_LINUX_DMA_BUF_EXT, + None, + &EGLImageAttribs { + width: 1920, + height: 1080, + format: fourcc('AR24'), + planes: &[EGLPlaneAttrib { + fd: dmabuf_fd, + offset: 0, + pitch: stride, + }] + } +)?; + +// Render to texture +gl::framebuffer_texture_2d( + gl::READ_FRAMEBUFFER, + gl::COLOR_ATTACHMENT0, + gl::TEXTURE_2D, + egl_image.gl_texture_id, + 0 +); +``` + +```javascript +// Frontend - Not directly supported in standard WebGL! +// Requires browser extensions or custom WebKitGTK build +``` + +**Current Limitation:** +WebKitGTK doesn't expose DMABUF texture import to WebGL content directly. This is a research/experimental area. + +### Option 3: PipeWire + Portal (Recommended for Linux) + +Use PipeWire for screen sharing/streaming: + +```rust +// Use xdg-desktop-portal +use ashpd::desktop::screencast::Screencast; + +let screencast = Screencast::new().await?; +let session = screencast.create_session().await?; +// PipeWire handles DMABUF automatically +``` + +**Pros:** +- Standard Linux desktop integration +- DMABUF handled by PipeWire +- Works with Wayland and X11 + +**Cons:** +- Requires PipeWire running +- More setup complexity +- Overkill for single-app use case + +## Current Status + +### WebKitGTK DMABUF Support + +WebKitGTK can import DMABUF internally for: +- Video playback (GStreamer with DMABUF) +- Camera capture (v4l2 with DMABUF) + +**However**, DMABUF import to **WebGL contexts is not currently exposed** to JavaScript content. + +Check for updates: +- [WebKit Bug Tracker](https://bugs.webkit.org/) +- Search for: "DMA-BUF WebGL texture import" + +### Alternative: Video Element + GStreamer + +WebKitGTK supports GStreamer with DMABUF for video elements: + +```rust +// Use GStreamer to push DMABUF frames +use gstreamer as gst; +use gstreamer_app as gst_app; + +let pipeline = gst::parse::launch( + "appsrc name=src ! video/x-raw,format=ARGB,width=1920,height=1080 ! \ + glupload ! glcolorconvert ! gldownload ! \ + videoconvert ! appsink name=sink" +)?; +``` + +```javascript +// Display in