WGFX is a modern C++20 graphics and compute engine built on top of Google Dawn, the reference implementation of WebGPU. It bridges the gap between low-level GPU hardware control and high-level developer ergonomics for real-time scientific visualization, signal processing simulations, and interactive 3D engineering tooling.

WGFX Physically Based Rendering with 4K Texture Displacement Mapping


Architectural Philosophy & Core Design

Traditional desktop graphics programming often forces an uncomfortable compromise: the heavyweight complexity and multi-thousand-line boilerplate of raw Vulkan or DirectX 12, versus the outdated driver quirks and state-machine baggage of legacy OpenGL.

WebGPU via Dawn represents a modern sweet spot: an explicit, cross-platform graphics and compute API with rigorous validation layers, robust multi-queue synchronization, and first-class compute shader support.

WGFX wraps Dawn with zero-overhead C++20 idioms, automated resource lifetimes, and high-throughput compute abstractions:

  • Reactive Rendering Architecture: Unlike conventional game engines that run an unconstrained busy loop at 1000+ FPS consuming full CPU and GPU cores, WGFX implements an event-driven loop backed by SDL_WaitEventTimeout. The engine idles until user interaction occurs or background compute tasks explicitly trigger requestRender(). This slashes idle CPU and GPU power consumption to virtually zero while maintaining smooth 60–144 Hz rendering when active.
  • Application Profiles (AppConfig): Tailors window and resource overhead to the workload. Lightweight profiles like UiOnly or UiCompute completely omit 3D PBR render pipelines, depth/MSAA buffers, shadow maps, and audio systems when only ImGui tooling, compute graphs, or 2D plotting are required.
  • Unified Command Encoding (CommandList): A move-only command abstraction that composes compute dispatches, GPU buffer transfers, timestamp query resolves, and rasterization passes into a single ordered queue submission per frame, preventing pipeline stalls.
  • Extensible Render Features: Self-contained rendering stages (such as SegmentSet for 3D vector lines/trajectories, or custom post-processing passes) can be registered into the render pipeline dynamically.

C++20 API Architecture & Code Examples

1. The Reactive Application Harness (wgfx::App)

Subclassing wgfx::App provides an integrated lifecycle handling SDL3 windowing, High-DPI scaling, Dear ImGui / ImPlot docking, camera manipulation, and compute synchronization:

#include "wgfx/wgfx.hpp"
#include <iostream>

class RadarVisualizerApp : public wgfx::App {
public:
    RadarVisualizerApp() : wgfx::App(wgfx::AppConfig{
        .window_width = 1600,
        .window_height = 900,
        .title = "Radar Range-Doppler Analyzer",
        .aa_sample_count = 4,
        .presentation_mode = WGPUPresentMode_Fifo,
        .profile = wgfx::AppProfile::Full
    }) {}

    // Encode compute passes that run before the main render pass
    int encode_pre_render(wgfx::CommandList& commands) override {
        if (simulation_active) {
            fft_plan.record(commands, dsp_input_buffer, dsp_spectrum_buffer);
        }
        return 0;
    }

    // Main 3D scene rasterization pass
    int draw(WGPURenderPassEncoder renderPass) override {
        pbr_pipeline.bind(renderPass);
        antenna_model.draw(renderPass);
        return 0;
    }

    // Immediate-mode UI and real-time telemetry plotting
    int ui() override {
        ImGui::Begin("DSP Controls");
        if (ImGui::Button("Trigger Pulse Batch")) {
            simulation_active = true;
            requestRender(); // Wakes up event loop for immediate redraw
        }
        
        if (ImPlot::BeginPlot("Range-Doppler Power Spectrum (dBm)")) {
            ImPlot::PlotLine("Received Spectrum", frequencies.data(), 
                             power_dbm.data(), frequencies.size());
            ImPlot::EndPlot();
        }
        ImGui::End();
        return 0;
    }

private:
    bool simulation_active = false;
    wgfx::fft::FFTPlan fft_plan;
    wgfx::Buffer<wgfx::fft::Complex> dsp_input_buffer;
    wgfx::Buffer<wgfx::fft::Complex> dsp_spectrum_buffer;
    std::vector<float> frequencies;
    std::vector<float> power_dbm;
};

