Vixen
02b45cc4
csharp
public sealed class GeometryBuffer

Many meshes in one vertex buffer and one index buffer, each at its own offset.

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

Remarks

The other half of the sentence docs/plan/23-bindless-materials.md opens with. MeshRenderFeature binds "a vertex buffer, an index buffer and a material set per object", and a draw that binds anything per object cannot be merged with its neighbour. Records removed the third; this removes the first two. A run of objects whose geometry came from one of these binds nothing between them, so what separates two draws is the numbers in their arguments — which is exactly what an indirect buffer holds.

One buffer per vertex layout, and it has to be. A draw's vertexOffset is a vertex count that the GPU multiplies by the pipeline's stride. Two meshes of different formats in one buffer would be read at each other's stride, so the format is a property of the buffer rather than of the mesh in it — which is the same reason VertexLayout is part of PipelineKey.

⚠ Fixed capacity, and dropped rather than grown. Growing means a larger buffer, a copy recorded on some command list, and new handles — and the handles are the problem: every MeshDraw already built holds the old ones, so a grow would have to find and rewrite all of them or leave draws pointing at a destroyed buffer. A caller that needs more space makes a second buffer, which costs one bind between the two runs and nothing within either. Same trade MeshRenderer makes, for a related reason.

Device-local, so writing means staging. The whole point is geometry that does not cross the bus every frame, which rules out host-visible memory. So Write fills a staging region and Flush records the copies — two calls because they happen at different times: a level loads over many frames and the copies belong at one known point in one command list.

Fields and properties (13)

  • public BufferHandle Vertices

    The one vertex buffer every mesh in here is drawn from.

  • public BufferHandle Indices

    The one index buffer.

  • public int VertexStride

    How many bytes one vertex occupies.

  • public int IndexStride

    How many bytes one index occupies.

  • public IndexFormat IndexFormat

    Whether indices are 16- or 32-bit.

  • public int VertexCapacity

    How many vertices fit.

  • public int IndexCapacity

    How many indices fit.

  • public int UsedVertices

    How many vertices are allocated.

  • public int UsedIndices

    How many indices are allocated.

  • public int SliceCount

    How many slices are outstanding.

  • public int VertexFragmentCount

    How many free ranges the vertex space is in, which is what fragmentation looks like.

  • public long PendingBytes

    How many bytes are staged and not yet copied.

  • public long StagingCapacity

    How many bytes the staging region can hold before it has to be flushed.

Methods (9)

  • public GeometryBuffer(IGraphicsDevice device, int vertexStride, int vertexCapacity, int indexCapacity, IndexFormat indexFormat = UInt32, string name = "Geometry")

    Creates the pair of buffers and the staging region that fills them.

  • public bool CanStage(long bytes)

    Whether a write of this size can be staged without flushing first.

  • public bool Reserve(long bytes)

    Asks for the staging region to be at least this big, if nothing is using it.

  • public bool TryAllocate(int vertexCount, int indexCount, out GeometrySlice slice)

    Finds room for one mesh, or answers that there is none.

  • public void Free(in GeometrySlice slice)

    Gives one mesh's space back.

  • public void Write(in GeometrySlice slice, ReadOnlySpan<byte> vertices, ReadOnlySpan<byte> indices)

    Stages one mesh's bytes, to be copied by the next Flush.

  • public int Flush(ICommandList list)

    Records the copies everything staged since the last flush needs.

  • public void Apply(ref MeshDraw draw, in GeometrySlice slice, int vertexLayout = 0)

    Fills a draw record from a slice, leaving everything else alone.

  • public void Dispose()

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

Used by (11)

  • ArenaThirdPersonShooter
  • BindlessFrameTestsVixen.Rendering.Tests
  • DrawCompactionTestsVixen.Rendering.Tests
  • GeometryBufferTestsVixen.Rendering.Tests
  • GeometryResidencyVixen.Rendering
  • HarnessVixen.Rendering.Tests
  • MeshExtractionSystemVixen.Rendering
  • MeshExtractionTestsVixen.Rendering.Tests
  • MeshInstanceRendererVixen.Rendering
  • VirtualGeometryExtractionTestsVixen.Rendering.Tests
  • WorldRendererVixen.Engine.Renderer