-
Notifications
You must be signed in to change notification settings - Fork 2
GPU Driven Rendering
SparkEngine implements a GPU-driven rendering pipeline that performs frustum and hierarchical Z-buffer (HiZ) occlusion culling entirely on the GPU via compute shaders, then issues geometry draws through indirect dispatch. This eliminates CPU-side per-object visibility checks for scenes with thousands of instances.
Source: SparkEngine/Source/Graphics/GPUDrivenRenderer.h, SparkEngine/Source/Graphics/GPUOcclusionCulling.h
Namespace: Spark::Graphics
Tests: Tests/TestGPUDrivenRenderer.cpp (13 test cases)
Traditional rendering tests each object's visibility on the CPU, which becomes a bottleneck with thousands of draw calls. GPU-driven rendering uploads all instance bounding boxes to the GPU, runs a compute shader to cull invisible instances, and writes draw arguments directly — the CPU never touches per-instance visibility.
┌─────────────────────────────────────────────────────────────┐
│ Frame N-1: Render scene → depth buffer │
└───────────────────────────┬─────────────────────────────────┘
│
v
┌─────────────────────────────────────────────────────────────┐
│ BeginFrame(): Build HiZ mip chain from depth buffer │
│ │
│ Mip 0 (full res) → Mip 1 (half) → ... → Mip N (1x1) │
│ Each mip stores the MAX depth of the 2x2 parent region │
└───────────────────────────┬─────────────────────────────────┘
│
v
┌─────────────────────────────────────────────────────────────┐
│ CullAndDraw(): │
│ 1. Upload instance AABBs to GPU structured buffer │
│ 2. Dispatch cull compute shader: │
│ - Frustum plane test │
│ - HiZ occlusion test (project AABB → screen rect → │
│ sample HiZ at appropriate mip) │
│ 3. Write indirect draw args for visible instances │
│ 4. DrawIndexedInstancedIndirect │
└─────────────────────────────────────────────────────────────┘
Each frame follows two stages:
Builds the HiZ mip chain from the previous frame's depth buffer. Each mip level stores the maximum depth of its parent 2x2 region, creating a conservative depth pyramid.
- Upload: Instance AABBs are uploaded to a GPU structured buffer
-
Cull dispatch: A compute shader tests each AABB against:
- Frustum planes: 6-plane frustum test eliminates objects fully outside the view
- HiZ occlusion: Projects the AABB to a screen-space rectangle, selects the HiZ mip level matching the rectangle size, and compares the AABB's nearest depth against the stored maximum depth
- Indirect args: Visible instances write their draw arguments to an indirect buffer
-
Draw:
DrawIndexedInstancedIndirectrenders all visible geometry in one call
A 1-frame-deferred readback avoids CPU-GPU sync stalls when reading back statistics.
struct CullSettings
{
bool enableFrustumCull = true; // Frustum plane culling
bool enableHiZCull = true; // Hierarchical Z-buffer occlusion
bool freezeCulling = false; // Debug: freeze at current camera
};struct CullStatistics
{
uint32_t totalInstances; // Submitted for culling
uint32_t visibleInstances; // Passed all tests
uint32_t culledByFrustum; // Removed by frustum
uint32_t culledByHiZ; // Removed by occlusion
};struct alignas(16) GPUInstanceAABB
{
float minX, minY, minZ;
float padding0;
float maxX, maxY, maxZ;
float padding1;
};16-byte aligned for GPU structured buffer compatibility.
| Method | Description |
|---|---|
Initialize(device, context, maxInstances) |
Create GPU resources. Default max: 8192 instances |
Shutdown() |
Release all GPU resources |
BeginFrame(depthSRV, width, height) |
Build HiZ mip chain from depth buffer |
CullAndDraw(aabbs, count, view, proj, ib, vb, stride, indexCount) |
Cull and draw |
GetVisibleCount() |
Visible instances from last frame |
GetStatistics() |
Full CullStatistics struct |
GetSettings() / SetSettings()
|
Read/write CullSettings
|
Console_GetStatus() |
Formatted debug string |
The GPUOcclusionCuller provides a standalone HiZ occlusion testing API, usable independently of the full GPU-driven renderer.
struct HiZPyramid
{
static constexpr int kMaxMips = 12; // Up to 4096x4096
void Build(const float* depthBuffer, uint32_t w, uint32_t h);
float Sample(int mip, uint32_t x, uint32_t y) const;
};The pyramid stores maximum depth values at progressively coarser resolutions. A bounding box is occluded if its nearest depth is greater than the HiZ value at its screen extent.
bool IsVisible(float screenMinX, float screenMinY,
float screenMaxX, float screenMaxY,
float nearDepth) const;Projects screen-space bounds and tests against the appropriate HiZ mip level.
std::vector<uint32_t> CullBatch(
const std::vector<OcclusionAABB>& objects,
const float* viewProjMatrix) const;Tests multiple world-space AABBs at once, returning indices of visible objects.
auto& renderer = GPUDrivenRenderer::GetInstance();
renderer.Initialize(device, context, 16384);
// Each frame:
renderer.BeginFrame(depthSRV, screenWidth, screenHeight);
// Prepare instance AABBs
std::vector<GPUInstanceAABB> aabbs = BuildAABBs(sceneObjects);
renderer.CullAndDraw(
aabbs.data(), static_cast<uint32_t>(aabbs.size()),
viewMatrix, projMatrix,
indexBuffer, vertexBuffer, vertexStride, totalIndexCount);
// Check stats
const auto& stats = renderer.GetStatistics();
LOG_INFO("Visible: {}/{} (frustum culled: {}, HiZ culled: {})",
stats.visibleInstances, stats.totalInstances,
stats.culledByFrustum, stats.culledByHiZ);- GraphicsEngine: Can be used alongside or instead of CPU frustum culling
- MeshClusterSystem: Provides meshlet-level AABBs for fine-grained culling. See Mesh Shaders
- GPU Scene Buffer: Shared GPU buffer for instance transforms and material IDs
-
Platform: Requires D3D11 compute shaders. CPU reference implementation available via
GPUOcclusionCuller
- Rendering and Graphics — Overall rendering architecture
- Mesh Shaders — Meshlet-based rendering with per-meshlet culling
- GPU Particles — Related GPU compute pipeline
- Clustered Lighting — 3D frustum grid for light culling
Published from ad9c3c1953cc. Edit the canonical source in wiki/.
- Documentation
- Docs route
- Wiki index
- Guides
- Tutorials
- Samples
- Examples
- API Reference
- API route
- Reference
- Build Guide
- Dependencies
- FAQ
- Changelog
- Roadmap
- Contributing
- Code of Conduct
- Home
- FAQ
- Getting Started
- Quick-Start Tutorial
- Making Your First Game
- Making Your First Multiplayer Game
- Artist Workflow Guide
- Editor Walkthrough
- Migration Guide
- How SparkEngine Works
- Architecture Overview
- Engine Architecture Flowchart
- Creating a Game Module
- Game Modules (catalog)
- Entity Component System
- Rendering and Graphics
- Physics
- Cloth Simulation
- Audio
- Input System
- Camera System
- Scripting with AngelScript
- Visual Scripting
- AI and Navigation
- Animation
- 2D Systems
- Networking
- Dedicated Server
- Multiplayer Quick Start
- Area Server Architecture
- Scene Management
- Large World Support
- Collaborative Editing
- Coroutine System
- Event System
- Event Response System
- Job System
- UI System
- UI Layout Extensions
- Localization
- Dialogue System
- Destruction System
- Replay System
- Achievement System
- Loading System
- Mod System
- Content Delivery
- Tween System
- Memory Integrity
- Gameplay Systems
- Terrain and Procedural Generation
- Save System
- Persistence System
- Day Night Cycle and Weather
- Cinematic Sequencer
- Runtime Prefabs
- SparkEditor
- Editor Tutorials
- SparkConsole
- SparkDaemon
- Shader Pipeline
- Asset Pipeline
- Asset Validation
- Asset Migration
- Game Packaging
- Online Services
- DataTable System
- Loot and Crafting System
- CSG System
- Font System
- Timer Manager
- Movie Render Pipeline
- HLOD and World Partition
- Remote Debug System
- Selection Manager
- Asset Dependency Graph
- Editor Automation
- File Watcher
- Project Templates
- System Requirements
- VR Support
- Mobile Platform
- Accessibility
- Platform Input
- Cross-Compilation: Wine Testing
- RHI Abstraction Layer
- D3D11 Backend
- D3D12 Backend
- Vulkan Backend
- OpenGL Backend
- Metal Backend
- DXR Raytracing
- Hybrid Ray Tracing
- Upscaling (DLSS/FSR)
- Render Graph
- Shader Graph
- GPU Particles
- GPU-Driven Rendering
- Volumetric Fog
- Volumetric Clouds
- Global Illumination
- Virtual Texturing
- Water Rendering
- Clustered Lighting
- Material System
- Post-Processing
- Shadow System
- Particle System
- Decal System
- Sky and Atmosphere
- Foliage System
- Mesh Shaders
- Neural Rendering
- Configuration Reference
- Performance Tips
- Benchmark Framework
- Threading Model
- Memory Safety
- Memory Management Patterns
- Build System and CMake Modules
- Profiler and Debugging
- Performance Profiling Guide
- Telemetry System
- Golden Image Testing
- Utilities
- Testing
- Codebase Statistics
- Codebase Health
- Error Handling Patterns
- Hot Reload Overview
- Troubleshooting
- Contributing
- Workflow Patterns
- Build Optimizations
- CI Reproducible Builds
- GitHub API and PR Checks
- Git Rebase Conflicts
- Clang-Format
- Code Quality Violations
- AI Bloat Pattern
- MinGW + Wine Cross-Compilation
- Live Editor Testing
- Engine & Renderer Landscape
- DuetOS Portability Catalog
- Five-Engine Analysis
- Eleven-Engine Analysis
- ThorVG / Unity Graphics Analysis
- Advanced Techniques Catalog
- Third-Party Library Evaluation
- Engine Viability Evaluation
- Engine Feature Recommendations
- Project Recommendations
- Mac Compatibility Analysis
- Codebase Observations
- Codebase Bloat Audit
- Test Suite Audit
- Documentation Coverage Audit
- ThirdParty Dependencies Audit
- Load Test Baseline
- Gameplay Systems Status
- SparkGame Module Status
- Stub and Abandoned Features
- Memory Integrity System
- Memory Safety Evaluation
- Hardware Acceleration Systems
- Jolt Physics Integration
- GPU/CPU Separation Plan
- Daemon Services Architecture
- Reflection & Polymorphism Refactoring Plan
- SparkBuild In-Tree
- Wine No-JobSystem Breakthrough
- Wine Role and Fallback Tiers