mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-06-28 03:16:23 +02:00
Merge Latest Ryujinx (Unstable)
This commit is contained in:
parent
aaefc0a9e5
commit
12ab8bc3e2
1237 changed files with 48656 additions and 21399 deletions
|
@ -2,6 +2,7 @@ using Ryujinx.Graphics.GAL;
|
|||
using Ryujinx.Graphics.Shader;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
@ -30,10 +31,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
public readonly PipelineCache PipelineCache;
|
||||
|
||||
public readonly AutoFlushCounter AutoFlush;
|
||||
public readonly Action EndRenderPassDelegate;
|
||||
|
||||
protected PipelineDynamicState DynamicState;
|
||||
protected bool IsMainPipeline;
|
||||
private PipelineState _newState;
|
||||
private bool _stateDirty;
|
||||
private bool _graphicsStateDirty;
|
||||
private bool _computeStateDirty;
|
||||
private bool _bindingBarriersDirty;
|
||||
private PrimitiveTopology _topology;
|
||||
|
||||
private ulong _currentPipelineHandle;
|
||||
|
@ -52,7 +57,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
protected FramebufferParams FramebufferParams;
|
||||
private Auto<DisposableFramebuffer> _framebuffer;
|
||||
private RenderPassHolder _rpHolder;
|
||||
private Auto<DisposableRenderPass> _renderPass;
|
||||
private RenderPassHolder _nullRenderPass;
|
||||
private int _writtenAttachmentCount;
|
||||
|
||||
private bool _framebufferUsingColorWriteMask;
|
||||
|
@ -80,9 +87,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
private bool _tfEnabled;
|
||||
private bool _tfActive;
|
||||
|
||||
private readonly PipelineColorBlendAttachmentState[] _storedBlend;
|
||||
private FeedbackLoopAspects _feedbackLoop;
|
||||
private bool _passWritesDepthStencil;
|
||||
|
||||
private ulong _drawCountSinceBarrier;
|
||||
private readonly PipelineColorBlendAttachmentState[] _storedBlend;
|
||||
public ulong DrawCount { get; private set; }
|
||||
public bool RenderPassActive { get; private set; }
|
||||
|
||||
|
@ -92,15 +100,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
Device = device;
|
||||
|
||||
AutoFlush = new AutoFlushCounter(gd);
|
||||
EndRenderPassDelegate = EndRenderPass;
|
||||
|
||||
var pipelineCacheCreateInfo = new PipelineCacheCreateInfo
|
||||
{
|
||||
SType = StructureType.PipelineCacheCreateInfo,
|
||||
};
|
||||
|
||||
gd.Api.CreatePipelineCache(device, pipelineCacheCreateInfo, null, out PipelineCache).ThrowOnError();
|
||||
gd.Api.CreatePipelineCache(device, in pipelineCacheCreateInfo, null, out PipelineCache).ThrowOnError();
|
||||
|
||||
_descriptorSetUpdater = new DescriptorSetUpdater(gd, this);
|
||||
_descriptorSetUpdater = new DescriptorSetUpdater(gd, device);
|
||||
_vertexBufferUpdater = new VertexBufferUpdater(gd);
|
||||
|
||||
_transformFeedbackBuffers = new BufferState[Constants.MaxTransformFeedbackBuffers];
|
||||
|
@ -122,7 +131,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
public void Initialize()
|
||||
{
|
||||
_descriptorSetUpdater.Initialize();
|
||||
_descriptorSetUpdater.Initialize(IsMainPipeline);
|
||||
|
||||
QuadsToTrisPattern = new IndexBufferPattern(Gd, 4, 6, 0, new[] { 0, 1, 2, 0, 2, 3 }, 4, false);
|
||||
TriFanToTrisPattern = new IndexBufferPattern(Gd, 3, 3, 2, new[] { int.MinValue, -1, 0 }, 1, true);
|
||||
|
@ -130,48 +139,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
public unsafe void Barrier()
|
||||
{
|
||||
if (_drawCountSinceBarrier != DrawCount)
|
||||
{
|
||||
_drawCountSinceBarrier = DrawCount;
|
||||
|
||||
// Barriers are not supported inside a render pass on Apple GPUs.
|
||||
// As a workaround, end the render pass.
|
||||
if (Gd.Vendor == Vendor.Apple)
|
||||
{
|
||||
EndRenderPass();
|
||||
}
|
||||
}
|
||||
|
||||
MemoryBarrier memoryBarrier = new()
|
||||
{
|
||||
SType = StructureType.MemoryBarrier,
|
||||
SrcAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit,
|
||||
DstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit,
|
||||
};
|
||||
|
||||
PipelineStageFlags pipelineStageFlags = PipelineStageFlags.VertexShaderBit | PipelineStageFlags.FragmentShaderBit;
|
||||
|
||||
if (Gd.Capabilities.SupportsGeometryShader)
|
||||
{
|
||||
pipelineStageFlags |= PipelineStageFlags.GeometryShaderBit;
|
||||
}
|
||||
|
||||
if (Gd.Capabilities.SupportsTessellationShader)
|
||||
{
|
||||
pipelineStageFlags |= PipelineStageFlags.TessellationControlShaderBit | PipelineStageFlags.TessellationEvaluationShaderBit;
|
||||
}
|
||||
|
||||
Gd.Api.CmdPipelineBarrier(
|
||||
CommandBuffer,
|
||||
pipelineStageFlags,
|
||||
pipelineStageFlags,
|
||||
0,
|
||||
1,
|
||||
memoryBarrier,
|
||||
0,
|
||||
null,
|
||||
0,
|
||||
null);
|
||||
Gd.Barriers.QueueMemoryBarrier();
|
||||
}
|
||||
|
||||
public void ComputeBarrier()
|
||||
|
@ -198,6 +166,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
public void BeginTransformFeedback(PrimitiveTopology topology)
|
||||
{
|
||||
Gd.Barriers.EnableTfbBarriers(true);
|
||||
_tfEnabled = true;
|
||||
}
|
||||
|
||||
|
@ -244,14 +213,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
CreateRenderPass();
|
||||
}
|
||||
|
||||
Gd.Barriers.Flush(Cbs, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||
|
||||
BeginRenderPass();
|
||||
|
||||
var clearValue = new ClearValue(new ClearColorValue(color.Red, color.Green, color.Blue, color.Alpha));
|
||||
var attachment = new ClearAttachment(ImageAspectFlags.ColorBit, (uint)index, clearValue);
|
||||
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
|
||||
|
||||
FramebufferParams.InsertClearBarrier(Cbs, index);
|
||||
|
||||
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
|
||||
}
|
||||
|
||||
|
@ -282,36 +251,19 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
CreateRenderPass();
|
||||
}
|
||||
|
||||
Gd.Barriers.Flush(Cbs, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||
|
||||
BeginRenderPass();
|
||||
|
||||
var attachment = new ClearAttachment(flags, 0, clearValue);
|
||||
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
|
||||
|
||||
FramebufferParams.InsertClearBarrierDS(Cbs);
|
||||
|
||||
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
|
||||
}
|
||||
|
||||
public unsafe void CommandBufferBarrier()
|
||||
{
|
||||
MemoryBarrier memoryBarrier = new()
|
||||
{
|
||||
SType = StructureType.MemoryBarrier,
|
||||
SrcAccessMask = BufferHolder.DefaultAccessFlags,
|
||||
DstAccessMask = AccessFlags.IndirectCommandReadBit,
|
||||
};
|
||||
|
||||
Gd.Api.CmdPipelineBarrier(
|
||||
CommandBuffer,
|
||||
PipelineStageFlags.AllCommandsBit,
|
||||
PipelineStageFlags.DrawIndirectBit,
|
||||
0,
|
||||
1,
|
||||
memoryBarrier,
|
||||
0,
|
||||
null,
|
||||
0,
|
||||
null);
|
||||
Gd.Barriers.QueueCommandBufferBarrier();
|
||||
}
|
||||
|
||||
public void CopyBuffer(BufferHandle source, BufferHandle destination, int srcOffset, int dstOffset, int size)
|
||||
|
@ -351,7 +303,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
}
|
||||
|
||||
EndRenderPass();
|
||||
RecreatePipelineIfNeeded(PipelineBindPoint.Compute);
|
||||
RecreateComputePipelineIfNeeded();
|
||||
|
||||
Gd.Api.CmdDispatch(CommandBuffer, (uint)groupsX, (uint)groupsY, (uint)groupsZ);
|
||||
}
|
||||
|
@ -364,19 +316,23 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
}
|
||||
|
||||
EndRenderPass();
|
||||
RecreatePipelineIfNeeded(PipelineBindPoint.Compute);
|
||||
RecreateComputePipelineIfNeeded();
|
||||
|
||||
Gd.Api.CmdDispatchIndirect(CommandBuffer, indirectBuffer.Get(Cbs, indirectBufferOffset, 12).Value, (ulong)indirectBufferOffset);
|
||||
}
|
||||
|
||||
public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
|
||||
{
|
||||
if (!_program.IsLinked || vertexCount == 0)
|
||||
if (vertexCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!RecreateGraphicsPipelineIfNeeded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RecreatePipelineIfNeeded(PipelineBindPoint.Graphics);
|
||||
BeginRenderPass();
|
||||
DrawCount++;
|
||||
|
||||
|
@ -435,13 +391,18 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
public void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int firstVertex, int firstInstance)
|
||||
{
|
||||
if (!_program.IsLinked || indexCount == 0)
|
||||
if (indexCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateIndexBufferPattern();
|
||||
RecreatePipelineIfNeeded(PipelineBindPoint.Graphics);
|
||||
|
||||
if (!RecreateGraphicsPipelineIfNeeded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BeginRenderPass();
|
||||
DrawCount++;
|
||||
|
||||
|
@ -474,17 +435,17 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
public void DrawIndexedIndirect(BufferRange indirectBuffer)
|
||||
{
|
||||
if (!_program.IsLinked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var buffer = Gd.BufferManager
|
||||
.GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false)
|
||||
.Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
|
||||
|
||||
UpdateIndexBufferPattern();
|
||||
RecreatePipelineIfNeeded(PipelineBindPoint.Graphics);
|
||||
|
||||
if (!RecreateGraphicsPipelineIfNeeded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BeginRenderPass();
|
||||
DrawCount++;
|
||||
|
||||
|
@ -520,11 +481,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
public void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
||||
{
|
||||
if (!_program.IsLinked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var countBuffer = Gd.BufferManager
|
||||
.GetBuffer(CommandBuffer, parameterBuffer.Handle, parameterBuffer.Offset, parameterBuffer.Size, false)
|
||||
.Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value;
|
||||
|
@ -534,7 +490,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
.Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
|
||||
|
||||
UpdateIndexBufferPattern();
|
||||
RecreatePipelineIfNeeded(PipelineBindPoint.Graphics);
|
||||
|
||||
if (!RecreateGraphicsPipelineIfNeeded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BeginRenderPass();
|
||||
DrawCount++;
|
||||
|
||||
|
@ -612,18 +573,17 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
public void DrawIndirect(BufferRange indirectBuffer)
|
||||
{
|
||||
if (!_program.IsLinked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Support quads and other unsupported topologies.
|
||||
|
||||
var buffer = Gd.BufferManager
|
||||
.GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false)
|
||||
.Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size, false).Value;
|
||||
|
||||
RecreatePipelineIfNeeded(PipelineBindPoint.Graphics);
|
||||
if (!RecreateGraphicsPipelineIfNeeded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BeginRenderPass();
|
||||
ResumeTransformFeedbackInternal();
|
||||
DrawCount++;
|
||||
|
@ -639,11 +599,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
if (!_program.IsLinked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var buffer = Gd.BufferManager
|
||||
.GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false)
|
||||
.Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size, false).Value;
|
||||
|
@ -654,7 +609,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
// TODO: Support quads and other unsupported topologies.
|
||||
|
||||
RecreatePipelineIfNeeded(PipelineBindPoint.Graphics);
|
||||
if (!RecreateGraphicsPipelineIfNeeded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BeginRenderPass();
|
||||
ResumeTransformFeedbackInternal();
|
||||
DrawCount++;
|
||||
|
@ -677,9 +636,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
var oldStencilTestEnable = _newState.StencilTestEnable;
|
||||
var oldDepthTestEnable = _newState.DepthTestEnable;
|
||||
var oldDepthWriteEnable = _newState.DepthWriteEnable;
|
||||
var oldTopology = _newState.Topology;
|
||||
var oldViewports = DynamicState.Viewports;
|
||||
var oldViewportsCount = _newState.ViewportsCount;
|
||||
var oldTopology = _topology;
|
||||
|
||||
_newState.CullMode = CullModeFlags.None;
|
||||
_newState.StencilTestEnable = false;
|
||||
|
@ -699,7 +658,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_newState.StencilTestEnable = oldStencilTestEnable;
|
||||
_newState.DepthTestEnable = oldDepthTestEnable;
|
||||
_newState.DepthWriteEnable = oldDepthWriteEnable;
|
||||
_newState.Topology = oldTopology;
|
||||
SetPrimitiveTopology(oldTopology);
|
||||
|
||||
DynamicState.SetViewports(ref oldViewports, oldViewportsCount);
|
||||
|
||||
|
@ -710,6 +669,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
public void EndTransformFeedback()
|
||||
{
|
||||
Gd.Barriers.EnableTfbBarriers(false);
|
||||
PauseTransformFeedbackInternal();
|
||||
_tfEnabled = false;
|
||||
}
|
||||
|
@ -739,14 +699,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_vertexBufferUpdater.Commit(Cbs);
|
||||
}
|
||||
|
||||
#pragma warning disable CA1822 // Mark member as static
|
||||
public void SetAlphaTest(bool enable, float reference, CompareOp op)
|
||||
{
|
||||
// This is currently handled using shader specialization, as Vulkan does not support alpha test.
|
||||
// In the future, we may want to use this to write the reference value into the support buffer,
|
||||
// to avoid creating one version of the shader per reference value used.
|
||||
}
|
||||
#pragma warning restore CA1822
|
||||
|
||||
public void SetBlendState(AdvancedBlendDescriptor blend)
|
||||
{
|
||||
|
@ -861,6 +819,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_newState.DepthTestEnable = depthTest.TestEnable;
|
||||
_newState.DepthWriteEnable = depthTest.WriteEnable;
|
||||
_newState.DepthCompareOp = depthTest.Func.Convert();
|
||||
|
||||
UpdatePassDepthStencil();
|
||||
SignalStateChange();
|
||||
}
|
||||
|
||||
|
@ -876,9 +836,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
SignalStateChange();
|
||||
}
|
||||
|
||||
public void SetImage(int binding, ITexture image, Format imageFormat)
|
||||
public void SetImage(ShaderStage stage, int binding, ITexture image)
|
||||
{
|
||||
_descriptorSetUpdater.SetImage(binding, image, imageFormat);
|
||||
_descriptorSetUpdater.SetImage(Cbs, stage, binding, image);
|
||||
}
|
||||
|
||||
public void SetImage(int binding, Auto<DisposableImageView> image)
|
||||
|
@ -886,6 +846,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_descriptorSetUpdater.SetImage(binding, image);
|
||||
}
|
||||
|
||||
public void SetImageArray(ShaderStage stage, int binding, IImageArray array)
|
||||
{
|
||||
_descriptorSetUpdater.SetImageArray(Cbs, stage, binding, array);
|
||||
}
|
||||
|
||||
public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
|
||||
{
|
||||
_descriptorSetUpdater.SetImageArraySeparate(Cbs, stage, setIndex, array);
|
||||
}
|
||||
|
||||
public void SetIndexBuffer(BufferRange buffer, IndexType type)
|
||||
{
|
||||
if (buffer.Handle != BufferHandle.Null)
|
||||
|
@ -928,7 +898,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
// TODO: Default levels (likely needs emulation on shaders?)
|
||||
}
|
||||
|
||||
#pragma warning disable CA1822 // Mark member as static
|
||||
public void SetPointParameters(float size, bool isProgramPointSize, bool enablePointSprite, Origin origin)
|
||||
{
|
||||
// TODO.
|
||||
|
@ -938,7 +907,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
{
|
||||
// TODO.
|
||||
}
|
||||
#pragma warning restore CA1822
|
||||
|
||||
public void SetPrimitiveRestart(bool enable, int index)
|
||||
{
|
||||
|
@ -965,9 +933,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
_program = internalProgram;
|
||||
|
||||
_descriptorSetUpdater.SetProgram(internalProgram);
|
||||
_descriptorSetUpdater.SetProgram(Cbs, internalProgram, _currentPipelineHandle != 0);
|
||||
_bindingBarriersDirty = true;
|
||||
|
||||
_newState.PipelineLayout = internalProgram.PipelineLayout;
|
||||
_newState.HasTessellationControlShader = internalProgram.HasTessellationControlShader;
|
||||
_newState.StagesCount = (uint)stages.Length;
|
||||
|
||||
stages.CopyTo(_newState.Stages.AsSpan()[..stages.Length]);
|
||||
|
@ -1000,6 +970,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
{
|
||||
_newState.RasterizerDiscardEnable = discard;
|
||||
SignalStateChange();
|
||||
|
||||
if (!discard && Gd.IsQualcommProprietary)
|
||||
{
|
||||
// On Adreno, enabling rasterizer discard somehow corrupts the viewport state.
|
||||
// Force it to be updated on next use to work around this bug.
|
||||
DynamicState.ForceAllDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask)
|
||||
|
@ -1055,7 +1032,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
private void SetRenderTargetsInternal(ITexture[] colors, ITexture depthStencil, bool filterWriteMasked)
|
||||
{
|
||||
CreateFramebuffer(colors, depthStencil, filterWriteMasked);
|
||||
FramebufferParams?.UpdateModifications();
|
||||
CreateRenderPass();
|
||||
SignalStateChange();
|
||||
SignalAttachmentChange();
|
||||
|
@ -1110,6 +1086,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_newState.StencilFrontPassOp = stencilTest.FrontDpPass.Convert();
|
||||
_newState.StencilFrontDepthFailOp = stencilTest.FrontDpFail.Convert();
|
||||
_newState.StencilFrontCompareOp = stencilTest.FrontFunc.Convert();
|
||||
|
||||
UpdatePassDepthStencil();
|
||||
SignalStateChange();
|
||||
}
|
||||
|
||||
|
@ -1133,6 +1111,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_descriptorSetUpdater.SetTextureAndSamplerIdentitySwizzle(Cbs, stage, binding, texture, sampler);
|
||||
}
|
||||
|
||||
public void SetTextureArray(ShaderStage stage, int binding, ITextureArray array)
|
||||
{
|
||||
_descriptorSetUpdater.SetTextureArray(Cbs, stage, binding, array);
|
||||
}
|
||||
|
||||
public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
|
||||
{
|
||||
_descriptorSetUpdater.SetTextureArraySeparate(Cbs, stage, setIndex, array);
|
||||
}
|
||||
|
||||
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
|
||||
{
|
||||
PauseTransformFeedbackInternal();
|
||||
|
@ -1163,12 +1151,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_descriptorSetUpdater.SetUniformBuffers(CommandBuffer, buffers);
|
||||
}
|
||||
|
||||
#pragma warning disable CA1822 // Mark member as static
|
||||
public void SetUserClipDistance(int index, bool enableClip)
|
||||
{
|
||||
// TODO.
|
||||
}
|
||||
#pragma warning restore CA1822
|
||||
|
||||
public void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
|
||||
{
|
||||
|
@ -1362,26 +1348,19 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
SignalCommandBufferChange();
|
||||
}
|
||||
|
||||
public void ForceTextureDirty()
|
||||
{
|
||||
_descriptorSetUpdater.ForceTextureDirty();
|
||||
}
|
||||
|
||||
public void ForceImageDirty()
|
||||
{
|
||||
_descriptorSetUpdater.ForceImageDirty();
|
||||
}
|
||||
|
||||
public unsafe void TextureBarrier()
|
||||
{
|
||||
MemoryBarrier memoryBarrier = new()
|
||||
{
|
||||
SType = StructureType.MemoryBarrier,
|
||||
SrcAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit,
|
||||
DstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit,
|
||||
};
|
||||
|
||||
Gd.Api.CmdPipelineBarrier(
|
||||
CommandBuffer,
|
||||
PipelineStageFlags.FragmentShaderBit,
|
||||
PipelineStageFlags.FragmentShaderBit,
|
||||
0,
|
||||
1,
|
||||
memoryBarrier,
|
||||
0,
|
||||
null,
|
||||
0,
|
||||
null);
|
||||
Gd.Barriers.QueueTextureBarrier();
|
||||
}
|
||||
|
||||
public void TextureBarrierTiled()
|
||||
|
@ -1456,7 +1435,23 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
}
|
||||
}
|
||||
|
||||
if (IsMainPipeline)
|
||||
{
|
||||
FramebufferParams?.ClearBindings();
|
||||
}
|
||||
|
||||
FramebufferParams = new FramebufferParams(Device, colors, depthStencil);
|
||||
|
||||
if (IsMainPipeline)
|
||||
{
|
||||
FramebufferParams.AddBindings();
|
||||
|
||||
_newState.FeedbackLoopAspects = FeedbackLoopAspects.None;
|
||||
_bindingBarriersDirty = true;
|
||||
}
|
||||
|
||||
_passWritesDepthStencil = false;
|
||||
UpdatePassDepthStencil();
|
||||
UpdatePipelineAttachmentFormats();
|
||||
}
|
||||
|
||||
|
@ -1465,6 +1460,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
var dstAttachmentFormats = _newState.Internal.AttachmentFormats.AsSpan();
|
||||
FramebufferParams.AttachmentFormats.CopyTo(dstAttachmentFormats);
|
||||
_newState.Internal.AttachmentIntegerFormatMask = FramebufferParams.AttachmentIntegerFormatMask;
|
||||
_newState.Internal.LogicOpsAllowed = FramebufferParams.LogicOpsAllowed;
|
||||
|
||||
for (int i = FramebufferParams.AttachmentFormats.Length; i < dstAttachmentFormats.Length; i++)
|
||||
{
|
||||
|
@ -1478,113 +1474,134 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
protected unsafe void CreateRenderPass()
|
||||
{
|
||||
const int MaxAttachments = Constants.MaxRenderTargets + 1;
|
||||
|
||||
AttachmentDescription[] attachmentDescs = null;
|
||||
|
||||
var subpass = new SubpassDescription
|
||||
{
|
||||
PipelineBindPoint = PipelineBindPoint.Graphics,
|
||||
};
|
||||
|
||||
AttachmentReference* attachmentReferences = stackalloc AttachmentReference[MaxAttachments];
|
||||
|
||||
var hasFramebuffer = FramebufferParams != null;
|
||||
|
||||
if (hasFramebuffer && FramebufferParams.AttachmentsCount != 0)
|
||||
{
|
||||
attachmentDescs = new AttachmentDescription[FramebufferParams.AttachmentsCount];
|
||||
|
||||
for (int i = 0; i < FramebufferParams.AttachmentsCount; i++)
|
||||
{
|
||||
attachmentDescs[i] = new AttachmentDescription(
|
||||
0,
|
||||
FramebufferParams.AttachmentFormats[i],
|
||||
TextureStorage.ConvertToSampleCountFlags(Gd.Capabilities.SupportedSampleCounts, FramebufferParams.AttachmentSamples[i]),
|
||||
AttachmentLoadOp.Load,
|
||||
AttachmentStoreOp.Store,
|
||||
AttachmentLoadOp.Load,
|
||||
AttachmentStoreOp.Store,
|
||||
ImageLayout.General,
|
||||
ImageLayout.General);
|
||||
}
|
||||
|
||||
int colorAttachmentsCount = FramebufferParams.ColorAttachmentsCount;
|
||||
|
||||
if (colorAttachmentsCount > MaxAttachments - 1)
|
||||
{
|
||||
colorAttachmentsCount = MaxAttachments - 1;
|
||||
}
|
||||
|
||||
if (colorAttachmentsCount != 0)
|
||||
{
|
||||
int maxAttachmentIndex = FramebufferParams.MaxColorAttachmentIndex;
|
||||
subpass.ColorAttachmentCount = (uint)maxAttachmentIndex + 1;
|
||||
subpass.PColorAttachments = &attachmentReferences[0];
|
||||
|
||||
// Fill with VK_ATTACHMENT_UNUSED to cover any gaps.
|
||||
for (int i = 0; i <= maxAttachmentIndex; i++)
|
||||
{
|
||||
subpass.PColorAttachments[i] = new AttachmentReference(Vk.AttachmentUnused, ImageLayout.Undefined);
|
||||
}
|
||||
|
||||
for (int i = 0; i < colorAttachmentsCount; i++)
|
||||
{
|
||||
int bindIndex = FramebufferParams.AttachmentIndices[i];
|
||||
|
||||
subpass.PColorAttachments[bindIndex] = new AttachmentReference((uint)i, ImageLayout.General);
|
||||
}
|
||||
}
|
||||
|
||||
if (FramebufferParams.HasDepthStencil)
|
||||
{
|
||||
uint dsIndex = (uint)FramebufferParams.AttachmentsCount - 1;
|
||||
|
||||
subpass.PDepthStencilAttachment = &attachmentReferences[MaxAttachments - 1];
|
||||
*subpass.PDepthStencilAttachment = new AttachmentReference(dsIndex, ImageLayout.General);
|
||||
}
|
||||
}
|
||||
|
||||
var subpassDependency = PipelineConverter.CreateSubpassDependency();
|
||||
|
||||
fixed (AttachmentDescription* pAttachmentDescs = attachmentDescs)
|
||||
{
|
||||
var renderPassCreateInfo = new RenderPassCreateInfo
|
||||
{
|
||||
SType = StructureType.RenderPassCreateInfo,
|
||||
PAttachments = pAttachmentDescs,
|
||||
AttachmentCount = attachmentDescs != null ? (uint)attachmentDescs.Length : 0,
|
||||
PSubpasses = &subpass,
|
||||
SubpassCount = 1,
|
||||
PDependencies = &subpassDependency,
|
||||
DependencyCount = 1,
|
||||
};
|
||||
|
||||
Gd.Api.CreateRenderPass(Device, renderPassCreateInfo, null, out var renderPass).ThrowOnError();
|
||||
|
||||
_renderPass?.Dispose();
|
||||
_renderPass = new Auto<DisposableRenderPass>(new DisposableRenderPass(Gd.Api, Device, renderPass));
|
||||
}
|
||||
|
||||
EndRenderPass();
|
||||
|
||||
_framebuffer?.Dispose();
|
||||
_framebuffer = hasFramebuffer ? FramebufferParams.Create(Gd.Api, Cbs, _renderPass) : null;
|
||||
if (!hasFramebuffer || FramebufferParams.AttachmentsCount == 0)
|
||||
{
|
||||
// Use the null framebuffer.
|
||||
_nullRenderPass ??= new RenderPassHolder(Gd, Device, new RenderPassCacheKey(), FramebufferParams);
|
||||
|
||||
_rpHolder = _nullRenderPass;
|
||||
_renderPass = _nullRenderPass.GetRenderPass();
|
||||
_framebuffer = _nullRenderPass.GetFramebuffer(Gd, Cbs, FramebufferParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
(_rpHolder, _framebuffer) = FramebufferParams.GetPassAndFramebuffer(Gd, Device, Cbs);
|
||||
|
||||
_renderPass = _rpHolder.GetRenderPass();
|
||||
}
|
||||
}
|
||||
|
||||
protected void SignalStateChange()
|
||||
{
|
||||
_stateDirty = true;
|
||||
_graphicsStateDirty = true;
|
||||
_computeStateDirty = true;
|
||||
}
|
||||
|
||||
private void RecreatePipelineIfNeeded(PipelineBindPoint pbp)
|
||||
private void RecreateComputePipelineIfNeeded()
|
||||
{
|
||||
if (_computeStateDirty || Pbp != PipelineBindPoint.Compute)
|
||||
{
|
||||
CreatePipeline(PipelineBindPoint.Compute);
|
||||
_computeStateDirty = false;
|
||||
Pbp = PipelineBindPoint.Compute;
|
||||
|
||||
if (_bindingBarriersDirty)
|
||||
{
|
||||
// Stale barriers may have been activated by switching program. Emit any that are relevant.
|
||||
_descriptorSetUpdater.InsertBindingBarriers(Cbs);
|
||||
|
||||
_bindingBarriersDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||
|
||||
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Compute);
|
||||
}
|
||||
|
||||
private bool ChangeFeedbackLoop(FeedbackLoopAspects aspects)
|
||||
{
|
||||
if (_feedbackLoop != aspects)
|
||||
{
|
||||
if (Gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
|
||||
{
|
||||
DynamicState.SetFeedbackLoop(aspects);
|
||||
}
|
||||
else
|
||||
{
|
||||
_newState.FeedbackLoopAspects = aspects;
|
||||
}
|
||||
|
||||
_feedbackLoop = aspects;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool UpdateFeedbackLoop()
|
||||
{
|
||||
List<TextureView> hazards = _descriptorSetUpdater.FeedbackLoopHazards;
|
||||
|
||||
if ((hazards?.Count ?? 0) > 0)
|
||||
{
|
||||
FeedbackLoopAspects aspects = 0;
|
||||
|
||||
foreach (TextureView view in hazards)
|
||||
{
|
||||
// May need to enforce feedback loop layout here in the future.
|
||||
// Though technically, it should always work with the general layout.
|
||||
|
||||
if (view.Info.Format.IsDepthOrStencil())
|
||||
{
|
||||
if (_passWritesDepthStencil)
|
||||
{
|
||||
// If depth/stencil isn't written in the pass, it doesn't count as a feedback loop.
|
||||
|
||||
aspects |= FeedbackLoopAspects.Depth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aspects |= FeedbackLoopAspects.Color;
|
||||
}
|
||||
}
|
||||
|
||||
return ChangeFeedbackLoop(aspects);
|
||||
}
|
||||
else if (_feedbackLoop != 0)
|
||||
{
|
||||
return ChangeFeedbackLoop(FeedbackLoopAspects.None);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void UpdatePassDepthStencil()
|
||||
{
|
||||
if (!RenderPassActive)
|
||||
{
|
||||
_passWritesDepthStencil = false;
|
||||
}
|
||||
|
||||
// Stencil test being enabled doesn't necessarily mean a write, but it's not critical to check.
|
||||
_passWritesDepthStencil |= (_newState.DepthTestEnable && _newState.DepthWriteEnable) || _newState.StencilTestEnable;
|
||||
}
|
||||
|
||||
private bool RecreateGraphicsPipelineIfNeeded()
|
||||
{
|
||||
if (AutoFlush.ShouldFlushDraw(DrawCount))
|
||||
{
|
||||
Gd.FlushAllCommands();
|
||||
}
|
||||
|
||||
DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
||||
DynamicState.ReplayIfDirty(Gd, CommandBuffer);
|
||||
|
||||
if (_needsIndexBufferRebind && _indexBufferPattern == null)
|
||||
{
|
||||
|
@ -1618,17 +1635,33 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_vertexBufferUpdater.Commit(Cbs);
|
||||
}
|
||||
|
||||
if (_stateDirty || Pbp != pbp)
|
||||
if (_bindingBarriersDirty)
|
||||
{
|
||||
CreatePipeline(pbp);
|
||||
_stateDirty = false;
|
||||
Pbp = pbp;
|
||||
// Stale barriers may have been activated by switching program. Emit any that are relevant.
|
||||
_descriptorSetUpdater.InsertBindingBarriers(Cbs);
|
||||
|
||||
_bindingBarriersDirty = false;
|
||||
}
|
||||
|
||||
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, pbp);
|
||||
if (UpdateFeedbackLoop() || _graphicsStateDirty || Pbp != PipelineBindPoint.Graphics)
|
||||
{
|
||||
if (!CreatePipeline(PipelineBindPoint.Graphics))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_graphicsStateDirty = false;
|
||||
Pbp = PipelineBindPoint.Graphics;
|
||||
}
|
||||
|
||||
Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||
|
||||
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Graphics);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void CreatePipeline(PipelineBindPoint pbp)
|
||||
private bool CreatePipeline(PipelineBindPoint pbp)
|
||||
{
|
||||
// We can only create a pipeline if the have the shader stages set.
|
||||
if (_newState.Stages != null)
|
||||
|
@ -1638,10 +1671,25 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
CreateRenderPass();
|
||||
}
|
||||
|
||||
if (!_program.IsLinked)
|
||||
{
|
||||
// Background compile failed, we likely can't create the pipeline because the shader is broken
|
||||
// or the driver failed to compile it.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var pipeline = pbp == PipelineBindPoint.Compute
|
||||
? _newState.CreateComputePipeline(Gd, Device, _program, PipelineCache)
|
||||
: _newState.CreateGraphicsPipeline(Gd, Device, _program, PipelineCache, _renderPass.Get(Cbs).Value);
|
||||
|
||||
if (pipeline == null)
|
||||
{
|
||||
// Host failed to create the pipeline, likely due to driver bugs.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ulong pipelineHandle = pipeline.GetUnsafe().Value.Handle;
|
||||
|
||||
if (_currentPipelineHandle != pipelineHandle)
|
||||
|
@ -1653,12 +1701,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
Gd.Api.CmdBindPipeline(CommandBuffer, pbp, Pipeline.Get(Cbs).Value);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private unsafe void BeginRenderPass()
|
||||
{
|
||||
if (!RenderPassActive)
|
||||
{
|
||||
FramebufferParams.InsertLoadOpBarriers(Gd, Cbs);
|
||||
|
||||
var renderArea = new Rect2D(null, new Extent2D(FramebufferParams.Width, FramebufferParams.Height));
|
||||
var clearValue = new ClearValue();
|
||||
|
||||
|
@ -1672,7 +1724,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
ClearValueCount = 1,
|
||||
};
|
||||
|
||||
Gd.Api.CmdBeginRenderPass(CommandBuffer, renderPassBeginInfo, SubpassContents.Inline);
|
||||
Gd.Api.CmdBeginRenderPass(CommandBuffer, in renderPassBeginInfo, SubpassContents.Inline);
|
||||
RenderPassActive = true;
|
||||
}
|
||||
}
|
||||
|
@ -1681,6 +1733,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
{
|
||||
if (RenderPassActive)
|
||||
{
|
||||
FramebufferParams.AddStoreOpUsage();
|
||||
|
||||
PauseTransformFeedbackInternal();
|
||||
Gd.Api.CmdEndRenderPass(CommandBuffer);
|
||||
SignalRenderPassEnd();
|
||||
|
@ -1724,8 +1778,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
{
|
||||
if (disposing)
|
||||
{
|
||||
_renderPass?.Dispose();
|
||||
_framebuffer?.Dispose();
|
||||
_nullRenderPass?.Dispose();
|
||||
_newState.Dispose();
|
||||
_descriptorSetUpdater.Dispose();
|
||||
_vertexBufferUpdater.Dispose();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue