Skip to content

Latest commit

 

History

20 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

Model Renderer: CPU vs GPU Software Rasterizer

A 3D software rasterizer implemented twice — once on the CPU with OpenMP, once on the GPU with CUDA — to directly compare performance across architectures.

The CPU version uses bounding box rasterization parallelized across 6 cores with OpenMP. The GPU version uses tile-based deferred rendering, binning triangles into 32x32 pixel tiles and assigning each tile to a CUDA block, giving 262,144 threads running simultaneously with the z-buffer kept in shared memory to avoid global memory round-trips.

Results

Tested on a 15,066 triangle model at 1024x1024 with toon, grayscale, and tangent-space normal map shaders. Hardware: RTX 5060 Ti, Ryzen 5 7600X.

Metric CPU GPU Speedup
Total render time 0.48s 0.11s 4.2x
Time per triangle 31.9 us 7.3 us 4.4x
Compute time ~470ms ~87us 5,402x
Memory transfer N/A ~722us N/A

The 5,402x compute speedup versus the 4.2x end-to-end speedup shows the workload is latency-bound at this model size — memory allocation dominates roughly 90% of CUDA API time. A larger model would push GPU utilisation above the 33% measured here.

Architecture

The CPU renderer calculates a bounding box per triangle and tests every pixel inside it for containment using barycentric coordinates, with OpenMP parallelising the outer loop. Memory access patterns are irregular which hurts cache efficiency.

The GPU renderer pre-sorts triangles into screen-space tiles before the kernel launches. Each CUDA block owns one tile and keeps its z-buffer in shared memory, eliminating cache misses on depth testing. Threads within a block process pixels in the tile in parallel.

Key differences:

  • 12 CPU threads vs 262,144 GPU threads
  • 50 GB/s CPU memory bandwidth vs 900 GB/s GPU
  • Barycentric coordinate testing (CPU) vs edge function testing (GPU)
  • Global memory z-buffer (CPU) vs shared memory z-buffer (GPU)

Build

CPU

cd cpu
mkdir build && cd build
cmake ..
make
./renderer ../obj/diablo3_pose/diablo3_pose.obj

GPU

cd cuda_gpu
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make
./renderer ../obj/diablo3_pose/diablo3_pose.obj

Profiling

CPU

perf record ./cpu_renderer
perf report

GPU

# System-level
nsys profile --output=gpu_profile ./renderer ../obj/diablo3_pose/diablo3_pose.obj

# Kernel-level
ncu --section ComputeWorkloadAnalysis \
    --section MemoryWorkloadAnalysis \
    --section SpeedOfLight \
    --apply-rules yes \
    --export gpu_kernel_profile \
    ./renderer ../obj/diablo3_pose/diablo3_pose.obj

Future work

  • Persistent kernels and better memory coalescing on the GPU
  • SIMD intrinsics and cache-aware data layouts on the CPU
  • Larger scene to saturate GPU utilisation and measure scaling

Built with C++20, CUDA 13.1, OpenMP, and CMake.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages