A custom rendering engine built in C++ using Vulkan as Graphics API, designed and focused on modern GPU-driven rendering techniques.

Architecture

Architecture
  • MgxEngine
    • Creates GLFW window
    • Updates input
    • Invokes Tick callback
    • Calls render
  • MgxRenderer
    • Creates Vulkan instance
    • Creates swapchain
    • Creates and submits command buffers
    • Declare render passes
    • Presents to swapchain
  • MgxRenderGraph
    • Manages passes
    • Manages resource transitions
    • Records command buffer
      • Draw
      • Dispatch
      • Copy/Fill
      • Bind
      • PushConstants
  • MgxDescriptorManager
    • Creates descriptor pools
    • Creates descriptor layouts
    • Allocates descriptor sets
    • Writes descriptor sets
    • Binds descriptor sets
  • MgxScene
    • Manages entities
    • Manages systems (particles, boids)
    • Uploads changed data to staging buffers
    • Sort batches for optimized drawing
  • MgxInput
    • Key values
    • Axis values
    • Bind actions
  • MgxMath
    • Unity-like design (Vector4, Quaternion, Matrix4x4, etc)
    • Matrix multiplications optimized with SSE
    • SimplexNoise

Frame Lifecycle

Frame Lifecycle
  • Poll windows events
    • Process GLFW window events.
    • MgxInput => Record pressed keys and mouse scroll value.
  • Update input
    • MgxInput => Update axis values and call input events.
  • Tick
    • Invoke Tick callback.
    • The app updates the scene (spawn entities, update camera, etc).
  • Acquire swapchain image
    • Acquire next swapchain image to draw on it (currently using double buffering with Mailbox/FIFO present modes).
  • Compile RenderGraph
    • Check resource usage on each pass and subpasses.
    • Create image and buffer memory barriers to sync read/write accesses to these resources.
    • Determines when color and depth attachments need to be cleared.
  • Execute RenderGraph
    • Records CommandBuffer.
    • Insert memory barriers generated by compilation.
    • Executes each pass (check Pipeline section).
  • Submit CommandBuffer
    • Submit recorded command buffer to queue.
  • Present
    • Present to current swapchain image.

Pipeline

  • Initialize Buffers => Initialize buffers to zero.
  • Bake Skybox => Sample HDR skybox texture and creates skybox cubemap.
  • Bake Irradiance => Samples skybox cubemap and generates irradiance cubemap.
  • Bake Prefiltered => Samples skybox cubemap and generates prefiltered cubemap (one mip per roughness level).
  • Bake BRDF LUT => Compute BRDF LUT texture to be used in PBR shader.
  • Copy Buffers => Copy data changes from staging buffers to GPU local buffers.
  • Reset Counters => Reset instance count on each draw command in DrawCommandBuffer.
  • Spawn => Spawn new instances by writing Instance Buffer (only particles for now).
  • Kinematics => Transform (move, rotate, scale) instances accordingly (kinematic, particles and boids).
  • Frustum Culling => Test camera frustum against instance bounds (static instances only) and writes instance count per batch.
  • Prefix Scan => Using instance count calculates first instance (offset) on each batch.
  • Compaction => Writes visible instances buffer.
  • Depth Only => Renders depth using indirect drawing.
  • Hi-Z Copy => Copy depth attachment to Hi-Z texture.
  • Hi-Z Downsample => Down sample Hi-Z texture from high to low mip levels.
  • Reset Counters => Reset instance count on each draw command in DrawCommandBuffer.
  • Frustum Culling => Test camera frustum against instance bounds and writes instance count per batch.
  • Occlusion Culling => Test object depth against Hi-Z texture sampled depth to cull occluded instances.
  • Prefix Scan => Using instance count calculates first instance (offset) on each batch.
  • Compaction => Writes visible instances buffer.
  • Shadow => Renders depth from light perspective using indirect drawing (not used for now).
  • Forward => Renders visible instances using indirect drawing and material batching.
  • Skybox => Renders skybox behind.
  • Bloom Bright => Extracts brightness from rendered image and writes to bloom texture.
  • Bloom Downsample => Downsamples the bloom texture from high to low mip levels.
  • Bloom Upsample => Upsamples the bloom texture from low to high mip levels.
  • Post Process => Applies bloom and tone mapping to rendered image.

Demo: Kinematics + Particles

6,000 spheres leaving a trace of particles (around 60,000 particles in total).

Demo: Flocking

10,000 paper planes flocking

RenderDoc Frame Captures

Instance and Boid Buffers

Instance count after culling

Indirect drawing color output

Indirect drawing depth output

Bloom texture