264 lines
7.7 KiB
C#
264 lines
7.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Numerics;
|
|
using System.Runtime.InteropServices;
|
|
using TerraFX.Interop.DirectX;
|
|
|
|
namespace Auspex.Rendering.Direct3D;
|
|
|
|
internal sealed class QuadBlitter : IDisposable
|
|
{
|
|
public struct Constants
|
|
{
|
|
public Matrix4x4 ViewProj;
|
|
}
|
|
|
|
public struct Vertex
|
|
{
|
|
public Vector3 Position;
|
|
|
|
public Vector2 UV;
|
|
|
|
public Vector4 Color;
|
|
}
|
|
|
|
public struct DrawSegment
|
|
{
|
|
public IntPtr TextureSRV;
|
|
|
|
public int StartVertex;
|
|
|
|
public int VertexCount;
|
|
}
|
|
|
|
public sealed class Data : HlslShaderData<Vertex>
|
|
{
|
|
public sealed class Builder : HlslShaderBuilder<Vertex>
|
|
{
|
|
private readonly List<DrawSegment> _segments;
|
|
|
|
private IntPtr _currentTexture;
|
|
|
|
private int _segmentStart;
|
|
|
|
internal Builder(FrameRenderContext ctx, Data data)
|
|
: base(data._buffer.Map(ctx))
|
|
{
|
|
_segments = data._segments;
|
|
_segments.Clear();
|
|
_currentTexture = (IntPtr)0;
|
|
_segmentStart = 0;
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
FinalizeSegment();
|
|
base.Dispose();
|
|
}
|
|
|
|
public void SetTexture(IntPtr srv)
|
|
{
|
|
if (srv != _currentTexture)
|
|
{
|
|
FinalizeSegment();
|
|
_currentTexture = srv;
|
|
_segmentStart = _inner.CurElements;
|
|
}
|
|
}
|
|
|
|
private void FinalizeSegment()
|
|
{
|
|
int num = _inner.CurElements - _segmentStart;
|
|
if (num > 0 && _currentTexture != (IntPtr)0)
|
|
{
|
|
_segments.Add(new DrawSegment
|
|
{
|
|
TextureSRV = _currentTexture,
|
|
StartVertex = _segmentStart,
|
|
VertexCount = num
|
|
});
|
|
}
|
|
}
|
|
|
|
public void Add(Vector3 position, Vector2 uv, Vector4 color)
|
|
{
|
|
_inner.Add(new Vertex
|
|
{
|
|
Position = position,
|
|
UV = uv,
|
|
Color = color
|
|
});
|
|
}
|
|
}
|
|
|
|
internal readonly List<DrawSegment> _segments = new List<DrawSegment>();
|
|
|
|
internal GpuBuffer<Vertex> Buffer => _buffer;
|
|
|
|
public Data(FrameRenderContext ctx, int maxCount, bool dynamic)
|
|
: base("QuadBlitter", ctx, maxCount, dynamic)
|
|
{
|
|
}
|
|
|
|
public Builder Map(FrameRenderContext ctx)
|
|
{
|
|
return new Builder(ctx, this);
|
|
}
|
|
}
|
|
|
|
private unsafe ID3D11Buffer* _constantBuffer;
|
|
|
|
private unsafe ID3D11InputLayout* _il;
|
|
|
|
private unsafe ID3D11VertexShader* _vs;
|
|
|
|
private unsafe ID3D11PixelShader* _ps;
|
|
|
|
private unsafe ID3D11SamplerState* _sampler;
|
|
|
|
public unsafe QuadBlitter(FrameRenderContext ctx)
|
|
{
|
|
ReadOnlySpan<byte> source = "struct Vertex\n{\n float3 pos : POSITION;\n float2 uv : TEXCOORD;\n float4 color : COLOR;\n};\n\nstruct VSOutput\n{\n float4 projPos : SV_POSITION;\n float2 uv : TEXCOORD;\n float4 color : COLOR;\n};\n\nstruct Constants\n{\n float4x4 viewProj;\n};\nConstants k : register(c0);\n\nTexture2D<float4> tex : register(t0);\nSamplerState samp : register(s0);\n\nVSOutput vs(Vertex v)\n{\n VSOutput o;\n o.projPos = mul(float4(v.pos, 1), k.viewProj);\n o.uv = v.uv;\n o.color = v.color;\n return o;\n}\n\nfloat4 ps(VSOutput input) : SV_TARGET\n{\n return tex.Sample(samp, input.uv) * input.color;\n}"u8;
|
|
TriangleFillShader.CompileShader(source, "vs"u8, "vs_5_0"u8, out var blob, "QuadBlitter VS");
|
|
TriangleFillShader.CompileShader(source, "ps"u8, "ps_5_0"u8, out var blob2, "QuadBlitter 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 = 64u,
|
|
Usage = D3D11_USAGE.D3D11_USAGE_DEFAULT,
|
|
BindFlags = 4u
|
|
};
|
|
ID3D11Buffer* constantBuffer = default(ID3D11Buffer*);
|
|
Marshal.ThrowExceptionForHR(ctx.Device->CreateBuffer(&d3D11_BUFFER_DESC, null, &constantBuffer));
|
|
_constantBuffer = constantBuffer;
|
|
fixed (byte* semanticName = "POSITION"u8)
|
|
{
|
|
fixed (byte* semanticName2 = "TEXCOORD"u8)
|
|
{
|
|
fixed (byte* semanticName3 = "COLOR"u8)
|
|
{
|
|
D3D11_INPUT_ELEMENT_DESC* ptr = stackalloc D3D11_INPUT_ELEMENT_DESC[3];
|
|
*ptr = new D3D11_INPUT_ELEMENT_DESC
|
|
{
|
|
SemanticName = (sbyte*)semanticName,
|
|
SemanticIndex = 0u,
|
|
Format = DXGI_FORMAT.DXGI_FORMAT_R32G32B32_FLOAT,
|
|
AlignedByteOffset = uint.MaxValue,
|
|
InputSlot = 0u,
|
|
InputSlotClass = D3D11_INPUT_CLASSIFICATION.D3D11_INPUT_PER_VERTEX_DATA,
|
|
InstanceDataStepRate = 0u
|
|
};
|
|
ptr[1] = new D3D11_INPUT_ELEMENT_DESC
|
|
{
|
|
SemanticName = (sbyte*)semanticName2,
|
|
SemanticIndex = 0u,
|
|
Format = DXGI_FORMAT.DXGI_FORMAT_R32G32_FLOAT,
|
|
AlignedByteOffset = uint.MaxValue,
|
|
InputSlot = 0u,
|
|
InputSlotClass = D3D11_INPUT_CLASSIFICATION.D3D11_INPUT_PER_VERTEX_DATA,
|
|
InstanceDataStepRate = 0u
|
|
};
|
|
ptr[2] = new D3D11_INPUT_ELEMENT_DESC
|
|
{
|
|
SemanticName = (sbyte*)semanticName3,
|
|
SemanticIndex = 0u,
|
|
Format = DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT,
|
|
AlignedByteOffset = uint.MaxValue,
|
|
InputSlot = 0u,
|
|
InputSlotClass = D3D11_INPUT_CLASSIFICATION.D3D11_INPUT_PER_VERTEX_DATA,
|
|
InstanceDataStepRate = 0u
|
|
};
|
|
ID3D11InputLayout* il = default(ID3D11InputLayout*);
|
|
Marshal.ThrowExceptionForHR(ctx.Device->CreateInputLayout(ptr, 3u, blob->GetBufferPointer(), blob->GetBufferSize(), &il));
|
|
_il = il;
|
|
}
|
|
}
|
|
}
|
|
D3D11_SAMPLER_DESC d3D11_SAMPLER_DESC = new D3D11_SAMPLER_DESC
|
|
{
|
|
Filter = D3D11_FILTER.D3D11_FILTER_MIN_MAG_MIP_LINEAR,
|
|
AddressU = D3D11_TEXTURE_ADDRESS_MODE.D3D11_TEXTURE_ADDRESS_CLAMP,
|
|
AddressV = D3D11_TEXTURE_ADDRESS_MODE.D3D11_TEXTURE_ADDRESS_CLAMP,
|
|
AddressW = D3D11_TEXTURE_ADDRESS_MODE.D3D11_TEXTURE_ADDRESS_CLAMP,
|
|
MaxAnisotropy = 1u,
|
|
ComparisonFunc = D3D11_COMPARISON_FUNC.D3D11_COMPARISON_NEVER,
|
|
MaxLOD = float.MaxValue
|
|
};
|
|
ID3D11SamplerState* sampler = default(ID3D11SamplerState*);
|
|
Marshal.ThrowExceptionForHR(ctx.Device->CreateSamplerState(&d3D11_SAMPLER_DESC, &sampler));
|
|
_sampler = sampler;
|
|
blob->Release();
|
|
blob2->Release();
|
|
}
|
|
|
|
public unsafe void Dispose()
|
|
{
|
|
if (_constantBuffer != null)
|
|
{
|
|
_constantBuffer->Release();
|
|
_constantBuffer = null;
|
|
}
|
|
if (_il != null)
|
|
{
|
|
_il->Release();
|
|
_il = null;
|
|
}
|
|
if (_vs != null)
|
|
{
|
|
_vs->Release();
|
|
_vs = null;
|
|
}
|
|
if (_ps != null)
|
|
{
|
|
_ps->Release();
|
|
_ps = null;
|
|
}
|
|
if (_sampler != null)
|
|
{
|
|
_sampler->Release();
|
|
_sampler = null;
|
|
}
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
public unsafe void UpdateConstants(FrameRenderContext ctx, Constants consts)
|
|
{
|
|
consts.ViewProj = Matrix4x4.Transpose(consts.ViewProj);
|
|
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->IASetInputLayout(_il);
|
|
ctx.Context->VSSetShader(_vs, null, 0u);
|
|
ID3D11Buffer* constantBuffer = _constantBuffer;
|
|
ctx.Context->VSSetConstantBuffers(0u, 1u, &constantBuffer);
|
|
ctx.Context->PSSetShader(_ps, null, 0u);
|
|
ID3D11SamplerState* sampler = _sampler;
|
|
ctx.Context->PSSetSamplers(0u, 1u, &sampler);
|
|
ctx.Context->GSSetShader(null, null, 0u);
|
|
}
|
|
|
|
public unsafe void Draw(FrameRenderContext ctx, Data data)
|
|
{
|
|
Bind(ctx);
|
|
ID3D11Buffer* buffer = data.Buffer.Buffer;
|
|
uint elementSize = (uint)data.Buffer.ElementSize;
|
|
uint num = 0u;
|
|
ctx.Context->IASetVertexBuffers(0u, 1u, &buffer, &elementSize, &num);
|
|
foreach (DrawSegment segment in data._segments)
|
|
{
|
|
ID3D11ShaderResourceView* textureSRV = (ID3D11ShaderResourceView*)segment.TextureSRV;
|
|
ctx.Context->PSSetShaderResources(0u, 1u, &textureSRV);
|
|
ctx.Context->Draw((uint)segment.VertexCount, (uint)segment.StartVertex);
|
|
}
|
|
ID3D11ShaderResourceView* ptr = null;
|
|
ctx.Context->PSSetShaderResources(0u, 1u, &ptr);
|
|
}
|
|
}
|