Repository navigation
Why the CPU and GPU share code
The CPU rasterizer and the GPU kernel call the same functions for the fill rule, texture wrapping, texel blending and light falloff. Two implementations of one rule drift. One implementation cannot.
| Module | Shared functions |
|---|---|
render/fillrule.mojo |
Snapping, the edge function, the top-left bias, the sample position. |
render/linerule.mojo |
Which pixel a one-pixel line lights in each column, and the dash fold. |
render/pointrule.mojo |
Whether a point covers a pixel, its coordinate there, its size with distance and its mip level. |
render/texture.mojo |
wrap_index, blend_texels, mix_color. |
lights/lighting.mojo |
falloff. |
Each allocates nothing, prints nothing and raises nothing. That is what lets it compile for a device.
The rasterizer writes pixels and the kernel writes device memory. The lighting sum has a host version, Lighting.intensity_at, and a device version, _arriving, because the kernel reads a flat float buffer. The parity tests hold those two to the same numbers.
Coverage is integer arithmetic. The two backends must agree exactly, and the tests demand it.
Shading is floating point. A GPU contracts a * b + c into a fused multiply-add that rounds once where the CPU rounds twice. A channel whose exact value lands on a quantization midpoint can fall either side. Tests that interpolate shading allow one level per channel, and say so. One level cannot hide a wrong color, a wrong depth or a wrong pixel.
A bug inside a shared function makes both sides wrong together. tests/test_fillrule.mojo pins the fill rule against values derived from the definitions, and it found exactly such a bug once. See Why coverage uses fixed point.
Renderer.prepare produces one List[RasterVertex]. rasterize_all and GpuRenderer.draw consume that same list. The whole-scene parity tests prepare once and fill twice, so they compare two rasterizers rather than two pipelines.
Tutorials
How-to
Reference
- Scene graph
- Rotations
- Cameras
- Geometry
- Geometry addons
- Lofts and clipping groups
- Sculptor
- Procedural generators
- Meshes and assets
- Lines
- Points and sprites
- Helpers
- Scene objects
- Animated objects
- Raycasting
- Curves and paths
- Animation
- Skinning
- Materials
- Node materials
- TSL functions
- Lights
- Lighting addons
- Fog
- Textures
- Renderer
- Renderer hooks and material flags
- Rasterization
- GPU backend
- Render target
- Post-processing
- GPU computation
- Compute nodes
- Progressive light map
- Gaussian splats
- Voxel global illumination
- SVG renderer
- Image files
- Image decode queue
- Model files
- More model files
- Exporters
- Scene JSON
- Windowing and controls
- Math
- Norm consumers
- Math addons
- Units
- Coverage tool
- Commands
- Examples
- Benchmarks
- Extensions
- Shared physics
- Physics query snapshots
- Continuous collision
- Tick force restoration
- Water
- Animals
- Buildings
- CARLA
- Femur
- Tibia
- Fibula
- Patella
- Knee
- Muscles
- Vessels
- Lymph
- Nerves
- Integument
- Leg
- Foot
- Pelvis
- Torso
- Arm
- Hand
- Head
- Genome
- Game humanoid
- Humanoid fidelity
- Audio-aligned game faces
- Converted assets
- Mesh quality
- Segment inertia
Explanation
- Software rasterizer
- Scene graph as an array
- Linear color
- Normals are not colors
- Perspective correction
- Fixed-point coverage
- Per-fragment shading
- Mipmaps
- Sorted transparency
- Types and checks
- Render hooks as a trait
- Shared CPU and GPU code
- Bands and threads
- PNG structure
- Extensions beside the port
- CUDA teardown hang
- Mojo compiler hang