Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

EPU Architecture Overview

The Environment Processing Unit (EPU) is Nethercore ZX’s GPU-driven, fully procedural environment system. This page provides an architectural overview.

For the complete specification (opcode catalog, packing rules, and shader implementations), see:

  • nethercore-design/specs/epu-feature-catalog.md
  • nethercore/include/zx.rs
  • nethercore/nethercore-zx/shaders/epu/

For the current API reference and quick-start guide, see:


Introduction

The EPU provides a universal, stylized environment system that:

  • Renders backgrounds (sky/walls/void) with strong, art-directable motifs
  • Provides lighting data for objects (diffuse ambient + reflection color)

The system is designed around these hard constraints:

ConstraintValue
Config size128 bytes per environment state
Layer count8 sequential instructions
Instruction size128 bits (two u64 values)
CubemapsNone (fully procedural octahedral maps)
MipmapsYes (compute-generated downsample pyramid)
Color modelDirect RGB24 x 2 per layer
AestheticPS1/PS2-era stylized, quantized params

System Diagram

CPU (game)                                         GPU
---------                                         ---
Call epu_set(...), epu_textures(...), or epu_asset(...)   --->   [Compute] EPU_Build(configs/imports)
Call draw_epu() to request a background draw            - Evaluate 8-layer microprogram into EnvRadiance (mip 0)
Capture (viewport, pass) draw requests                  - Generate mip pyramid from EnvRadiance mip 0
                                                    - Extract SH9 from a coarse mip (e.g. 16x16)

Main render (background + objects)          --->   [Render] Sample prebuilt results
                                                  - Background: EPU environment draw per viewport/pass
                                                  - Specular:   EnvRadiance sampled by roughness (LOD)
                                                  - Diffuse:    SH9 evaluated at the shading normal

Radiance Flow

The EPU produces a single directional radiance signal per environment (EnvRadiance, mip 0). From that radiance, the runtime builds a downsample mip pyramid used for continuous roughness-based reflections, and extracts SH9 coefficients for diffuse ambient.


Data Model

PackedEnvironmentState (128 bytes)

Each environment is exactly 8 x 128-bit instructions:

SlotsKindRecommended Use
0-7MixedAuthor layers in the order you want them evaluated. Bounds rewrite RegionWeights; later feature layers consume the current regions. A common cadence is BOUNDS -> FEATURES -> BOUNDS -> FEATURES.

Implementation note: in the shaders, bounds opcodes return (sample, regions). Dispatch updates regions after every bounds layer, and feature layers apply region masking using the current regions.

Instruction Bit Layout (128-bit)

Each instruction is packed as two u64 values:

High word (bits 127..64):

bits 127..123: opcode     (5)  - 32 opcodes available
bits 122..120: region     (3)  - Bitfield: SKY=0b100, WALLS=0b010, FLOOR=0b001
bits 119..117: blend      (3)  - 8 blend modes
bits 116..112: meta5      (5)  - (domain_id<<3)|variant_id; use 0 when unused
bits 111..88:  color_a    (24) - RGB24 primary color
bits 87..64:   color_b    (24) - RGB24 secondary color

Low word (bits 63..0):

bits 63..56:   intensity  (8)  - Layer brightness
bits 55..48:   param_a    (8)  - Opcode-specific
bits 47..40:   param_b    (8)  - Opcode-specific
bits 39..32:   param_c    (8)  - Opcode-specific
bits 31..24:   param_d    (8)  - Opcode-specific
bits 23..8:    direction  (16) - Octahedral-encoded direction (u8,u8)
bits 7..4:     alpha_a    (4)  - color_a alpha (0-15)
bits 3..0:     alpha_b    (4)  - color_b alpha (0-15)

Opcodes

OpcodeNameKindPurpose
0x00NOPAnyDisable layer
0x01RAMPBoundsBounds gradient (sky/walls/floor)
0x02SECTORBoundsAzimuthal opening wedge modifier
0x03SILHOUETTEBoundsSkyline/horizon cutout modifier
0x04SPLITBoundsGeometric divisions
0x05CELLBoundsVoronoi/mosaic cells
0x06PATCHESBoundsNoise patches
0x07APERTUREBoundsShaped opening/viewport
0x08DECALFeatureSharp SDF shape (disk/ring/rect/line)
0x09GRIDFeatureRepeating lines/panels
0x0ASCATTERFeaturePoint field (stars/dust/bubbles)
0x0BFLOWFeatureAnimated noise/streaks/caustics
0x0CTRACEFeatureLine/crack patterns
0x0DVEILFeatureCurtain/ribbon effects
0x0EATMOSPHEREFeatureAtmospheric absorption + scattering
0x0FPLANEFeatureGround/surface textures
0x10CELESTIALFeatureMoon/sun/planet bodies
0x11PORTALFeaturePortal/vortex effects
0x12LOBEFeatureRegion-masked directional glow
0x13BANDFeatureRegion-masked horizon band

