-
Notifications
You must be signed in to change notification settings - Fork 2
Neural Rendering
SparkEngine's neural rendering subsystem uses small multi-layer perceptrons (MLPs) evaluated via GPU compute shaders to accelerate and enhance several rendering tasks: indirect lighting caching, texture compression, denoising, and super-resolution. The entire subsystem is self-contained with zero external ML framework dependencies -- all inference runs through a custom compute shader dispatch pipeline backed by D3D11 structured buffers, with an SSE2/AVX2 CPU fallback for headless and NullRHI modes.
Source: SparkEngine/Source/Graphics/Neural/
Namespace: Spark::Graphics::Neural
CMake toggle: ENABLE_NEURAL_RENDERING=ON (defines SPARK_NEURAL_RENDERING=1)
- Architecture Overview
- Neural Inference Engine
- Neural Radiance Cache
- Neural Texture Compression (NTC)
- Neural Post-Processing
- Weight Serialization (.nnw)
- Console Commands
- Source Files
- See Also
All neural rendering components share a common inference backbone. Networks are described by NetworkDesc / LayerDesc structs, uploaded once, and evaluated in batches via the singleton NeuralInferenceEngine.
┌──────────────────────────────────────────────────────────────────────────┐
│ Neural Rendering Subsystem │
├──────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────┐ ┌──────────────────────┐ ┌────────────────┐ │
│ │ NeuralRadianceCache │ │ NeuralTextureCompr. │ │ NeuralPostProc │ │
│ │ │ │ │ │ │ │
│ │ Hash Grid (16 lvl) │ │ Per-block MLPs │ │ Denoiser │ │
│ │ + MLP decoder │ │ (u,v) -> RGBA │ │ Super-Res │ │
│ └──────────┬───────────┘ └──────────┬───────────┘ └───────┬────────┘ │
│ │ │ │ │
│ └─────────────┬───────────┘──────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────┐ │
│ │ NeuralInferenceEngine │ │
│ │ (Singleton) │ │
│ ├─────────────────────────────┤ │
│ │ CreateNetwork() │ │
│ │ UploadWeights() │ │
│ │ Evaluate() ─── GPU ──▶ Compute Shader (D3D11 CS) │
│ │ EvaluateCPU() ── CPU ──▶ CpuNeuralInference (SIMD) │
│ └─────────────────────────────┘ │
│ │ │
│ ┌────────────┴────────────┐ │
│ │ NeuralWeights │ │
│ │ SaveWeights / Load │ │
│ │ (.nnw binary format) │ │
│ └─────────────────────────┘ │
│ │
│ Shared types: NeuralTypes.h (ActivationType, LayerDesc, NetworkDesc, │
│ NetworkHandle, NeuralInferenceCB) │
└──────────────────────────────────────────────────────────────────────────┘
Key design constraints:
| Constant | Value | Purpose |
|---|---|---|
kMaxNetworkLayers |
8 | Max layers per network (shader constant buffer) |
kMaxNeuronsPerLayer |
256 | Shared memory limit in compute shader |
kNeuralThreadGroupSize |
64 | Thread group size for inference dispatch |
NeuralInferenceEngine is the core singleton that owns all GPU-resident networks and dispatches MLP evaluation. It is initialized at engine startup (see SparkEngine.cpp) and registered with EngineContext.
On D3D11, the engine compiles an HLSL compute shader at initialization. Each Evaluate() call:
- Binds the network's weight structured buffer as an SRV
- Fills a
NeuralInferenceCBconstant buffer with layer sizes, activations, and weight offsets - Dispatches
ceil(batchSize / 64)thread groups - Writes results to the output UAV
When no GPU is available (NullRHI, headless mode), inference falls back to CpuNeuralInference, which provides:
-
SIMD acceleration: Weights are repacked into
AlignedWeightLayoutwith rows padded to 8-float alignment for aligned AVX2/SSE2 loads - Multi-threaded batching: Batches of 16+ samples are split across JobSystem workers
-
ISA auto-detection:
CpuNeuralInference::Initialize()probes the CPU and binds the fastest kernel (SSE2 or AVX2)
// 1. Get the singleton (initialized at engine startup)
auto& engine = NeuralInferenceEngine::GetInstance();
// 2. Define architecture
NetworkDesc desc;
desc.name = "MyNetwork";
desc.layers = {
{32, 64, ActivationType::ReLU},
{64, 64, ActivationType::ReLU},
{64, 3, ActivationType::Sigmoid}
};
// 3. Create, upload weights, evaluate
NetworkHandle handle = engine.CreateNetwork(desc);
engine.UploadWeights(handle, trainedWeights);
engine.Evaluate(handle, inputSRV, outputUAV, batchSize);
// 4. Cleanup
engine.DestroyNetwork(handle);Activation functions supported by the shader:
| Enum | Formula |
|---|---|
ReLU |
max(0, x) |
LeakyReLU |
x > 0 ? x : 0.01 * x |
Sigmoid |
1 / (1 + exp(-x)) |
Tanh |
tanh(x) |
None |
Identity (linear output) |
NeuralRadianceCache implements a multi-resolution hash grid inspired by Instant NGP for caching indirect lighting. Instead of storing full irradiance probe grids, it learns a compact neural representation that maps (position, direction) to RGB radiance.
The cache uses 16 resolution levels (kHashGridLevels), each with 64K entries (kDefaultHashTableSize). Each entry stores a 2-float feature vector (kFeaturesPerEntry). A 3D position is hashed at each level, yielding a concatenated feature vector of 32 floats (16 levels x 2 features) that is fed through a small MLP decoder.
| Parameter | Default | Description |
|---|---|---|
hashTableSize |
65536 | Entries per resolution level |
mlpHiddenSize |
64 | Neurons per hidden layer |
mlpHiddenLayers |
2 | Number of hidden layers |
learningRate |
0.01 | SGD learning rate |
minResolution |
1.0 | Finest grid cell size (world units) |
maxResolution |
1024.0 | Coarsest grid cell size |
temporalBlend |
0.9 | EMA blend factor with previous frame |
Each frame, new radiance samples (from path tracing, screen-space GI, or other sources) are fed to Update(). The cache performs one round of stochastic gradient descent on the hash grid entries and MLP weights:
NeuralRadianceCache cache;
cache.Initialize({.hashTableSize = 65536, .learningRate = 0.01f});
// Each frame: feed samples from your GI solution
std::vector<RadianceSample> samples = GatherRadianceSamples();
cache.Update(samples.data(), static_cast<uint32_t>(samples.size()), deltaTime);A RadianceSample contains:
struct RadianceSample
{
float position[3]; // World-space position
float direction[3]; // View direction (normalized)
float radiance[3]; // RGB radiance value
};float position[3] = {10.0f, 2.0f, -5.0f};
float direction[3] = {0.0f, 1.0f, 0.0f};
float radiance[3];
// Single query
cache.QueryCPU(position, direction, radiance);
// Batch query (more efficient)
cache.QueryBatchCPU(positions, directions, outRadiance, batchSize);NeuralTextureCompressor compresses RGBA textures by training a tiny MLP per block. Each block MLP learns the mapping (u, v) -> (r, g, b, a) using positional encoding, and the network weights become the compressed representation. Decompression evaluates the MLP to reconstruct pixels.
- Divide the texture into blocks (default 16x16 pixels)
- Encode UV coordinates with positional encoding (sin/cos frequency bands)
- Train a per-block MLP via SGD to fit the block's pixels
- Store the trained weights as the compressed output
NeuralTextureCompressor ntc;
ntc.Initialize();
NTCOptions opts;
opts.qualityLevel = 2; // 0=fast, 1=medium, 2=high, 3=best
opts.blockSize = 16; // 16x16 pixel blocks
opts.positionalFrequencies = 4; // sin/cos frequency bands
auto compressed = ntc.Compress(rgbaPixels, 512, 512, opts);
// Save to disk
ntc.SaveNTEX(compressed, "texture.ntex");
// Load and decompress
auto loaded = ntc.LoadNTEX("texture.ntex");
auto decoded = ntc.DecompressCPU(loaded);| Level | Name | Description |
|---|---|---|
| 0 | Fast | Fewest training iterations, smallest networks |
| 1 | Medium | Balanced quality/speed |
| 2 | High | Default -- good quality, moderate compression time |
| 3 | Best | Maximum training iterations, highest fidelity |
The .ntex binary format stores one complete neural-compressed texture:
┌─────────────────────────────────────────────────┐
│ NTEXHeader (magic 'SNTX', version 1) │
│ - width, height, channels │
│ - blockSize, blocksX, blocksY │
│ - hiddenLayers, neuronsPerLayer │
│ - inputSize, outputSize │
│ - positionalFrequencies │
│ - weightsPerBlock, totalBlocks │
│ - qualityLevel │
│ - reserved[3] │
├─────────────────────────────────────────────────┤
│ Block 0 weights [float32 x weightsPerBlock] │
│ Block 1 weights [float32 x weightsPerBlock] │
│ ... │
│ Block N weights [float32 x weightsPerBlock] │
└─────────────────────────────────────────────────┘
All fields are little-endian uint32_t. The magic number is 0x58544E53 ("SNTX"). All blocks share the same MLP architecture (described in the header), so only the weight data varies per block.
Compression metrics are available via NeuralCompressedTexture:
size_t compressed = tex.GetCompressedSize(); // Total weight bytes
size_t original = tex.GetOriginalSize(); // width * height * channels
float ratio = tex.GetCompressionRatio(); // compressed / originalNeuralDenoiser implements the IDenoiser interface with a learned MLP that processes 8x8 pixel patches (kDenoisePatchSize). It accepts color input plus optional albedo and normal guide buffers.
MLP architecture:
- Input: noisy color (3 x 8 x 8 = 192 floats) + optional albedo (192) + normal (192)
- Hidden: 3 layers of 128 neurons, ReLU activation
- Output: denoised color (3 x 8 x 8 = 192 floats), Sigmoid activation
NeuralDenoiser denoiser;
denoiser.Initialize(settings);
denoiser.LoadWeights(pretrainedWeights);
denoiser.SetColorInput(colorBuffer);
denoiser.SetAlbedoGuide(albedoBuffer); // optional
denoiser.SetNormalGuide(normalBuffer); // optional
denoiser.Execute();
const float* result = denoiser.GetOutput();Falls back to pass-through if no weights are loaded (HasWeights() returns false).
NeuralSuperResolution upscales 8x8 patches to 16x16 (kSRScaleFactor = 2). Designed as an optional refinement pass after SparkSR temporal accumulation.
MLP architecture:
- Input: low-res color (3 x 8 x 8 = 192 floats) + optional depth (8 x 8 = 64 floats)
- Hidden: configurable (default 3 layers of 128 neurons)
- Output: high-res color (3 x 16 x 16 = 768 floats)
NeuralSuperResolution sr;
sr.Initialize({.hiddenSize = 128, .hiddenLayers = 3, .useDepthInput = true});
sr.LoadWeights(pretrainedWeights);
auto upscaled = sr.UpscaleCPU(lowResInput, depthBuffer, width, height);
// upscaled is (width * 2) x (height * 2) x 3 floatsThe .nnw (Neural Network Weights) format stores a NetworkDesc plus all float32 weights/biases in a single binary blob:
┌─────────────────────────────────────────┐
│ NNWHeader │
│ magic: 0x574E4E53 ('SNNW') │
│ version: 1 │
│ layerCount │
│ totalParameters │
├─────────────────────────────────────────┤
│ LayerDesc[0] .. LayerDesc[layerCount-1] │
│ (inputSize, outputSize, activation) │
├─────────────────────────────────────────┤
│ float32[totalParameters] │
│ weights + biases, layer by layer │
└─────────────────────────────────────────┘
// Save
TrainedNetwork network{desc, weights};
SaveWeights(network, "model.nnw");
// Load
TrainedNetwork loaded = LoadWeights("model.nnw");
engine.CreateNetwork(loaded.desc);
engine.UploadWeights(handle, loaded.weights);Each neural rendering component exposes a Console_GetStatus() method that returns a diagnostic string. These are accessible through the engine's subsystem status commands:
| Command | Description |
|---|---|
r_neural_status |
Print NeuralInferenceEngine status (GPU availability, network count, dispatch count) |
r_neural_cache_status |
Print NeuralRadianceCache status (hash table occupancy, sample count, training loss, memory) |
r_neural_ntc_status |
Print NeuralTextureCompressor status (textures compressed, compression ratio) |
r_neural_sr_status |
Print NeuralSuperResolution status (weights loaded, patches processed) |
r_neural_denoise_status |
Print NeuralDenoiser status (backend type, execution time) |
| File | Description |
|---|---|
Graphics/Neural/NeuralTypes.h |
Shared types: ActivationType, LayerDesc, NetworkDesc, NetworkHandle, NeuralInferenceCB
|
Graphics/Neural/NeuralInference.h/.cpp |
NeuralInferenceEngine -- GPU compute shader MLP evaluation singleton |
Graphics/Neural/CpuNeuralInference.h/.cpp |
CpuNeuralInference -- SIMD-optimized CPU fallback with multi-threaded batching |
Graphics/Neural/NeuralRadianceCache.h/.cpp |
NeuralRadianceCache -- multi-resolution hash grid + MLP for indirect lighting |
Graphics/Neural/NeuralTextureCompressor.h/.cpp |
NeuralTextureCompressor -- per-block MLP texture compression |
Graphics/Neural/NeuralTextureFormat.h |
.ntex binary format header (NTEXHeader, constants) |
Graphics/Neural/NeuralPostProcessing.h/.cpp |
NeuralDenoiser (IDenoiser impl) and NeuralSuperResolution
|
Graphics/Neural/NeuralWeights.h/.cpp |
.nnw weight serialization (SaveWeights, LoadWeights) |
All source paths are relative to SparkEngine/Source/.
- Global Illumination -- DDGI and Adaptive Probe Volumes (complementary to neural radiance cache)
- Virtual Texturing -- Streaming virtual texture system (NTC is an alternative compression approach)
- Post-Processing -- Traditional post-processing pipeline (neural denoiser/SR integrate here)
- Upscaling (DLSS/FSR) -- Temporal upscaling (neural SR is an optional enhancement pass)
- Rendering and Graphics -- Top-level graphics overview
- RHI Abstraction Layer -- Compute shader dispatch details
Published from bf219a7bdb9b. 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