forked from aly/qstbak
muffin v7.5.5
This commit is contained in:
parent
a8f2c1df37
commit
6266f9e6b7
110 changed files with 14907 additions and 6073 deletions
174
Auspex/Auspex.Rendering.Direct3D/ClipZoneShader.cs
Normal file
174
Auspex/Auspex.Rendering.Direct3D/ClipZoneShader.cs
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using TerraFX.Interop.DirectX;
|
||||
|
||||
namespace Auspex.Rendering.Direct3D;
|
||||
|
||||
internal sealed class ClipZoneShader : IDisposable
|
||||
{
|
||||
public struct Constants
|
||||
{
|
||||
public Vector2 ViewportSize;
|
||||
}
|
||||
|
||||
public struct Instance
|
||||
{
|
||||
public Vector2 Min;
|
||||
|
||||
public Vector2 Max;
|
||||
}
|
||||
|
||||
private readonly FrameRenderContext _ctx;
|
||||
|
||||
private readonly GpuBuffer<Instance> _buffer;
|
||||
|
||||
private GpuBuffer<Instance>.Builder? _builder;
|
||||
|
||||
private unsafe ID3D11Buffer* _constantBuffer;
|
||||
|
||||
private unsafe ID3D11InputLayout* _il;
|
||||
|
||||
private unsafe ID3D11VertexShader* _vs;
|
||||
|
||||
private unsafe ID3D11PixelShader* _ps;
|
||||
|
||||
public bool HasPending => _builder != null;
|
||||
|
||||
public unsafe ClipZoneShader(FrameRenderContext ctx, int maxRects)
|
||||
{
|
||||
_ctx = ctx;
|
||||
_buffer = new GpuBuffer<Instance>("ClipZone", ctx, maxRects, 1u, dynamic: true);
|
||||
ReadOnlySpan<byte> source = "cbuffer Constants : register(b0)\n{\n float2 viewportSize;\n};\n\nstruct Rect\n{\n float2 rmin : RECTMIN;\n float2 rmax : RECTMAX;\n};\n\nstruct VSOutput\n{\n float4 pos : SV_POSITION;\n};\n\nVSOutput vs(in Rect r, uint vid : SV_VertexID)\n{\n VSOutput o;\n float2 px = float2(\n (vid & 1) ? r.rmax.x : r.rmin.x,\n (vid & 2) ? r.rmax.y : r.rmin.y);\n float2 ndc = float2(\n px.x / viewportSize.x * 2.0 - 1.0,\n 1.0 - px.y / viewportSize.y * 2.0);\n o.pos = float4(ndc, 0, 1);\n return o;\n}\n\nvoid ps(VSOutput input)\n{\n}"u8;
|
||||
TriangleFillShader.CompileShader(source, "vs"u8, "vs_5_0"u8, out var blob, "ClipZone VS");
|
||||
TriangleFillShader.CompileShader(source, "ps"u8, "ps_5_0"u8, out var blob2, "ClipZone 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;
|
||||
fixed (byte* semanticName = "RECTMIN"u8)
|
||||
{
|
||||
fixed (byte* semanticName2 = "RECTMAX"u8)
|
||||
{
|
||||
D3D11_INPUT_ELEMENT_DESC* ptr = stackalloc D3D11_INPUT_ELEMENT_DESC[2];
|
||||
*ptr = new D3D11_INPUT_ELEMENT_DESC
|
||||
{
|
||||
SemanticName = (sbyte*)semanticName,
|
||||
SemanticIndex = 0u,
|
||||
Format = DXGI_FORMAT.DXGI_FORMAT_R32G32_FLOAT,
|
||||
AlignedByteOffset = uint.MaxValue,
|
||||
InputSlot = 0u,
|
||||
InputSlotClass = D3D11_INPUT_CLASSIFICATION.D3D11_INPUT_PER_INSTANCE_DATA,
|
||||
InstanceDataStepRate = 1u
|
||||
};
|
||||
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_INSTANCE_DATA,
|
||||
InstanceDataStepRate = 1u
|
||||
};
|
||||
ID3D11InputLayout* il = default(ID3D11InputLayout*);
|
||||
Marshal.ThrowExceptionForHR(ctx.Device->CreateInputLayout(ptr, 2u, blob->GetBufferPointer(), blob->GetBufferSize(), &il));
|
||||
_il = il;
|
||||
}
|
||||
}
|
||||
blob->Release();
|
||||
blob2->Release();
|
||||
}
|
||||
|
||||
public unsafe void Dispose()
|
||||
{
|
||||
_builder?.Dispose();
|
||||
_buffer.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;
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public unsafe void UpdateConstants(Constants consts)
|
||||
{
|
||||
_ctx.Context->UpdateSubresource((ID3D11Resource*)_constantBuffer, 0u, null, &consts, 0u, 0u);
|
||||
}
|
||||
|
||||
public void Add(Vector2 min, Vector2 max)
|
||||
{
|
||||
if (_builder == null)
|
||||
{
|
||||
_builder = _buffer.Map(_ctx);
|
||||
}
|
||||
Instance item = new Instance
|
||||
{
|
||||
Min = min,
|
||||
Max = max
|
||||
};
|
||||
_builder.Add(ref item);
|
||||
}
|
||||
|
||||
public unsafe void Flush()
|
||||
{
|
||||
if (_builder != null)
|
||||
{
|
||||
_builder.Dispose();
|
||||
_builder = null;
|
||||
Bind();
|
||||
ID3D11Buffer* buffer = _buffer.Buffer;
|
||||
uint elementSize = (uint)_buffer.ElementSize;
|
||||
uint num = 0u;
|
||||
_ctx.Context->IASetVertexBuffers(0u, 1u, &buffer, &elementSize, &num);
|
||||
_ctx.Context->DrawInstanced(4u, (uint)_buffer.CurElements, 0u, 0u);
|
||||
}
|
||||
}
|
||||
|
||||
public void Discard()
|
||||
{
|
||||
if (_builder != null)
|
||||
{
|
||||
_builder.Dispose();
|
||||
_builder = null;
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void Bind()
|
||||
{
|
||||
_ctx.Context->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY.D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
_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);
|
||||
_ctx.Context->GSSetShader(null, null, 0u);
|
||||
}
|
||||
}
|
||||
20
Auspex/Auspex.Rendering.Direct3D/ColorConversions.cs
Normal file
20
Auspex/Auspex.Rendering.Direct3D/ColorConversions.cs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
|
||||
namespace Auspex.Rendering.Direct3D;
|
||||
|
||||
internal static class ColorConversions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint ToUint(this Vector4 color)
|
||||
{
|
||||
return ImGui.ColorConvertFloat4ToU32(color);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector4 ToVector4(this uint color)
|
||||
{
|
||||
return ImGui.ColorConvertU32ToFloat4(color);
|
||||
}
|
||||
}
|
||||
787
Auspex/Auspex.Rendering.Direct3D/Direct3DRenderer.cs
Normal file
787
Auspex/Auspex.Rendering.Direct3D/Direct3DRenderer.cs
Normal file
|
|
@ -0,0 +1,787 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Control;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||
using TerraFX.Interop.DirectX;
|
||||
using TerraFX.Interop.Windows;
|
||||
|
||||
namespace Auspex.Rendering.Direct3D;
|
||||
|
||||
internal sealed class Direct3DRenderer : IDisposable
|
||||
{
|
||||
public const int MAX_FANS = 2048;
|
||||
|
||||
public const int MAX_TRIS = 65536;
|
||||
|
||||
public const int MAX_STROKE_SEGMENTS = 245760;
|
||||
|
||||
public const int MAX_CLIP_ZONES = 3072;
|
||||
|
||||
public const int MAX_TEXTURED_QUADS = 256;
|
||||
|
||||
private unsafe ID3D11DepthStencilState* _clipZoneDSS;
|
||||
|
||||
private unsafe ID3D11DepthStencilState* _shapeDSS;
|
||||
|
||||
private readonly TriangleFillShader.Data _triFillDynamicData;
|
||||
|
||||
private TriangleFillShader.Data.Builder? _triFillDynamicBuilder;
|
||||
|
||||
private readonly FanFillShader.Data _fanFillDynamicData;
|
||||
|
||||
private FanFillShader.Data.Builder? _fanFillDynamicBuilder;
|
||||
|
||||
private readonly StrokeShader.Data _strokeDynamicData;
|
||||
|
||||
private StrokeShader.Data.Builder? _strokeDynamicBuilder;
|
||||
|
||||
private readonly QuadBlitter.Data _texturedQuadDynamicData;
|
||||
|
||||
private QuadBlitter.Data.Builder? _texturedQuadDynamicBuilder;
|
||||
|
||||
internal readonly List<Vector3> SharedPath = new List<Vector3>();
|
||||
|
||||
private unsafe ID3D11RasterizerState* _rasterizerState;
|
||||
|
||||
public FrameRenderContext FrameRenderContext { get; init; } = new FrameRenderContext();
|
||||
|
||||
internal FrameRenderTarget? FrameRenderTarget { get; private set; }
|
||||
|
||||
public TriangleFillShader TriangleFillShader { get; init; }
|
||||
|
||||
public FanFillShader FanFillShader { get; init; }
|
||||
|
||||
public StrokeShader StrokeShader { get; init; }
|
||||
|
||||
public QuadBlitter QuadBlitter { get; init; }
|
||||
|
||||
public FullscreenPassShader? FSP { get; init; }
|
||||
|
||||
public ClipZoneShader ClipZone { get; init; }
|
||||
|
||||
internal SceneDepthCapture SceneDepth { get; init; }
|
||||
|
||||
public Matrix4x4 ViewProj { get; private set; }
|
||||
|
||||
public Vector2 ViewportSize { get; private set; }
|
||||
|
||||
public Vector3 CameraRight { get; private set; }
|
||||
|
||||
public Vector3 CameraUp { get; private set; }
|
||||
|
||||
public bool FanDegraded { get; private set; }
|
||||
|
||||
public bool StrokeDegraded { get; private set; }
|
||||
|
||||
public bool FSPDegraded { get; private set; }
|
||||
|
||||
public bool TexturedQuadDegraded { get; private set; }
|
||||
|
||||
internal HighResFontAtlas? WorldFont { get; private set; }
|
||||
|
||||
public Direct3DRenderer()
|
||||
{
|
||||
try
|
||||
{
|
||||
FanFillShader = new FanFillShader(FrameRenderContext);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
AuspexService.Log.Error(exception, "[Auspex] Failed to compile fan shader; starting in degraded mode.");
|
||||
FanDegraded = true;
|
||||
}
|
||||
_fanFillDynamicData = new FanFillShader.Data(FrameRenderContext, FanDegraded ? 1 : 2048, dynamic: true);
|
||||
try
|
||||
{
|
||||
StrokeShader = new StrokeShader(FrameRenderContext);
|
||||
}
|
||||
catch (Exception exception2)
|
||||
{
|
||||
AuspexService.Log.Error(exception2, "[Auspex] Failed to compile stroke shader; starting in degraded mode.");
|
||||
StrokeDegraded = true;
|
||||
}
|
||||
_strokeDynamicData = new StrokeShader.Data(FrameRenderContext, StrokeDegraded ? 1 : 245760, dynamic: true);
|
||||
try
|
||||
{
|
||||
QuadBlitter = new QuadBlitter(FrameRenderContext);
|
||||
}
|
||||
catch (Exception exception3)
|
||||
{
|
||||
AuspexService.Log.Error(exception3, "[Auspex] Failed to compile textured quad shader; starting in degraded mode.");
|
||||
TexturedQuadDegraded = true;
|
||||
}
|
||||
_texturedQuadDynamicData = new QuadBlitter.Data(FrameRenderContext, TexturedQuadDegraded ? 1 : 1536, dynamic: true);
|
||||
if (!TexturedQuadDegraded)
|
||||
{
|
||||
try
|
||||
{
|
||||
WorldFont = new HighResFontAtlas(FrameRenderContext);
|
||||
}
|
||||
catch (Exception exception4)
|
||||
{
|
||||
AuspexService.Log.Error(exception4, "[Auspex] Failed to create high-res world text font; world text will use low-res fallback.");
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
TriangleFillShader = new TriangleFillShader(FrameRenderContext);
|
||||
_triFillDynamicData = new TriangleFillShader.Data(FrameRenderContext, 65536 + (FanDegraded ? 737280 : 0), dynamic: true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Dispose();
|
||||
throw;
|
||||
}
|
||||
try
|
||||
{
|
||||
FSP = new FullscreenPassShader(FrameRenderContext);
|
||||
}
|
||||
catch (Exception exception5)
|
||||
{
|
||||
AuspexService.Log.Error(exception5, "[Auspex] Failed to compile FSP shader; starting in degraded mode.");
|
||||
FSPDegraded = true;
|
||||
}
|
||||
SceneDepth = new SceneDepthCapture();
|
||||
ClipZone = new ClipZoneShader(FrameRenderContext, 3072);
|
||||
CreateRasterizerState();
|
||||
CreateDepthStencilStates();
|
||||
}
|
||||
|
||||
private unsafe void CreateRasterizerState()
|
||||
{
|
||||
D3D11_RASTERIZER_DESC d3D11_RASTERIZER_DESC = new D3D11_RASTERIZER_DESC
|
||||
{
|
||||
FillMode = D3D11_FILL_MODE.D3D11_FILL_SOLID,
|
||||
CullMode = D3D11_CULL_MODE.D3D11_CULL_NONE,
|
||||
DepthClipEnable = true,
|
||||
ScissorEnable = true
|
||||
};
|
||||
ID3D11RasterizerState* rasterizerState = default(ID3D11RasterizerState*);
|
||||
Marshal.ThrowExceptionForHR(FrameRenderContext.Device->CreateRasterizerState(&d3D11_RASTERIZER_DESC, &rasterizerState));
|
||||
_rasterizerState = rasterizerState;
|
||||
}
|
||||
|
||||
private unsafe void CreateDepthStencilStates()
|
||||
{
|
||||
D3D11_DEPTH_STENCILOP_DESC d3D11_DEPTH_STENCILOP_DESC = new D3D11_DEPTH_STENCILOP_DESC
|
||||
{
|
||||
StencilFailOp = D3D11_STENCIL_OP.D3D11_STENCIL_OP_KEEP,
|
||||
StencilDepthFailOp = D3D11_STENCIL_OP.D3D11_STENCIL_OP_KEEP,
|
||||
StencilPassOp = D3D11_STENCIL_OP.D3D11_STENCIL_OP_REPLACE,
|
||||
StencilFunc = D3D11_COMPARISON_FUNC.D3D11_COMPARISON_ALWAYS
|
||||
};
|
||||
D3D11_DEPTH_STENCIL_DESC d3D11_DEPTH_STENCIL_DESC = new D3D11_DEPTH_STENCIL_DESC
|
||||
{
|
||||
DepthEnable = false,
|
||||
DepthWriteMask = D3D11_DEPTH_WRITE_MASK.D3D11_DEPTH_WRITE_MASK_ZERO,
|
||||
StencilEnable = true,
|
||||
StencilReadMask = byte.MaxValue,
|
||||
StencilWriteMask = byte.MaxValue,
|
||||
FrontFace = d3D11_DEPTH_STENCILOP_DESC,
|
||||
BackFace = d3D11_DEPTH_STENCILOP_DESC
|
||||
};
|
||||
ID3D11DepthStencilState* ptr = default(ID3D11DepthStencilState*);
|
||||
Marshal.ThrowExceptionForHR(FrameRenderContext.Device->CreateDepthStencilState(&d3D11_DEPTH_STENCIL_DESC, &ptr));
|
||||
_clipZoneDSS = ptr;
|
||||
D3D11_DEPTH_STENCILOP_DESC d3D11_DEPTH_STENCILOP_DESC2 = new D3D11_DEPTH_STENCILOP_DESC
|
||||
{
|
||||
StencilFailOp = D3D11_STENCIL_OP.D3D11_STENCIL_OP_KEEP,
|
||||
StencilDepthFailOp = D3D11_STENCIL_OP.D3D11_STENCIL_OP_KEEP,
|
||||
StencilPassOp = D3D11_STENCIL_OP.D3D11_STENCIL_OP_KEEP,
|
||||
StencilFunc = D3D11_COMPARISON_FUNC.D3D11_COMPARISON_EQUAL
|
||||
};
|
||||
D3D11_DEPTH_STENCIL_DESC d3D11_DEPTH_STENCIL_DESC2 = new D3D11_DEPTH_STENCIL_DESC
|
||||
{
|
||||
DepthEnable = false,
|
||||
DepthWriteMask = D3D11_DEPTH_WRITE_MASK.D3D11_DEPTH_WRITE_MASK_ZERO,
|
||||
StencilEnable = true,
|
||||
StencilReadMask = byte.MaxValue,
|
||||
StencilWriteMask = 0,
|
||||
FrontFace = d3D11_DEPTH_STENCILOP_DESC2,
|
||||
BackFace = d3D11_DEPTH_STENCILOP_DESC2
|
||||
};
|
||||
Marshal.ThrowExceptionForHR(FrameRenderContext.Device->CreateDepthStencilState(&d3D11_DEPTH_STENCIL_DESC2, &ptr));
|
||||
_shapeDSS = ptr;
|
||||
}
|
||||
|
||||
public unsafe void Dispose()
|
||||
{
|
||||
WorldFont?.Dispose();
|
||||
FrameRenderTarget?.Dispose();
|
||||
_triFillDynamicBuilder?.Dispose();
|
||||
_triFillDynamicData?.Dispose();
|
||||
_fanFillDynamicBuilder?.Dispose();
|
||||
_fanFillDynamicData?.Dispose();
|
||||
_strokeDynamicBuilder?.Dispose();
|
||||
_strokeDynamicData?.Dispose();
|
||||
_texturedQuadDynamicBuilder?.Dispose();
|
||||
_texturedQuadDynamicData?.Dispose();
|
||||
if (!FanDegraded)
|
||||
{
|
||||
FanFillShader.Dispose();
|
||||
}
|
||||
if (!StrokeDegraded)
|
||||
{
|
||||
StrokeShader.Dispose();
|
||||
}
|
||||
if (!TexturedQuadDegraded)
|
||||
{
|
||||
QuadBlitter.Dispose();
|
||||
}
|
||||
TriangleFillShader?.Dispose();
|
||||
FSP?.Dispose();
|
||||
SceneDepth.Dispose();
|
||||
ClipZone.Dispose();
|
||||
if (_clipZoneDSS != null)
|
||||
{
|
||||
_clipZoneDSS->Release();
|
||||
_clipZoneDSS = null;
|
||||
}
|
||||
if (_shapeDSS != null)
|
||||
{
|
||||
_shapeDSS->Release();
|
||||
_shapeDSS = null;
|
||||
}
|
||||
if (_rasterizerState != null)
|
||||
{
|
||||
_rasterizerState->Release();
|
||||
_rasterizerState = null;
|
||||
}
|
||||
FrameRenderContext.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
internal unsafe void BeginFrame()
|
||||
{
|
||||
Device* ptr = Device.Instance();
|
||||
ViewportSize = new Vector2(ptr->Width, ptr->Height);
|
||||
Control* ptr2 = Control.Instance();
|
||||
ViewProj = *(Matrix4x4*)(&ptr2->ViewProjectionMatrix);
|
||||
SceneDepth.Update();
|
||||
FFXIVClientStructs.FFXIV.Client.Game.Camera* activeCamera = ptr2->CameraManager.GetActiveCamera();
|
||||
FFXIVClientStructs.FFXIV.Client.Graphics.Render.Camera* ptr3 = ((activeCamera != null) ? activeCamera->SceneCamera.RenderCamera : null);
|
||||
if (ptr3 != null && Matrix4x4.Invert(ptr3->ProjectionMatrix, out var result))
|
||||
{
|
||||
Matrix4x4 matrix4x = ViewProj * result;
|
||||
CameraRight = Vector3.Normalize(new Vector3(matrix4x.M11, matrix4x.M21, matrix4x.M31));
|
||||
CameraUp = Vector3.Normalize(new Vector3(matrix4x.M12, matrix4x.M22, matrix4x.M32));
|
||||
}
|
||||
else
|
||||
{
|
||||
CameraRight = Vector3.UnitX;
|
||||
CameraUp = Vector3.UnitY;
|
||||
}
|
||||
Vector2 pixelToUv = ((SceneDepth.SRV != null) ? (SceneDepth.UvScale / ViewportSize) : Vector2.Zero);
|
||||
TriangleFillShader.UpdateConstants(FrameRenderContext, new TriangleFillShader.Constants
|
||||
{
|
||||
ViewProj = ViewProj,
|
||||
PixelToUv = pixelToUv
|
||||
});
|
||||
if (!FanDegraded)
|
||||
{
|
||||
FanFillShader.UpdateConstants(FrameRenderContext, new FanFillShader.Constants
|
||||
{
|
||||
ViewProj = ViewProj,
|
||||
PixelToUv = pixelToUv
|
||||
});
|
||||
}
|
||||
if (!StrokeDegraded)
|
||||
{
|
||||
StrokeShader.UpdateConstants(FrameRenderContext, new StrokeShader.Constants
|
||||
{
|
||||
ViewProj = ViewProj,
|
||||
RenderTargetSize = new Vector2(ViewportSize.X, ViewportSize.Y),
|
||||
PixelToUv = pixelToUv
|
||||
});
|
||||
}
|
||||
if (!TexturedQuadDegraded)
|
||||
{
|
||||
QuadBlitter.UpdateConstants(FrameRenderContext, new QuadBlitter.Constants
|
||||
{
|
||||
ViewProj = ViewProj
|
||||
});
|
||||
}
|
||||
if (!FSPDegraded)
|
||||
{
|
||||
bool flag = AuspexService.Hints.ClipNativeUI && !SceneDepth.IsResolutionScaled;
|
||||
FSP.UpdateConstants(FrameRenderContext, new FullscreenPassShader.Constants
|
||||
{
|
||||
MaxAlpha = AuspexService.Hints.MaxAlphaFraction,
|
||||
ClipNativeUI = (flag ? 1f : 0f)
|
||||
});
|
||||
}
|
||||
if (FrameRenderTarget == null || FrameRenderTarget.Size != ViewportSize)
|
||||
{
|
||||
FrameRenderTarget?.Dispose();
|
||||
FrameRenderTarget = new FrameRenderTarget(FrameRenderContext, (int)ViewportSize.X, (int)ViewportSize.Y, AuspexService.Hints.AlphaBlendMode);
|
||||
}
|
||||
FrameRenderTarget.Bind(FrameRenderContext);
|
||||
FrameRenderContext.Context->RSSetState(_rasterizerState);
|
||||
RECT rECT = new RECT
|
||||
{
|
||||
left = 0,
|
||||
top = 0,
|
||||
right = (int)ViewportSize.X,
|
||||
bottom = (int)ViewportSize.Y
|
||||
};
|
||||
FrameRenderContext.Context->RSSetScissorRects(1u, &rECT);
|
||||
}
|
||||
|
||||
internal void Flush()
|
||||
{
|
||||
if (_triFillDynamicBuilder != null)
|
||||
{
|
||||
_triFillDynamicBuilder.Dispose();
|
||||
_triFillDynamicBuilder = null;
|
||||
TriangleFillShader.Bind(FrameRenderContext);
|
||||
_triFillDynamicData.DrawAll(FrameRenderContext);
|
||||
}
|
||||
if (!FanDegraded && _fanFillDynamicBuilder != null)
|
||||
{
|
||||
_fanFillDynamicBuilder.Dispose();
|
||||
_fanFillDynamicBuilder = null;
|
||||
FanFillShader.Bind(FrameRenderContext);
|
||||
_fanFillDynamicData.DrawAll(FrameRenderContext);
|
||||
}
|
||||
if (!StrokeDegraded && _strokeDynamicBuilder != null)
|
||||
{
|
||||
_strokeDynamicBuilder.Dispose();
|
||||
_strokeDynamicBuilder = null;
|
||||
StrokeShader.Bind(FrameRenderContext);
|
||||
_strokeDynamicData.DrawAll(FrameRenderContext);
|
||||
}
|
||||
if (!TexturedQuadDegraded && _texturedQuadDynamicBuilder != null)
|
||||
{
|
||||
_texturedQuadDynamicBuilder.Dispose();
|
||||
_texturedQuadDynamicBuilder = null;
|
||||
QuadBlitter.Draw(FrameRenderContext, _texturedQuadDynamicData);
|
||||
}
|
||||
}
|
||||
|
||||
internal unsafe void SetScissorRect(Vector2 min, Vector2 max)
|
||||
{
|
||||
Flush();
|
||||
RECT rECT = new RECT
|
||||
{
|
||||
left = (int)min.X,
|
||||
top = (int)min.Y,
|
||||
right = (int)max.X,
|
||||
bottom = (int)max.Y
|
||||
};
|
||||
FrameRenderContext.Context->RSSetScissorRects(1u, &rECT);
|
||||
}
|
||||
|
||||
internal unsafe void ClearScissorRect()
|
||||
{
|
||||
Flush();
|
||||
RECT rECT = new RECT
|
||||
{
|
||||
left = 0,
|
||||
top = 0,
|
||||
right = (int)ViewportSize.X,
|
||||
bottom = (int)ViewportSize.Y
|
||||
};
|
||||
FrameRenderContext.Context->RSSetScissorRects(1u, &rECT);
|
||||
}
|
||||
|
||||
public void AddClipZone(Vector2 min, Vector2 max)
|
||||
{
|
||||
ClipZone.Add(min, max);
|
||||
}
|
||||
|
||||
internal unsafe FrameRenderTarget EndFrame()
|
||||
{
|
||||
bool num = _triFillDynamicBuilder != null || (!FanDegraded && _fanFillDynamicBuilder != null) || (!StrokeDegraded && _strokeDynamicBuilder != null) || (!TexturedQuadDegraded && _texturedQuadDynamicBuilder != null);
|
||||
bool hasPending = ClipZone.HasPending;
|
||||
if (num && SceneDepth.SRV != null)
|
||||
{
|
||||
ID3D11DepthStencilView* clipStencilDSV = FrameRenderTarget.ClipStencilDSV;
|
||||
FrameRenderContext.Context->OMSetRenderTargets(0u, null, clipStencilDSV);
|
||||
FrameRenderContext.Context->ClearDepthStencilView(clipStencilDSV, 2u, 0f, 0);
|
||||
if (hasPending)
|
||||
{
|
||||
ClipZone.UpdateConstants(new ClipZoneShader.Constants
|
||||
{
|
||||
ViewportSize = new Vector2(ViewportSize.X, ViewportSize.Y)
|
||||
});
|
||||
FrameRenderContext.Context->OMSetDepthStencilState(_clipZoneDSS, 1u);
|
||||
ClipZone.Flush();
|
||||
}
|
||||
ID3D11RenderTargetView* baseRTV = FrameRenderTarget.BaseRTV;
|
||||
FrameRenderContext.Context->OMSetRenderTargets(1u, &baseRTV, clipStencilDSV);
|
||||
FrameRenderContext.Context->OMSetDepthStencilState(_shapeDSS, 0u);
|
||||
ID3D11ShaderResourceView* sRV = SceneDepth.SRV;
|
||||
FrameRenderContext.Context->PSSetShaderResources(0u, 1u, &sRV);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClipZone.Discard();
|
||||
}
|
||||
Flush();
|
||||
if (SceneDepth.SRV != null)
|
||||
{
|
||||
ID3D11ShaderResourceView* ptr = null;
|
||||
FrameRenderContext.Context->PSSetShaderResources(0u, 1u, &ptr);
|
||||
}
|
||||
if (!FSPDegraded)
|
||||
{
|
||||
Device* ptr2 = Device.Instance();
|
||||
if (ptr2 != null && ptr2->SwapChain != null && ptr2->SwapChain->BackBuffer != null && ptr2->SwapChain->BackBuffer->D3D11Texture2D != null)
|
||||
{
|
||||
ID3D11Texture2D* d3D11Texture2D = (ID3D11Texture2D*)ptr2->SwapChain->BackBuffer->D3D11Texture2D;
|
||||
FrameRenderTarget.ExecuteFSP(FrameRenderContext, d3D11Texture2D, FSP, AuspexService.Hints.ClipNativeUI && !SceneDepth.IsResolutionScaled);
|
||||
}
|
||||
else
|
||||
{
|
||||
AuspexService.Log.Warning("[Auspex] Direct3DRenderer.EndFrame: Device or BackBuffer is null; skipping combined pass.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FrameRenderTarget.CopyBaseToProcessed(FrameRenderContext);
|
||||
}
|
||||
FrameRenderContext.Execute();
|
||||
return FrameRenderTarget;
|
||||
}
|
||||
|
||||
public void DrawTriangle(Vector3 a, Vector3 b, Vector3 c, uint colorA, uint colorB, uint colorC, AxDxParams p)
|
||||
{
|
||||
TriangleFillShader.Data.Builder triFills = GetTriFills();
|
||||
triFills.Add(a, colorA.ToVector4(), p);
|
||||
triFills.Add(b, colorB.ToVector4(), p);
|
||||
triFills.Add(c, colorC.ToVector4(), p);
|
||||
}
|
||||
|
||||
private void DrawTriangle(Vector3 a, Vector3 b, Vector3 c, Vector4 colorA, Vector4 colorB, Vector4 colorC, AxDxParams p)
|
||||
{
|
||||
TriangleFillShader.Data.Builder triFills = GetTriFills();
|
||||
triFills.Add(a, colorA, p);
|
||||
triFills.Add(b, colorB, p);
|
||||
triFills.Add(c, colorC, p);
|
||||
}
|
||||
|
||||
private TriangleFillShader.Data.Builder GetTriFills()
|
||||
{
|
||||
return _triFillDynamicBuilder ?? (_triFillDynamicBuilder = _triFillDynamicData.Map(FrameRenderContext));
|
||||
}
|
||||
|
||||
private void DrawTriangleFan(Vector3 center, float innerRadius, float outerRadius, float minAngle, float maxAngle, uint innerColor, uint outerColor, uint numSegments = 0u, AxDxParams p = default(AxDxParams))
|
||||
{
|
||||
float num = maxAngle - minAngle;
|
||||
if (num == 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (numSegments == 0)
|
||||
{
|
||||
numSegments = (uint)(MathF.Abs(num) * 8f);
|
||||
}
|
||||
float num2 = num / (float)numSegments;
|
||||
Vector4 vector = innerColor.ToVector4();
|
||||
Vector4 vector2 = outerColor.ToVector4();
|
||||
Vector3 vector3 = default(Vector3);
|
||||
for (int i = 0; i <= numSegments; i++)
|
||||
{
|
||||
float num3 = (float)Math.PI / 2f + minAngle + (float)i * num2;
|
||||
Vector3 vector4 = new Vector3(MathF.Cos(num3), 0f, MathF.Sin(num3));
|
||||
if (i > 0)
|
||||
{
|
||||
if (innerRadius > 0f)
|
||||
{
|
||||
DrawTriangle(center + innerRadius * vector3, center + outerRadius * vector3, center + outerRadius * vector4, vector, vector2, vector2, p);
|
||||
DrawTriangle(center + outerRadius * vector4, center + innerRadius * vector4, center + innerRadius * vector3, vector2, vector, vector, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawTriangle(center, center + outerRadius * vector3, center + outerRadius * vector4, vector, vector2, vector2, p);
|
||||
}
|
||||
}
|
||||
vector3 = vector4;
|
||||
}
|
||||
}
|
||||
|
||||
internal void DrawTriangleFanGradient<T>(Vector3 center, float innerRadius, float outerRadius, float minAngle, float maxAngle, T gradient, uint numSegments = 0u, AxDxParams p = default(AxDxParams)) where T : IPctGradient
|
||||
{
|
||||
float num = maxAngle - minAngle;
|
||||
if (num == 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (numSegments == 0)
|
||||
{
|
||||
numSegments = (uint)(MathF.Abs(num) * 8f);
|
||||
}
|
||||
float num2 = num / (float)numSegments;
|
||||
Vector3 vector = default(Vector3);
|
||||
for (int i = 0; i <= numSegments; i++)
|
||||
{
|
||||
float num3 = (float)Math.PI / 2f + minAngle + (float)i * num2;
|
||||
Vector3 vector2 = new Vector3(MathF.Cos(num3), 0f, MathF.Sin(num3));
|
||||
if (i > 0)
|
||||
{
|
||||
if (innerRadius > 0f)
|
||||
{
|
||||
Vector3 vector3 = center + innerRadius * vector;
|
||||
Vector3 vector4 = center + outerRadius * vector;
|
||||
Vector3 vector5 = center + outerRadius * vector2;
|
||||
Vector3 vector6 = center + innerRadius * vector2;
|
||||
DrawTriangle(vector3, vector4, vector5, gradient.ColorAt(vector3).ToVector4(), gradient.ColorAt(vector4).ToVector4(), gradient.ColorAt(vector5).ToVector4(), p);
|
||||
DrawTriangle(vector5, vector6, vector3, gradient.ColorAt(vector5).ToVector4(), gradient.ColorAt(vector6).ToVector4(), gradient.ColorAt(vector3).ToVector4(), p);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 vector7 = center + outerRadius * vector;
|
||||
Vector3 vector8 = center + outerRadius * vector2;
|
||||
DrawTriangle(center, vector7, vector8, gradient.ColorAt(center).ToVector4(), gradient.ColorAt(vector7).ToVector4(), gradient.ColorAt(vector8).ToVector4(), p);
|
||||
}
|
||||
}
|
||||
vector = vector2;
|
||||
}
|
||||
}
|
||||
|
||||
internal void DrawTerrainFan(Vector3 origin, float innerRadius, float outerRadius, float minAngle, float maxAngle, uint innerColor, uint outerColor, float resolution, float yOffset, uint numSegments = 0u, AxDxParams p = default(AxDxParams))
|
||||
{
|
||||
float num = maxAngle - minAngle;
|
||||
if (num == 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
uint num2 = ((numSegments != 0) ? numSegments : ((uint)MathF.Ceiling(MathF.Abs(num) * outerRadius / resolution)));
|
||||
if (num2 == 0)
|
||||
{
|
||||
num2 = 1u;
|
||||
}
|
||||
int num3 = Math.Max(1, (int)MathF.Ceiling((outerRadius - innerRadius) / resolution));
|
||||
float num4 = num / (float)num2;
|
||||
Vector4 value = innerColor.ToVector4();
|
||||
Vector4 value2 = outerColor.ToVector4();
|
||||
Vector3 a = ((innerRadius == 0f) ? TerrainVertex(origin, Vector3.Zero, 0f, yOffset) : default(Vector3));
|
||||
float num5 = (float)Math.PI / 2f + minAngle;
|
||||
Vector3 direction = new Vector3(MathF.Cos(num5), 0f, MathF.Sin(num5));
|
||||
for (int i = 1; i <= num2; i++)
|
||||
{
|
||||
float num6 = (float)Math.PI / 2f + minAngle + (float)i * num4;
|
||||
Vector3 vector = new Vector3(MathF.Cos(num6), 0f, MathF.Sin(num6));
|
||||
for (int j = 0; j < num3; j++)
|
||||
{
|
||||
float num7 = innerRadius + (outerRadius - innerRadius) * (float)j / (float)num3;
|
||||
float radius = innerRadius + (outerRadius - innerRadius) * (float)(j + 1) / (float)num3;
|
||||
float amount = (float)j / (float)num3;
|
||||
float amount2 = (float)(j + 1) / (float)num3;
|
||||
Vector4 vector2 = Vector4.Lerp(value, value2, amount);
|
||||
Vector4 vector3 = Vector4.Lerp(value, value2, amount2);
|
||||
if (num7 > 0f)
|
||||
{
|
||||
Vector3 vector4 = TerrainVertex(origin, direction, num7, yOffset);
|
||||
Vector3 b = TerrainVertex(origin, direction, radius, yOffset);
|
||||
Vector3 vector5 = TerrainVertex(origin, vector, radius, yOffset);
|
||||
Vector3 b2 = TerrainVertex(origin, vector, num7, yOffset);
|
||||
DrawTriangle(vector4, b, vector5, vector2, vector3, vector3, p);
|
||||
DrawTriangle(vector5, b2, vector4, vector3, vector2, vector2, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 b3 = TerrainVertex(origin, direction, radius, yOffset);
|
||||
Vector3 c = TerrainVertex(origin, vector, radius, yOffset);
|
||||
DrawTriangle(a, b3, c, vector2, vector3, vector3, p);
|
||||
}
|
||||
}
|
||||
direction = vector;
|
||||
}
|
||||
}
|
||||
|
||||
internal void DrawTerrainFanGradient<T>(Vector3 origin, float innerRadius, float outerRadius, float minAngle, float maxAngle, T gradient, float resolution, float yOffset, uint numSegments = 0u, AxDxParams p = default(AxDxParams)) where T : IPctGradient
|
||||
{
|
||||
float num = maxAngle - minAngle;
|
||||
if (num == 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
uint num2 = ((numSegments != 0) ? numSegments : ((uint)MathF.Ceiling(MathF.Abs(num) * outerRadius / resolution)));
|
||||
if (num2 == 0)
|
||||
{
|
||||
num2 = 1u;
|
||||
}
|
||||
int num3 = Math.Max(1, (int)MathF.Ceiling((outerRadius - innerRadius) / resolution));
|
||||
float num4 = num / (float)num2;
|
||||
Vector3 vector = ((innerRadius == 0f) ? TerrainVertex(origin, Vector3.Zero, 0f, yOffset) : default(Vector3));
|
||||
Vector4 colorA = ((innerRadius == 0f) ? gradient.ColorAt(vector).ToVector4() : default(Vector4));
|
||||
float num5 = (float)Math.PI / 2f + minAngle;
|
||||
Vector3 direction = new Vector3(MathF.Cos(num5), 0f, MathF.Sin(num5));
|
||||
for (int i = 1; i <= num2; i++)
|
||||
{
|
||||
float num6 = (float)Math.PI / 2f + minAngle + (float)i * num4;
|
||||
Vector3 vector2 = new Vector3(MathF.Cos(num6), 0f, MathF.Sin(num6));
|
||||
for (int j = 0; j < num3; j++)
|
||||
{
|
||||
float num7 = innerRadius + (outerRadius - innerRadius) * (float)j / (float)num3;
|
||||
float radius = innerRadius + (outerRadius - innerRadius) * (float)(j + 1) / (float)num3;
|
||||
if (num7 > 0f)
|
||||
{
|
||||
Vector3 vector3 = TerrainVertex(origin, direction, num7, yOffset);
|
||||
Vector3 vector4 = TerrainVertex(origin, direction, radius, yOffset);
|
||||
Vector3 vector5 = TerrainVertex(origin, vector2, radius, yOffset);
|
||||
Vector3 vector6 = TerrainVertex(origin, vector2, num7, yOffset);
|
||||
DrawTriangle(vector3, vector4, vector5, gradient.ColorAt(vector3).ToVector4(), gradient.ColorAt(vector4).ToVector4(), gradient.ColorAt(vector5).ToVector4(), p);
|
||||
DrawTriangle(vector5, vector6, vector3, gradient.ColorAt(vector5).ToVector4(), gradient.ColorAt(vector6).ToVector4(), gradient.ColorAt(vector3).ToVector4(), p);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 vector7 = TerrainVertex(origin, direction, radius, yOffset);
|
||||
Vector3 vector8 = TerrainVertex(origin, vector2, radius, yOffset);
|
||||
DrawTriangle(vector, vector7, vector8, colorA, gradient.ColorAt(vector7).ToVector4(), gradient.ColorAt(vector8).ToVector4(), p);
|
||||
}
|
||||
}
|
||||
direction = vector2;
|
||||
}
|
||||
}
|
||||
|
||||
internal void DrawTerrainQuad(Vector3 a, Vector3 b, Vector3 c, Vector3 d, uint colorA, uint colorB, uint colorC, uint colorD, float resolution, float yOffset, AxDxParams p = default(AxDxParams))
|
||||
{
|
||||
float num = MathF.Max(Vector3.Distance(a, b), Vector3.Distance(d, c));
|
||||
float num2 = MathF.Max(Vector3.Distance(b, c), Vector3.Distance(a, d));
|
||||
int num3 = Math.Max(1, (int)MathF.Ceiling(num / resolution));
|
||||
int num4 = Math.Max(1, (int)MathF.Ceiling(num2 / resolution));
|
||||
Vector4 a2 = colorA.ToVector4();
|
||||
Vector4 b2 = colorB.ToVector4();
|
||||
Vector4 c2 = colorC.ToVector4();
|
||||
Vector4 d2 = colorD.ToVector4();
|
||||
for (int i = 0; i < num3; i++)
|
||||
{
|
||||
float u = (float)i / (float)num3;
|
||||
float u2 = (float)(i + 1) / (float)num3;
|
||||
for (int j = 0; j < num4; j++)
|
||||
{
|
||||
float v = (float)j / (float)num4;
|
||||
float v2 = (float)(j + 1) / (float)num4;
|
||||
Vector3 vector = TerrainVertexBilinear(a, b, c, d, u, v, yOffset);
|
||||
Vector3 b3 = TerrainVertexBilinear(a, b, c, d, u2, v, yOffset);
|
||||
Vector3 vector2 = TerrainVertexBilinear(a, b, c, d, u2, v2, yOffset);
|
||||
Vector3 b4 = TerrainVertexBilinear(a, b, c, d, u, v2, yOffset);
|
||||
Vector4 vector3 = BilinearColorV4(a2, b2, c2, d2, u, v);
|
||||
Vector4 colorB2 = BilinearColorV4(a2, b2, c2, d2, u2, v);
|
||||
Vector4 vector4 = BilinearColorV4(a2, b2, c2, d2, u2, v2);
|
||||
Vector4 colorB3 = BilinearColorV4(a2, b2, c2, d2, u, v2);
|
||||
DrawTriangle(vector, b3, vector2, vector3, colorB2, vector4, p);
|
||||
DrawTriangle(vector2, b4, vector, vector4, colorB3, vector3, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void DrawTerrainQuadGradient<T>(Vector3 a, Vector3 b, Vector3 c, Vector3 d, T gradient, float resolution, float yOffset, AxDxParams p = default(AxDxParams)) where T : IPctGradient
|
||||
{
|
||||
float num = MathF.Max(Vector3.Distance(a, b), Vector3.Distance(d, c));
|
||||
float num2 = MathF.Max(Vector3.Distance(b, c), Vector3.Distance(a, d));
|
||||
int num3 = Math.Max(1, (int)MathF.Ceiling(num / resolution));
|
||||
int num4 = Math.Max(1, (int)MathF.Ceiling(num2 / resolution));
|
||||
for (int i = 0; i < num3; i++)
|
||||
{
|
||||
float u = (float)i / (float)num3;
|
||||
float u2 = (float)(i + 1) / (float)num3;
|
||||
for (int j = 0; j < num4; j++)
|
||||
{
|
||||
float v = (float)j / (float)num4;
|
||||
float v2 = (float)(j + 1) / (float)num4;
|
||||
Vector3 vector = TerrainVertexBilinear(a, b, c, d, u, v, yOffset);
|
||||
Vector3 vector2 = TerrainVertexBilinear(a, b, c, d, u2, v, yOffset);
|
||||
Vector3 vector3 = TerrainVertexBilinear(a, b, c, d, u2, v2, yOffset);
|
||||
Vector3 vector4 = TerrainVertexBilinear(a, b, c, d, u, v2, yOffset);
|
||||
DrawTriangle(vector, vector2, vector3, gradient.ColorAt(vector).ToVector4(), gradient.ColorAt(vector2).ToVector4(), gradient.ColorAt(vector3).ToVector4(), p);
|
||||
DrawTriangle(vector3, vector4, vector, gradient.ColorAt(vector3).ToVector4(), gradient.ColorAt(vector4).ToVector4(), gradient.ColorAt(vector).ToVector4(), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Vector3 TerrainVertex(Vector3 origin, Vector3 direction, float radius, float yOffset)
|
||||
{
|
||||
float x = origin.X + direction.X * radius;
|
||||
float z = origin.Z + direction.Z * radius;
|
||||
float terrainYRaw = AxTerrainQuery.GetTerrainYRaw(x, z);
|
||||
float y = (float.IsNaN(terrainYRaw) ? origin.Y : terrainYRaw) + yOffset;
|
||||
return new Vector3(x, y, z);
|
||||
}
|
||||
|
||||
private static Vector3 TerrainVertexBilinear(Vector3 a, Vector3 b, Vector3 c, Vector3 d, float u, float v, float yOffset)
|
||||
{
|
||||
Vector3 result = a * (1f - u) * (1f - v) + b * u * (1f - v) + c * u * v + d * (1f - u) * v;
|
||||
float terrainYRaw = AxTerrainQuery.GetTerrainYRaw(result.X, result.Z);
|
||||
float y = result.Y;
|
||||
result.Y = (float.IsNaN(terrainYRaw) ? y : terrainYRaw) + yOffset;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Vector4 BilinearColorV4(Vector4 a, Vector4 b, Vector4 c, Vector4 d, float u, float v)
|
||||
{
|
||||
return a * (1f - u) * (1f - v) + b * u * (1f - v) + c * u * v + d * (1f - u) * v;
|
||||
}
|
||||
|
||||
public void DrawFan(Vector3 center, float innerRadius, float outerRadius, float minAngle, float maxAngle, uint innerColor, uint outerColor, uint numSegments = 0u, AxDxParams p = default(AxDxParams))
|
||||
{
|
||||
if (!FanDegraded)
|
||||
{
|
||||
if (numSegments == 0)
|
||||
{
|
||||
numSegments = (uint)MathF.Max(4f, MathF.Ceiling(MathF.Abs(maxAngle - minAngle) * 16f));
|
||||
}
|
||||
numSegments = Math.Min(numSegments, 360u);
|
||||
GetFanFills().Add(center, innerRadius, outerRadius, minAngle, maxAngle, innerColor.ToVector4(), outerColor.ToVector4(), numSegments, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawTriangleFan(center, innerRadius, outerRadius, minAngle, maxAngle, innerColor, outerColor, numSegments, p);
|
||||
}
|
||||
}
|
||||
|
||||
private FanFillShader.Data.Builder GetFanFills()
|
||||
{
|
||||
return _fanFillDynamicBuilder ?? (_fanFillDynamicBuilder = _fanFillDynamicData.Map(FrameRenderContext));
|
||||
}
|
||||
|
||||
public void DrawStroke(List<Vector3> world, float thickness, uint color, bool closed = false, float dashLength = 0f, float gapLength = 0f, float dashOffset = 0f, uint? colorEnd = null, AxLineCap cap = AxLineCap.Butt, AxLineJoin join = AxLineJoin.None, AxDxParams p = default(AxDxParams))
|
||||
{
|
||||
if (!StrokeDegraded)
|
||||
{
|
||||
GetStroke().Add(world, thickness, color.ToVector4(), closed, dashLength, gapLength, dashOffset, colorEnd.HasValue ? new Vector4?(colorEnd.Value.ToVector4()) : ((Vector4?)null), (float)cap, (float)join, p);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawStroke(List<Vector3> world, ReadOnlySpan<float> thicknesses, uint color, bool closed = false, float dashLength = 0f, float gapLength = 0f, float dashOffset = 0f, uint? colorEnd = null, AxLineCap cap = AxLineCap.Butt, AxLineJoin join = AxLineJoin.None, AxDxParams p = default(AxDxParams))
|
||||
{
|
||||
if (!StrokeDegraded)
|
||||
{
|
||||
GetStroke().Add(world, thicknesses, color.ToVector4(), closed, dashLength, gapLength, dashOffset, colorEnd.HasValue ? new Vector4?(colorEnd.Value.ToVector4()) : ((Vector4?)null), (float)cap, (float)join, p);
|
||||
}
|
||||
}
|
||||
|
||||
private StrokeShader.Data.Builder GetStroke()
|
||||
{
|
||||
return _strokeDynamicBuilder ?? (_strokeDynamicBuilder = _strokeDynamicData.Map(FrameRenderContext));
|
||||
}
|
||||
|
||||
public void DrawTexturedQuad(IntPtr textureSRV, Vector3 a, Vector3 b, Vector3 c, Vector3 d, uint color)
|
||||
{
|
||||
DrawTexturedQuad(textureSRV, a, b, c, d, color, new Vector2(0f, 0f), new Vector2(1f, 1f));
|
||||
}
|
||||
|
||||
public void DrawTexturedQuad(IntPtr textureSRV, Vector3 a, Vector3 b, Vector3 c, Vector3 d, uint color, Vector2 uvMin, Vector2 uvMax)
|
||||
{
|
||||
QuadBlitter.Data.Builder texturedQuads = GetTexturedQuads();
|
||||
texturedQuads.SetTexture(textureSRV);
|
||||
Vector4 color2 = color.ToVector4();
|
||||
texturedQuads.Add(a, new Vector2(uvMin.X, uvMin.Y), color2);
|
||||
texturedQuads.Add(b, new Vector2(uvMax.X, uvMin.Y), color2);
|
||||
texturedQuads.Add(c, new Vector2(uvMax.X, uvMax.Y), color2);
|
||||
texturedQuads.Add(a, new Vector2(uvMin.X, uvMin.Y), color2);
|
||||
texturedQuads.Add(c, new Vector2(uvMax.X, uvMax.Y), color2);
|
||||
texturedQuads.Add(d, new Vector2(uvMin.X, uvMax.Y), color2);
|
||||
}
|
||||
|
||||
private QuadBlitter.Data.Builder GetTexturedQuads()
|
||||
{
|
||||
return _texturedQuadDynamicBuilder ?? (_texturedQuadDynamicBuilder = _texturedQuadDynamicData.Map(FrameRenderContext));
|
||||
}
|
||||
}
|
||||
288
Auspex/Auspex.Rendering.Direct3D/FanFillShader.cs
Normal file
288
Auspex/Auspex.Rendering.Direct3D/FanFillShader.cs
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using TerraFX.Interop.DirectX;
|
||||
|
||||
namespace Auspex.Rendering.Direct3D;
|
||||
|
||||
internal sealed class FanFillShader : IDisposable
|
||||
{
|
||||
public struct Constants
|
||||
{
|
||||
public Matrix4x4 ViewProj;
|
||||
|
||||
public Vector2 PixelToUv;
|
||||
}
|
||||
|
||||
public struct Instance
|
||||
{
|
||||
public Vector3 Origin;
|
||||
|
||||
public float InnerRadius;
|
||||
|
||||
public float OuterRadius;
|
||||
|
||||
public float MinAngle;
|
||||
|
||||
public float MaxAngle;
|
||||
|
||||
public float NumSegments;
|
||||
|
||||
public Vector4 ColorOrigin;
|
||||
|
||||
public Vector4 ColorEnd;
|
||||
|
||||
public float OccludedAlpha;
|
||||
|
||||
public float OcclusionTolerance;
|
||||
|
||||
public float FadeStart;
|
||||
|
||||
public float FadeStop;
|
||||
}
|
||||
|
||||
public sealed class Data : HlslShaderData<Instance>
|
||||
{
|
||||
public sealed class Builder : HlslShaderBuilder<Instance>
|
||||
{
|
||||
internal Builder(FrameRenderContext ctx, Data data)
|
||||
: base(data._buffer.Map(ctx))
|
||||
{
|
||||
}
|
||||
|
||||
public void Add(Vector3 world, float innerRadius, float outerRadius, float minAngle, float maxAngle, Vector4 colorOrigin, Vector4 colorEnd, float numSegments, AxDxParams p)
|
||||
{
|
||||
_inner.Add(new Instance
|
||||
{
|
||||
Origin = world,
|
||||
InnerRadius = innerRadius,
|
||||
OuterRadius = outerRadius,
|
||||
MinAngle = minAngle,
|
||||
MaxAngle = maxAngle,
|
||||
NumSegments = numSegments,
|
||||
ColorOrigin = colorOrigin,
|
||||
ColorEnd = colorEnd,
|
||||
OccludedAlpha = p.OccludedAlpha,
|
||||
OcclusionTolerance = p.OcclusionTolerance,
|
||||
FadeStart = p.FadeStart,
|
||||
FadeStop = p.FadeStop
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public Data(FrameRenderContext ctx, int maxCount, bool dynamic)
|
||||
: base("Fan", ctx, maxCount, dynamic)
|
||||
{
|
||||
}
|
||||
|
||||
public Builder Map(FrameRenderContext ctx)
|
||||
{
|
||||
return new Builder(ctx, this);
|
||||
}
|
||||
|
||||
public unsafe void DrawAll(FrameRenderContext ctx)
|
||||
{
|
||||
ID3D11Buffer* buffer = _buffer.Buffer;
|
||||
uint elementSize = (uint)_buffer.ElementSize;
|
||||
uint num = 0u;
|
||||
ctx.Context->IASetVertexBuffers(0u, 1u, &buffer, &elementSize, &num);
|
||||
ctx.Context->DrawInstanced(722u, (uint)_buffer.CurElements, 0u, 0u);
|
||||
}
|
||||
}
|
||||
|
||||
private const int VerticesPerInstance = 722;
|
||||
|
||||
private unsafe ID3D11Buffer* _constantBuffer;
|
||||
|
||||
private unsafe ID3D11InputLayout* _il;
|
||||
|
||||
private unsafe ID3D11VertexShader* _vs;
|
||||
|
||||
private unsafe ID3D11PixelShader* _ps;
|
||||
|
||||
public unsafe FanFillShader(FrameRenderContext ctx)
|
||||
{
|
||||
byte[] bytes = Encoding.UTF8.GetBytes("#define PI 3.14159265359f\n#define MAX_SEGMENTS 360\n\ncbuffer Constants : register(b0)\n{\n float4x4 viewProj;\n float2 pixelToUv;\n};\n\nTexture2D<float4> _sceneDepth : register(t0);\nSamplerState _occlusionSampler\n{\n Filter = MIN_MAG_MIP_POINT;\n AddressU = CLAMP;\n AddressV = CLAMP;\n};\n\n// fadeParams: x=OccludedAlpha, y=OcclusionTolerance (m), z=FadeStart (m), w=FadeStop (m).\nfloat4 applyShared(float4 color, float3 projPos, float4 fadeParams)\n{\n float2 uv = projPos.xy * pixelToUv;\n float sceneNdcZ = _sceneDepth.Sample(_occlusionSampler, uv).r;\n\n float near = viewProj._m32;\n float shapeWorldZ = near / max(projPos.z, 1e-6);\n float sceneWorldZ = near / max(sceneNdcZ, 1e-6);\n\n float behindMeters = max(shapeWorldZ - sceneWorldZ, 0.0);\n float occlusion = behindMeters <= fadeParams.y ? 1.0 : fadeParams.x;\n\n float distanceFactor = 1.0;\n if (fadeParams.w < 1e10)\n {\n float range = max(fadeParams.w - fadeParams.z, 1e-4);\n distanceFactor = saturate((fadeParams.w - shapeWorldZ) / range);\n }\n\n color.a *= occlusion * distanceFactor;\n return color;\n}\n\nstruct Fan\n{\n float3 origin : WORLD;\n float innerRadius : RADIUS0;\n float outerRadius : RADIUS1;\n float minAngle : ANGLE0;\n float maxAngle : ANGLE1;\n float numSegments : NUMSEGMENTS;\n float4 colorOrigin : INSTANCECOLOR0;\n float4 colorEnd : INSTANCECOLOR1;\n float4 fadeParams : FADEPARAMS;\n};\n\nstruct VSOutput\n{\n float4 projPos : SV_POSITION;\n float4 color : COLOR;\n float2 tex : TEXCOORD;\n float4 fadeParams : FADEPARAMS;\n};\n\nVSOutput vs(in Fan instance, uint vertexId: SV_VERTEXID, uint instanceId: SV_INSTANCEID)\n{\n VSOutput o;\n\n uint segs = (uint)instance.numSegments;\n uint i = min(vertexId / 2, segs);\n\n float radius = 0;\n if (vertexId % 2 == 0) {\n o.color = instance.colorOrigin;\n o.tex.y = 0;\n radius = instance.innerRadius;\n } else {\n o.color = instance.colorEnd;\n o.tex.y = instance.outerRadius - instance.innerRadius;\n radius = instance.outerRadius;\n }\n float totalAngle = instance.maxAngle - instance.minAngle;\n float angleStep = totalAngle / instance.numSegments;\n float angle = PI / 2 + instance.minAngle + i * angleStep;\n float3 offset = radius * float3(cos(angle), 0, sin(angle));\n\n o.tex.x = angle;\n o.projPos = mul(float4(instance.origin + offset, 1.0), viewProj);\n o.fadeParams = instance.fadeParams;\n return o;\n}\n\nfloat4 ps(VSOutput input) : SV_TARGET\n{\n return applyShared(input.color, input.projPos.xyz, input.fadeParams);\n}");
|
||||
TriangleFillShader.CompileShader(bytes, "vs"u8, "vs_5_0"u8, out var blob, "Circle VS");
|
||||
TriangleFillShader.CompileShader(bytes, "ps"u8, "ps_5_0"u8, out var blob2, "Circle 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 = 80u,
|
||||
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 = "WORLD"u8)
|
||||
{
|
||||
fixed (byte* semanticName2 = "RADIUS"u8)
|
||||
{
|
||||
fixed (byte* semanticName3 = "ANGLE"u8)
|
||||
{
|
||||
fixed (byte* semanticName4 = "NUMSEGMENTS"u8)
|
||||
{
|
||||
fixed (byte* semanticName5 = "INSTANCECOLOR"u8)
|
||||
{
|
||||
fixed (byte* semanticName6 = "FADEPARAMS"u8)
|
||||
{
|
||||
D3D11_INPUT_ELEMENT_DESC* ptr = stackalloc D3D11_INPUT_ELEMENT_DESC[9];
|
||||
*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_INSTANCE_DATA,
|
||||
InstanceDataStepRate = 1u
|
||||
};
|
||||
ptr[1] = new D3D11_INPUT_ELEMENT_DESC
|
||||
{
|
||||
SemanticName = (sbyte*)semanticName2,
|
||||
SemanticIndex = 0u,
|
||||
Format = DXGI_FORMAT.DXGI_FORMAT_R32_FLOAT,
|
||||
AlignedByteOffset = uint.MaxValue,
|
||||
InputSlot = 0u,
|
||||
InputSlotClass = D3D11_INPUT_CLASSIFICATION.D3D11_INPUT_PER_INSTANCE_DATA,
|
||||
InstanceDataStepRate = 1u
|
||||
};
|
||||
ptr[2] = new D3D11_INPUT_ELEMENT_DESC
|
||||
{
|
||||
SemanticName = (sbyte*)semanticName2,
|
||||
SemanticIndex = 1u,
|
||||
Format = DXGI_FORMAT.DXGI_FORMAT_R32_FLOAT,
|
||||
AlignedByteOffset = uint.MaxValue,
|
||||
InputSlot = 0u,
|
||||
InputSlotClass = D3D11_INPUT_CLASSIFICATION.D3D11_INPUT_PER_INSTANCE_DATA,
|
||||
InstanceDataStepRate = 1u
|
||||
};
|
||||
ptr[3] = new D3D11_INPUT_ELEMENT_DESC
|
||||
{
|
||||
SemanticName = (sbyte*)semanticName3,
|
||||
SemanticIndex = 0u,
|
||||
Format = DXGI_FORMAT.DXGI_FORMAT_R32_FLOAT,
|
||||
AlignedByteOffset = uint.MaxValue,
|
||||
InputSlot = 0u,
|
||||
InputSlotClass = D3D11_INPUT_CLASSIFICATION.D3D11_INPUT_PER_INSTANCE_DATA,
|
||||
InstanceDataStepRate = 1u
|
||||
};
|
||||
ptr[4] = new D3D11_INPUT_ELEMENT_DESC
|
||||
{
|
||||
SemanticName = (sbyte*)semanticName3,
|
||||
SemanticIndex = 1u,
|
||||
Format = DXGI_FORMAT.DXGI_FORMAT_R32_FLOAT,
|
||||
AlignedByteOffset = uint.MaxValue,
|
||||
InputSlot = 0u,
|
||||
InputSlotClass = D3D11_INPUT_CLASSIFICATION.D3D11_INPUT_PER_INSTANCE_DATA,
|
||||
InstanceDataStepRate = 1u
|
||||
};
|
||||
ptr[5] = new D3D11_INPUT_ELEMENT_DESC
|
||||
{
|
||||
SemanticName = (sbyte*)semanticName4,
|
||||
SemanticIndex = 0u,
|
||||
Format = DXGI_FORMAT.DXGI_FORMAT_R32_FLOAT,
|
||||
AlignedByteOffset = uint.MaxValue,
|
||||
InputSlot = 0u,
|
||||
InputSlotClass = D3D11_INPUT_CLASSIFICATION.D3D11_INPUT_PER_INSTANCE_DATA,
|
||||
InstanceDataStepRate = 1u
|
||||
};
|
||||
ptr[6] = new D3D11_INPUT_ELEMENT_DESC
|
||||
{
|
||||
SemanticName = (sbyte*)semanticName5,
|
||||
SemanticIndex = 0u,
|
||||
Format = DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||||
AlignedByteOffset = uint.MaxValue,
|
||||
InputSlot = 0u,
|
||||
InputSlotClass = D3D11_INPUT_CLASSIFICATION.D3D11_INPUT_PER_INSTANCE_DATA,
|
||||
InstanceDataStepRate = 1u
|
||||
};
|
||||
ptr[7] = new D3D11_INPUT_ELEMENT_DESC
|
||||
{
|
||||
SemanticName = (sbyte*)semanticName5,
|
||||
SemanticIndex = 1u,
|
||||
Format = DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||||
AlignedByteOffset = uint.MaxValue,
|
||||
InputSlot = 0u,
|
||||
InputSlotClass = D3D11_INPUT_CLASSIFICATION.D3D11_INPUT_PER_INSTANCE_DATA,
|
||||
InstanceDataStepRate = 1u
|
||||
};
|
||||
ptr[8] = new D3D11_INPUT_ELEMENT_DESC
|
||||
{
|
||||
SemanticName = (sbyte*)semanticName6,
|
||||
SemanticIndex = 0u,
|
||||
Format = DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||||
AlignedByteOffset = uint.MaxValue,
|
||||
InputSlot = 0u,
|
||||
InputSlotClass = D3D11_INPUT_CLASSIFICATION.D3D11_INPUT_PER_INSTANCE_DATA,
|
||||
InstanceDataStepRate = 1u
|
||||
};
|
||||
ID3D11InputLayout* il = default(ID3D11InputLayout*);
|
||||
Marshal.ThrowExceptionForHR(ctx.Device->CreateInputLayout(ptr, 9u, blob->GetBufferPointer(), blob->GetBufferSize(), &il));
|
||||
_il = il;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
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_TRIANGLESTRIP);
|
||||
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);
|
||||
ctx.Context->PSSetConstantBuffers(0u, 1u, &constantBuffer);
|
||||
ctx.Context->GSSetShader(null, null, 0u);
|
||||
}
|
||||
|
||||
public void Draw(FrameRenderContext ctx, Data data)
|
||||
{
|
||||
Bind(ctx);
|
||||
data.DrawAll(ctx);
|
||||
}
|
||||
}
|
||||
49
Auspex/Auspex.Rendering.Direct3D/FrameRenderContext.cs
Normal file
49
Auspex/Auspex.Rendering.Direct3D/FrameRenderContext.cs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using TerraFX.Interop.DirectX;
|
||||
|
||||
namespace Auspex.Rendering.Direct3D;
|
||||
|
||||
internal sealed class FrameRenderContext : IDisposable
|
||||
{
|
||||
public unsafe ID3D11Device* Device { get; private set; }
|
||||
|
||||
public unsafe ID3D11DeviceContext* Context { get; private set; }
|
||||
|
||||
public unsafe FrameRenderContext()
|
||||
{
|
||||
Device = (ID3D11Device*)FFXIVClientStructs.FFXIV.Client.Graphics.Kernel.Device.Instance()->D3D11Forwarder;
|
||||
Device->AddRef();
|
||||
ID3D11DeviceContext* context = default(ID3D11DeviceContext*);
|
||||
Marshal.ThrowExceptionForHR(Device->CreateDeferredContext(0u, &context));
|
||||
Context = context;
|
||||
}
|
||||
|
||||
public unsafe void Dispose()
|
||||
{
|
||||
if (Context != null)
|
||||
{
|
||||
Context->Release();
|
||||
Context = null;
|
||||
}
|
||||
if (Device != null)
|
||||
{
|
||||
Device->Release();
|
||||
Device = null;
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public unsafe void Execute()
|
||||
{
|
||||
ID3D11CommandList* ptr = default(ID3D11CommandList*);
|
||||
Marshal.ThrowExceptionForHR(Context->FinishCommandList(false, &ptr));
|
||||
ID3D11DeviceContext* ptr2 = default(ID3D11DeviceContext*);
|
||||
Device->GetImmediateContext(&ptr2);
|
||||
ptr2->ExecuteCommandList(ptr, true);
|
||||
ptr2->Release();
|
||||
ptr->Release();
|
||||
Context->ClearState();
|
||||
}
|
||||
}
|
||||
293
Auspex/Auspex.Rendering.Direct3D/FrameRenderTarget.cs
Normal file
293
Auspex/Auspex.Rendering.Direct3D/FrameRenderTarget.cs
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
91
Auspex/Auspex.Rendering.Direct3D/FullscreenPassShader.cs
Normal file
91
Auspex/Auspex.Rendering.Direct3D/FullscreenPassShader.cs
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
147
Auspex/Auspex.Rendering.Direct3D/GpuBuffer.cs
Normal file
147
Auspex/Auspex.Rendering.Direct3D/GpuBuffer.cs
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
146
Auspex/Auspex.Rendering.Direct3D/HighResFontAtlas.cs
Normal file
146
Auspex/Auspex.Rendering.Direct3D/HighResFontAtlas.cs
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using TerraFX.Interop.DirectX;
|
||||
|
||||
namespace Auspex.Rendering.Direct3D;
|
||||
|
||||
internal sealed class HighResFontAtlas : IDisposable
|
||||
{
|
||||
private struct ImFontConfigHead
|
||||
{
|
||||
public IntPtr FontData;
|
||||
|
||||
public int FontDataSize;
|
||||
|
||||
public byte FontDataOwnedByAtlas;
|
||||
|
||||
private byte _pad1;
|
||||
|
||||
private byte _pad2;
|
||||
|
||||
private byte _pad3;
|
||||
|
||||
public int FontNo;
|
||||
|
||||
public float SizePixels;
|
||||
}
|
||||
|
||||
private const float HighResFontSize = 64f;
|
||||
|
||||
private IntPtr _atlas;
|
||||
|
||||
private unsafe ID3D11Texture2D* _texture;
|
||||
|
||||
private unsafe ID3D11ShaderResourceView* _srv;
|
||||
|
||||
public ImFontPtr Font { get; }
|
||||
|
||||
public unsafe IntPtr TextureSRV => (nint)_srv;
|
||||
|
||||
public unsafe HighResFontAtlas(FrameRenderContext ctx)
|
||||
{
|
||||
_atlas = ImFontAtlas_ImFontAtlas();
|
||||
try
|
||||
{
|
||||
IntPtr intPtr = ImFontConfig_ImFontConfig();
|
||||
try
|
||||
{
|
||||
((ImFontConfigHead*)intPtr)->SizePixels = 64f;
|
||||
IntPtr intPtr2 = ImFontAtlas_AddFontDefault(_atlas, intPtr);
|
||||
Font = Unsafe.As<IntPtr, ImFontPtr>(ref intPtr2);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ImFontConfig_destroy(intPtr);
|
||||
}
|
||||
if (!ImFontAtlas_Build(_atlas))
|
||||
{
|
||||
throw new InvalidOperationException("Failed to build high-res font atlas");
|
||||
}
|
||||
byte* pSysMem = default(byte*);
|
||||
int num = default(int);
|
||||
int height = default(int);
|
||||
int num2 = default(int);
|
||||
ImFontAtlas_GetTexDataAsRGBA32(_atlas, 0, &pSysMem, &num, &height, &num2);
|
||||
D3D11_TEXTURE2D_DESC d3D11_TEXTURE2D_DESC = new D3D11_TEXTURE2D_DESC
|
||||
{
|
||||
Width = (uint)num,
|
||||
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 = 8u
|
||||
};
|
||||
D3D11_SUBRESOURCE_DATA d3D11_SUBRESOURCE_DATA = new D3D11_SUBRESOURCE_DATA
|
||||
{
|
||||
pSysMem = pSysMem,
|
||||
SysMemPitch = (uint)(num * num2)
|
||||
};
|
||||
ID3D11Texture2D* texture = default(ID3D11Texture2D*);
|
||||
Marshal.ThrowExceptionForHR(ctx.Device->CreateTexture2D(&d3D11_TEXTURE2D_DESC, &d3D11_SUBRESOURCE_DATA, &texture));
|
||||
_texture = texture;
|
||||
ID3D11ShaderResourceView* srv = default(ID3D11ShaderResourceView*);
|
||||
Marshal.ThrowExceptionForHR(ctx.Device->CreateShaderResourceView((ID3D11Resource*)_texture, null, &srv));
|
||||
_srv = srv;
|
||||
ImFontAtlas_ClearTexData(_atlas);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void Dispose()
|
||||
{
|
||||
if (_srv != null)
|
||||
{
|
||||
_srv->Release();
|
||||
_srv = null;
|
||||
}
|
||||
if (_texture != null)
|
||||
{
|
||||
_texture->Release();
|
||||
_texture = null;
|
||||
}
|
||||
if (_atlas != (IntPtr)0)
|
||||
{
|
||||
ImFontAtlas_destroy(_atlas);
|
||||
_atlas = (IntPtr)0;
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
[DllImport("cimgui")]
|
||||
private static extern IntPtr ImFontAtlas_ImFontAtlas();
|
||||
|
||||
[DllImport("cimgui")]
|
||||
private static extern void ImFontAtlas_destroy(IntPtr self);
|
||||
|
||||
[DllImport("cimgui")]
|
||||
private static extern IntPtr ImFontAtlas_AddFontDefault(IntPtr self, IntPtr font_cfg);
|
||||
|
||||
[DllImport("cimgui")]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
private static extern bool ImFontAtlas_Build(IntPtr self);
|
||||
|
||||
[DllImport("cimgui")]
|
||||
private unsafe static extern void ImFontAtlas_GetTexDataAsRGBA32(IntPtr self, int texture_index, byte** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel);
|
||||
|
||||
[DllImport("cimgui")]
|
||||
private static extern void ImFontAtlas_ClearTexData(IntPtr self);
|
||||
|
||||
[DllImport("cimgui")]
|
||||
private static extern IntPtr ImFontConfig_ImFontConfig();
|
||||
|
||||
[DllImport("cimgui")]
|
||||
private static extern void ImFontConfig_destroy(IntPtr self);
|
||||
}
|
||||
24
Auspex/Auspex.Rendering.Direct3D/HlslShaderBuilder.cs
Normal file
24
Auspex/Auspex.Rendering.Direct3D/HlslShaderBuilder.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
|
||||
namespace Auspex.Rendering.Direct3D;
|
||||
|
||||
internal abstract class HlslShaderBuilder<TElement> : IDisposable where TElement : unmanaged
|
||||
{
|
||||
private protected readonly GpuBuffer<TElement>.Builder _inner;
|
||||
|
||||
protected HlslShaderBuilder(GpuBuffer<TElement>.Builder inner)
|
||||
{
|
||||
_inner = inner;
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
_inner.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public void Add(ref TElement inst)
|
||||
{
|
||||
_inner.Add(ref inst);
|
||||
}
|
||||
}
|
||||
29
Auspex/Auspex.Rendering.Direct3D/HlslShaderData.cs
Normal file
29
Auspex/Auspex.Rendering.Direct3D/HlslShaderData.cs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using TerraFX.Interop.DirectX;
|
||||
|
||||
namespace Auspex.Rendering.Direct3D;
|
||||
|
||||
internal abstract class HlslShaderData<TElement> : IDisposable where TElement : unmanaged
|
||||
{
|
||||
private protected readonly GpuBuffer<TElement> _buffer;
|
||||
|
||||
protected HlslShaderData(string name, FrameRenderContext ctx, int maxCount, bool dynamic)
|
||||
{
|
||||
_buffer = new GpuBuffer<TElement>(name, ctx, maxCount, 1u, dynamic);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_buffer.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private protected unsafe void DrawVertices(FrameRenderContext ctx, int first, int count)
|
||||
{
|
||||
ID3D11Buffer* buffer = _buffer.Buffer;
|
||||
uint elementSize = (uint)_buffer.ElementSize;
|
||||
uint num = 0u;
|
||||
ctx.Context->IASetVertexBuffers(0u, 1u, &buffer, &elementSize, &num);
|
||||
ctx.Context->Draw((uint)count, (uint)first);
|
||||
}
|
||||
}
|
||||
264
Auspex/Auspex.Rendering.Direct3D/QuadBlitter.cs
Normal file
264
Auspex/Auspex.Rendering.Direct3D/QuadBlitter.cs
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
98
Auspex/Auspex.Rendering.Direct3D/SceneDepthCapture.cs
Normal file
98
Auspex/Auspex.Rendering.Direct3D/SceneDepthCapture.cs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||
using TerraFX.Interop.DirectX;
|
||||
|
||||
namespace Auspex.Rendering.Direct3D;
|
||||
|
||||
internal sealed class SceneDepthCapture : IDisposable
|
||||
{
|
||||
private unsafe ID3D11Texture2D* _copy;
|
||||
|
||||
private unsafe ID3D11ShaderResourceView* _copySRV;
|
||||
|
||||
private uint _copyWidth;
|
||||
|
||||
private uint _copyHeight;
|
||||
|
||||
public unsafe ID3D11ShaderResourceView* SRV => _copySRV;
|
||||
|
||||
public Vector2 UvScale { get; private set; } = new Vector2(1f, 1f);
|
||||
|
||||
public bool IsResolutionScaled { get; private set; }
|
||||
|
||||
public unsafe void Dispose()
|
||||
{
|
||||
if (_copySRV != null)
|
||||
{
|
||||
_copySRV->Release();
|
||||
_copySRV = null;
|
||||
}
|
||||
if (_copy != null)
|
||||
{
|
||||
_copy->Release();
|
||||
_copy = null;
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
internal unsafe void Update()
|
||||
{
|
||||
RenderTargetManager* ptr = RenderTargetManager.Instance();
|
||||
Texture* ptr2 = ((ptr != null) ? ptr->DepthStencil : null);
|
||||
if (ptr2 == null || ptr2->D3D11Texture2D == null)
|
||||
{
|
||||
AuspexService.Log.Warning("[Auspex] SceneDepthCapture: scene depth source unavailable.");
|
||||
return;
|
||||
}
|
||||
Device* ptr3 = Device.Instance();
|
||||
IsResolutionScaled = ptr2->ActualWidth != ptr3->Width || ptr2->ActualHeight != ptr3->Height;
|
||||
ID3D11Texture2D* d3D11Texture2D = (ID3D11Texture2D*)ptr2->D3D11Texture2D;
|
||||
D3D11_TEXTURE2D_DESC srcDesc = default(D3D11_TEXTURE2D_DESC);
|
||||
d3D11Texture2D->GetDesc(&srcDesc);
|
||||
EnsureCopy(srcDesc);
|
||||
ID3D11DeviceContext* ptr4 = default(ID3D11DeviceContext*);
|
||||
((ID3D11Device*)ptr3->D3D11Forwarder)->GetImmediateContext(&ptr4);
|
||||
ptr4->CopyResource((ID3D11Resource*)_copy, (ID3D11Resource*)d3D11Texture2D);
|
||||
ptr4->Release();
|
||||
UvScale = new Vector2((ptr2->AllocatedWidth != 0) ? ((float)ptr2->ActualWidth / (float)ptr2->AllocatedWidth) : 1f, (ptr2->AllocatedHeight != 0) ? ((float)ptr2->ActualHeight / (float)ptr2->AllocatedHeight) : 1f);
|
||||
}
|
||||
|
||||
private unsafe void EnsureCopy(D3D11_TEXTURE2D_DESC srcDesc)
|
||||
{
|
||||
if (_copy == null || _copyWidth != srcDesc.Width || _copyHeight != srcDesc.Height)
|
||||
{
|
||||
if (_copySRV != null)
|
||||
{
|
||||
_copySRV->Release();
|
||||
_copySRV = null;
|
||||
}
|
||||
if (_copy != null)
|
||||
{
|
||||
_copy->Release();
|
||||
_copy = null;
|
||||
}
|
||||
ID3D11Device* d3D11Forwarder = (ID3D11Device*)Device.Instance()->D3D11Forwarder;
|
||||
D3D11_TEXTURE2D_DESC d3D11_TEXTURE2D_DESC = srcDesc;
|
||||
d3D11_TEXTURE2D_DESC.Format = DXGI_FORMAT.DXGI_FORMAT_R24G8_TYPELESS;
|
||||
d3D11_TEXTURE2D_DESC.BindFlags = 8u;
|
||||
ID3D11Texture2D* copy = default(ID3D11Texture2D*);
|
||||
Marshal.ThrowExceptionForHR(d3D11Forwarder->CreateTexture2D(&d3D11_TEXTURE2D_DESC, null, ©));
|
||||
_copy = copy;
|
||||
_copyWidth = srcDesc.Width;
|
||||
_copyHeight = srcDesc.Height;
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC d3D11_SHADER_RESOURCE_VIEW_DESC = new D3D11_SHADER_RESOURCE_VIEW_DESC
|
||||
{
|
||||
Format = DXGI_FORMAT.DXGI_FORMAT_R24_UNORM_X8_TYPELESS,
|
||||
ViewDimension = D3D_SRV_DIMENSION.D3D_SRV_DIMENSION_TEXTURE2D
|
||||
};
|
||||
d3D11_SHADER_RESOURCE_VIEW_DESC.Texture2D.MostDetailedMip = 0u;
|
||||
d3D11_SHADER_RESOURCE_VIEW_DESC.Texture2D.MipLevels = 1u;
|
||||
ID3D11ShaderResourceView* copySRV = default(ID3D11ShaderResourceView*);
|
||||
Marshal.ThrowExceptionForHR(d3D11Forwarder->CreateShaderResourceView((ID3D11Resource*)_copy, &d3D11_SHADER_RESOURCE_VIEW_DESC, ©SRV));
|
||||
_copySRV = copySRV;
|
||||
}
|
||||
}
|
||||
}
|
||||
6
Auspex/Auspex.Rendering.Direct3D/ShapeSharedShader.cs
Normal file
6
Auspex/Auspex.Rendering.Direct3D/ShapeSharedShader.cs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
namespace Auspex.Rendering.Direct3D;
|
||||
|
||||
internal static class ShapeSharedShader
|
||||
{
|
||||
public const string Mixin = "\nTexture2D<float4> _sceneDepth : register(t0);\nSamplerState _occlusionSampler\n{\n Filter = MIN_MAG_MIP_POINT;\n AddressU = CLAMP;\n AddressV = CLAMP;\n};\n\n// fadeParams: x=OccludedAlpha, y=OcclusionTolerance (m), z=FadeStart (m), w=FadeStop (m).\nfloat4 applyShared(float4 color, float3 projPos, float4 fadeParams)\n{\n float2 uv = projPos.xy * pixelToUv;\n float sceneNdcZ = _sceneDepth.Sample(_occlusionSampler, uv).r;\n\n float near = viewProj._m32;\n float shapeWorldZ = near / max(projPos.z, 1e-6);\n float sceneWorldZ = near / max(sceneNdcZ, 1e-6);\n\n float behindMeters = max(shapeWorldZ - sceneWorldZ, 0.0);\n float occlusion = behindMeters <= fadeParams.y ? 1.0 : fadeParams.x;\n\n float distanceFactor = 1.0;\n if (fadeParams.w < 1e10)\n {\n float range = max(fadeParams.w - fadeParams.z, 1e-4);\n distanceFactor = saturate((fadeParams.w - shapeWorldZ) / range);\n }\n\n color.a *= occlusion * distanceFactor;\n return color;\n}";
|
||||
}
|
||||
503
Auspex/Auspex.Rendering.Direct3D/StrokeShader.cs
Normal file
503
Auspex/Auspex.Rendering.Direct3D/StrokeShader.cs
Normal file
File diff suppressed because one or more lines are too long
225
Auspex/Auspex.Rendering.Direct3D/TriangleFillShader.cs
Normal file
225
Auspex/Auspex.Rendering.Direct3D/TriangleFillShader.cs
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using TerraFX.Interop.DirectX;
|
||||
using TerraFX.Interop.Windows;
|
||||
|
||||
namespace Auspex.Rendering.Direct3D;
|
||||
|
||||
internal sealed class TriangleFillShader : IDisposable
|
||||
{
|
||||
public struct Constants
|
||||
{
|
||||
public Matrix4x4 ViewProj;
|
||||
|
||||
public Vector2 PixelToUv;
|
||||
}
|
||||
|
||||
public struct Instance
|
||||
{
|
||||
public Vector3 Point;
|
||||
|
||||
public Vector4 Color;
|
||||
|
||||
public Vector4 FadeParams;
|
||||
}
|
||||
|
||||
public sealed class Data : HlslShaderData<Instance>
|
||||
{
|
||||
public sealed class Builder : HlslShaderBuilder<Instance>
|
||||
{
|
||||
internal Builder(FrameRenderContext ctx, Data data)
|
||||
: base(data._buffer.Map(ctx))
|
||||
{
|
||||
}
|
||||
|
||||
public void Add(Vector3 world, Vector4 color, AxDxParams p)
|
||||
{
|
||||
_inner.Add(new Instance
|
||||
{
|
||||
Point = world,
|
||||
Color = color,
|
||||
FadeParams = new Vector4(p.OccludedAlpha, p.OcclusionTolerance, p.FadeStart, p.FadeStop)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public Data(FrameRenderContext ctx, int maxCount, bool dynamic)
|
||||
: base("Triangle", ctx, maxCount, dynamic)
|
||||
{
|
||||
}
|
||||
|
||||
public Builder Map(FrameRenderContext ctx)
|
||||
{
|
||||
return new Builder(ctx, this);
|
||||
}
|
||||
|
||||
public void DrawSubset(FrameRenderContext ctx, int firstPoint, int numPoints)
|
||||
{
|
||||
DrawVertices(ctx, firstPoint, numPoints);
|
||||
}
|
||||
|
||||
public void DrawAll(FrameRenderContext ctx)
|
||||
{
|
||||
DrawVertices(ctx, 0, _buffer.CurElements);
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe ID3D11Buffer* _constantBuffer;
|
||||
|
||||
private unsafe ID3D11InputLayout* _il;
|
||||
|
||||
private unsafe ID3D11VertexShader* _vs;
|
||||
|
||||
private unsafe ID3D11PixelShader* _ps;
|
||||
|
||||
public unsafe TriangleFillShader(FrameRenderContext ctx)
|
||||
{
|
||||
byte[] bytes = Encoding.UTF8.GetBytes("cbuffer Constants : register(b0)\n{\n float4x4 viewProj;\n float2 pixelToUv;\n};\n\nTexture2D<float4> _sceneDepth : register(t0);\nSamplerState _occlusionSampler\n{\n Filter = MIN_MAG_MIP_POINT;\n AddressU = CLAMP;\n AddressV = CLAMP;\n};\n\n// fadeParams: x=OccludedAlpha, y=OcclusionTolerance (m), z=FadeStart (m), w=FadeStop (m).\nfloat4 applyShared(float4 color, float3 projPos, float4 fadeParams)\n{\n float2 uv = projPos.xy * pixelToUv;\n float sceneNdcZ = _sceneDepth.Sample(_occlusionSampler, uv).r;\n\n float near = viewProj._m32;\n float shapeWorldZ = near / max(projPos.z, 1e-6);\n float sceneWorldZ = near / max(sceneNdcZ, 1e-6);\n\n float behindMeters = max(shapeWorldZ - sceneWorldZ, 0.0);\n float occlusion = behindMeters <= fadeParams.y ? 1.0 : fadeParams.x;\n\n float distanceFactor = 1.0;\n if (fadeParams.w < 1e10)\n {\n float range = max(fadeParams.w - fadeParams.z, 1e-4);\n distanceFactor = saturate((fadeParams.w - shapeWorldZ) / range);\n }\n\n color.a *= occlusion * distanceFactor;\n return color;\n}\n\nstruct Point\n{\n float3 pos : WORLD;\n float4 color : COLOR;\n float4 fadeParams : FADEPARAMS;\n};\n\nstruct VSOutput\n{\n float4 projPos : SV_POSITION;\n float4 color : COLOR;\n float4 fadeParams : FADEPARAMS;\n};\n\nVSOutput vs(Point v)\n{\n VSOutput vs;\n vs.projPos = mul(float4(v.pos, 1), viewProj);\n vs.color = v.color;\n vs.fadeParams = v.fadeParams;\n return vs;\n}\n\nfloat4 ps(VSOutput input) : SV_TARGET\n{\n return applyShared(input.color, input.projPos.xyz, input.fadeParams);\n}");
|
||||
CompileShader(bytes, "vs"u8, "vs_5_0"u8, out var blob, "Point VS");
|
||||
CompileShader(bytes, "ps"u8, "ps_5_0"u8, out var blob2, "Point 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 = 80u,
|
||||
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 = "WORLD"u8)
|
||||
{
|
||||
fixed (byte* semanticName2 = "COLOR"u8)
|
||||
{
|
||||
fixed (byte* semanticName3 = "FADEPARAMS"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_R32G32B32A32_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
ctx.Context->PSSetConstantBuffers(0u, 1u, &constantBuffer);
|
||||
ctx.Context->GSSetShader(null, null, 0u);
|
||||
}
|
||||
|
||||
public void Draw(FrameRenderContext ctx, Data data)
|
||||
{
|
||||
Bind(ctx);
|
||||
data.DrawAll(ctx);
|
||||
}
|
||||
|
||||
internal unsafe static void CompileShader(ReadOnlySpan<byte> source, ReadOnlySpan<byte> entryPoint, ReadOnlySpan<byte> target, out ID3DBlob* blob, string label)
|
||||
{
|
||||
ID3DBlob* ptr = null;
|
||||
ID3DBlob* ptr2 = null;
|
||||
HRESULT hRESULT;
|
||||
fixed (byte* pSrcData = source)
|
||||
{
|
||||
fixed (byte* pEntrypoint = entryPoint)
|
||||
{
|
||||
fixed (byte* pTarget = target)
|
||||
{
|
||||
hRESULT = DirectX.D3DCompile(pSrcData, (nuint)source.Length, null, null, null, (sbyte*)pEntrypoint, (sbyte*)pTarget, 0u, 0u, &ptr, &ptr2);
|
||||
}
|
||||
}
|
||||
}
|
||||
string text = null;
|
||||
if (ptr2 != null)
|
||||
{
|
||||
text = Encoding.UTF8.GetString((byte*)ptr2->GetBufferPointer(), (int)(nuint)ptr2->GetBufferSize()).TrimEnd('\0');
|
||||
ptr2->Release();
|
||||
}
|
||||
AuspexService.Log.Debug(label + " compile: " + text);
|
||||
if (hRESULT.FAILED)
|
||||
{
|
||||
if (ptr != null)
|
||||
{
|
||||
ptr->Release();
|
||||
}
|
||||
throw new InvalidOperationException("Shader compilation failed (" + label + "): " + text);
|
||||
}
|
||||
blob = ptr;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue