using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Dalamud.Plugin.Services; using TerraFX.Interop.DirectX; namespace Auspex.Rendering.Direct3D; internal sealed class GpuBuffer : IDisposable where T : unmanaged { public sealed class Builder : IDisposable { private FrameRenderContext _ctx; private GpuBuffer _buffer; private unsafe byte* _dataPtr; private int _offset; private unsafe ID3D11Buffer* _staging; public int CurElements => _buffer.CurElements; internal unsafe Builder(FrameRenderContext ctx, GpuBuffer buffer) { _ctx = ctx; _buffer = buffer; buffer.CurElements = 0; buffer._hasWarnedOverflow = false; _offset = 0; D3D11_MAPPED_SUBRESOURCE d3D11_MAPPED_SUBRESOURCE = default(D3D11_MAPPED_SUBRESOURCE); if (buffer.Dynamic) { Marshal.ThrowExceptionForHR(ctx.Context->Map((ID3D11Resource*)buffer.Buffer, 0u, D3D11_MAP.D3D11_MAP_WRITE_DISCARD, 0u, &d3D11_MAPPED_SUBRESOURCE)); _dataPtr = (byte*)d3D11_MAPPED_SUBRESOURCE.pData; return; } D3D11_BUFFER_DESC d3D11_BUFFER_DESC = new D3D11_BUFFER_DESC { ByteWidth = (uint)(buffer.ElementSize * buffer.MaxElements), Usage = D3D11_USAGE.D3D11_USAGE_STAGING, CPUAccessFlags = 65536u }; ID3D11Buffer* staging = default(ID3D11Buffer*); Marshal.ThrowExceptionForHR(ctx.Device->CreateBuffer(&d3D11_BUFFER_DESC, null, &staging)); _staging = staging; Marshal.ThrowExceptionForHR(ctx.Context->Map((ID3D11Resource*)_staging, 0u, D3D11_MAP.D3D11_MAP_WRITE_DISCARD, 0u, &d3D11_MAPPED_SUBRESOURCE)); _dataPtr = (byte*)d3D11_MAPPED_SUBRESOURCE.pData; } public unsafe void Dispose() { if (_buffer.Dynamic) { _ctx.Context->Unmap((ID3D11Resource*)_buffer.Buffer, 0u); } else { _ctx.Context->Unmap((ID3D11Resource*)_staging, 0u); _ctx.Context->CopyResource((ID3D11Resource*)_buffer.Buffer, (ID3D11Resource*)_staging); _staging->Release(); _staging = null; } GC.SuppressFinalize(this); } public unsafe void Add(ref T item) { if (_buffer.CurElements >= _buffer.MaxElements) { if (!_buffer._hasWarnedOverflow) { _buffer._hasWarnedOverflow = true; IPluginLog log = AuspexService.Log; DefaultInterpolatedStringHandler val = default(DefaultInterpolatedStringHandler); ((DefaultInterpolatedStringHandler)(ref val))._002Ector(60, 2); ((DefaultInterpolatedStringHandler)(ref val)).AppendLiteral("[Auspex] "); ((DefaultInterpolatedStringHandler)(ref val)).AppendFormatted(_buffer.FriendlyName); ((DefaultInterpolatedStringHandler)(ref val)).AppendLiteral(" buffer full ("); ((DefaultInterpolatedStringHandler)(ref val)).AppendFormatted(_buffer.MaxElements); ((DefaultInterpolatedStringHandler)(ref val)).AppendLiteral(" elements); further elements dropped."); log.Warning(((DefaultInterpolatedStringHandler)(ref val)).ToStringAndClear()); } } else { GpuBuffer buffer = _buffer; int curElements = buffer.CurElements + 1; buffer.CurElements = curElements; Unsafe.CopyBlockUnaligned((void*)(_dataPtr + _offset), Unsafe.AsPointer(ref item), (uint)sizeof(T)); _offset += sizeof(T); } } public void Add(T item) { Add(ref item); } } private bool _hasWarnedOverflow; public string FriendlyName { get; private set; } public bool Dynamic { get; init; } public int ElementSize { get; init; } public int MaxElements { get; init; } public int CurElements { get; private set; } public unsafe ID3D11Buffer* Buffer { get; init; } public unsafe GpuBuffer(string friendlyName, FrameRenderContext ctx, int maxElements, uint bindFlags, bool dynamic) { FriendlyName = friendlyName; Dynamic = dynamic; ElementSize = sizeof(T); MaxElements = maxElements; D3D11_BUFFER_DESC d3D11_BUFFER_DESC = new D3D11_BUFFER_DESC { ByteWidth = (uint)(ElementSize * maxElements), Usage = (dynamic ? D3D11_USAGE.D3D11_USAGE_DYNAMIC : D3D11_USAGE.D3D11_USAGE_DEFAULT), BindFlags = bindFlags, CPUAccessFlags = (dynamic ? 65536u : 0u) }; ID3D11Buffer* buffer = default(ID3D11Buffer*); Marshal.ThrowExceptionForHR(ctx.Device->CreateBuffer(&d3D11_BUFFER_DESC, null, &buffer)); Buffer = buffer; } public unsafe void Dispose() { if (Buffer != null) { Buffer->Release(); } GC.SuppressFinalize(this); } public Builder Map(FrameRenderContext ctx) { return new Builder(ctx, this); } }