qstbak/Auspex/Auspex.Rendering.Direct3D/FrameRenderTarget.cs
2026-08-17 20:25:32 +10:00

293 lines
11 KiB
C#

using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
namespace Auspex.Rendering.Direct3D;
internal sealed class FrameRenderTarget : IDisposable
{
private unsafe ID3D11Texture2D* _baseRT;
private unsafe ID3D11RenderTargetView* _baseRTV;
private unsafe ID3D11ShaderResourceView* _baseSRV;
private unsafe ID3D11Texture2D* _processedRT;
private unsafe ID3D11RenderTargetView* _processedRTV;
private unsafe ID3D11ShaderResourceView* _processedSRV;
private unsafe ID3D11Texture2D* _backBufferCopy;
private unsafe ID3D11ShaderResourceView* _backBufferSRV;
private unsafe ID3D11Texture2D* _clipStencil;
private unsafe ID3D11DepthStencilView* _clipStencilDSV;
private unsafe ID3D11BlendState* _defaultBlendState;
private unsafe ID3D11BlendState* _fspBlendState;
public Vector2 Size { get; private set; }
public uint Width => (uint)Size.X;
public uint Height => (uint)Size.Y;
internal unsafe ID3D11DepthStencilView* ClipStencilDSV => _clipStencilDSV;
internal unsafe ID3D11RenderTargetView* BaseRTV => _baseRTV;
public unsafe IntPtr ImguiHandle => (nint)_processedSRV;
public AxTexture Texture => new AxTexture(ImguiHandle, Width, Height);
public unsafe FrameRenderTarget(FrameRenderContext ctx, int width, int height, AlphaBlendMode blendMode)
{
Size = new Vector2(width, height);
D3D11_TEXTURE2D_DESC d3D11_TEXTURE2D_DESC = new D3D11_TEXTURE2D_DESC
{
Width = (uint)width,
Height = (uint)height,
MipLevels = 1u,
ArraySize = 1u,
Format = DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM,
SampleDesc = new DXGI_SAMPLE_DESC
{
Count = 1u,
Quality = 0u
},
Usage = D3D11_USAGE.D3D11_USAGE_DEFAULT,
BindFlags = 40u,
CPUAccessFlags = 0u,
MiscFlags = 0u
};
ID3D11Texture2D* ptr = default(ID3D11Texture2D*);
Marshal.ThrowExceptionForHR(ctx.Device->CreateTexture2D(&d3D11_TEXTURE2D_DESC, null, &ptr));
_baseRT = ptr;
ID3D11RenderTargetView* ptr2 = default(ID3D11RenderTargetView*);
Marshal.ThrowExceptionForHR(ctx.Device->CreateRenderTargetView((ID3D11Resource*)_baseRT, null, &ptr2));
_baseRTV = ptr2;
ID3D11ShaderResourceView* ptr3 = default(ID3D11ShaderResourceView*);
Marshal.ThrowExceptionForHR(ctx.Device->CreateShaderResourceView((ID3D11Resource*)_baseRT, null, &ptr3));
_baseSRV = ptr3;
Marshal.ThrowExceptionForHR(ctx.Device->CreateTexture2D(&d3D11_TEXTURE2D_DESC, null, &ptr));
_processedRT = ptr;
Marshal.ThrowExceptionForHR(ctx.Device->CreateRenderTargetView((ID3D11Resource*)_processedRT, null, &ptr2));
_processedRTV = ptr2;
Marshal.ThrowExceptionForHR(ctx.Device->CreateShaderResourceView((ID3D11Resource*)_processedRT, null, &ptr3));
_processedSRV = ptr3;
D3D11_TEXTURE2D_DESC d3D11_TEXTURE2D_DESC2 = new D3D11_TEXTURE2D_DESC
{
Width = (uint)width,
Height = (uint)height,
MipLevels = 1u,
ArraySize = 1u,
Format = DXGI_FORMAT.DXGI_FORMAT_R24G8_TYPELESS,
SampleDesc = new DXGI_SAMPLE_DESC
{
Count = 1u,
Quality = 0u
},
Usage = D3D11_USAGE.D3D11_USAGE_DEFAULT,
BindFlags = 64u,
CPUAccessFlags = 0u,
MiscFlags = 0u
};
Marshal.ThrowExceptionForHR(ctx.Device->CreateTexture2D(&d3D11_TEXTURE2D_DESC2, null, &ptr));
_clipStencil = ptr;
D3D11_DEPTH_STENCIL_VIEW_DESC d3D11_DEPTH_STENCIL_VIEW_DESC = new D3D11_DEPTH_STENCIL_VIEW_DESC
{
Format = DXGI_FORMAT.DXGI_FORMAT_D24_UNORM_S8_UINT,
ViewDimension = D3D11_DSV_DIMENSION.D3D11_DSV_DIMENSION_TEXTURE2D
};
d3D11_DEPTH_STENCIL_VIEW_DESC.Texture2D.MipSlice = 0u;
ID3D11DepthStencilView* clipStencilDSV = default(ID3D11DepthStencilView*);
Marshal.ThrowExceptionForHR(ctx.Device->CreateDepthStencilView((ID3D11Resource*)_clipStencil, &d3D11_DEPTH_STENCIL_VIEW_DESC, &clipStencilDSV));
_clipStencilDSV = clipStencilDSV;
D3D11_BLEND_DESC d3D11_BLEND_DESC = default(D3D11_BLEND_DESC);
global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef<D3D11_BLEND_DESC._RenderTarget_e__FixedBuffer, D3D11_RENDER_TARGET_BLEND_DESC>(ref d3D11_BLEND_DESC.RenderTarget).RenderTargetWriteMask = 15;
if (blendMode != AlphaBlendMode.None)
{
global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef<D3D11_BLEND_DESC._RenderTarget_e__FixedBuffer, D3D11_RENDER_TARGET_BLEND_DESC>(ref d3D11_BLEND_DESC.RenderTarget).BlendEnable = true;
global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef<D3D11_BLEND_DESC._RenderTarget_e__FixedBuffer, D3D11_RENDER_TARGET_BLEND_DESC>(ref d3D11_BLEND_DESC.RenderTarget).SrcBlend = D3D11_BLEND.D3D11_BLEND_SRC_ALPHA;
global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef<D3D11_BLEND_DESC._RenderTarget_e__FixedBuffer, D3D11_RENDER_TARGET_BLEND_DESC>(ref d3D11_BLEND_DESC.RenderTarget).DestBlend = D3D11_BLEND.D3D11_BLEND_INV_SRC_ALPHA;
global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef<D3D11_BLEND_DESC._RenderTarget_e__FixedBuffer, D3D11_RENDER_TARGET_BLEND_DESC>(ref d3D11_BLEND_DESC.RenderTarget).BlendOp = D3D11_BLEND_OP.D3D11_BLEND_OP_ADD;
global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef<D3D11_BLEND_DESC._RenderTarget_e__FixedBuffer, D3D11_RENDER_TARGET_BLEND_DESC>(ref d3D11_BLEND_DESC.RenderTarget).SrcBlendAlpha = D3D11_BLEND.D3D11_BLEND_ONE;
global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef<D3D11_BLEND_DESC._RenderTarget_e__FixedBuffer, D3D11_RENDER_TARGET_BLEND_DESC>(ref d3D11_BLEND_DESC.RenderTarget).DestBlendAlpha = D3D11_BLEND.D3D11_BLEND_INV_SRC_ALPHA;
switch (blendMode)
{
case AlphaBlendMode.Add:
global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef<D3D11_BLEND_DESC._RenderTarget_e__FixedBuffer, D3D11_RENDER_TARGET_BLEND_DESC>(ref d3D11_BLEND_DESC.RenderTarget).BlendOpAlpha = D3D11_BLEND_OP.D3D11_BLEND_OP_ADD;
break;
case AlphaBlendMode.Max:
global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef<D3D11_BLEND_DESC._RenderTarget_e__FixedBuffer, D3D11_RENDER_TARGET_BLEND_DESC>(ref d3D11_BLEND_DESC.RenderTarget).BlendOpAlpha = D3D11_BLEND_OP.D3D11_BLEND_OP_MAX;
break;
}
global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef<D3D11_BLEND_DESC._RenderTarget_e__FixedBuffer, D3D11_RENDER_TARGET_BLEND_DESC>(ref d3D11_BLEND_DESC.RenderTarget).RenderTargetWriteMask = 15;
}
ID3D11BlendState* ptr4 = default(ID3D11BlendState*);
Marshal.ThrowExceptionForHR(ctx.Device->CreateBlendState(&d3D11_BLEND_DESC, &ptr4));
_defaultBlendState = ptr4;
D3D11_BLEND_DESC d3D11_BLEND_DESC2 = default(D3D11_BLEND_DESC);
global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef<D3D11_BLEND_DESC._RenderTarget_e__FixedBuffer, D3D11_RENDER_TARGET_BLEND_DESC>(ref d3D11_BLEND_DESC2.RenderTarget).RenderTargetWriteMask = 15;
Marshal.ThrowExceptionForHR(ctx.Device->CreateBlendState(&d3D11_BLEND_DESC2, &ptr4));
_fspBlendState = ptr4;
}
public unsafe void Bind(FrameRenderContext ctx)
{
byte* intPtr = stackalloc byte[16];
// IL initblk instruction
Unsafe.InitBlock(intPtr, 0, 16);
float* colorRGBA = (float*)intPtr;
ctx.Context->ClearRenderTargetView(_baseRTV, colorRGBA);
D3D11_VIEWPORT d3D11_VIEWPORT = new D3D11_VIEWPORT
{
TopLeftX = 0f,
TopLeftY = 0f,
Width = Size.X,
Height = Size.Y,
MinDepth = 0f,
MaxDepth = 1f
};
ctx.Context->RSSetViewports(1u, &d3D11_VIEWPORT);
ctx.Context->OMSetBlendState(_defaultBlendState, null, uint.MaxValue);
ID3D11RenderTargetView* baseRTV = _baseRTV;
ctx.Context->OMSetRenderTargets(1u, &baseRTV, null);
}
public unsafe void CopyBaseToProcessed(FrameRenderContext ctx)
{
ctx.Context->CopyResource((ID3D11Resource*)_processedRT, (ID3D11Resource*)_baseRT);
}
public unsafe void ExecuteFSP(FrameRenderContext ctx, ID3D11Texture2D* backBuffer, FullscreenPassShader fsp, bool clipNativeUI)
{
if (clipNativeUI)
{
D3D11_TEXTURE2D_DESC d3D11_TEXTURE2D_DESC = default(D3D11_TEXTURE2D_DESC);
backBuffer->GetDesc(&d3D11_TEXTURE2D_DESC);
ValidateBackBufferResources(ctx.Device, &d3D11_TEXTURE2D_DESC);
ctx.Context->CopyResource((ID3D11Resource*)_backBufferCopy, (ID3D11Resource*)backBuffer);
}
ctx.Context->OMSetBlendState(_fspBlendState, null, uint.MaxValue);
byte* intPtr = stackalloc byte[16];
// IL initblk instruction
Unsafe.InitBlock(intPtr, 0, 16);
float* colorRGBA = (float*)intPtr;
ctx.Context->ClearRenderTargetView(_processedRTV, colorRGBA);
ID3D11RenderTargetView* processedRTV = _processedRTV;
ctx.Context->OMSetRenderTargets(1u, &processedRTV, null);
fsp.Draw(ctx, _baseSRV, _backBufferSRV);
}
private unsafe void ValidateBackBufferResources(ID3D11Device* device, D3D11_TEXTURE2D_DESC* backBufferDesc)
{
bool flag = _backBufferCopy == null;
if (!flag)
{
D3D11_TEXTURE2D_DESC d3D11_TEXTURE2D_DESC = default(D3D11_TEXTURE2D_DESC);
_backBufferCopy->GetDesc(&d3D11_TEXTURE2D_DESC);
flag = d3D11_TEXTURE2D_DESC.Width != backBufferDesc->Width || d3D11_TEXTURE2D_DESC.Height != backBufferDesc->Height;
}
if (flag)
{
if (_backBufferCopy != null)
{
_backBufferCopy->Release();
_backBufferCopy = null;
}
if (_backBufferSRV != null)
{
_backBufferSRV->Release();
_backBufferSRV = null;
}
D3D11_TEXTURE2D_DESC d3D11_TEXTURE2D_DESC2 = *backBufferDesc;
d3D11_TEXTURE2D_DESC2.BindFlags = 8u;
ID3D11Texture2D* backBufferCopy = default(ID3D11Texture2D*);
HRESULT hRESULT = device->CreateTexture2D(&d3D11_TEXTURE2D_DESC2, null, &backBufferCopy);
Marshal.ThrowExceptionForHR(hRESULT);
_backBufferCopy = backBufferCopy;
ID3D11ShaderResourceView* backBufferSRV = default(ID3D11ShaderResourceView*);
hRESULT = device->CreateShaderResourceView((ID3D11Resource*)_backBufferCopy, null, &backBufferSRV);
if (hRESULT < 0)
{
_backBufferCopy->Release();
_backBufferCopy = null;
Marshal.ThrowExceptionForHR(hRESULT);
}
_backBufferSRV = backBufferSRV;
}
}
public unsafe void Dispose()
{
GC.SuppressFinalize(this);
if (_baseRT != null)
{
_baseRT->Release();
_baseRT = null;
}
if (_baseRTV != null)
{
_baseRTV->Release();
_baseRTV = null;
}
if (_baseSRV != null)
{
_baseSRV->Release();
_baseSRV = null;
}
if (_processedRT != null)
{
_processedRT->Release();
_processedRT = null;
}
if (_processedRTV != null)
{
_processedRTV->Release();
_processedRTV = null;
}
if (_processedSRV != null)
{
_processedSRV->Release();
_processedSRV = null;
}
if (_backBufferCopy != null)
{
_backBufferCopy->Release();
_backBufferCopy = null;
}
if (_backBufferSRV != null)
{
_backBufferSRV->Release();
_backBufferSRV = null;
}
if (_clipStencilDSV != null)
{
_clipStencilDSV->Release();
_clipStencilDSV = null;
}
if (_clipStencil != null)
{
_clipStencil->Release();
_clipStencil = null;
}
if (_defaultBlendState != null)
{
_defaultBlendState->Release();
_defaultBlendState = null;
}
if (_fspBlendState != null)
{
_fspBlendState->Release();
_fspBlendState = null;
}
}
}