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(ref d3D11_BLEND_DESC.RenderTarget).RenderTargetWriteMask = 15; if (blendMode != AlphaBlendMode.None) { global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef(ref d3D11_BLEND_DESC.RenderTarget).BlendEnable = true; global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef(ref d3D11_BLEND_DESC.RenderTarget).SrcBlend = D3D11_BLEND.D3D11_BLEND_SRC_ALPHA; global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef(ref d3D11_BLEND_DESC.RenderTarget).DestBlend = D3D11_BLEND.D3D11_BLEND_INV_SRC_ALPHA; global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef(ref d3D11_BLEND_DESC.RenderTarget).BlendOp = D3D11_BLEND_OP.D3D11_BLEND_OP_ADD; global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef(ref d3D11_BLEND_DESC.RenderTarget).SrcBlendAlpha = D3D11_BLEND.D3D11_BLEND_ONE; global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef(ref d3D11_BLEND_DESC.RenderTarget).DestBlendAlpha = D3D11_BLEND.D3D11_BLEND_INV_SRC_ALPHA; switch (blendMode) { case AlphaBlendMode.Add: global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef(ref d3D11_BLEND_DESC.RenderTarget).BlendOpAlpha = D3D11_BLEND_OP.D3D11_BLEND_OP_ADD; break; case AlphaBlendMode.Max: global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef(ref d3D11_BLEND_DESC.RenderTarget).BlendOpAlpha = D3D11_BLEND_OP.D3D11_BLEND_OP_MAX; break; } global::_003CPrivateImplementationDetails_003E.InlineArrayFirstElementRef(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(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; } } }