-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem
The wgpu GPU renderer is fully wired and running — it creates a Metal surface on the Tauri window, uploads frame data via write_texture(), and renders a fullscreen quad. But the frames are invisible because the webview is opaque and covers the entire window.
When we disabled the IPC frame path (to avoid duplicate work), the screen went black because the webview was rendering nothing and blocking the wgpu surface underneath.
Goal
Make the wgpu-rendered frames visible by making the webview transparent in the session area, so the GPU-rendered content shows through.
Architecture
┌──── Window ─────────────────────────────┐
│ │
│ LAYER 0: wgpu Metal Surface │
│ ┌──────────────────────────────────┐ │
│ │ GPU-rendered RDP frames │ │
│ │ (fullscreen textured quad) │ │
│ └──────────────────────────────────┘ │
│ │
│ LAYER 1: WebView (transparent bg) │
│ ┌──────────────────────────────────┐ │
│ │ ┌─────┐ Toolbar (opaque) │ │
│ │ │ Side│ ┌────────────────────┐ │ │
│ │ │ bar │ │ │ │ │
│ │ │ │ │ TRANSPARENT AREA │ │ │
│ │ │ │ │ (GPU shows thru) │ │ │
│ │ │ │ │ │ │ │
│ │ └─────┘ └────────────────────┘ │ │
│ │ StatusBar (opaque) │ │
│ └──────────────────────────────────┘ │
└──────────────────────────────────────────┘
Implementation
Step 1: Enable transparent window
In tauri.conf.json:
{
"app": {
"windows": [{
"transparent": true
}]
}
}Step 2: Make session canvas area transparent
In SessionCanvas.tsx, change the canvas container background:
// Before:
<div className="relative w-full h-full bg-black overflow-hidden">
// After:
<div className="relative w-full h-full bg-transparent overflow-hidden">Also ensure the <canvas> element itself has no background, or is hidden when the GPU renderer is active.
Step 3: Tell frontend when GPU renderer is active
Add a Tauri command is_gpu_renderer_active() -> bool that checks if Arc<GpuRenderer> exists in state. The frontend uses this to:
- Hide the
<canvas>element (or setdisplay: none) - Stop processing IPC frame packets (save CPU)
- Show "GPU Accelerated" badge in toolbar
Step 4: Disable IPC frame path when GPU active
In session.rs, re-enable the conditional:
if self.shared_frame.is_none() {
// Only send IPC frames when GPU renderer is NOT active
let packet = encode_image_update_packet(...);
self.send_frame_packet(packet)?;
}Step 5: Verify layer ordering on macOS
The wgpu Metal CAMetalLayer must be BELOW the WKWebView's layer in the NSView hierarchy. Tauri may handle this automatically when transparent: true is set, but verify with:
lldb: po [[window contentView] subviews]
Known risks
- Flickering: Reported in tauri-apps/tauri#9220 — wgpu and webview "fighting" for the surface. The tauri-wgpu-cam project confirms it works on macOS.
- Bundled builds: tauri-apps/tauri#13415 — transparent windows may show as white after bundling. Test with
cargo tauri build.
Files to modify
tauri.conf.json— settransparent: truesrc/components/session/SessionCanvas.tsx— transparent bg, hide canvas when GPU activesrc-tauri/src/commands/session.rs— addis_gpu_renderer_activecommandsrc-tauri/src/rdp/session.rs— conditional IPC skipsrc/styles/globals.css— ensure body/root allow transparency