int main() {
    RadarVisualizerApp app;
    return app.run();
}

2. High-Level Compute Pipeline & Typed Buffers (wgfx::compute)

Managing compute passes, bind groups, and staging memory in raw WebGPU requires dozens of descriptor structs. WGFX provides type-safe Buffer<T> abstractions and a variadic ComputePass builder:

#include "wgfx/compute.hpp"

void execute_vector_scale(const wgfx::DeviceContext& context, 
                          std::span<const float> input_data, 
                          float scale_factor,
                          std::span<float> output_results) 
{
    const uint32_t count = static_cast<uint32_t>(input_data.size());

    // Allocate typed GPU buffers
    wgfx::Buffer<float> in_buf(context, "InputBuffer", count, 
        WGPUBufferUsage_Storage | WGPUBufferUsage_CopyDst);
    wgfx::Buffer<float> out_buf(context, "OutputBuffer", count, 
        WGPUBufferUsage_Storage | WGPUBufferUsage_CopySrc);
    wgfx::Buffer<float> staging_buf(context, "StagingReadback", count, 
        WGPUBufferUsage_MapRead | WGPUBufferUsage_CopyDst);

    // Upload data from host to GPU VRAM
    in_buf.write(input_data);

    // Compile or retrieve cached compute pipeline from WGSL source
    auto pipeline = wgfx::ComputeShader::create(context, "shaders/scale.wgsl", "main");

    // Compose compute pass using variadic bind group builder
    wgfx::ComputePass pass(context, pipeline);
    pass.addBindGroup(0, in_buf, out_buf);
    pass.dispatch((count + 63) / 64);
    
    // Copy result to CPU-readable staging buffer and submit to GPU queue
    pass.stageOutput(out_buf, staging_buf);
    pass.submit();

    // Synchronous or asynchronous map-read back into CPU memory
    staging_buf.read(output_results);
}

Companion WGSL compute shader (shaders/scale.wgsl):

@group(0) @binding(0) var<storage, read> input_data: array<f32>;
@group(0) @binding(1) var<storage, read_write> output_data: array<f32>;

@compute @workgroup_size(64, 1, 1)
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
    let index = id.x;
    if (index < arrayLength(&input_data)) {
        output_data[index] = input_data[index] * 2.5;
    }
}

WebGPU Hardware Instancing: 100,000 Cubes Animated Concurrently via Compute Shader at 144 FPS


3. GPU-Accelerated FFT Library (wgfx::fft)

WGFX includes an in-house WebGPU compute Fast Fourier Transform engine inspired by NVIDIA’s CUFFT:

  • Transform Types: 1D and 2D Complex-to-Complex (C2C), Real-to-Complex (R2C), and Complex-to-Real (C2R) forward and inverse transforms.
  • Optimized WGSL Kernels: Stockham auto-sort algorithm, Radix-4 kernels, Bluestein chirped-Z transform for arbitrary non-power-of-two lengths, and Hermite-symmetry packing/unpacking for real signals.
  • Direct CommandList Pipelining: FFT plans record multi-pass compute dispatches directly into an active CommandList without forcing GPU flushes or host synchronization points.
#include "wgfx/fft/fft.hpp"

void run_2d_spectrum_analysis(const wgfx::DeviceContext& context) {
    const uint32_t width = 1024;
    const uint32_t height = 1024;

    // Create 2D Complex-to-Complex Plan (Width x Height)
    wgfx::fft::FFTPlan plan2d = wgfx::fft::FFTPlan::create2D(
        context, width, height, 
        wgfx::fft::TransformType::C2C, 
        /*batch=*/1, 
        wgfx::fft::Normalization::Unitary
    );

    wgfx::Buffer<wgfx::fft::Complex> spatial_domain(context, "SpatialImage", 
        width * height, WGPUBufferUsage_Storage | WGPUBufferUsage_CopyDst);
    wgfx::Buffer<wgfx::fft::Complex> frequency_domain(context, "FrequencySpectrum", 
        width * height, WGPUBufferUsage_Storage | WGPUBufferUsage_CopySrc);

    // Record FFT execution into an existing CommandList alongside other compute/render work
    wgfx::CommandList cmdList(context, "FFT Spectrum Analysis");
    plan2d.record(cmdList, spatial_domain, frequency_domain, wgfx::fft::Direction::Forward);

    // Submit batch to the GPU queue asynchronously
    wgfx::JobManager jobs(context);
    wgfx::Submission future = jobs.submit(std::move(cmdList));
    jobs.waitForFuture(future);
}

