Renderer Module


date: 2026-05-30 tags:

  • d_Rendering
  • d_Module cssclasses:
  • Aurora.css Status: Current Linker:
  • VULKAN” System:
  • VULKAN” Class:
  • Renderer Module” Parent Class: Interfaces: Used by:
  • VULKAN” Type:
  • Public
  • Abstract Attributes: Namespace: ArctisAurora.EngineWork.Rendering.Modules SourceFile: AuroraEngine/Core/Rendering/Modules/RenderingModule.cs VerifiedAgainst: 2026-07-28

Description

The abstract base for a render module — a self-contained mini-renderer with its own queue, pipeline, descriptors, and an offscreen output image. Modules render into their own target; the compositor then samples and blends every module’s output into the swapchain. This is how the VULKAN renderer keeps game/UI/post passes independent and composes them at the end.

A concrete module (e.g. UI Rasterizer Module) supplies its feature set, descriptor layout, pipeline, and draw commands by overriding the abstract members below.

Modules use dynamic rendering (Vulkan 1.3 core), so there is no VkRenderPass and no VkFramebuffer anywhere in the module surface. A module names its attachment format at pipeline creation via PipelineRenderingCreateInfo, hands the image view straight to CmdBeginRendering when recording, and issues its own layout transitions with ImageBarrier on both sides of the rendering instance.

API summary

MemberKindSummary
rendererType / RendererStageabstract propModule identity (Game / UI / PostProcessing).
features / features12abstract propPhysical-device + Vulkan 1.2 features this module needs; the renderer ORs them together when creating the logical device.
descriptorTypes / shaderStages / descriptorBindingFlags / descriptorMaxCountsabstract propDeclarative descriptor-set layout description.
PrepareObjects()abstractAllocate command pool/queue, build mesh component, hook entity groups.
CreatePipeline()abstractBuild the module’s graphics pipeline, declaring its attachment formats in PipelineRenderingCreateInfo.
outputFormatconstThe offscreen colour format. Shared by the images and the pipeline’s format declaration so the two cannot drift apart.
CreateOutputImages()virtualAllocate the offscreen colour targets (outputFormat, SampledBit).
ImageBarrier(...)staticThe layout transition a render pass used to imply. Called either side of CmdBeginRendering/CmdEndRendering.
UpdateModule(frame)abstractPer-frame rebuild (descriptors, instance buffers) when dirty.
WriteCommandBuffers(frame)abstractRecord the draw commands.
DestroySizeDependentResources()virtualTear down output images on window resize (see VULKAN → swapchain recreation).

Fields & Properties

internal Pipeline pipeline;
internal PipelineLayout pipelineLayout;

public CommandPool moduleCommandPool;
internal CommandBuffer[] commandBuffers;
public bool[] isDirty = { true, true, true };   // per swapchain image

// offscreen render target (sampled by the compositor)
internal const Format outputFormat = Format.R8G8B8A8Unorm;
public Image[] outputImages;
public ImageView[] outputImageViews;
public DeviceMemory[] imageDeviceMemory;
public int compositorOrder = 0;                 // blend order in the compositor

internal AuroraCamera camera;
internal FrameResources[] frameResources;       // descriptor pool + sets, one per frame

Methods

Lifecycle (driven by the renderer)

The renderer calls these in order during bootstrap: PrepareObjects → CreateOutputImages → CreatePipeline. Each frame, if the module’s isDirty[image] is set or HasPendingWork(image) reports work the module found by polling, the renderer calls UpdateModule, which re-records via WriteCommandBuffers.

Descriptors

CreateDescriptorSetLayout (virtual) builds the layouts from the declarative descriptorTypes / shaderStages / descriptorBindingFlags arrays; AllocateDescriptorSets handles the variable-count last binding (bindless arrays). Concrete modules fill them in UpdateDescriptorSets.

Resize

DestroySizeDependentResources (null-safe) drops the output images so the renderer can recreate them at the new size; pipelines use dynamic viewport/scissor so they are not rebuilt. Under dynamic rendering there are no framebuffers to rebuild either, so a resize only touches images and the compositor’s descriptors.

Layout transitions

A render pass used to do these for free: its attachment initial/final layouts moved the image in and out, and its subpass dependencies supplied the barrier around it. CmdBeginRendering does none of that, so each module issues the transitions itself via ImageBarrier — one before CmdBeginRendering to reach ColorAttachmentOptimal, one after CmdEndRendering to reach whatever the consumer needs (ShaderReadOnlyOptimal for a module the compositor samples, PresentSrcKhr for the compositor itself).

Helpers

internal static void ImageBarrier(CommandBuffer commandBuffer, Image image,
    ImageLayout oldLayout, ImageLayout newLayout,
    PipelineStageFlags srcStage, PipelineStageFlags dstStage,
    AccessFlags srcAccess, AccessFlags dstAccess);
internal static ShaderModule CreateShaderModule(ref Vk vk, ref Device logicalDevice, byte[] code);
internal static byte[] ReadFile(string fileName);