Vixen
02b45cc4
csharp
public sealed class ForwardLightingRenderFeature

Which lights reach each object, and getting that list to the shader.

No guide page documents this yet — the page shows what the code says about itself.

Remarks

Stride's ForwardLightingRenderFeature model, which docs/plan/06 names as the forward path's per-object light list and as the fallback the clustered path degrades to where compute is absent. A fragment iterates the lights its object was given rather than every light in the scene, which is what makes a scene with two hundred lights cost what a scene with eight does.

Lights are selected against objects, never against the view frustum. That looks like a missed optimisation and is a correctness requirement: a lamp behind the camera lights everything in front of it, so culling lights by the frustum would darken exactly the objects that are on screen. The frustum has already done its work — the objects considered here are the ones that survived it.

One buffer, one descriptor, a per-draw offset. Every object's block lives in one uniform buffer and is reached through DynamicUniformBuffer, so a thousand objects cost a thousand offsets rather than a thousand descriptor sets. Allocating a set per draw is the single most common reason a Vulkan renderer ends up slower than the D3D11 one it replaced.

One set per frame, from a DescriptorAllocator, not one set for ever. The buffer is recreated when the scene outgrows it, and a set held across frames would have to be rewritten to point at the new one — which is a write to a set the frames still in flight are reading, and drivers execute that without a word. The ring is exactly FramesInFlight deep, so the set this frame writes is one no frame still in flight can be reading. The buffer needs no such care: IGraphicsDevice defers every destruction until the frames that could reference the handle have retired, which descriptor writes have no equivalent of.

The directional light is not in the list. It has no position to test against an object, so it reaches everything, and paying list traversal for something present in every list is paying for nothing — ForwardPlus.rvn takes it as its own uniform for the same reason. Sun is what a per-frame binder reads.

Fields and properties (33)

  • public const int HeaderSize

    How many bytes precede the light array in the block.

  • public const int ProbeIndexOffset

    Where the chosen probe's index sits in the header.

  • public const int ProbeWeightOffset

    Where the chosen probe's weight sits in the header.

  • public override string Name

    The sub-feature's name, for logging and profiling.

  • public RenderDataKey<LightAssignment> Assignments

    Where each object's block starts, and how many lights it holds.

  • public IList<RenderLight> Lights

    The scene's lights. Filled by whatever extracts them.

  • public int MaxLightsPerObject

    How many lights one object's block has room for.

  • public int OffsetAlignment

    What a dynamic uniform offset must be a multiple of.

  • public IGraphicsDevice? Device

    The device the light buffer lives on. Set before the first frame that prepares.

  • public bool Clustered

    Whether the scene's lights are culled into a cluster grid instead of into per-object lists.

  • public BufferHandle SceneBuffer

    Every light in the scene, as the culling pass reads them.

  • public int SceneLightCount

    How many lights the scene buffer holds this frame.

  • public int SceneLightBase

    Which entry of SceneBuffer this frame's lights start at.

  • public ParameterCollection? Scene

    Where to publish the scene's light buffer, or null to publish it nowhere.

  • public string ShaderName

    Which pass's names to publish under.

  • public IReadOnlyList<PermutationKey<bool>> PermutationKeys
  • public bool UseRecords

    Whether this frame's per-object scalars go into a buffer rather than into a bound block.

  • public BufferHandle RecordBuffer

    The buffer the per-object records live in, for a host binding it once a frame.

  • public int RecordBase

    Which record this frame's objects start at.

  • public ReadOnlySpan<ObjectRecord> Records

    What was written this frame, for a test or an inspector.

  • public DescriptorSetSlot Slot

    Which descriptor set the block is bound to.

  • public ReflectionProbeSelector? Probes

    Which reflection probe each object gets, or null to leave every object without one.

  • public uint Binding

    Which binding within that set.

  • public ShaderStage Stages

    Which stages read the light list.

  • public RenderLight? Sun

    The brightest directional light, or null when the scene has none.

  • public BufferHandle Buffer

    The buffer every object's block lives in.

  • public DescriptorSetHandle Descriptors

    This frame's set, valid from the moment Prepare has run.

  • public bool IsRecording
  • public DescriptorSetLayoutHandle Layout

    The layout its set is made from — the pass's own, taken from the effect.

  • public MaterialRenderFeature? Materials

    Where an unset Layout is taken from, once a shader has resolved.

  • public int SetCount

    How many sets the ring has had to create, which settles at frames-in-flight.

  • public int BlockStride

    How many bytes one object's block occupies, alignment included.

  • public int UsedBytes

    How many bytes of the buffer this frame filled.

Methods (9)

  • public ForwardLightingRenderFeature()

    Creates the feature, interning its permutation key.

  • public bool ValueOf(RenderSystem system, RenderObjectId id, int index)

    This sub-feature's value for one object and one of its keys.

  • public bool EnableRecords(PermutationKey<bool> shaderKey, bool addressable)

    Turns the per-object record path on, where the draw can address a record at all.

  • public ReadOnlySpan<byte> Block(RenderSystem system, RenderObjectId id)

    The bytes written for one object, for a test or an inspector.

  • public IEnumerable<PunctualLightData> LightsFor(RenderSystem system, RenderObjectId id)

    The lights one object was given, brightest first.

  • protected internal override void Initialize(RenderSystem system)

    Registers this sub-feature's per-object data. Called once.

  • protected internal override void Prepare(RenderSystem system)
  • public void Draw(RenderSystem system, RenderDrawContext context, in RenderNode node)

    Records this sub-feature's contribution for one node.

  • public void Dispose()

    Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.

Used by (23)

  • ArenaThirdPersonShooter
  • ClusteredLightingTestsVixen.Rendering.Tests
  • ClusteredShadingDeviceTestsVixen.Graphics.Golden.Tests
  • CompositorBuilderVixen.Rendering
  • DrawCompactionTestsVixen.Rendering.Tests
  • ForwardFrameTestsVixen.Rendering.Tests
  • ForwardLightingTestsVixen.Rendering.Tests
  • ForwardPlusLayoutTestsVixen.Rendering.Tests
  • FrameVixen.Rendering.Tests
  • GpuDrivenCompositorTestsVixen.Rendering.Tests
  • HarnessVixen.Rendering.Tests
  • HarnessVixen.Rendering.Tests
  • HarnessVixen.Rendering.Tests
  • HarnessVixen.Rendering.Tests
  • HarnessVixen.Rendering.Tests
  • IrradianceBounceDeviceTestsVixen.Graphics.Golden.Tests
  • IrradianceShadingDeviceTestsVixen.Graphics.Golden.Tests
  • LightExtractionSystemVixen.Rendering
  • LightExtractionTestsVixen.Rendering.Tests
  • MaterialRecordBufferTestsVixen.Rendering.Tests
  • ObjectRecordTestsVixen.Rendering.Tests
  • SceneLightingTestsVixen.Rendering.Tests
  • WorldRendererVixen.Engine.Renderer