Skip to main content

What is GPUI?

GPUI is Glass’s custom GPU-accelerated UI framework written in Rust. It provides:
  • Cross-platform rendering using Metal, DirectX, or Vulkan
  • Reactive state management with entity-based architecture
  • High performance with minimal allocations and efficient updates
  • Type-safe UI construction at compile time
GPUI is maintained as a separate project: https://github.com/Obsydian-HQ/gpui

Core GPUI Crates

Glass depends on several GPUI crates:
gpui = { git = "https://github.com/Obsydian-HQ/gpui.git" }
gpui_macros = { git = "https://github.com/Obsydian-HQ/gpui.git" }
gpui_tokio = { git = "https://github.com/Obsydian-HQ/gpui.git" }
collections = { git = "https://github.com/Obsydian-HQ/gpui.git" }
util = { git = "https://github.com/Obsydian-HQ/gpui.git" }
sum_tree = { git = "https://github.com/Obsydian-HQ/gpui.git" }
scheduler = { git = "https://github.com/Obsydian-HQ/gpui.git" }
refineable = { git = "https://github.com/Obsydian-HQ/gpui.git" }
media = { git = "https://github.com/Obsydian-HQ/gpui.git" }
http_client = { git = "https://github.com/Obsydian-HQ/gpui.git" }

Context Types

GPUI uses context types to manage state and provide capabilities:

App Context

App is the root context providing access to global state:
fn do_something(cx: &mut App) {
    // Access entities
    let entity = cx.new(|cx| MyState::new());
    
    // Spawn async work
    cx.spawn(|cx| async move {
        // Background work
    });
}

Window Context

Window provides access to window state and rendering:
fn render_ui(window: &mut Window, cx: &mut App) {
    // Dispatch actions
    window.dispatch_action(action, cx);
    
    // Manage focus
    window.focus(&focus_handle);
}

Entity Context

Context<T> is provided when updating an entity:
impl Editor {
    fn update_text(&mut self, cx: &mut Context<Self>) {
        // Mutate self
        self.buffer.insert(...);
        
        // Trigger re-render
        cx.notify();
    }
}

Async Contexts

AsyncApp and AsyncWindowContext can be held across await points:
cx.spawn(|mut cx| async move {
    let result = some_async_fn().await;
    cx.update(|cx| {
        // Update state with result
    })?;
});

Entity System

Entities are created via the context:
let editor = cx.new(|cx| Editor::new(cx));
This returns an Entity<Editor> handle.

Element System

UI is built by implementing the Render trait:
struct MyView {
    message: SharedString,
}

impl Render for MyView {
    fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
        div()
            .flex()
            .items_center()
            .p_4()
            .border_1()
            .border_color(rgb(0xcccccc))
            .child(self.message.clone())
    }
}

Element Composition

Elements are composed using a builder pattern:
div()
    .w_full()
    .h(px(400.))
    .flex()
    .flex_col()
    .gap_2()
    .child(
        div()
            .text_lg()
            .font_bold()
            .child("Title")
    )
    .child(
        div()
            .text_sm()
            .text_color(rgb(0x666666))
            .child("Description")
    )

Styling

GPUI uses a Tailwind-like API for styling:
  • w_full(), h_full() - Full width/height
  • flex(), flex_col() - Flexbox layout
  • p_4(), px_2(), py_1() - Padding
  • m_4(), mx_2() - Margin
  • gap_2() - Gap between flex items
  • border_1(), border_color() - Borders
  • bg(), text_color() - Colors
  • rounded_lg() - Border radius

Conditional Rendering

div()
    .when(condition, |this| {
        this.bg(red())
    })
    .when_some(optional_value, |this, value| {
        this.child(format!("Value: {}", value))
    })

Event Handling

Input Events

div()
    .on_click(|event, window, cx| {
        println!("Clicked at {:?}", event.position);
    })
    .on_mouse_down(|event, window, cx| {
        // Handle mouse down
    })

Actions

Actions are typed commands dispatched via keybindings:
// Define an action
#[derive(Clone, PartialEq, Debug)]
struct Save;

impl_actions!(editor, [Save]);

// Register handler
div()
    .on_action(cx.listener(|this: &mut Editor, _: &Save, window, cx| {
        this.save(window, cx);
    }))

State Management

Notifications

Trigger UI updates when state changes:
impl Editor {
    fn update_buffer(&mut self, cx: &mut Context<Self>) {
        self.buffer.insert(...);
        cx.notify(); // Re-render this view
    }
}

Observations

Observe changes to another entity:
cx.observe(&buffer, |this: &mut Editor, buffer, cx| {
    // Called when buffer emits notify
    this.handle_buffer_change(buffer, cx);
}).detach();

Entity Events

Entities can emit custom events that other entities subscribe to.
// Emit event
impl EventEmitter<BufferEvent> for Buffer {}

impl Buffer {
    fn edit(&mut self, cx: &mut Context<Self>) {
        // ... make changes
        cx.emit(BufferEvent::Edited);
    }
}

// Subscribe to events
cx.subscribe(&buffer, |this: &mut Editor, buffer, event, cx| {
    match event {
        BufferEvent::Edited => this.handle_edit(cx),
        BufferEvent::Saved => this.handle_save(cx),
    }
}).detach();

Concurrency

Spawning Tasks

// Foreground task (main thread)
let task = cx.spawn(|cx| async move {
    // Async work on main thread
});

// Background task (thread pool)
let task = cx.background_spawn(async move {
    // CPU-intensive or blocking work
});

// Keep task alive or it will be cancelled
task.detach();

Task Lifecycle

let result = task.await;
Waits for the task to complete.

Graphics Backend

GPUI uses wgpu for cross-platform GPU access:
  • macOS: Metal backend
  • Windows: DirectX 12 backend
  • Linux: Vulkan backend

Rendering Pipeline

  1. Element tree construction (Render::render())
  2. Layout calculation (Taffy flexbox engine)
  3. Paint phase (GPU commands)
  4. Frame submission to GPU

Platform Integration

Window Management

cx.open_window(WindowOptions::default(), |window, cx| {
    // Initialize window content
    MyView::new(cx)
});

Platform Features

  • Native menus (macOS)
  • File dialogs
  • Clipboard access
  • System notifications
  • Screen capture

Performance Characteristics

Efficient Updates

  • Only changed elements are re-rendered
  • Layout is incremental
  • GPU commands are batched

Memory Management

  • SharedString for string deduplication
  • Copy-on-write semantics
  • Automatic cleanup via Rust’s ownership

Frame Timing

  • 60 FPS target
  • VSync synchronization
  • Input latency minimization

Build docs developers (and LLMs) love