GPU Acceleration Test - WebAssembly Demo

View on GitHub

This project demonstrates GPU acceleration using modern graphics APIs, implemented in Rust. It features two branches: the main branch for native desktop applications and the web-integration branch for browser-based WebAssembly deployment.

Status: Loading WebAssembly module...

GPU Acceleration in Rust: From Desktop to Web with WebAssembly

Modern graphics programming has evolved significantly, with GPU acceleration becoming essential for high-performance applications. This project demonstrates GPU acceleration using Rust and how it can be adapted to run in web browsers through WebAssembly.

The Main Branch: Native GPU Acceleration

The main branch is a native desktop application that leverages hardware-accelerated graphics through the wgpu library, providing maximum performance by directly accessing the system's GPU capabilities.

// main/src/lib.rs
pub mod texture;
pub mod vertex;
pub mod render_device;
pub mod system_info;
pub mod state;
pub mod debug;
pub mod device_selector;

Key components include the application entry point, rendering pipeline, geometry definitions, shaders, debug overlay, and device selection for CPU/GPU rendering.

Project Overview

Web Integration Branch

The web-integration branch extends the core rendering engine to work in web browsers through WebAssembly, allowing GPU-accelerated rendering to run directly in modern browsers without plugins.

Technical Stack:

The web integration uses conditional compilation to separate platform-specific code:

#[cfg(target_arch = "wasm32")]
// Web-specific code

#[cfg(not(target_arch = "wasm32"))]
// Desktop-specific code

Web-specific features include canvas integration, WebGL context management, and browser event handling.

Main Branch (Desktop)

The main branch focuses on native desktop performance, using platform-specific graphics APIs for maximum efficiency.

Technical Stack:

The desktop version includes hardware-specific optimizations, detailed system information, and an interactive debug overlay.

How It Works

Both versions share the same core rendering pipeline:

  1. Initialize the graphics context (WebGL for web, native API for desktop)
  2. Create shader programs using WGSL
  3. Set up vertex and index buffers for 3D geometry
  4. Create texture resources
  5. Implement a render loop with transformation matrices
  6. Display performance metrics

The web version compiles to WebAssembly and interfaces with WebGL, while the desktop version compiles to native code and interfaces directly with graphics drivers.

Shared Components

Both branches share several key components:

1. Vertex Definitions

// From vertex.rs
#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Vertex {
    pub position: [f32; 3],
    pub tex_coords: [f32; 2],
    pub normal: [f32; 3],
}

2. Render Device Abstraction

// From render_device.rs
#[derive(Clone, Debug, PartialEq)]
pub enum RenderDevice {
    CPU,
    GPU(String),
}

3. Transformation Logic

// Create matrices for 3D rendering
let projection = Mat4::perspective_rh(45.0 * (PI / 180.0), aspect, 0.1, 100.0);
let view = Mat4::look_at_rh(
    Vec3::new(0.0, 0.0, 3.0), // Camera position
    Vec3::new(0.0, 0.0, 0.0), // Look at origin
    Vec3::new(0.0, 1.0, 0.0), // Up vector
);

Browser Compatibility

The web version requires a browser with WebGL 2 support:

A dedicated GPU is recommended for optimal performance.

Deep Dive: Main Branch Architecture

The main branch leverages hardware-accelerated graphics through wgpu, with these key components:

Initialization Process

// Main application initialization
fn main() -> Result<()> {
    // Create wgpu instance
    let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
        backends: wgpu::Backends::all(),
        ..Default::default()
    });
    
    // Get system info and select rendering device
    let mut system_info = get_system_info(&instance);
    let render_device = prompt_device_selection(&mut system_info);
    
    // Create and run the application
    let event_loop = EventLoop::new().unwrap();
    event_loop.run_app(&mut App { /* ... */ })?;
    Ok(())
}

Shader Implementation

The application uses WGSL (WebGPU Shading Language) for its shaders:

// Vertex shader
struct VertexInput {
    @location(0) position: vec3,
    @location(1) tex_coords: vec2,
    @location(2) normal: vec3,
};

@vertex
fn vs_main(model: VertexInput) -> VertexOutput {
    var out: VertexOutput;
    out.tex_coords = model.tex_coords;
    out.clip_position = uniforms.model_view_proj * vec4(model.position, 1.0);
    out.normal = model.normal;
    return out;
}

// Fragment shader
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4 {
    return textureSample(t_diffuse, s_diffuse, in.tex_coords);
}

3D Geometry and Animation

The application renders a textured 3D cube with position, texture coordinates, and normal vectors. The cube rotates continuously, with transformation matrices handling the 3D perspective and camera positioning.

Debug Overlay

The application includes a comprehensive debug overlay implemented with egui:

Input Handling

User input is processed in the State::input() method:

Performance Optimization

The application includes several performance optimizations:

Device Selection

The application allows choosing between CPU and GPU rendering:

Technical Challenges

The main branch addresses several technical challenges:

Code Structure

The codebase is organized into modular components:

This modular approach makes the code maintainable and extensible, allowing for easy addition of new features or optimization of existing ones.

Deep Dive: Web Integration Architecture

The web-integration branch adapts the core architecture to run in browsers through WebAssembly:

WebAssembly Integration

// Web-specific module
#[cfg(target_arch = "wasm32")]
pub mod web;

// Exposed functions for JavaScript
#[wasm_bindgen]
pub fn init() {
    init_logging();
}

#[wasm_bindgen]
pub async fn initialize(canvas: HtmlCanvasElement) -> Result {
    // Initialize WebGL context
}

#[wasm_bindgen]
pub fn start_render_loop() -> Result<(), JsValue> {
    // Start animation frame loop
}

WebGL Rendering Pipeline

The web version adapts the main branch's rendering pipeline to use WebGL 2:

Key Differences Between Branches

1. Graphics API

2. Rendering Architecture

3. Platform Integration

4. Build System

The codebase uses conditional compilation to handle these differences:

#[cfg(target_arch = "wasm32")]
// Web-specific code

#[cfg(not(target_arch = "wasm32"))]
// Desktop-specific code

Conclusion

This project showcases Rust's power in creating cross-platform, high-performance graphics applications using WebAssembly.

Key highlights:

Copied to your clipboard