283 lines
12 KiB
C#
283 lines
12 KiB
C#
#nullable enable
|
|
using System.Diagnostics;
|
|
using SharpDX.Direct3D11;
|
|
using SharpDX.DXGI;
|
|
using SharpDX.Mathematics.Interop;
|
|
using T3.Core.DataTypes;
|
|
using T3.Core.DataTypes.Vector;
|
|
using T3.Core.Operator;
|
|
using T3.Core.Operator.Slots;
|
|
using T3.Core.Resource;
|
|
using T3.Editor.Gui.Windows;
|
|
using Device = SharpDX.Direct3D11.Device;
|
|
using Texture2D = T3.Core.DataTypes.Texture2D;
|
|
using Utilities = T3.Core.Utils.Utilities;
|
|
|
|
namespace T3.Editor.Gui.OutputUi;
|
|
|
|
internal sealed class CommandOutputUi : OutputUi<Command>
|
|
{
|
|
public bool GizmosEnabled { get; set; } = false;
|
|
|
|
internal CommandOutputUi()
|
|
{
|
|
_onGridInstanceDisposed = OnGridInstanceDisposed;
|
|
|
|
// ensure op exists for drawing grid
|
|
var outputWindowGridSymbolId = Guid.Parse("e5588101-5686-4b02-ab7d-e58199ba552e");
|
|
|
|
if(!SymbolRegistry.TryGetSymbol(outputWindowGridSymbolId, out var outputWindowGridSymbol))
|
|
{
|
|
Log.Error("CommandOutputUi: Could not find grid Gizmo symbol");
|
|
return;
|
|
}
|
|
|
|
_outputWindowGridSymbol = outputWindowGridSymbol;
|
|
}
|
|
|
|
protected override void Recompute(ISlot slot, EvaluationContext context)
|
|
{
|
|
if (!EnsureGridOutputsExist())
|
|
{
|
|
return;
|
|
}
|
|
|
|
var originalCamMatrix = context.WorldToCamera;
|
|
var originalViewMatrix = context.CameraToClipSpace;
|
|
|
|
// Invalidate
|
|
StartInvalidation(slot);
|
|
|
|
// Setup render target - TODO: this should not be done for all 'Command' outputs as most of them don't produce image content
|
|
var device = ResourceManager.Device;
|
|
|
|
var size = context.RequestedResolution;
|
|
UpdateTextures(device, size, Format.R16G16B16A16_Float);
|
|
var deviceContext = device.ImmediateContext;
|
|
var prevViewports = deviceContext.Rasterizer.GetViewports<RawViewportF>();
|
|
|
|
RenderTargetView?[]? prevTargetViews = deviceContext.OutputMerger.GetRenderTargets(2);
|
|
deviceContext.Rasterizer.SetViewport(new SharpDX.Viewport(0, 0, size.Width, size.Height, 0.0f, 1.0f));
|
|
deviceContext.OutputMerger.SetTargets(_msaaDepthBufferDsv, _msaaColorBufferRtv);
|
|
|
|
var colorRgba = new RawColor4(context.BackgroundColor.X,
|
|
context.BackgroundColor.Y,
|
|
context.BackgroundColor.Z,
|
|
context.BackgroundColor.W);
|
|
deviceContext.ClearRenderTargetView(_msaaColorBufferRtv, colorRgba);
|
|
if (_msaaDepthBufferDsv != null)
|
|
deviceContext.ClearDepthStencilView(_msaaDepthBufferDsv, DepthStencilClearFlags.Depth, 1.0f, 0);
|
|
|
|
// Evaluate the operator
|
|
slot.Update(context);
|
|
|
|
if (context.ShowGizmos != T3.Core.Operator.GizmoVisibility.Off)
|
|
{
|
|
context.WorldToCamera = originalCamMatrix;
|
|
context.CameraToClipSpace = originalViewMatrix;
|
|
|
|
if(_gridOutputs != null && _gridOutputs.Count > 0)
|
|
{
|
|
var outputSlot = _gridOutputs[0];
|
|
outputSlot.InvalidateGraph();
|
|
outputSlot.Update(context);
|
|
}
|
|
}
|
|
|
|
if (MsaaSampleCount > 1 && _msaaColorBuffer != null && _resolvedColorBuffer != null)
|
|
{
|
|
try
|
|
{
|
|
deviceContext.ResolveSubresource(_msaaColorBuffer, 0, _resolvedColorBuffer, 0,
|
|
_resolvedColorBuffer.Description.Format);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Log.Warning("Failed to resolve MSAA buffer: " + e.Message);
|
|
}
|
|
}
|
|
|
|
// Restore previous setup
|
|
deviceContext.Rasterizer.SetViewports(prevViewports);
|
|
deviceContext.OutputMerger.SetTargets(prevTargetViews);
|
|
|
|
if (prevTargetViews == null)
|
|
{
|
|
Log.Warning("Can't dispose obsolete RenderTargetView after draw. This indicates corrupted a render context.");
|
|
}
|
|
else
|
|
{
|
|
// Clean up ref counts for RTVs
|
|
foreach (var t in prevTargetViews)
|
|
{
|
|
if (t == null || t.IsDisposed)
|
|
continue;
|
|
|
|
t.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool EnsureGridOutputsExist()
|
|
{
|
|
if (_gridOutputs != null)
|
|
return true;
|
|
|
|
if (_outputWindowGridSymbol == null || !_outputWindowGridSymbol.TryGetParentlessInstance(out var gridInstance))
|
|
{
|
|
Log.Error($"{nameof(CommandOutputUi)} Could not create grid instance");
|
|
return false;
|
|
}
|
|
|
|
gridInstance.Disposing += _onGridInstanceDisposed;
|
|
_gridInstance = gridInstance;
|
|
_gridOutputs = gridInstance.Outputs;
|
|
return true;
|
|
}
|
|
|
|
private void OnGridInstanceDisposed(IResourceConsumer gridInstanceAsResourceConsumer)
|
|
{
|
|
_gridOutputs = null;
|
|
_gridInstance!.Disposing -= _onGridInstanceDisposed;
|
|
_gridInstance = null;
|
|
}
|
|
|
|
public override IOutputUi Clone()
|
|
{
|
|
return new CommandOutputUi()
|
|
{
|
|
OutputDefinition = OutputDefinition,
|
|
PosOnCanvas = PosOnCanvas,
|
|
Size = Size
|
|
};
|
|
}
|
|
|
|
protected override void DrawTypedValue(ISlot slot, string viewId)
|
|
{
|
|
var canvas = ImageOutputCanvas.Current;
|
|
if (canvas == null)
|
|
return;
|
|
|
|
Debug.Assert(slot is Slot<Command>);
|
|
|
|
var outputTexture = _resolvedColorBuffer ?? _msaaColorBuffer;
|
|
if (outputTexture != null)
|
|
{
|
|
canvas.DrawTexture(outputTexture);
|
|
}
|
|
}
|
|
|
|
private void UpdateTextures(Device device, Int2 size, Format format)
|
|
{
|
|
try
|
|
{
|
|
if (_msaaColorBuffer != null)
|
|
{
|
|
var currentDesc = _msaaColorBuffer.Description;
|
|
if (currentDesc.Width == size.Width
|
|
&& currentDesc.Height == size.Height
|
|
&& currentDesc.Format == format
|
|
&& currentDesc.SampleDescription.Count == MsaaSampleCount)
|
|
return;
|
|
|
|
Utilities.Dispose(ref _msaaColorBufferRtv);
|
|
Utilities.Dispose(ref _msaaColorBuffer);
|
|
}
|
|
|
|
Utilities.Dispose(ref _resolvedColorBufferSrv);
|
|
Utilities.Dispose(ref _resolvedColorBufferRtv);
|
|
Utilities.Dispose(ref _resolvedColorBuffer);
|
|
|
|
var msaaDesc = _defaultColorDescription with
|
|
{
|
|
Format = format,
|
|
Width = size.Width,
|
|
Height = size.Height,
|
|
SampleDescription = new SampleDescription(MsaaSampleCount, 0),
|
|
};
|
|
|
|
_msaaColorBuffer = Texture2D.CreateTexture2D(msaaDesc);
|
|
_msaaColorBufferRtv = new RenderTargetView(device, _msaaColorBuffer,
|
|
new RenderTargetViewDescription
|
|
{
|
|
Format = format,
|
|
Dimension = RenderTargetViewDimension.Texture2DMultisampled
|
|
});
|
|
|
|
var resolvedDesc = _defaultColorDescription with
|
|
{
|
|
Format = format,
|
|
Width = size.Width,
|
|
Height = size.Height,
|
|
SampleDescription = new SampleDescription(1, 0),
|
|
};
|
|
|
|
_resolvedColorBuffer = Texture2D.CreateTexture2D(resolvedDesc);
|
|
_resolvedColorBufferSrv = new ShaderResourceView(device, _resolvedColorBuffer);
|
|
_resolvedColorBufferRtv = new RenderTargetView(device, _resolvedColorBuffer);
|
|
|
|
Utilities.Dispose(ref _msaaDepthBufferDsv);
|
|
Utilities.Dispose(ref _msaaDepthBuffer);
|
|
|
|
var depthDesc = _defaultDepthDescription with
|
|
{
|
|
Width = size.Width,
|
|
Height = size.Height,
|
|
SampleDescription = new SampleDescription(MsaaSampleCount, 0),
|
|
};
|
|
|
|
_msaaDepthBuffer = Texture2D.CreateTexture2D(depthDesc);
|
|
var depthViewDesc = new DepthStencilViewDescription
|
|
{
|
|
Format = Format.D32_Float,
|
|
Dimension = DepthStencilViewDimension.Texture2DMultisampled
|
|
};
|
|
|
|
_msaaDepthBufferDsv = new DepthStencilView(device, _msaaDepthBuffer, depthViewDesc);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Log.Warning("Failed to generate texture: " + e.Message);
|
|
}
|
|
}
|
|
|
|
private static readonly Texture2DDescription _defaultColorDescription = new()
|
|
{
|
|
ArraySize = 1,
|
|
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
|
|
CpuAccessFlags = CpuAccessFlags.None,
|
|
MipLevels = 1,
|
|
OptionFlags = ResourceOptionFlags.None,
|
|
SampleDescription = new SampleDescription(1, 0),
|
|
Usage = ResourceUsage.Default
|
|
};
|
|
|
|
private static readonly Texture2DDescription _defaultDepthDescription = new()
|
|
{
|
|
ArraySize = 1,
|
|
BindFlags = BindFlags.DepthStencil,
|
|
CpuAccessFlags = CpuAccessFlags.None,
|
|
Format = Format.R32_Typeless,
|
|
Width = 1,
|
|
Height = 1,
|
|
MipLevels = 1,
|
|
OptionFlags = ResourceOptionFlags.None,
|
|
SampleDescription = new SampleDescription(1, 0),
|
|
Usage = ResourceUsage.Default
|
|
};
|
|
|
|
private const int MsaaSampleCount = 4;
|
|
private Texture2D? _msaaColorBuffer;
|
|
private RenderTargetView? _msaaColorBufferRtv;
|
|
private Texture2D? _resolvedColorBuffer;
|
|
private ShaderResourceView? _resolvedColorBufferSrv;
|
|
private RenderTargetView? _resolvedColorBufferRtv;
|
|
private Texture2D? _msaaDepthBuffer;
|
|
private DepthStencilView? _msaaDepthBufferDsv;
|
|
|
|
// instance management
|
|
private readonly Symbol? _outputWindowGridSymbol;
|
|
private Instance? _gridInstance;
|
|
private readonly Action<IResourceConsumer> _onGridInstanceDisposed;
|
|
private IReadOnlyList<ISlot>? _gridOutputs;
|
|
} |