Real-Time Ocean Wave Simulation: 2048×2048 (4.19M points) 2D GPU IFFT Evaluated in 0.018 ms at 144 FPS with Fresnel Shading and Foam Generation


4. Physically Based Rendering (PBR) & Lighting Pipeline

The rendering module implements a modern physically based graphics pipeline:

  • Cook-Torrance Microfacet BRDF: Evaluates GGX normal distribution, Smith geometric shadowing, and Schlick Fresnel approximation.
  • Clustered Forward Lighting: Divides the camera view frustum into a 3D grid of clusters via compute shaders (cluster_lights.wgsl), culling dozens of point and spotlights into per-cluster light index lists for efficient single-pass forward rendering.
  • Percentage-Closer Soft Shadows (PCSS): Dynamically calculates blocker depth and penumbra width to produce realistic contact hardening (crisp near contact, diffuse further away).
  • HDRI Reflections: Real-time HDR equirectangular skybox maps prefiltered into GGX specular mip chains (prefilter_environment.wgsl).
  • Tonemapping: Configurable ACES Filmic, AgX, and Reinhard tonemapping operators in WGSL.

Clustered Forward Lighting in a Cornell Box: Emissive Panels, Spotlights with 1024px Shadows, and Point Lights with Shadow Cubemaps

High-Dynamic-Range (HDRI) Equirectangular Environment Reflections Prefiltered into GGX Specular Mip Chains


Exploratory Simulations & Tools

WGFX serves as the graphics and compute substrate for diverse engineering applications:

  • fft_ocean: Synthesizes open ocean water surfaces using the Tessendorf/Phillips wave spectrum evaluated via 2D GPU IFFTs, complete with real-time Fresnel water shading, subsurface scattering approximations, and foam crest tracking.
  • rocket: Multi-stage 6-DOF rocket simulation evaluating variable motor thrust profiles, atmospheric drag curves, and apogee events with real-time multi-channel telemetry plotted via ImPlot.
  • model: 3D asset inspection harness powered by EnTT (ECS) and Assimp, featuring PBR materials, HDRI reflections, and soft contact shadows.
  • fft_diffraction: Interactive Fourier optics workbench simulating near-field (Fresnel) and far-field (Fraunhofer) optical diffraction across arbitrary apertures (James Webb Space Telescope hexagonal segment array, gratings, slits, and knife edges).
  • antenna: Real-time phased array antenna simulator computing beamforming radiation patterns across dynamic azimuth/elevation steering vectors on the GPU.
  • flows: Integration with Taskflow to orchestrate complex heterogeneous directed acyclic graphs (DAGs) across multi-threaded CPU worker pools and WebGPU compute queues.
  • tonemapping: Side-by-side interactive comparator analyzing exposure, luminance distribution, and color reproduction across ACES, AgX, and Reinhard curves.

6-DOF Rocket Flight Simulation with Real-Time ImPlot Telemetry Streaming

EnTT ECS Model Viewer: Loading Complex Satellite Models via Assimp with PBR Shading and HDRI Lighting


Tech Stack & Dependencies

  • Language: C++20 (Clang 16+, GCC 13+, MSVC 2022)
  • GPU Backend: WebGPU via Google Dawn & WGSL Shaders
  • Windowing & Input: SDL3 (Native High-DPI & Retina support)
  • UI & Visualization: Dear ImGui, ImPlot, ImPlot3D, ImGuiFileDialog
  • Mathematics & ECS: GLM (OpenGL Mathematics), EnTT
  • Asset Loading & Audio: Assimp (3D models), stb (textures/images), miniaudio (audio DSP)
  • Concurrency: Taskflow
  • Build System: Modern CMake with CPM.cmake