forked from aly/qstbak
147 lines
4.4 KiB
C#
147 lines
4.4 KiB
C#
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<T> : IDisposable where T : unmanaged
|
|
{
|
|
public sealed class Builder : IDisposable
|
|
{
|
|
private FrameRenderContext _ctx;
|
|
|
|
private GpuBuffer<T> _buffer;
|
|
|
|
private unsafe byte* _dataPtr;
|
|
|
|
private int _offset;
|
|
|
|
private unsafe ID3D11Buffer* _staging;
|
|
|
|
public int CurElements => _buffer.CurElements;
|
|
|
|
internal unsafe Builder(FrameRenderContext ctx, GpuBuffer<T> 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<int>(_buffer.MaxElements);
|
|
((DefaultInterpolatedStringHandler)(ref val)).AppendLiteral(" elements); further elements dropped.");
|
|
log.Warning(((DefaultInterpolatedStringHandler)(ref val)).ToStringAndClear());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GpuBuffer<T> buffer = _buffer;
|
|
int curElements = buffer.CurElements + 1;
|
|
buffer.CurElements = curElements;
|
|
Unsafe.CopyBlockUnaligned((void*)(_dataPtr + _offset), Unsafe.AsPointer<T>(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);
|
|
}
|
|
}
|