Instruction file imported from XDzzzzzZyq/OpengL (
.github/instructions/renderer.instructions.md). Copyright stays with the author.
Renderer System
Overview
The Renderer is a pure rendering service that consumes immutable Scene data and produces rendered frames. It must remain stateless with respect to application logic.
Location
src/render/Renderer.h- Main renderer classsrc/render/RenderConfigs.h- Render settingssrc/render/buffer/- GPU buffer abstractionssrc/render/shaders/- Shader management
Core Responsibilities
-
Framebuffer Management
- Create and resize framebuffers dynamically
- Manage render targets for deferred rendering
- Handle viewport resolution changes
-
Scene Rendering
- Traverse Scene objects via Context
- Submit geometry to GPU
- Execute multi-pass rendering pipeline
- Apply post-processing effects
-
GPU Resource Ownership
- Create and destroy OpenGL objects
- Manage vertex buffers, index buffers, textures
- Handle shader compilation and linking
- Ensure deterministic cleanup
-
Lighting and Shading
- PBR material evaluation
- Multi-light rendering (point, sun, spot, area)
- IBL (Image-Based Lighting)
- Shadow mapping with soft shadows
Data Flow
Context (immutable Scene) → Renderer (RAII) → GPU → FrameBuffer
↑
RenderConfigs (settings)
Input:
Context- Provides read-only access to:- Active Camera (view/projection matrices)
- Active Environment (IBL textures)
- Scene objects (Mesh, Light, etc.)
RenderConfigs- User-configurable settings:- Resolution
- Anti-aliasing (FXAA)
- Ambient occlusion (SSAO)
- Shadow quality
- Exposure
Output:
- Rendered frame in
FrameBuffer - Accessible via
GetFrameBufferPtr()
Note: Renderer is constructed with a Window reference to guarantee a current GL context at construction time.
Key Methods
RAII Initialization (Constructor)
// New RAII constructor signature
Renderer(EventPool& evt, Window& w);
- Requirements:
- A
Window&is passed to guarantee a current GL context before resource creation. - In the constructor path, set
glewExperimental = GL_TRUEbeforeglewInit()as recommended. - Subscribes to necessary events as part of construction.
- Renderer is non-copyable:
Renderer(const Renderer&) = delete;
Renderer& operator=(const Renderer&) = delete;
// Example (conceptual)
Renderer(EventPool& evt, Window& w)
{
// must be called after window creation and context is current
glewExperimental = GL_TRUE; // recommended prior to glewInit()
glewInit();
// subscribe to events, allocate GPU resources, etc.
}
- Note: There is no separate
Init(EventPool&)phase; initialization occurs in construction, aligning with RAII semantics. - The destructor (~Renderer) will clean up GPU resources deterministically.
Rendering
void Render(const Context& ctx, bool rend = true, bool buff = true);
ctx- Immutable scene contextrend- Enable rasterization passbuff- Enable buffer outputs- Executes full rendering pipeline
Frame Management
void NewFrame();
- Clears buffers
- Resets per-frame state
- Prepares for next render
Utilities
void Reset(); // Reset renderer state
void ConstructSDF(const Context& ctx); // Build SDF for soft shadows
void ScreenShot(); // Save current frame to file
Architectural Boundaries
✅ Renderer MAY:
- Read Scene data via Context (const access)
- Subscribe to Events for configuration changes
- Own GPU resources (buffers, textures, shaders)
- Emit performance metrics or warnings
❌ Renderer MUST NOT:
- Mutate Scene objects
- Depend on Editor or UI layers
- Store application-level state
- Directly call UI or Editor functions
Current State and TODOs
The Renderer is undergoing a refactor to achieve true statelessness:
Legacy State (to be removed):
r_frame_width,r_frame_height→ Move to RenderContextr_render_result→ Managed externallyr_buffer_list→ Centralize buffer managementr_render_icons,r_is_preview→ Move to EditorContextr_light_data→ Should be computed on-demandr_config→ Already accessible via RenderContext
Target Architecture:
- Renderer receives all state via
Render(ctx, config) - No mutable state between frames
- Pure function:
(Context, Config) → FrameBuffer
GPU Resource Ownership
Buffer Types
- VertexBuffer - Vertex attribute data (positions, normals, UVs)
- IndexBuffer - Triangle indices
- UniformBuffer - Per-draw shader uniforms
- StorageBuffer - Large read/write data (lights, compute results)
- FrameBuffer - Render targets with color/depth attachments
- RenderBuffer - Non-texture attachments (depth/stencil)
Lifetime Management
- Resources created in the constructor and released in the destructor (RAII).
- No separate
Init()orReset()required for typical usage. - All GPU resources are owned and cleaned up by the Renderer instance.
Rendering Pipeline Stages
-
Geometry Pass (Deferred)
- G-Buffer output: positions, normals, albedo, metallic/roughness
- Depth buffer for occlusion
-
Lighting Pass
- Read G-Buffer
- Accumulate lighting from all sources
- Apply PBR BRDF
-
IBL Pass
- Sample environment maps
- Diffuse irradiance + specular reflections
-
Post-Processing
- SSAO (Screen-Space Ambient Occlusion)
- SSR (Screen-Space Reflections)
- Shadow composition
- Anti-aliasing (FXAA)
- Tone mapping (Filmic)
-
Composite to Final
- Combine all passes
- Gamma correction
- Output to viewport framebuffer
Performance Guidelines
- Minimize state changes (batch by material/shader)
- Use instancing for repeated geometry
- Cull objects outside frustum
- Lazy-update GPU buffers (only on change)
- Profile GPU time per pass
- Target 16ms frame budget (60 FPS)
Error Handling
- Check OpenGL errors after major operations
- Validate framebuffer completeness
- Log shader compilation failures
- Assert on precondition violations
- Graceful degradation on unsupported features