Vienna-WebGPU-Engine

Rendering Architecture Notes (CPU → GPU → Render)

This document consolidates the current and intended rendering architecture, clarifying responsibilities, data flow, and lifecycle across Scene Nodes, CPU render data, GPU render objects, and the render cycle.

It reflects:


0. Path Management

Two Path Systems

Application Assets (basePath): Example-specific assets

Build Location Set By  
Debug Example source directory ASSETS_ROOT_DIR CMake define <example_dir>/assets/ (source)
Release Executable dir getExecutablePath() at runtime <exe>/assets/ (deployed)

2. Engine Library Resource Paths (resourceRoot)

Build resourceRoot Value Determined By Engine Resources Location
Debug Project root + /resources/ DEBUG_ROOT_DIR + /resources/ <project>/resources/ (source)
Release Library dir + /resources/ getEnginePath() + /resources/ <lib>/resources/ (deployed)

Usage:

// Application assets
auto appTexture = PathProvider::getTextures("brick.png");

// Engine resources
auto engineShader = PathProvider::getResource("PBR_Lit_Shader.wgsl");

Key Rules:

0.2 Build Output Locations

Project Root/
├── build/
│   └── Windows/
│       ├── Debug/          # Engine library + dependencies
│       └── Release/
├── examples/
│   └── build/
│       └── <example_name>/
│           └── Windows/
│               ├── Debug/  # Example executable + copied assets
│               └── Release/
└── resources/              # Source assets (Debug builds access directly)

Key Points:


1. Core Design Principles

1.1 Single Responsibility

Each layer has a strict responsibility:

Layer Responsibility
Scene Nodes Visibility, transforms, scene logic
CPU Render Data Geometry, materials, submesh layout
GPU Render Objects GPU buffers, bind groups, pipelines
RenderItem One draw call
Renderer Sorting, batching, issuing draws

No layer reaches “up” or sideways.


2. CPU-Side Data Model

2.1 Mesh (CPU)

Indented example:

Mesh
 ├─ vertices[]
 └─ indices[]

2.2 Submesh (CPU)

Indented example:

struct Submesh
{
    uint32_t indexOffset;
    uint32_t indexCount;
    MaterialHandle material;
};

2.3 Model (CPU)

Indented example:

Model
 ├─ MeshHandle
 └─ Submesh[]

2.4 ObjLoader Output (ObjGeometryData)

ObjLoader does not create materials or GPU objects.

It outputs:

Indented example:

ObjGeometryData
{
    vertices
    indices
    materials          // tinyobj materials
    materialRanges[]   // offset + count + materialId
}

This avoids:


3. GPU-Side Objects

3.1 WebGPUMesh

Indented example:

WebGPUMesh
 ├─ vertexBuffer
 ├─ indexBuffer
 └─ updateGPUResources()

Submeshes do not become separate GPU meshes.

3.2 WebGPUMaterial

Indented example:

WebGPUMaterial
 ├─ shaderType OR customShaderName
 ├─ textures[]
 ├─ bindGroup
 └─ updateGPUResources()

Shader lookup happens via:

context.shaderRegistry()

3.3 ShaderRegistry

Materials store identifiers, not shader objects.


4. RenderItem


5. Scene Nodes

5.1 RenderNode

5.2 Example ModelNode


6. Render Cycle

  1. PreRender
    • Setup state, transform matrices
  2. RenderCollect
    • Nodes push CPU objects
    • GPU objects created / cached lazily
    • RenderItems collected for batching / sorting
  3. Sort & Batch
    • Sort by:
      • Shader / pipeline
      • Material
      • Depth (optional)
    • Minimize pipeline / bind group switches
  4. Draw
    • Iterate RenderItems
    • Bind shader / material
    • Draw mesh / submesh range
  5. PostRender
    • Cleanup (optional)

7. GPU Resource Update Logic