mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-03-24 11:00:17 +00:00
651 lines
25 KiB
C#
651 lines
25 KiB
C#
using Ryujinx.Common;
|
|
using Ryujinx.Graphics.GAL;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
|
{
|
|
/// <summary>
|
|
/// Vertex, tessellation and geometry as compute shader context.
|
|
/// </summary>
|
|
class VtgAsComputeContext : IDisposable
|
|
{
|
|
private const int DummyBufferSize = 16;
|
|
|
|
private readonly GpuContext _context;
|
|
|
|
/// <summary>
|
|
/// Cache of buffer textures used for vertex and index buffers.
|
|
/// </summary>
|
|
private class BufferTextureCache : IDisposable
|
|
{
|
|
private readonly Dictionary<Format, ITexture> _cache;
|
|
|
|
/// <summary>
|
|
/// Creates a new instance of the buffer texture cache.
|
|
/// </summary>
|
|
public BufferTextureCache()
|
|
{
|
|
_cache = new();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a cached or creates and caches a buffer texture with the specified format.
|
|
/// </summary>
|
|
/// <param name="renderer">Renderer where the texture will be used</param>
|
|
/// <param name="format">Format of the buffer texture</param>
|
|
/// <returns>Buffer texture</returns>
|
|
public ITexture Get(IRenderer renderer, Format format)
|
|
{
|
|
if (!_cache.TryGetValue(format, out ITexture bufferTexture))
|
|
{
|
|
bufferTexture = renderer.CreateTexture(new TextureCreateInfo(
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
format.GetBytesPerElement(),
|
|
format,
|
|
DepthStencilMode.Depth,
|
|
Target.TextureBuffer,
|
|
SwizzleComponent.Red,
|
|
SwizzleComponent.Green,
|
|
SwizzleComponent.Blue,
|
|
SwizzleComponent.Alpha));
|
|
|
|
_cache.Add(format, bufferTexture);
|
|
}
|
|
|
|
return bufferTexture;
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
foreach (var texture in _cache.Values)
|
|
{
|
|
texture.Release();
|
|
}
|
|
|
|
_cache.Clear();
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Buffer state.
|
|
/// </summary>
|
|
private struct Buffer
|
|
{
|
|
/// <summary>
|
|
/// Buffer handle.
|
|
/// </summary>
|
|
public BufferHandle Handle;
|
|
|
|
/// <summary>
|
|
/// Current free buffer offset.
|
|
/// </summary>
|
|
public int Offset;
|
|
|
|
/// <summary>
|
|
/// Total buffer size in bytes.
|
|
/// </summary>
|
|
public int Size;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Index buffer state.
|
|
/// </summary>
|
|
private readonly struct IndexBuffer
|
|
{
|
|
/// <summary>
|
|
/// Buffer handle.
|
|
/// </summary>
|
|
public BufferHandle Handle { get; }
|
|
|
|
/// <summary>
|
|
/// Index count.
|
|
/// </summary>
|
|
public int Count { get; }
|
|
|
|
/// <summary>
|
|
/// Size in bytes.
|
|
/// </summary>
|
|
public int Size { get; }
|
|
|
|
/// <summary>
|
|
/// Creates a new index buffer state.
|
|
/// </summary>
|
|
/// <param name="handle">Buffer handle</param>
|
|
/// <param name="count">Index count</param>
|
|
/// <param name="size">Size in bytes</param>
|
|
public IndexBuffer(BufferHandle handle, int count, int size)
|
|
{
|
|
Handle = handle;
|
|
Count = count;
|
|
Size = size;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a full range starting from the beggining of the buffer.
|
|
/// </summary>
|
|
/// <returns>Range</returns>
|
|
public readonly BufferRange ToRange()
|
|
{
|
|
return new BufferRange(Handle, 0, Size);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a range starting from the beggining of the buffer, with the specified size.
|
|
/// </summary>
|
|
/// <param name="size">Size in bytes of the range</param>
|
|
/// <returns>Range</returns>
|
|
public readonly BufferRange ToRange(int size)
|
|
{
|
|
return new BufferRange(Handle, 0, size);
|
|
}
|
|
}
|
|
|
|
private readonly BufferTextureCache[] _bufferTextures;
|
|
private BufferHandle _dummyBuffer;
|
|
private Buffer _vertexDataBuffer;
|
|
private Buffer _geometryVertexDataBuffer;
|
|
private Buffer _geometryIndexDataBuffer;
|
|
private BufferHandle _sequentialIndexBuffer;
|
|
private int _sequentialIndexBufferCount;
|
|
|
|
private readonly Dictionary<PrimitiveTopology, IndexBuffer> _topologyRemapBuffers;
|
|
|
|
/// <summary>
|
|
/// Vertex information buffer updater.
|
|
/// </summary>
|
|
public VertexInfoBufferUpdater VertexInfoBufferUpdater { get; }
|
|
|
|
/// <summary>
|
|
/// Creates a new instance of the vertex, tessellation and geometry as compute shader context.
|
|
/// </summary>
|
|
/// <param name="context"></param>
|
|
public VtgAsComputeContext(GpuContext context)
|
|
{
|
|
_context = context;
|
|
_bufferTextures = new BufferTextureCache[Constants.TotalVertexBuffers + 2];
|
|
_topologyRemapBuffers = new();
|
|
VertexInfoBufferUpdater = new(context.Renderer);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the number of complete primitives that can be formed with a given vertex count, for a given topology.
|
|
/// </summary>
|
|
/// <param name="primitiveType">Topology</param>
|
|
/// <param name="count">Vertex count</param>
|
|
/// <returns>Total of complete primitives</returns>
|
|
public static int GetPrimitivesCount(PrimitiveTopology primitiveType, int count)
|
|
{
|
|
return primitiveType switch
|
|
{
|
|
PrimitiveTopology.Lines => count / 2,
|
|
PrimitiveTopology.LinesAdjacency => count / 4,
|
|
PrimitiveTopology.LineLoop => count > 1 ? count : 0,
|
|
PrimitiveTopology.LineStrip => Math.Max(count - 1, 0),
|
|
PrimitiveTopology.LineStripAdjacency => Math.Max(count - 3, 0),
|
|
PrimitiveTopology.Triangles => count / 3,
|
|
PrimitiveTopology.TrianglesAdjacency => count / 6,
|
|
PrimitiveTopology.TriangleStrip or
|
|
PrimitiveTopology.TriangleFan or
|
|
PrimitiveTopology.Polygon => Math.Max(count - 2, 0),
|
|
PrimitiveTopology.TriangleStripAdjacency => Math.Max(count - 2, 0) / 2,
|
|
PrimitiveTopology.Quads => (count / 4) * 2, // In triangles.
|
|
PrimitiveTopology.QuadStrip => Math.Max((count - 2) / 2, 0) * 2, // In triangles.
|
|
_ => count,
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the total of vertices that a single primitive has, for the specified topology.
|
|
/// </summary>
|
|
/// <param name="primitiveType">Topology</param>
|
|
/// <returns>Vertex count</returns>
|
|
private static int GetVerticesPerPrimitive(PrimitiveTopology primitiveType)
|
|
{
|
|
return primitiveType switch
|
|
{
|
|
PrimitiveTopology.Lines or
|
|
PrimitiveTopology.LineLoop or
|
|
PrimitiveTopology.LineStrip => 2,
|
|
PrimitiveTopology.LinesAdjacency or
|
|
PrimitiveTopology.LineStripAdjacency => 4,
|
|
PrimitiveTopology.Triangles or
|
|
PrimitiveTopology.TriangleStrip or
|
|
PrimitiveTopology.TriangleFan or
|
|
PrimitiveTopology.Polygon => 3,
|
|
PrimitiveTopology.TrianglesAdjacency or
|
|
PrimitiveTopology.TriangleStripAdjacency => 6,
|
|
PrimitiveTopology.Quads or
|
|
PrimitiveTopology.QuadStrip => 3, // 2 triangles.
|
|
_ => 1,
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a cached or creates a new buffer that can be used to map linear indices to ones
|
|
/// of a specified topology, and build complete primitives.
|
|
/// </summary>
|
|
/// <param name="topology">Topology</param>
|
|
/// <param name="count">Number of input vertices that needs to be mapped using that buffer</param>
|
|
/// <returns>Remap buffer range</returns>
|
|
public BufferRange GetOrCreateTopologyRemapBuffer(PrimitiveTopology topology, int count)
|
|
{
|
|
if (!_topologyRemapBuffers.TryGetValue(topology, out IndexBuffer buffer) || buffer.Count < count)
|
|
{
|
|
if (buffer.Handle != BufferHandle.Null)
|
|
{
|
|
_context.Renderer.DeleteBuffer(buffer.Handle);
|
|
}
|
|
|
|
buffer = CreateTopologyRemapBuffer(topology, count);
|
|
_topologyRemapBuffers[topology] = buffer;
|
|
|
|
return buffer.ToRange();
|
|
}
|
|
|
|
return buffer.ToRange(Math.Max(GetPrimitivesCount(topology, count) * GetVerticesPerPrimitive(topology), 1) * sizeof(uint));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new topology remap buffer.
|
|
/// </summary>
|
|
/// <param name="topology">Topology</param>
|
|
/// <param name="count">Maximum of vertices that will be accessed</param>
|
|
/// <returns>Remap buffer range</returns>
|
|
private IndexBuffer CreateTopologyRemapBuffer(PrimitiveTopology topology, int count)
|
|
{
|
|
// Size can't be zero as creating zero sized buffers is invalid.
|
|
Span<int> data = new int[Math.Max(GetPrimitivesCount(topology, count) * GetVerticesPerPrimitive(topology), 1)];
|
|
|
|
switch (topology)
|
|
{
|
|
case PrimitiveTopology.Points:
|
|
case PrimitiveTopology.Lines:
|
|
case PrimitiveTopology.LinesAdjacency:
|
|
case PrimitiveTopology.Triangles:
|
|
case PrimitiveTopology.TrianglesAdjacency:
|
|
case PrimitiveTopology.Patches:
|
|
for (int index = 0; index < data.Length; index++)
|
|
{
|
|
data[index] = index;
|
|
}
|
|
break;
|
|
case PrimitiveTopology.LineLoop:
|
|
data[^1] = 0;
|
|
|
|
for (int index = 0; index < ((data.Length - 1) & ~1); index += 2)
|
|
{
|
|
data[index] = index >> 1;
|
|
data[index + 1] = (index >> 1) + 1;
|
|
}
|
|
break;
|
|
case PrimitiveTopology.LineStrip:
|
|
for (int index = 0; index < ((data.Length - 1) & ~1); index += 2)
|
|
{
|
|
data[index] = index >> 1;
|
|
data[index + 1] = (index >> 1) + 1;
|
|
}
|
|
break;
|
|
case PrimitiveTopology.TriangleStrip:
|
|
int tsTrianglesCount = data.Length / 3;
|
|
int tsOutIndex = 3;
|
|
|
|
if (tsTrianglesCount > 0)
|
|
{
|
|
data[0] = 0;
|
|
data[1] = 1;
|
|
data[2] = 2;
|
|
}
|
|
|
|
for (int tri = 1; tri < tsTrianglesCount; tri++)
|
|
{
|
|
int baseIndex = tri * 3;
|
|
|
|
if ((tri & 1) != 0)
|
|
{
|
|
data[baseIndex] = tsOutIndex - 1;
|
|
data[baseIndex + 1] = tsOutIndex - 2;
|
|
data[baseIndex + 2] = tsOutIndex++;
|
|
}
|
|
else
|
|
{
|
|
data[baseIndex] = tsOutIndex - 2;
|
|
data[baseIndex + 1] = tsOutIndex - 1;
|
|
data[baseIndex + 2] = tsOutIndex++;
|
|
}
|
|
}
|
|
break;
|
|
case PrimitiveTopology.TriangleFan:
|
|
case PrimitiveTopology.Polygon:
|
|
int tfTrianglesCount = data.Length / 3;
|
|
int tfOutIndex = 1;
|
|
|
|
for (int index = 0; index < tfTrianglesCount * 3; index += 3)
|
|
{
|
|
data[index] = 0;
|
|
data[index + 1] = tfOutIndex;
|
|
data[index + 2] = ++tfOutIndex;
|
|
}
|
|
break;
|
|
case PrimitiveTopology.Quads:
|
|
int qQuadsCount = data.Length / 6;
|
|
|
|
for (int quad = 0; quad < qQuadsCount; quad++)
|
|
{
|
|
int index = quad * 6;
|
|
int qIndex = quad * 4;
|
|
|
|
data[index] = qIndex;
|
|
data[index + 1] = qIndex + 1;
|
|
data[index + 2] = qIndex + 2;
|
|
data[index + 3] = qIndex;
|
|
data[index + 4] = qIndex + 2;
|
|
data[index + 5] = qIndex + 3;
|
|
}
|
|
break;
|
|
case PrimitiveTopology.QuadStrip:
|
|
int qsQuadsCount = data.Length / 6;
|
|
|
|
if (qsQuadsCount > 0)
|
|
{
|
|
data[0] = 0;
|
|
data[1] = 1;
|
|
data[2] = 2;
|
|
data[3] = 0;
|
|
data[4] = 2;
|
|
data[5] = 3;
|
|
}
|
|
|
|
for (int quad = 1; quad < qsQuadsCount; quad++)
|
|
{
|
|
int index = quad * 6;
|
|
int qIndex = quad * 2;
|
|
|
|
data[index] = qIndex + 1;
|
|
data[index + 1] = qIndex;
|
|
data[index + 2] = qIndex + 2;
|
|
data[index + 3] = qIndex + 1;
|
|
data[index + 4] = qIndex + 2;
|
|
data[index + 5] = qIndex + 3;
|
|
}
|
|
break;
|
|
case PrimitiveTopology.LineStripAdjacency:
|
|
for (int index = 0; index < ((data.Length - 3) & ~3); index += 4)
|
|
{
|
|
int lIndex = index >> 2;
|
|
|
|
data[index] = lIndex;
|
|
data[index + 1] = lIndex + 1;
|
|
data[index + 2] = lIndex + 2;
|
|
data[index + 3] = lIndex + 3;
|
|
}
|
|
break;
|
|
case PrimitiveTopology.TriangleStripAdjacency:
|
|
int tsaTrianglesCount = data.Length / 6;
|
|
int tsaOutIndex = 6;
|
|
|
|
if (tsaTrianglesCount > 0)
|
|
{
|
|
data[0] = 0;
|
|
data[1] = 1;
|
|
data[2] = 2;
|
|
data[3] = 3;
|
|
data[4] = 4;
|
|
data[5] = 5;
|
|
}
|
|
|
|
for (int tri = 1; tri < tsaTrianglesCount; tri++)
|
|
{
|
|
int baseIndex = tri * 6;
|
|
|
|
if ((tri & 1) != 0)
|
|
{
|
|
data[baseIndex] = tsaOutIndex - 2;
|
|
data[baseIndex + 1] = tsaOutIndex - 1;
|
|
data[baseIndex + 2] = tsaOutIndex - 4;
|
|
data[baseIndex + 3] = tsaOutIndex - 3;
|
|
data[baseIndex + 4] = tsaOutIndex++;
|
|
data[baseIndex + 5] = tsaOutIndex++;
|
|
}
|
|
else
|
|
{
|
|
data[baseIndex] = tsaOutIndex - 4;
|
|
data[baseIndex + 1] = tsaOutIndex - 3;
|
|
data[baseIndex + 2] = tsaOutIndex - 2;
|
|
data[baseIndex + 3] = tsaOutIndex - 1;
|
|
data[baseIndex + 4] = tsaOutIndex++;
|
|
data[baseIndex + 5] = tsaOutIndex++;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
ReadOnlySpan<byte> dataBytes = MemoryMarshal.Cast<int, byte>(data);
|
|
|
|
BufferHandle buffer = _context.Renderer.CreateBuffer(dataBytes.Length, BufferAccess.DeviceMemory);
|
|
_context.Renderer.SetBufferData(buffer, 0, dataBytes);
|
|
|
|
return new IndexBuffer(buffer, count, dataBytes.Length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a buffer texture with a given format, for the given index.
|
|
/// </summary>
|
|
/// <param name="index">Index of the buffer texture</param>
|
|
/// <param name="format">Format of the buffer texture</param>
|
|
/// <returns>Buffer texture</returns>
|
|
public ITexture EnsureBufferTexture(int index, Format format)
|
|
{
|
|
return (_bufferTextures[index] ??= new()).Get(_context.Renderer, format);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the offset and size of usable storage on the output vertex buffer.
|
|
/// </summary>
|
|
/// <param name="size">Size in bytes that will be used</param>
|
|
/// <returns>Usable offset and size on the buffer</returns>
|
|
public (int, int) GetVertexDataBuffer(int size)
|
|
{
|
|
return EnsureBuffer(ref _vertexDataBuffer, size);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the offset and size of usable storage on the output geometry shader vertex buffer.
|
|
/// </summary>
|
|
/// <param name="size">Size in bytes that will be used</param>
|
|
/// <returns>Usable offset and size on the buffer</returns>
|
|
public (int, int) GetGeometryVertexDataBuffer(int size)
|
|
{
|
|
return EnsureBuffer(ref _geometryVertexDataBuffer, size);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the offset and size of usable storage on the output geometry shader index buffer.
|
|
/// </summary>
|
|
/// <param name="size">Size in bytes that will be used</param>
|
|
/// <returns>Usable offset and size on the buffer</returns>
|
|
public (int, int) GetGeometryIndexDataBuffer(int size)
|
|
{
|
|
return EnsureBuffer(ref _geometryIndexDataBuffer, size);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a range of the output vertex buffer for binding.
|
|
/// </summary>
|
|
/// <param name="offset">Offset of the range</param>
|
|
/// <param name="size">Size of the range in bytes</param>
|
|
/// <param name="write">Indicates if the buffer contents will be modified</param>
|
|
/// <returns>Range</returns>
|
|
public BufferRange GetVertexDataBufferRange(int offset, int size, bool write)
|
|
{
|
|
return new BufferRange(_vertexDataBuffer.Handle, offset, size, write);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a range of the output geometry shader vertex buffer for binding.
|
|
/// </summary>
|
|
/// <param name="offset">Offset of the range</param>
|
|
/// <param name="size">Size of the range in bytes</param>
|
|
/// <param name="write">Indicates if the buffer contents will be modified</param>
|
|
/// <returns>Range</returns>
|
|
public BufferRange GetGeometryVertexDataBufferRange(int offset, int size, bool write)
|
|
{
|
|
return new BufferRange(_geometryVertexDataBuffer.Handle, offset, size, write);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a range of the output geometry shader index buffer for binding.
|
|
/// </summary>
|
|
/// <param name="offset">Offset of the range</param>
|
|
/// <param name="size">Size of the range in bytes</param>
|
|
/// <param name="write">Indicates if the buffer contents will be modified</param>
|
|
/// <returns>Range</returns>
|
|
public BufferRange GetGeometryIndexDataBufferRange(int offset, int size, bool write)
|
|
{
|
|
return new BufferRange(_geometryIndexDataBuffer.Handle, offset, size, write);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the range for a dummy 16 bytes buffer, filled with zeros.
|
|
/// </summary>
|
|
/// <returns>Dummy buffer range</returns>
|
|
public BufferRange GetDummyBufferRange()
|
|
{
|
|
if (_dummyBuffer == BufferHandle.Null)
|
|
{
|
|
_dummyBuffer = _context.Renderer.CreateBuffer(DummyBufferSize, BufferAccess.DeviceMemory);
|
|
_context.Renderer.Pipeline.ClearBuffer(_dummyBuffer, 0, DummyBufferSize, 0);
|
|
}
|
|
|
|
return new BufferRange(_dummyBuffer, 0, DummyBufferSize);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the range for a sequential index buffer, with ever incrementing index values.
|
|
/// </summary>
|
|
/// <param name="count">Minimum number of indices that the buffer should have</param>
|
|
/// <returns>Buffer handle</returns>
|
|
public BufferHandle GetSequentialIndexBuffer(int count)
|
|
{
|
|
if (_sequentialIndexBufferCount < count)
|
|
{
|
|
if (_sequentialIndexBuffer != BufferHandle.Null)
|
|
{
|
|
_context.Renderer.DeleteBuffer(_sequentialIndexBuffer);
|
|
}
|
|
|
|
_sequentialIndexBuffer = _context.Renderer.CreateBuffer(count * sizeof(uint), BufferAccess.DeviceMemory);
|
|
_sequentialIndexBufferCount = count;
|
|
|
|
Span<int> data = new int[count];
|
|
|
|
for (int index = 0; index < count; index++)
|
|
{
|
|
data[index] = index;
|
|
}
|
|
|
|
_context.Renderer.SetBufferData(_sequentialIndexBuffer, 0, MemoryMarshal.Cast<int, byte>(data));
|
|
}
|
|
|
|
return _sequentialIndexBuffer;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ensure that a buffer exists, is large enough, and allocates a sub-region of the specified size inside the buffer.
|
|
/// </summary>
|
|
/// <param name="buffer">Buffer state</param>
|
|
/// <param name="size">Required size in bytes</param>
|
|
/// <returns>Allocated offset and size</returns>
|
|
private (int, int) EnsureBuffer(ref Buffer buffer, int size)
|
|
{
|
|
int newSize = buffer.Offset + size;
|
|
|
|
if (buffer.Size < newSize)
|
|
{
|
|
if (buffer.Handle != BufferHandle.Null)
|
|
{
|
|
_context.Renderer.DeleteBuffer(buffer.Handle);
|
|
}
|
|
|
|
buffer.Handle = _context.Renderer.CreateBuffer(newSize, BufferAccess.DeviceMemory);
|
|
buffer.Size = newSize;
|
|
}
|
|
|
|
int offset = buffer.Offset;
|
|
|
|
buffer.Offset = BitUtils.AlignUp(newSize, _context.Capabilities.StorageBufferOffsetAlignment);
|
|
|
|
return (offset, size);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Frees all buffer sub-regions that were previously allocated.
|
|
/// </summary>
|
|
public void FreeBuffers()
|
|
{
|
|
_vertexDataBuffer.Offset = 0;
|
|
_geometryVertexDataBuffer.Offset = 0;
|
|
_geometryIndexDataBuffer.Offset = 0;
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
for (int index = 0; index < _bufferTextures.Length; index++)
|
|
{
|
|
_bufferTextures[index]?.Dispose();
|
|
_bufferTextures[index] = null;
|
|
}
|
|
|
|
DestroyIfNotNull(ref _dummyBuffer);
|
|
DestroyIfNotNull(ref _vertexDataBuffer.Handle);
|
|
DestroyIfNotNull(ref _geometryVertexDataBuffer.Handle);
|
|
DestroyIfNotNull(ref _geometryIndexDataBuffer.Handle);
|
|
DestroyIfNotNull(ref _sequentialIndexBuffer);
|
|
|
|
foreach (var indexBuffer in _topologyRemapBuffers.Values)
|
|
{
|
|
_context.Renderer.DeleteBuffer(indexBuffer.Handle);
|
|
}
|
|
|
|
_topologyRemapBuffers.Clear();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes a buffer if the handle is valid (not null), then sets the handle to null.
|
|
/// </summary>
|
|
/// <param name="handle">Buffer handle</param>
|
|
private void DestroyIfNotNull(ref BufferHandle handle)
|
|
{
|
|
if (handle != BufferHandle.Null)
|
|
{
|
|
_context.Renderer.DeleteBuffer(handle);
|
|
handle = BufferHandle.Null;
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|
|
}
|