Blend Modes (8 modes)

ValueNameFormula
0ADDdst + src * a
1MULTIPLYdst * mix(1, src, a)
2MAXmax(dst, src * a)
3LERPmix(dst, src, a)
4SCREEN1 - (1-dst)*(1-src*a)
5HSV_MODHSV shift dst by src
6MINmin(dst, src * a)
7OVERLAYPhotoshop-style overlay

Compute Pipeline

Implementation note: Internally, the runtime still stores outputs in array slots, but those slots are private implementation detail. Games use immediate-mode EPU setters (epu_set(...), epu_textures(...), epu_asset(...)), and each draw captures whichever EPU source is current at that moment.

The EPU runtime maintains these outputs per internal slot:

OutputTypePurpose
EnvRadiance[slot]mip-mapped octahedral 2D arrayBackground + roughness-based reflections
SH9[slot]storage bufferL2 diffuse irradiance (spherical harmonics)

Frame Execution Order

  1. Capture EPU draw requests (per viewport/pass) and determine active immediate-mode EPU sources
  2. Resolve those sources to internal slots, cap to MAX_ACTIVE_ENVS
  3. Determine which internal slots are dirty (hash or imported-face cache miss)
  4. Dispatch compute passes:
    • Environment evaluation (build EnvRadiance mip 0)
    • Imported cube-face conversion when needed
    • Mip pyramid generation (2x2 downsample chain)
    • Irradiance extraction (SH9)
  5. Barrier: compute to render
  6. Render background + objects (sampling by resolved internal slot)

Render Integration

Background Sampling

Procedural EPU sources render the background by evaluating the EPU directly per pixel (L_hi(dir)), not by sampling EnvRadiance. This guarantees the sky is never limited by the EnvRadiance base resolution.

Imported face-texture sources render the background from EnvRadiance mip 0 after cube-to-octahedral conversion.

Reflection Sampling

Sample EnvRadiance with a continuous roughness-to-LOD mapping across mip levels. A common mapping is:

  • lod = (roughness^2) * (mip_count - 1)

Then sample at that LOD (trilinear) or lerp between floor(lod) and ceil(lod).

To avoid hard cutoffs while still preserving mirror-quality reflections, add a high-frequency residual term that fades out with roughness:

  • alpha = roughness^2
  • L_spec = L_lp + (1 - alpha) * (L_hi - L0)
    • L_hi is procedural EPU evaluation at the reflection direction
    • L0 is EnvRadiance sampled at mip 0
    • L_lp is EnvRadiance sampled at the roughness-derived LOD

Imported face-texture sources skip the procedural residual and use only the octahedral mip chain.

Ambient Lighting

Diffuse ambient is evaluated from SH9 coefficients at the shading normal n.


Multiple Environments

The EPU supports multiple environments per frame through internal texture-array slot indexing:

  • All outputs are stored in array layers indexed by an internal resolved slot
  • Renderers pass that resolved slot per draw/instance (internal)
  • No per-draw rebinding required
ConstantTypical Value
MAX_ENV_STATES256
MAX_ACTIVE_ENVS32
EPU_MAP_SIZE128 (default; override via NETHERCORE_EPU_MAP_SIZE)
EPU_MIN_MIP_SIZE4 (default; override via NETHERCORE_EPU_MIN_MIP_SIZE)
EPU_IRRAD_TARGET_SIZE16

Dirty-State Caching

For environments, the EPU tracks:

  • state_hash: Hash of the 128-byte procedural config
  • valid: Whether the cached entry has been initialized
  • imported-face cache entries keyed by face-handle tuple or asset ID

Update policy:

ConditionAction
Unused this frameSkip
Used + unchangedSkip
Used + changedRebuild, then update state_hash

Format Summary

AspectValue
Instruction size128-bit
Environment size128 bytes
Opcode bits5-bit (32 opcodes)
Region3-bit mask (combinable)
Blend modes8 modes
ColorRGB24 × 2 per layer
EmissiveReserved (future use)
Alpha4-bit × 2 (per-color)
Parameters4 (+param_d)

Full Specification

For complete details including:

  • WGSL shader implementations
  • Per-opcode parameter tables
  • Example configurations
  • Performance considerations

See: