ca59c3f499
* Vulkan: Feedback loop improvements This PR allows the Vulkan backend to detect attachment feedback loops. These are currently used in the following ways: - Partial use of VK_EXT_attachment_feedback_loop_layout - All renderable textures have AttachmentFeedbackLoopBitExt - Compile pipelines with Color/DepthStencil feedback loop flags when present - Support using FragmentBarrier for feedback loops (fixes regressions from https://github.com/Ryujinx/Ryujinx/pull/7012 ) TODO: - AMD GPUs may need layout transitions for it to properly allow textures to be used in feedback loops. - Use dynamic state for feedback loops. The background pipeline will always miss since feedback loop state isn't known on the GPU project. - How is the barrier dependency flag used? (DXVK just ignores it, there's no vulkan validation...) - Improve subpass dependencies to fix validation errors * Mark field readonly * Add feedback loop dynamic state * fix: add MoltenVK resolver workaround fix: add MoltenVK resolver workaround * Formatting * Fix more complaints * RADV dcc workaround * Use dynamic state properly, cleanup. * Use aspects flags in more places
203 lines
6.3 KiB
C#
203 lines
6.3 KiB
C#
using Ryujinx.Common.Memory;
|
|
using Silk.NET.Vulkan;
|
|
using Silk.NET.Vulkan.Extensions.EXT;
|
|
|
|
namespace Ryujinx.Graphics.Vulkan
|
|
{
|
|
struct PipelineDynamicState
|
|
{
|
|
private float _depthBiasSlopeFactor;
|
|
private float _depthBiasConstantFactor;
|
|
private float _depthBiasClamp;
|
|
|
|
public int ScissorsCount;
|
|
private Array16<Rect2D> _scissors;
|
|
|
|
private uint _backCompareMask;
|
|
private uint _backWriteMask;
|
|
private uint _backReference;
|
|
private uint _frontCompareMask;
|
|
private uint _frontWriteMask;
|
|
private uint _frontReference;
|
|
|
|
private Array4<float> _blendConstants;
|
|
|
|
private FeedbackLoopAspects _feedbackLoopAspects;
|
|
|
|
public uint ViewportsCount;
|
|
public Array16<Viewport> Viewports;
|
|
|
|
private enum DirtyFlags
|
|
{
|
|
None = 0,
|
|
Blend = 1 << 0,
|
|
DepthBias = 1 << 1,
|
|
Scissor = 1 << 2,
|
|
Stencil = 1 << 3,
|
|
Viewport = 1 << 4,
|
|
FeedbackLoop = 1 << 5,
|
|
All = Blend | DepthBias | Scissor | Stencil | Viewport | FeedbackLoop,
|
|
}
|
|
|
|
private DirtyFlags _dirty;
|
|
|
|
public void SetBlendConstants(float r, float g, float b, float a)
|
|
{
|
|
_blendConstants[0] = r;
|
|
_blendConstants[1] = g;
|
|
_blendConstants[2] = b;
|
|
_blendConstants[3] = a;
|
|
|
|
_dirty |= DirtyFlags.Blend;
|
|
}
|
|
|
|
public void SetDepthBias(float slopeFactor, float constantFactor, float clamp)
|
|
{
|
|
_depthBiasSlopeFactor = slopeFactor;
|
|
_depthBiasConstantFactor = constantFactor;
|
|
_depthBiasClamp = clamp;
|
|
|
|
_dirty |= DirtyFlags.DepthBias;
|
|
}
|
|
|
|
public void SetScissor(int index, Rect2D scissor)
|
|
{
|
|
_scissors[index] = scissor;
|
|
|
|
_dirty |= DirtyFlags.Scissor;
|
|
}
|
|
|
|
public void SetStencilMasks(
|
|
uint backCompareMask,
|
|
uint backWriteMask,
|
|
uint backReference,
|
|
uint frontCompareMask,
|
|
uint frontWriteMask,
|
|
uint frontReference)
|
|
{
|
|
_backCompareMask = backCompareMask;
|
|
_backWriteMask = backWriteMask;
|
|
_backReference = backReference;
|
|
_frontCompareMask = frontCompareMask;
|
|
_frontWriteMask = frontWriteMask;
|
|
_frontReference = frontReference;
|
|
|
|
_dirty |= DirtyFlags.Stencil;
|
|
}
|
|
|
|
public void SetViewport(int index, Viewport viewport)
|
|
{
|
|
Viewports[index] = viewport;
|
|
|
|
_dirty |= DirtyFlags.Viewport;
|
|
}
|
|
|
|
public void SetViewports(ref Array16<Viewport> viewports, uint viewportsCount)
|
|
{
|
|
Viewports = viewports;
|
|
ViewportsCount = viewportsCount;
|
|
|
|
if (ViewportsCount != 0)
|
|
{
|
|
_dirty |= DirtyFlags.Viewport;
|
|
}
|
|
}
|
|
|
|
public void SetFeedbackLoop(FeedbackLoopAspects aspects)
|
|
{
|
|
_feedbackLoopAspects = aspects;
|
|
|
|
_dirty |= DirtyFlags.FeedbackLoop;
|
|
}
|
|
|
|
public void ForceAllDirty()
|
|
{
|
|
_dirty = DirtyFlags.All;
|
|
}
|
|
|
|
public void ReplayIfDirty(VulkanRenderer gd, CommandBuffer commandBuffer)
|
|
{
|
|
Vk api = gd.Api;
|
|
|
|
if (_dirty.HasFlag(DirtyFlags.Blend))
|
|
{
|
|
RecordBlend(api, commandBuffer);
|
|
}
|
|
|
|
if (_dirty.HasFlag(DirtyFlags.DepthBias))
|
|
{
|
|
RecordDepthBias(api, commandBuffer);
|
|
}
|
|
|
|
if (_dirty.HasFlag(DirtyFlags.Scissor))
|
|
{
|
|
RecordScissor(api, commandBuffer);
|
|
}
|
|
|
|
if (_dirty.HasFlag(DirtyFlags.Stencil))
|
|
{
|
|
RecordStencilMasks(api, commandBuffer);
|
|
}
|
|
|
|
if (_dirty.HasFlag(DirtyFlags.Viewport))
|
|
{
|
|
RecordViewport(api, commandBuffer);
|
|
}
|
|
|
|
if (_dirty.HasFlag(DirtyFlags.FeedbackLoop) && gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
|
|
{
|
|
RecordFeedbackLoop(gd.DynamicFeedbackLoopApi, commandBuffer);
|
|
}
|
|
|
|
_dirty = DirtyFlags.None;
|
|
}
|
|
|
|
private void RecordBlend(Vk api, CommandBuffer commandBuffer)
|
|
{
|
|
api.CmdSetBlendConstants(commandBuffer, _blendConstants.AsSpan());
|
|
}
|
|
|
|
private readonly void RecordDepthBias(Vk api, CommandBuffer commandBuffer)
|
|
{
|
|
api.CmdSetDepthBias(commandBuffer, _depthBiasConstantFactor, _depthBiasClamp, _depthBiasSlopeFactor);
|
|
}
|
|
|
|
private void RecordScissor(Vk api, CommandBuffer commandBuffer)
|
|
{
|
|
if (ScissorsCount != 0)
|
|
{
|
|
api.CmdSetScissor(commandBuffer, 0, (uint)ScissorsCount, _scissors.AsSpan());
|
|
}
|
|
}
|
|
|
|
private readonly void RecordStencilMasks(Vk api, CommandBuffer commandBuffer)
|
|
{
|
|
api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backCompareMask);
|
|
api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backWriteMask);
|
|
api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.FaceBackBit, _backReference);
|
|
api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontCompareMask);
|
|
api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontWriteMask);
|
|
api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontReference);
|
|
}
|
|
|
|
private void RecordViewport(Vk api, CommandBuffer commandBuffer)
|
|
{
|
|
if (ViewportsCount != 0)
|
|
{
|
|
api.CmdSetViewport(commandBuffer, 0, ViewportsCount, Viewports.AsSpan());
|
|
}
|
|
}
|
|
|
|
private readonly void RecordFeedbackLoop(ExtAttachmentFeedbackLoopDynamicState api, CommandBuffer commandBuffer)
|
|
{
|
|
ImageAspectFlags aspects = (_feedbackLoopAspects & FeedbackLoopAspects.Color) != 0 ? ImageAspectFlags.ColorBit : 0;
|
|
|
|
if ((_feedbackLoopAspects & FeedbackLoopAspects.Depth) != 0)
|
|
{
|
|
aspects |= ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit;
|
|
}
|
|
|
|
api.CmdSetAttachmentFeedbackLoopEnable(commandBuffer, aspects);
|
|
}
|
|
}
|
|
}
|