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

91 lines
3.8 KiB
C#

using System;
using System.Runtime.InteropServices;
using TerraFX.Interop.DirectX;
namespace Auspex.Rendering.Direct3D;
internal sealed class FullscreenPassShader : IDisposable
{
public struct Constants
{
public float MaxAlpha;
public float ClipNativeUI;
}
private unsafe ID3D11Buffer* _constantBuffer;
private unsafe ID3D11VertexShader* _vs;
private unsafe ID3D11PixelShader* _ps;
public unsafe FullscreenPassShader(FrameRenderContext ctx)
{
ReadOnlySpan<byte> source = "struct Constants\n{\n float maxAlpha;\n float clipNativeUI;\n};\nConstants k : register(b0);\n\nTexture2D<float4> inputTexture : register(t0);\nTexture2D<float4> maskTexture : register(t1);\n\nSamplerState TextureSampler\n{\n Filter = MIN_MAG_MIP_POINT;\n AddressU = CLAMP;\n AddressV = CLAMP;\n};\n\nstruct VSOutput\n{\n float4 pos : SV_POSITION;\n float2 uv: TEXCOORD;\n};\n\nVSOutput vs(uint id : SV_VertexID)\n{\n VSOutput output;\n\tfloat2 uv = float2((id << 1) & 2, id & 2);\n\toutput.pos = float4(uv * float2(2, -2) + float2(-1, 1), 0, 1);\n output.uv = uv;\n return output;\n}\n\nfloat4 ps(VSOutput input) : SV_Target\n{\n float4 color = inputTexture.Sample(TextureSampler, input.uv);\n if (color.a > 0)\n {\n color.rgb /= color.a;\n }\n float maskAlpha = 1;\n if (k.clipNativeUI > 0.5)\n {\n float4 mask = maskTexture.Sample(TextureSampler, input.uv);\n // Apply mask alpha squared\n // (I don't think this is mathematically correct but it looks better)\n maskAlpha = 1 - mask.a;\n maskAlpha *= maskAlpha;\n }\n color.a = min(color.a, k.maxAlpha) * maskAlpha;\n return color;\n}"u8;
TriangleFillShader.CompileShader(source, "vs"u8, "vs_5_0"u8, out var blob, "FSP VS");
TriangleFillShader.CompileShader(source, "ps"u8, "ps_5_0"u8, out var blob2, "FSP PS");
ID3D11VertexShader* vs = default(ID3D11VertexShader*);
Marshal.ThrowExceptionForHR(ctx.Device->CreateVertexShader(blob->GetBufferPointer(), blob->GetBufferSize(), null, &vs));
_vs = vs;
ID3D11PixelShader* ps = default(ID3D11PixelShader*);
Marshal.ThrowExceptionForHR(ctx.Device->CreatePixelShader(blob2->GetBufferPointer(), blob2->GetBufferSize(), null, &ps));
_ps = ps;
D3D11_BUFFER_DESC d3D11_BUFFER_DESC = new D3D11_BUFFER_DESC
{
ByteWidth = 16u,
Usage = D3D11_USAGE.D3D11_USAGE_DEFAULT,
BindFlags = 4u
};
ID3D11Buffer* constantBuffer = default(ID3D11Buffer*);
Marshal.ThrowExceptionForHR(ctx.Device->CreateBuffer(&d3D11_BUFFER_DESC, null, &constantBuffer));
_constantBuffer = constantBuffer;
blob->Release();
blob2->Release();
}
public unsafe void Dispose()
{
if (_constantBuffer != null)
{
_constantBuffer->Release();
_constantBuffer = null;
}
if (_vs != null)
{
_vs->Release();
_vs = null;
}
if (_ps != null)
{
_ps->Release();
_ps = null;
}
GC.SuppressFinalize(this);
}
public unsafe void UpdateConstants(FrameRenderContext ctx, Constants consts)
{
ctx.Context->UpdateSubresource((ID3D11Resource*)_constantBuffer, 0u, null, &consts, 0u, 0u);
}
public unsafe void Bind(FrameRenderContext ctx)
{
ctx.Context->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY.D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ctx.Context->VSSetShader(_vs, null, 0u);
ctx.Context->PSSetShader(_ps, null, 0u);
ID3D11Buffer* constantBuffer = _constantBuffer;
ctx.Context->PSSetConstantBuffers(0u, 1u, &constantBuffer);
ctx.Context->GSSetShader(null, null, 0u);
}
public unsafe void Draw(FrameRenderContext ctx, ID3D11ShaderResourceView* baseSRV, ID3D11ShaderResourceView* maskSRV)
{
ctx.Context->PSSetShaderResources(0u, 1u, &baseSRV);
ctx.Context->PSSetShaderResources(1u, 1u, &maskSRV);
Bind(ctx);
ctx.Context->Draw(3u, 0u);
ID3D11ShaderResourceView* ptr = null;
ctx.Context->PSSetShaderResources(0u, 1u, &ptr);
ctx.Context->PSSetShaderResources(1u, 1u, &ptr);
}
}