134 lines
4.4 KiB
C#
134 lines
4.4 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
using System.Windows;
|
|
using System.Windows.Threading;
|
|
using Intromat.DXExt;
|
|
using Intromat.Pipelines;
|
|
using SharpDX.Direct3D;
|
|
using SharpDX.Direct3D9;
|
|
using Splat;
|
|
using D3D11 = SharpDX.Direct3D11;
|
|
|
|
namespace Intromat.Graphics
|
|
{
|
|
public class DxHost
|
|
{
|
|
public delegate void RenderDelegate(D3D11.Device device, D3D11.DeviceContext deviceContext);
|
|
|
|
public readonly ConcurrentQueue<RenderDelegate> _actionQueue;
|
|
public readonly D3D11.Device Device;
|
|
private readonly Thread _renderThread;
|
|
private IntPtr _renderWindowHandle;
|
|
public DeviceEx? D3D9Device;
|
|
public Dispatcher? RenderDispatcher;
|
|
public Dispatcher? MainDispatcher;
|
|
private readonly ManualResetEvent _renderThreadStarted = new(false);
|
|
public readonly D3D11.UserDefinedAnnotation? _annotation;
|
|
public readonly GraphicsAnalysis? _graphicsAnalysis;
|
|
|
|
public DxHost()
|
|
{
|
|
#if DEBUG
|
|
var flags = D3D11.DeviceCreationFlags.Debug;
|
|
#else
|
|
var flags = D3D11.DeviceCreationFlags.None;
|
|
#endif
|
|
Device = new D3D11.Device(DriverType.Hardware, flags);
|
|
_annotation = Device.ImmediateContext.QueryInterface<D3D11.UserDefinedAnnotation>();
|
|
_graphicsAnalysis = DebugInterface.TryCreateGraphicsAnalysis();
|
|
|
|
_actionQueue = new();
|
|
_renderThread = new(RenderThreadStart) { Name = "WPF SwapChain" };
|
|
_renderThread.SetApartmentState(ApartmentState.STA);
|
|
_renderThread.Start();
|
|
_renderThreadStarted.WaitOne();
|
|
|
|
var device = Device;
|
|
var context = Device.ImmediateContext;
|
|
MainDispatcher = Dispatcher.CurrentDispatcher;
|
|
Locator.CurrentMutable.Register(() => new DisplayTexturePipeline(device, context));
|
|
}
|
|
|
|
public void Load(Window window)
|
|
{
|
|
_renderWindowHandle = Process.GetCurrentProcess().MainWindowHandle;
|
|
CreateDevice();
|
|
}
|
|
|
|
public void Unload()
|
|
{
|
|
RenderDispatcher?.BeginInvokeShutdown(DispatcherPriority.Background);
|
|
RenderDispatcher = null;
|
|
}
|
|
|
|
private void RenderThreadStart(object? o)
|
|
{
|
|
RenderDispatcher = Dispatcher.CurrentDispatcher;
|
|
RenderDispatcher.BeginInvoke(new Action(UpdateFrameTick));
|
|
_renderThreadStarted.Set();
|
|
Dispatcher.Run();
|
|
}
|
|
|
|
private void UpdateFrameTick()
|
|
{
|
|
if (RenderDispatcher == null)
|
|
return;
|
|
|
|
if (_actionQueue.Count == 0)
|
|
{
|
|
RenderDispatcher.BeginInvoke(new Action(UpdateFrameTick), DispatcherPriority.Background);
|
|
return;
|
|
}
|
|
|
|
EnsureTargetDevice();
|
|
while (_actionQueue.TryDequeue(out var action))
|
|
action(Device, Device.ImmediateContext);
|
|
|
|
RenderDispatcher?.BeginInvoke(new Action(UpdateFrameTick), DispatcherPriority.Render);
|
|
}
|
|
|
|
public void EnqueueAction(RenderDelegate action)
|
|
{
|
|
_actionQueue.Enqueue(action);
|
|
}
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern IntPtr MonitorFromWindow(IntPtr hWnd, int flags);
|
|
|
|
private void EnsureTargetDevice()
|
|
{
|
|
if (D3D9Device != null)
|
|
return;
|
|
|
|
MainDispatcher!.Invoke(CreateDevice);
|
|
}
|
|
|
|
private void CreateDevice()
|
|
{
|
|
var d3d9Ex = new Direct3DEx();
|
|
var adapter = 0;
|
|
|
|
if (d3d9Ex.AdapterCount > 1)
|
|
{
|
|
const int monitorDefaultToNearest = 2;
|
|
var hMon = MonitorFromWindow(_renderWindowHandle, monitorDefaultToNearest);
|
|
|
|
foreach (var a in d3d9Ex.AdaptersEx)
|
|
if (a.Monitor == hMon)
|
|
adapter = a.Adapter;
|
|
}
|
|
|
|
var parameters = new PresentParameters
|
|
{
|
|
PresentationInterval = PresentInterval.Immediate,
|
|
SwapEffect = SwapEffect.Discard,
|
|
Windowed = true
|
|
};
|
|
|
|
D3D9Device = new DeviceEx(d3d9Ex, adapter, DeviceType.Hardware, _renderWindowHandle, CreateFlags.HardwareVertexProcessing | CreateFlags.FpuPreserve | CreateFlags.Multithreaded, parameters);
|
|
}
|
|
}
|
|
} |