mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-09-27 20:07:54 +02:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e6e4076bf | ||
|
|
ab7176e6fc | ||
|
|
20868546b0 |
@@ -413,10 +413,6 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
context.CurrOp = opCode;
|
context.CurrOp = opCode;
|
||||||
|
|
||||||
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
|
||||||
Operand dispAddressAddr = context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset()));
|
|
||||||
context.Store(dispAddressAddr, Const(opCode.Address));
|
|
||||||
|
|
||||||
bool isLastOp = opcIndex == block.OpCodes.Count - 1;
|
bool isLastOp = opcIndex == block.OpCodes.Count - 1;
|
||||||
|
|
||||||
if (isLastOp)
|
if (isLastOp)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32
|
|||||||
{
|
{
|
||||||
static class Decoder<T> where T : IInstEmit
|
static class Decoder<T> where T : IInstEmit
|
||||||
{
|
{
|
||||||
public static MultiBlock DecodeMulti(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, bool singleBlock, bool isThumb)
|
public static MultiBlock DecodeMulti(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, bool isThumb)
|
||||||
{
|
{
|
||||||
List<Block> blocks = [];
|
List<Block> blocks = [];
|
||||||
List<ulong> branchTargets = [];
|
List<ulong> branchTargets = [];
|
||||||
@@ -24,7 +24,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32
|
|||||||
|
|
||||||
blocks.Add(block);
|
blocks.Add(block);
|
||||||
|
|
||||||
if (block.IsTruncated || (singleBlock && block.EndsWithBranch) || !HasNextBlock(block, block.EndAddress - 4UL, branchTargets))
|
if (block.IsTruncated || !HasNextBlock(block, block.EndAddress - 4UL, branchTargets))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
|||||||
|
|
||||||
public static CompiledFunction Compile(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, IAddressTable<ulong> funcTable, nint dispatchStubPtr, bool isThumb)
|
public static CompiledFunction Compile(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, IAddressTable<ulong> funcTable, nint dispatchStubPtr, bool isThumb)
|
||||||
{
|
{
|
||||||
MultiBlock multiBlock = Decoder<InstEmit>.DecodeMulti(cpuPreset, memoryManager, address, singleBlock: true, isThumb);
|
MultiBlock multiBlock = Decoder<InstEmit>.DecodeMulti(cpuPreset, memoryManager, address, isThumb);
|
||||||
|
|
||||||
Dictionary<ulong, int> targets = new();
|
Dictionary<ulong, int> targets = new();
|
||||||
|
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
|
|
||||||
public static CompiledFunction Compile(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, IAddressTable<ulong> funcTable, nint dispatchStubPtr)
|
public static CompiledFunction Compile(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, IAddressTable<ulong> funcTable, nint dispatchStubPtr)
|
||||||
{
|
{
|
||||||
MultiBlock multiBlock = Decoder.DecodeMulti(cpuPreset, memoryManager, address, singleBlock: true);
|
MultiBlock multiBlock = Decoder.DecodeMulti(cpuPreset, memoryManager, address);
|
||||||
|
|
||||||
Dictionary<ulong, int> targets = new();
|
Dictionary<ulong, int> targets = new();
|
||||||
List<PendingBranch> pendingBranches = [];
|
List<PendingBranch> pendingBranches = [];
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
private const uint NzcvFlags = 0xfu << 28;
|
private const uint NzcvFlags = 0xfu << 28;
|
||||||
private const uint CFlag = 0x1u << 29;
|
private const uint CFlag = 0x1u << 29;
|
||||||
|
|
||||||
public static MultiBlock DecodeMulti(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, bool singleBlock)
|
public static MultiBlock DecodeMulti(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address)
|
||||||
{
|
{
|
||||||
List<Block> blocks = [];
|
List<Block> blocks = [];
|
||||||
List<ulong> branchTargets = [];
|
List<ulong> branchTargets = [];
|
||||||
@@ -35,7 +35,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
|
|
||||||
blocks.Add(block);
|
blocks.Add(block);
|
||||||
|
|
||||||
if (block.IsTruncated || (singleBlock && block.EndsWithBranch) || !HasNextBlock(block, block.EndAddress - 4UL, branchTargets))
|
if (block.IsTruncated || !HasNextBlock(block, block.EndAddress - 4UL, branchTargets))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
public readonly bool SupportsGeometryShader;
|
public readonly bool SupportsGeometryShader;
|
||||||
public readonly bool SupportsGeometryShaderPassthrough;
|
public readonly bool SupportsGeometryShaderPassthrough;
|
||||||
public readonly bool SupportsTransformFeedback;
|
public readonly bool SupportsTransformFeedback;
|
||||||
public readonly bool SupportsImageBufferPixelAlignment;
|
|
||||||
public readonly bool SupportsImageLoadFormatted;
|
public readonly bool SupportsImageLoadFormatted;
|
||||||
public readonly bool SupportsLayerVertexTessellation;
|
public readonly bool SupportsLayerVertexTessellation;
|
||||||
public readonly bool SupportsMismatchingViewFormat;
|
public readonly bool SupportsMismatchingViewFormat;
|
||||||
@@ -44,7 +43,6 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
public readonly bool SupportsShaderBarrierDivergence;
|
public readonly bool SupportsShaderBarrierDivergence;
|
||||||
public readonly bool SupportsShaderFloat64;
|
public readonly bool SupportsShaderFloat64;
|
||||||
public readonly bool SupportsShaderNonUniformIndexing;
|
public readonly bool SupportsShaderNonUniformIndexing;
|
||||||
public readonly bool SupportsTextureBufferPixelAlignment;
|
|
||||||
public readonly bool SupportsTextureGatherOffsets;
|
public readonly bool SupportsTextureGatherOffsets;
|
||||||
public readonly bool SupportsTextureShadowLod;
|
public readonly bool SupportsTextureShadowLod;
|
||||||
public readonly bool SupportsVertexStoreAndAtomics;
|
public readonly bool SupportsVertexStoreAndAtomics;
|
||||||
@@ -103,7 +101,6 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
bool supportsGeometryShader,
|
bool supportsGeometryShader,
|
||||||
bool supportsGeometryShaderPassthrough,
|
bool supportsGeometryShaderPassthrough,
|
||||||
bool supportsTransformFeedback,
|
bool supportsTransformFeedback,
|
||||||
bool supportsImageBufferPixelAlignment,
|
|
||||||
bool supportsImageLoadFormatted,
|
bool supportsImageLoadFormatted,
|
||||||
bool supportsLayerVertexTessellation,
|
bool supportsLayerVertexTessellation,
|
||||||
bool supportsMismatchingViewFormat,
|
bool supportsMismatchingViewFormat,
|
||||||
@@ -115,7 +112,6 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
bool supportsShaderBarrierDivergence,
|
bool supportsShaderBarrierDivergence,
|
||||||
bool supportsShaderFloat64,
|
bool supportsShaderFloat64,
|
||||||
bool supportsShaderNonUniformIndexing,
|
bool supportsShaderNonUniformIndexing,
|
||||||
bool supportsTextureBufferPixelAlignment,
|
|
||||||
bool supportsTextureGatherOffsets,
|
bool supportsTextureGatherOffsets,
|
||||||
bool supportsTextureShadowLod,
|
bool supportsTextureShadowLod,
|
||||||
bool supportsVertexStoreAndAtomics,
|
bool supportsVertexStoreAndAtomics,
|
||||||
@@ -168,7 +164,6 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
SupportsGeometryShader = supportsGeometryShader;
|
SupportsGeometryShader = supportsGeometryShader;
|
||||||
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
||||||
SupportsTransformFeedback = supportsTransformFeedback;
|
SupportsTransformFeedback = supportsTransformFeedback;
|
||||||
SupportsImageBufferPixelAlignment = supportsImageBufferPixelAlignment;
|
|
||||||
SupportsImageLoadFormatted = supportsImageLoadFormatted;
|
SupportsImageLoadFormatted = supportsImageLoadFormatted;
|
||||||
SupportsLayerVertexTessellation = supportsLayerVertexTessellation;
|
SupportsLayerVertexTessellation = supportsLayerVertexTessellation;
|
||||||
SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
|
SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
|
||||||
@@ -180,7 +175,6 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
|
SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
|
||||||
SupportsShaderFloat64 = supportsShaderFloat64;
|
SupportsShaderFloat64 = supportsShaderFloat64;
|
||||||
SupportsShaderNonUniformIndexing = supportsShaderNonUniformIndexing;
|
SupportsShaderNonUniformIndexing = supportsShaderNonUniformIndexing;
|
||||||
SupportsTextureBufferPixelAlignment = supportsTextureBufferPixelAlignment;
|
|
||||||
SupportsTextureGatherOffsets = supportsTextureGatherOffsets;
|
SupportsTextureGatherOffsets = supportsTextureGatherOffsets;
|
||||||
SupportsTextureShadowLod = supportsTextureShadowLod;
|
SupportsTextureShadowLod = supportsTextureShadowLod;
|
||||||
SupportsVertexStoreAndAtomics = supportsVertexStoreAndAtomics;
|
SupportsVertexStoreAndAtomics = supportsVertexStoreAndAtomics;
|
||||||
|
|||||||
@@ -466,7 +466,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
engine.UpdateState(ulong.MaxValue & ~(1UL << StateUpdater.ShaderStateIndex));
|
engine.UpdateState(ulong.MaxValue & ~(1UL << StateUpdater.ShaderStateIndex));
|
||||||
|
|
||||||
_channel.TextureManager.SignalRenderTargetsModifiable();
|
|
||||||
_channel.TextureManager.UpdateRenderTargets();
|
_channel.TextureManager.UpdateRenderTargets();
|
||||||
|
|
||||||
int textureId = _state.State.DrawTextureTextureId;
|
int textureId = _state.State.DrawTextureTextureId;
|
||||||
@@ -804,7 +803,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
int index = (argument >> 6) & 0xf;
|
int index = (argument >> 6) & 0xf;
|
||||||
int layer = (argument >> 10) & 0x3ff;
|
int layer = (argument >> 10) & 0x3ff;
|
||||||
|
|
||||||
RenderTargetUpdateFlags updateFlags = RenderTargetUpdateFlags.SingleColor | RenderTargetUpdateFlags.ForClear;
|
RenderTargetUpdateFlags updateFlags = RenderTargetUpdateFlags.SingleColor;
|
||||||
|
|
||||||
if (layer != 0 || layerCount > 1)
|
if (layer != 0 || layerCount > 1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,11 +38,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
DiscardClip = 1 << 4,
|
DiscardClip = 1 << 4,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates that the render target will be used for a clear operation.
|
|
||||||
/// </summary>
|
|
||||||
ForClear = 1 << 5,
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default update flags for draw.
|
/// Default update flags for draw.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
private ProgramPipelineState _pipeline;
|
private ProgramPipelineState _pipeline;
|
||||||
|
|
||||||
private bool _fsReadsFragCoord;
|
private bool _fsReadsFragCoord;
|
||||||
private bool _fsAlwaysDiscards;
|
|
||||||
private bool _vsUsesDrawParameters;
|
private bool _vsUsesDrawParameters;
|
||||||
private bool _vtgWritesRtLayer;
|
private bool _vtgWritesRtLayer;
|
||||||
private byte _vsClipDistancesWritten;
|
private byte _vsClipDistancesWritten;
|
||||||
@@ -492,8 +491,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
Span<RtColorState> rtColorStateSpan = _state.State.RtColorState.AsSpan();
|
Span<RtColorState> rtColorStateSpan = _state.State.RtColorState.AsSpan();
|
||||||
|
|
||||||
bool rtModifiable = updateFlags.HasFlag(RenderTargetUpdateFlags.ForClear) || !_fsAlwaysDiscards;
|
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
{
|
{
|
||||||
int rtIndex = useControl ? rtControl.UnpackPermutationIndex(index) : index;
|
int rtIndex = useControl ? rtControl.UnpackPermutationIndex(index) : index;
|
||||||
@@ -502,7 +499,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
if (index >= count || !IsRtEnabled(colorState) || (singleColor && index != singleUse))
|
if (index >= count || !IsRtEnabled(colorState) || (singleColor && index != singleUse))
|
||||||
{
|
{
|
||||||
changedScale |= _channel.TextureManager.SetRenderTargetColor(index, null, rtModifiable);
|
changedScale |= _channel.TextureManager.SetRenderTargetColor(index, null);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -521,7 +518,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
samplesInY,
|
samplesInY,
|
||||||
sizeHint);
|
sizeHint);
|
||||||
|
|
||||||
changedScale |= _channel.TextureManager.SetRenderTargetColor(index, color, rtModifiable);
|
changedScale |= _channel.TextureManager.SetRenderTargetColor(index, color);
|
||||||
|
|
||||||
if (color != null)
|
if (color != null)
|
||||||
{
|
{
|
||||||
@@ -575,7 +572,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
changedScale |= _channel.TextureManager.SetRenderTargetDepthStencil(depthStencil, rtModifiable);
|
changedScale |= _channel.TextureManager.SetRenderTargetDepthStencil(depthStencil);
|
||||||
|
|
||||||
if (changedScale)
|
if (changedScale)
|
||||||
{
|
{
|
||||||
@@ -777,11 +774,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
float width = scaleX * 2;
|
float width = scaleX * 2;
|
||||||
float height = scaleY * 2;
|
float height = scaleY * 2;
|
||||||
|
|
||||||
if (yNegate)
|
|
||||||
{
|
|
||||||
y += _state.State.ScreenScissorState.Height - MathF.Abs(height);
|
|
||||||
}
|
|
||||||
|
|
||||||
float scale = _channel.TextureManager.RenderTargetScale;
|
float scale = _channel.TextureManager.RenderTargetScale;
|
||||||
if (scale != 1f)
|
if (scale != 1f)
|
||||||
{
|
{
|
||||||
@@ -1525,38 +1517,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
_currentProgramInfo[stageIndex] = info;
|
_currentProgramInfo[stageIndex] = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
_fsReadsFragCoord = false;
|
if (gs.Shaders[5]?.Info.UsesFragCoord == true)
|
||||||
|
|
||||||
ShaderProgramInfo fragmentShaderInfo = gs.Shaders[5]?.Info;
|
|
||||||
|
|
||||||
if (fragmentShaderInfo != null)
|
|
||||||
{
|
{
|
||||||
if (fragmentShaderInfo.UsesFragCoord)
|
// Make sure we update the viewport size on the support buffer if it will be consumed on the new shader.
|
||||||
|
|
||||||
|
if (!_fsReadsFragCoord && (_state.State.YControl & YControl.NegateY) != 0)
|
||||||
{
|
{
|
||||||
// Make sure we update the viewport size on the support buffer if it will be consumed on the new shader.
|
UpdateSupportBufferViewportSize();
|
||||||
|
|
||||||
if (!_fsReadsFragCoord && (_state.State.YControl & YControl.NegateY) != 0)
|
|
||||||
{
|
|
||||||
UpdateSupportBufferViewportSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
_fsReadsFragCoord = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_fsAlwaysDiscards != fragmentShaderInfo.HasUnconditionalDiscard)
|
_fsReadsFragCoord = true;
|
||||||
{
|
|
||||||
_fsAlwaysDiscards = fragmentShaderInfo.HasUnconditionalDiscard;
|
|
||||||
|
|
||||||
if (!_fsAlwaysDiscards)
|
|
||||||
{
|
|
||||||
_channel.TextureManager.RefreshModifiedTextures();
|
|
||||||
_channel.TextureManager.SignalRenderTargetsModifiable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_fsAlwaysDiscards = false;
|
_fsReadsFragCoord = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gs.VertexAsCompute != null)
|
if (gs.VertexAsCompute != null)
|
||||||
|
|||||||
@@ -1572,6 +1572,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// <param name="bound">True if the texture has been bound, false if it has been unbound</param>
|
/// <param name="bound">True if the texture has been bound, false if it has been unbound</param>
|
||||||
public void SignalModifying(bool bound)
|
public void SignalModifying(bool bound)
|
||||||
{
|
{
|
||||||
|
if (bound)
|
||||||
|
{
|
||||||
|
_scaledSetScore = Math.Max(0, _scaledSetScore - 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (_modifiedStale || Group.HasCopyDependencies || Group.HasFlushBuffer)
|
if (_modifiedStale || Group.HasCopyDependencies || Group.HasFlushBuffer)
|
||||||
{
|
{
|
||||||
_modifiedStale = false;
|
_modifiedStale = false;
|
||||||
@@ -1579,18 +1584,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
_physicalMemory.TextureCache.Lift(this);
|
_physicalMemory.TextureCache.Lift(this);
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Signals that a render target texture has been either bound or unbound.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bound">True if the texture has been bound, false if it has been unbound</param>
|
|
||||||
public void SignalBindingChange(bool bound)
|
|
||||||
{
|
|
||||||
if (bound)
|
if (bound)
|
||||||
{
|
{
|
||||||
_scaledSetScore = Math.Max(0, _scaledSetScore - 1);
|
|
||||||
|
|
||||||
IncrementReferenceCount();
|
IncrementReferenceCount();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using Ryujinx.Graphics.Gpu.Engine.Types;
|
|||||||
using Ryujinx.Graphics.Gpu.Memory;
|
using Ryujinx.Graphics.Gpu.Memory;
|
||||||
using Ryujinx.Graphics.Gpu.Shader;
|
using Ryujinx.Graphics.Gpu.Shader;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using Ryujinx.Memory.Range;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -68,9 +67,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
private int _lastFragmentTotal;
|
private int _lastFragmentTotal;
|
||||||
|
|
||||||
private readonly int _bufferTextureAlignment;
|
|
||||||
private readonly int _bufferImageAlignment;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a new instance of the texture bindings manager.
|
/// Constructs a new instance of the texture bindings manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -112,10 +108,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
_textureCounts = [];
|
_textureCounts = [];
|
||||||
|
|
||||||
int alignment = context.Capabilities.TextureBufferOffsetAlignment;
|
|
||||||
_bufferTextureAlignment = context.Capabilities.SupportsTextureBufferPixelAlignment ? 0 : alignment;
|
|
||||||
_bufferImageAlignment = context.Capabilities.SupportsImageBufferPixelAlignment ? 0 : alignment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -529,12 +521,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
if (hostTexture != null && texture.Target == Target.TextureBuffer)
|
if (hostTexture != null && texture.Target == Target.TextureBuffer)
|
||||||
{
|
{
|
||||||
MultiRange range = GetAlignedBufferTextureRange(texture, index, stageIndex, false);
|
|
||||||
|
|
||||||
// Ensure that the buffer texture is using the correct buffer as storage.
|
// Ensure that the buffer texture is using the correct buffer as storage.
|
||||||
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
||||||
// to ensure we're not using a old buffer that was already deleted.
|
// to ensure we're not using a old buffer that was already deleted.
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, range, bindingInfo, false);
|
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, false);
|
||||||
|
|
||||||
// Cache is not used for buffer texture, it must always rebind.
|
// Cache is not used for buffer texture, it must always rebind.
|
||||||
state.CachedTexture = null;
|
state.CachedTexture = null;
|
||||||
@@ -669,9 +659,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
||||||
// to ensure we're not using a old buffer that was already deleted.
|
// to ensure we're not using a old buffer that was already deleted.
|
||||||
|
|
||||||
MultiRange range = GetAlignedBufferTextureRange(texture, index, stageIndex, true);
|
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, true);
|
||||||
|
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, range, bindingInfo, true);
|
|
||||||
|
|
||||||
// Cache is not used for buffer texture, it must always rebind.
|
// Cache is not used for buffer texture, it must always rebind.
|
||||||
state.CachedTexture = null;
|
state.CachedTexture = null;
|
||||||
@@ -704,61 +692,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
return specStateMatches;
|
return specStateMatches;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the aligned address of the texture according to the host requirements.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="texture">Texture to have its address aligned</param>
|
|
||||||
/// <param name="index">Index of the texture in the shader</param>
|
|
||||||
/// <param name="stageIndex">Index of the shader stage</param>
|
|
||||||
/// <param name="isImage">True if the texture is bound as image, false for sampled textures</param>
|
|
||||||
/// <returns>Aligned address and size of the buffer texture</returns>
|
|
||||||
private MultiRange GetAlignedBufferTextureRange(Texture texture, int index, int stageIndex, bool isImage)
|
|
||||||
{
|
|
||||||
MultiRange range = texture.Range;
|
|
||||||
int alignment = isImage ? _bufferImageAlignment : _bufferTextureAlignment;
|
|
||||||
|
|
||||||
if (alignment != 0)
|
|
||||||
{
|
|
||||||
MemoryRange firstRange = range.GetSubRange(0);
|
|
||||||
ulong misalign = firstRange.Address & ((ulong)alignment - 1);
|
|
||||||
int offset = misalign != 0 ? (int)misalign / texture.Info.FormatInfo.BytesPerPixel : 0;
|
|
||||||
|
|
||||||
if (misalign != 0)
|
|
||||||
{
|
|
||||||
firstRange = new MemoryRange(firstRange.Address - misalign, firstRange.Size + misalign);
|
|
||||||
|
|
||||||
if (range.Count > 1)
|
|
||||||
{
|
|
||||||
MemoryRange[] ranges = new MemoryRange[range.Count];
|
|
||||||
|
|
||||||
ranges[0] = firstRange;
|
|
||||||
|
|
||||||
for (int i = 1; i < range.Count; i++)
|
|
||||||
{
|
|
||||||
ranges[i] = range.GetSubRange(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
range = new MultiRange(ranges);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
range = new MultiRange(firstRange.Address, firstRange.Size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isImage)
|
|
||||||
{
|
|
||||||
_context.SupportBufferUpdater.UpdateBufferImageOffset(stageIndex, index, offset);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_context.SupportBufferUpdater.UpdateBufferTextureOffset(stageIndex, index, offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return range;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the texture descriptor for a given texture handle.
|
/// Gets the texture descriptor for a given texture handle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -19,39 +19,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
private readonly TexturePoolCache _texturePoolCache;
|
private readonly TexturePoolCache _texturePoolCache;
|
||||||
private readonly SamplerPoolCache _samplerPoolCache;
|
private readonly SamplerPoolCache _samplerPoolCache;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Bound render target texture modification report state.
|
|
||||||
/// </summary>
|
|
||||||
[Flags]
|
|
||||||
private enum BindState : byte
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Render target texture has not been signalled for modification, and can't be modified on the next render operations.
|
|
||||||
/// </summary>
|
|
||||||
None = 0,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Render target texture has been signalled for modification.
|
|
||||||
/// </summary>
|
|
||||||
Bound = 1 << 0,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Render target texture might be modified on the next render operations.
|
|
||||||
/// </summary>
|
|
||||||
Modified = 1 << 1,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Render target texture has been signalled for modification and might be modified on the next render operations.
|
|
||||||
/// </summary>
|
|
||||||
BoundModified = Bound | Modified,
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Texture[] _rtColors;
|
private readonly Texture[] _rtColors;
|
||||||
private readonly ITexture[] _rtHostColors;
|
private readonly ITexture[] _rtHostColors;
|
||||||
private readonly BindState[] _rtColorsBound;
|
private readonly bool[] _rtColorsBound;
|
||||||
private Texture _rtDepthStencil;
|
private Texture _rtDepthStencil;
|
||||||
private ITexture _rtHostDs;
|
private ITexture _rtHostDs;
|
||||||
private BindState _rtDsBound;
|
private bool _rtDsBound;
|
||||||
|
|
||||||
public int ClipRegionWidth { get; private set; }
|
public int ClipRegionWidth { get; private set; }
|
||||||
public int ClipRegionHeight { get; private set; }
|
public int ClipRegionHeight { get; private set; }
|
||||||
@@ -82,7 +55,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
_rtColors = new Texture[Constants.TotalRenderTargets];
|
_rtColors = new Texture[Constants.TotalRenderTargets];
|
||||||
_rtHostColors = new ITexture[Constants.TotalRenderTargets];
|
_rtHostColors = new ITexture[Constants.TotalRenderTargets];
|
||||||
_rtColorsBound = new BindState[Constants.TotalRenderTargets];
|
_rtColorsBound = new bool[Constants.TotalRenderTargets];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -178,39 +151,27 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">The index of the color buffer to set (up to 8)</param>
|
/// <param name="index">The index of the color buffer to set (up to 8)</param>
|
||||||
/// <param name="color">The color buffer texture</param>
|
/// <param name="color">The color buffer texture</param>
|
||||||
/// <param name="modified">Indicates if the following render operations will modidify <paramref name="color"/> contents</param>
|
|
||||||
/// <returns>True if render target scale must be updated.</returns>
|
/// <returns>True if render target scale must be updated.</returns>
|
||||||
public bool SetRenderTargetColor(int index, Texture color, bool modified)
|
public bool SetRenderTargetColor(int index, Texture color)
|
||||||
{
|
{
|
||||||
bool hasValue = color != null;
|
bool hasValue = color != null;
|
||||||
bool changesScale = (hasValue != (_rtColors[index] != null)) || (hasValue && RenderTargetScale != color.ScaleFactor);
|
bool changesScale = (hasValue != (_rtColors[index] != null)) || (hasValue && RenderTargetScale != color.ScaleFactor);
|
||||||
|
|
||||||
if (_rtColors[index] != color)
|
if (_rtColors[index] != color)
|
||||||
{
|
{
|
||||||
Texture oldColor = _rtColors[index];
|
if (_rtColorsBound[index])
|
||||||
|
|
||||||
if (oldColor != null)
|
|
||||||
{
|
{
|
||||||
if (_rtColorsBound[index].HasFlag(BindState.Bound))
|
_rtColors[index]?.SignalModifying(false);
|
||||||
{
|
}
|
||||||
oldColor.SignalModifying(false);
|
else
|
||||||
}
|
{
|
||||||
|
_rtColorsBound[index] = true;
|
||||||
oldColor.SignalBindingChange(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_rtColorsBound[index] = modified ? BindState.BoundModified : BindState.None;
|
|
||||||
|
|
||||||
if (color != null)
|
if (color != null)
|
||||||
{
|
{
|
||||||
color.SynchronizeMemory();
|
color.SynchronizeMemory();
|
||||||
|
color.SignalModifying(true);
|
||||||
if (modified)
|
|
||||||
{
|
|
||||||
color.SignalModifying(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
color.SignalBindingChange(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_rtColors[index] = color;
|
_rtColors[index] = color;
|
||||||
@@ -223,39 +184,27 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// Sets the render target depth-stencil buffer.
|
/// Sets the render target depth-stencil buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="depthStencil">The depth-stencil buffer texture</param>
|
/// <param name="depthStencil">The depth-stencil buffer texture</param>
|
||||||
/// <param name="modified">Indicates if the following render operations will modidify <paramref name="depthStencil"/> contents</param>
|
|
||||||
/// <returns>True if render target scale must be updated.</returns>
|
/// <returns>True if render target scale must be updated.</returns>
|
||||||
public bool SetRenderTargetDepthStencil(Texture depthStencil, bool modified)
|
public bool SetRenderTargetDepthStencil(Texture depthStencil)
|
||||||
{
|
{
|
||||||
bool hasValue = depthStencil != null;
|
bool hasValue = depthStencil != null;
|
||||||
bool changesScale = (hasValue != (_rtDepthStencil != null)) || (hasValue && RenderTargetScale != depthStencil.ScaleFactor);
|
bool changesScale = (hasValue != (_rtDepthStencil != null)) || (hasValue && RenderTargetScale != depthStencil.ScaleFactor);
|
||||||
|
|
||||||
if (_rtDepthStencil != depthStencil)
|
if (_rtDepthStencil != depthStencil)
|
||||||
{
|
{
|
||||||
Texture oldDepthStencil = _rtDepthStencil;
|
if (_rtDsBound)
|
||||||
|
|
||||||
if (oldDepthStencil != null)
|
|
||||||
{
|
{
|
||||||
if (_rtDsBound.HasFlag(BindState.Bound))
|
_rtDepthStencil?.SignalModifying(false);
|
||||||
{
|
}
|
||||||
oldDepthStencil.SignalModifying(false);
|
else
|
||||||
}
|
{
|
||||||
|
_rtDsBound = true;
|
||||||
oldDepthStencil.SignalBindingChange(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_rtDsBound = modified ? BindState.BoundModified : BindState.None;
|
|
||||||
|
|
||||||
if (depthStencil != null)
|
if (depthStencil != null)
|
||||||
{
|
{
|
||||||
depthStencil.SynchronizeMemory();
|
depthStencil.SynchronizeMemory();
|
||||||
|
depthStencil.SignalModifying(true);
|
||||||
if (modified)
|
|
||||||
{
|
|
||||||
depthStencil.SignalModifying(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
depthStencil.SignalBindingChange(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_rtDepthStencil = depthStencil;
|
_rtDepthStencil = depthStencil;
|
||||||
@@ -494,10 +443,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
{
|
{
|
||||||
hostDsTexture = dsTexture.HostTexture;
|
hostDsTexture = dsTexture.HostTexture;
|
||||||
|
|
||||||
if (_rtDsBound == BindState.Modified)
|
if (!_rtDsBound)
|
||||||
{
|
{
|
||||||
dsTexture.SignalModifying(true);
|
dsTexture.SignalModifying(true);
|
||||||
_rtDsBound |= BindState.Bound;
|
_rtDsBound = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,10 +470,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
{
|
{
|
||||||
hostTexture = texture.HostTexture;
|
hostTexture = texture.HostTexture;
|
||||||
|
|
||||||
if (_rtColorsBound[index] == BindState.Modified)
|
if (!_rtColorsBound[index])
|
||||||
{
|
{
|
||||||
texture.SignalModifying(true);
|
texture.SignalModifying(true);
|
||||||
_rtColorsBound[index] |= BindState.Bound;
|
_rtColorsBound[index] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,37 +518,24 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
{
|
{
|
||||||
Texture dsTexture = _rtDepthStencil;
|
Texture dsTexture = _rtDepthStencil;
|
||||||
|
|
||||||
if (dsTexture != null && _rtDsBound.HasFlag(BindState.Bound))
|
if (dsTexture != null && _rtDsBound)
|
||||||
{
|
{
|
||||||
dsTexture.SignalModifying(false);
|
dsTexture.SignalModifying(false);
|
||||||
_rtDsBound &= ~BindState.Bound;
|
_rtDsBound = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int index = 0; index < _rtColors.Length; index++)
|
for (int index = 0; index < _rtColors.Length; index++)
|
||||||
{
|
{
|
||||||
Texture texture = _rtColors[index];
|
Texture texture = _rtColors[index];
|
||||||
|
|
||||||
if (texture != null && _rtColorsBound[index].HasFlag(BindState.Bound))
|
if (texture != null && _rtColorsBound[index])
|
||||||
{
|
{
|
||||||
texture.SignalModifying(false);
|
texture.SignalModifying(false);
|
||||||
_rtColorsBound[index] &= ~BindState.Bound;
|
_rtColorsBound[index] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates that the currently bound render targets might be modified, if they are used on the next render operation.
|
|
||||||
/// </summary>
|
|
||||||
public void SignalRenderTargetsModifiable()
|
|
||||||
{
|
|
||||||
_rtDsBound |= BindState.Modified;
|
|
||||||
|
|
||||||
for (int index = 0; index < _rtColorsBound.Length; index++)
|
|
||||||
{
|
|
||||||
_rtColorsBound[index] |= BindState.Modified;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Forces the texture and sampler pools to be re-loaded from the cache on next use.
|
/// Forces the texture and sampler pools to be re-loaded from the cache on next use.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -636,11 +572,19 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
for (int i = 0; i < _rtColors.Length; i++)
|
for (int i = 0; i < _rtColors.Length; i++)
|
||||||
{
|
{
|
||||||
_rtColors[i]?.DecrementReferenceCount();
|
if (_rtColorsBound[i])
|
||||||
|
{
|
||||||
|
_rtColors[i]?.DecrementReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
_rtColors[i] = null;
|
_rtColors[i] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
_rtDepthStencil?.DecrementReferenceCount();
|
if (_rtDsBound)
|
||||||
|
{
|
||||||
|
_rtDepthStencil?.DecrementReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
_rtDepthStencil = null;
|
_rtDepthStencil = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,38 +129,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the offset used for accessing buffer textures that are not aligned to the host requirements.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stageIndex">Index of the shader stage where the texture is used</param>
|
|
||||||
/// <param name="bindingIndex">Index of the texture binding in the shader</param>
|
|
||||||
/// <param name="offset">Offset for the misaligned part of the address</param>
|
|
||||||
public void UpdateBufferTextureOffset(int stageIndex, int bindingIndex, int offset)
|
|
||||||
{
|
|
||||||
if (_data.BufferTextureOffset[stageIndex][bindingIndex].X != offset)
|
|
||||||
{
|
|
||||||
_data.BufferTextureOffset[stageIndex][bindingIndex].X = offset;
|
|
||||||
int index = stageIndex * SupportBuffer.TextureCount + bindingIndex;
|
|
||||||
MarkDirty(SupportBuffer.BufferTextureOffsetOffset + index * sizeof(int) * 4, sizeof(int));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the offset used for accessing buffer images that are not aligned to the host requirements.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stageIndex">Index of the shader stage where the image is used</param>
|
|
||||||
/// <param name="bindingIndex">Index of the image binding in the shader</param>
|
|
||||||
/// <param name="offset">Offset for the misaligned part of the address</param>
|
|
||||||
public void UpdateBufferImageOffset(int stageIndex, int bindingIndex, int offset)
|
|
||||||
{
|
|
||||||
if (_data.BufferTextureOffset[stageIndex][bindingIndex].Y != offset)
|
|
||||||
{
|
|
||||||
_data.BufferTextureOffset[stageIndex][bindingIndex].Y = offset;
|
|
||||||
int index = stageIndex * SupportBuffer.TextureCount + bindingIndex;
|
|
||||||
MarkDirty(SupportBuffer.BufferTextureOffsetOffset + index * sizeof(int) * 4 + sizeof(int), sizeof(int));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets whether the format of a given render target is a BGRA format.
|
/// Sets whether the format of a given render target is a BGRA format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||||
private const uint CodeGenVersion = 6371;
|
private const uint CodeGenVersion = 7354;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
@@ -170,11 +170,6 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UsesRtLayer;
|
public bool UsesRtLayer;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates that the fragment shader always discards the fragment, not producing any output for the bound render targets.
|
|
||||||
/// </summary>
|
|
||||||
public bool HasUnconditionalDiscard;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Bit mask with the clip distances written on the vertex stage.
|
/// Bit mask with the clip distances written on the vertex stage.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -811,7 +806,6 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
dataInfo.UsesInstanceId,
|
dataInfo.UsesInstanceId,
|
||||||
dataInfo.UsesDrawParameters,
|
dataInfo.UsesDrawParameters,
|
||||||
dataInfo.UsesRtLayer,
|
dataInfo.UsesRtLayer,
|
||||||
dataInfo.HasUnconditionalDiscard,
|
|
||||||
dataInfo.ClipDistancesWritten,
|
dataInfo.ClipDistancesWritten,
|
||||||
dataInfo.FragmentOutputMap);
|
dataInfo.FragmentOutputMap);
|
||||||
}
|
}
|
||||||
@@ -842,7 +836,6 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
UsesInstanceId = info.UsesInstanceId,
|
UsesInstanceId = info.UsesInstanceId,
|
||||||
UsesDrawParameters = info.UsesDrawParameters,
|
UsesDrawParameters = info.UsesDrawParameters,
|
||||||
UsesRtLayer = info.UsesRtLayer,
|
UsesRtLayer = info.UsesRtLayer,
|
||||||
HasUnconditionalDiscard = info.HasUnconditionalDiscard,
|
|
||||||
ClipDistancesWritten = info.ClipDistancesWritten,
|
ClipDistancesWritten = info.ClipDistancesWritten,
|
||||||
FragmentOutputMap = info.FragmentOutputMap,
|
FragmentOutputMap = info.FragmentOutputMap,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -207,10 +207,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
public bool QueryHostSupportsBgraFormat() => _context.Capabilities.SupportsBgraFormat;
|
public bool QueryHostSupportsBgraFormat() => _context.Capabilities.SupportsBgraFormat;
|
||||||
|
|
||||||
public bool QueryHostSupportsBufferImagePixelAlignment() => _context.Capabilities.SupportsImageBufferPixelAlignment;
|
|
||||||
|
|
||||||
public bool QueryHostSupportsBufferTexturePixelAlignment() => _context.Capabilities.SupportsTextureBufferPixelAlignment;
|
|
||||||
|
|
||||||
public bool QueryHostSupportsFragmentShaderInterlock() => _context.Capabilities.SupportsFragmentShaderInterlock;
|
public bool QueryHostSupportsFragmentShaderInterlock() => _context.Capabilities.SupportsFragmentShaderInterlock;
|
||||||
|
|
||||||
public bool QueryHostSupportsFragmentShaderOrderingIntel() => _context.Capabilities.SupportsFragmentShaderOrderingIntel;
|
public bool QueryHostSupportsFragmentShaderOrderingIntel() => _context.Capabilities.SupportsFragmentShaderOrderingIntel;
|
||||||
|
|||||||
@@ -430,8 +430,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
TranslatorContext lastInVertexPipeline = geometryToCompute ? translatorContexts[4] ?? currentStage : currentStage;
|
TranslatorContext lastInVertexPipeline = geometryToCompute ? translatorContexts[4] ?? currentStage : currentStage;
|
||||||
|
|
||||||
(program, ShaderProgramInfo vacInfo) = lastInVertexPipeline.GenerateVertexPassthroughForCompute();
|
program = lastInVertexPipeline.GenerateVertexPassthroughForCompute();
|
||||||
infoBuilder.AddStageInfoVac(vacInfo);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -536,7 +535,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
private ShaderAsCompute CreateHostVertexAsComputeProgram(ShaderProgram program, TranslatorContext context, bool tfEnabled)
|
private ShaderAsCompute CreateHostVertexAsComputeProgram(ShaderProgram program, TranslatorContext context, bool tfEnabled)
|
||||||
{
|
{
|
||||||
ShaderSource source = new(program.Code, program.BinaryCode, ShaderStage.Compute, program.Language);
|
ShaderSource source = new(program.Code, program.BinaryCode, ShaderStage.Compute, program.Language);
|
||||||
ShaderInfo info = ShaderInfoBuilder.BuildForVertexAsCompute(_context, program.Info, context.GetVertexAsComputeInfo(), tfEnabled);
|
ShaderInfo info = ShaderInfoBuilder.BuildForVertexAsCompute(_context, program.Info, tfEnabled);
|
||||||
|
|
||||||
return new(_context.Renderer.CreateProgram([source], info), program.Info, context.GetResourceReservations());
|
return new(_context.Renderer.CreateProgram([source], info), program.Info, context.GetResourceReservations());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
private void PopulateDescriptorAndUsages(ResourceStages stages, ResourceType type, int setIndex, int start, int count, bool write = false)
|
private void PopulateDescriptorAndUsages(ResourceStages stages, ResourceType type, int setIndex, int start, int count, bool write = false)
|
||||||
{
|
{
|
||||||
AddDescriptor(stages, type, setIndex, start, count);
|
AddDescriptor(stages, type, setIndex, start, count);
|
||||||
// AddUsage(stages, type, setIndex, start, count, write);
|
AddUsage(stages, type, setIndex, start, count, write);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -159,25 +159,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
AddUsage(info.Images, stages, isImage: true);
|
AddUsage(info.Images, stages, isImage: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddStageInfoVac(ShaderProgramInfo info)
|
|
||||||
{
|
|
||||||
ResourceStages stages = info.Stage switch
|
|
||||||
{
|
|
||||||
ShaderStage.Compute => ResourceStages.Compute,
|
|
||||||
ShaderStage.Vertex => ResourceStages.Vertex,
|
|
||||||
ShaderStage.TessellationControl => ResourceStages.TessellationControl,
|
|
||||||
ShaderStage.TessellationEvaluation => ResourceStages.TessellationEvaluation,
|
|
||||||
ShaderStage.Geometry => ResourceStages.Geometry,
|
|
||||||
ShaderStage.Fragment => ResourceStages.Fragment,
|
|
||||||
_ => ResourceStages.None,
|
|
||||||
};
|
|
||||||
|
|
||||||
AddUsage(info.CBuffers, stages, isStorage: false);
|
|
||||||
AddUsage(info.SBuffers, stages, isStorage: true);
|
|
||||||
AddUsage(info.Textures, stages, isImage: false);
|
|
||||||
AddUsage(info.Images, stages, isImage: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a resource descriptor to the list of descriptors.
|
/// Adds a resource descriptor to the list of descriptors.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -441,11 +422,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <param name="tfEnabled">Indicates if the graphics shader is used with transform feedback enabled</param>
|
/// <param name="tfEnabled">Indicates if the graphics shader is used with transform feedback enabled</param>
|
||||||
/// <param name="fromCache">True if the compute shader comes from a disk cache, false otherwise</param>
|
/// <param name="fromCache">True if the compute shader comes from a disk cache, false otherwise</param>
|
||||||
/// <returns>Shader information</returns>
|
/// <returns>Shader information</returns>
|
||||||
public static ShaderInfo BuildForVertexAsCompute(GpuContext context, ShaderProgramInfo info, ShaderProgramInfo info2, bool tfEnabled, bool fromCache = false)
|
public static ShaderInfo BuildForVertexAsCompute(GpuContext context, ShaderProgramInfo info, bool tfEnabled, bool fromCache = false)
|
||||||
{
|
{
|
||||||
ShaderInfoBuilder builder = new(context, tfEnabled, vertexAsCompute: true);
|
ShaderInfoBuilder builder = new(context, tfEnabled, vertexAsCompute: true);
|
||||||
|
|
||||||
builder.AddStageInfoVac(info2);
|
|
||||||
builder.AddStageInfo(info, vertexAsCompute: true);
|
builder.AddStageInfo(info, vertexAsCompute: true);
|
||||||
|
|
||||||
return builder.Build(null, fromCache);
|
return builder.Build(null, fromCache);
|
||||||
|
|||||||
@@ -174,7 +174,6 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
supportsGeometryShader: true,
|
supportsGeometryShader: true,
|
||||||
supportsGeometryShaderPassthrough: HwCapabilities.SupportsGeometryShaderPassthrough,
|
supportsGeometryShaderPassthrough: HwCapabilities.SupportsGeometryShaderPassthrough,
|
||||||
supportsTransformFeedback: true,
|
supportsTransformFeedback: true,
|
||||||
supportsImageBufferPixelAlignment: false,
|
|
||||||
supportsImageLoadFormatted: HwCapabilities.SupportsImageLoadFormatted,
|
supportsImageLoadFormatted: HwCapabilities.SupportsImageLoadFormatted,
|
||||||
supportsLayerVertexTessellation: HwCapabilities.SupportsShaderViewportLayerArray,
|
supportsLayerVertexTessellation: HwCapabilities.SupportsShaderViewportLayerArray,
|
||||||
supportsMismatchingViewFormat: HwCapabilities.SupportsMismatchingViewFormat,
|
supportsMismatchingViewFormat: HwCapabilities.SupportsMismatchingViewFormat,
|
||||||
@@ -186,7 +185,6 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
supportsShaderBarrierDivergence: !(intelWindows || intelUnix),
|
supportsShaderBarrierDivergence: !(intelWindows || intelUnix),
|
||||||
supportsShaderFloat64: true,
|
supportsShaderFloat64: true,
|
||||||
supportsShaderNonUniformIndexing: false,
|
supportsShaderNonUniformIndexing: false,
|
||||||
supportsTextureBufferPixelAlignment: false,
|
|
||||||
supportsTextureGatherOffsets: true,
|
supportsTextureGatherOffsets: true,
|
||||||
supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
|
supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
|
||||||
supportsVertexStoreAndAtomics: true,
|
supportsVertexStoreAndAtomics: true,
|
||||||
|
|||||||
@@ -522,7 +522,6 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||||||
|
|
||||||
enum PMode
|
enum PMode
|
||||||
{
|
{
|
||||||
Idx = 0,
|
|
||||||
F4e = 1,
|
F4e = 1,
|
||||||
B4e = 2,
|
B4e = 2,
|
||||||
Rc8 = 3,
|
Rc8 = 3,
|
||||||
|
|||||||
@@ -234,24 +234,6 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Queries host support for buffer image access with the buffer offset aligned to a single pixel rather than a fixed alignment.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>True if the host supports buffer image access with pixel alignment, false otherwise</returns>
|
|
||||||
bool QueryHostSupportsBufferImagePixelAlignment()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Queries host support for buffer texture access with the buffer offset aligned to a single pixel rather than a fixed alignment.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>True if the host supports buffer texture access with pixel alignment, false otherwise</returns>
|
|
||||||
bool QueryHostSupportsBufferTexturePixelAlignment()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries host support for fragment shader ordering critical sections on the shader code.
|
/// Queries host support for fragment shader ordering critical sections on the shader code.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -215,6 +215,34 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||||||
context.TranslatorContext.GpuAccessor.Log("Shader instruction Pret is not implemented.");
|
context.TranslatorContext.GpuAccessor.Log("Shader instruction Pret is not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void PrmtR(EmitterContext context)
|
||||||
|
{
|
||||||
|
context.GetOp<InstPrmtR>();
|
||||||
|
|
||||||
|
context.TranslatorContext.GpuAccessor.Log("Shader instruction PrmtR is not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PrmtI(EmitterContext context)
|
||||||
|
{
|
||||||
|
context.GetOp<InstPrmtI>();
|
||||||
|
|
||||||
|
context.TranslatorContext.GpuAccessor.Log("Shader instruction PrmtI is not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PrmtC(EmitterContext context)
|
||||||
|
{
|
||||||
|
context.GetOp<InstPrmtC>();
|
||||||
|
|
||||||
|
context.TranslatorContext.GpuAccessor.Log("Shader instruction PrmtC is not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PrmtRc(EmitterContext context)
|
||||||
|
{
|
||||||
|
context.GetOp<InstPrmtRc>();
|
||||||
|
|
||||||
|
context.TranslatorContext.GpuAccessor.Log("Shader instruction PrmtRc is not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
public static void R2b(EmitterContext context)
|
public static void R2b(EmitterContext context)
|
||||||
{
|
{
|
||||||
context.GetOp<InstR2b>();
|
context.GetOp<InstR2b>();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using Ryujinx.Graphics.Shader.Decoders;
|
using Ryujinx.Graphics.Shader.Decoders;
|
||||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
using Ryujinx.Graphics.Shader.Translation;
|
using Ryujinx.Graphics.Shader.Translation;
|
||||||
using System;
|
|
||||||
using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
|
using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
|
||||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||||
|
|
||||||
@@ -37,38 +37,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||||||
context.Copy(GetDest(op.Dest), GetSrcImm(context, op.Imm32));
|
context.Copy(GetDest(op.Dest), GetSrcImm(context, op.Imm32));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void PrmtR(EmitterContext context)
|
|
||||||
{
|
|
||||||
context.GetOp<InstPrmtR>();
|
|
||||||
|
|
||||||
context.TranslatorContext.GpuAccessor.Log("Shader instruction PrmtR is not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void PrmtI(EmitterContext context)
|
|
||||||
{
|
|
||||||
InstPrmtI op = context.GetOp<InstPrmtI>();
|
|
||||||
|
|
||||||
Operand op1 = GetSrcReg(context, op.SrcA);
|
|
||||||
Operand control = GetSrcImm(context, op.Imm20);
|
|
||||||
Operand op2 = GetSrcReg(context, op.SrcC);
|
|
||||||
|
|
||||||
EmitPrmt(context, op1, control, op2, op.PMode, op.Dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void PrmtC(EmitterContext context)
|
|
||||||
{
|
|
||||||
context.GetOp<InstPrmtC>();
|
|
||||||
|
|
||||||
context.TranslatorContext.GpuAccessor.Log("Shader instruction PrmtC is not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void PrmtRc(EmitterContext context)
|
|
||||||
{
|
|
||||||
context.GetOp<InstPrmtRc>();
|
|
||||||
|
|
||||||
context.TranslatorContext.GpuAccessor.Log("Shader instruction PrmtRc is not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void R2pR(EmitterContext context)
|
public static void R2pR(EmitterContext context)
|
||||||
{
|
{
|
||||||
InstR2pR op = context.GetOp<InstR2pR>();
|
InstR2pR op = context.GetOp<InstR2pR>();
|
||||||
@@ -201,39 +169,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||||||
context.Copy(GetDest(op.Dest), src);
|
context.Copy(GetDest(op.Dest), src);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SelR(EmitterContext context)
|
|
||||||
{
|
|
||||||
InstSelR op = context.GetOp<InstSelR>();
|
|
||||||
|
|
||||||
Operand srcA = GetSrcReg(context, op.SrcA);
|
|
||||||
Operand srcB = GetSrcReg(context, op.SrcB);
|
|
||||||
Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
|
|
||||||
|
|
||||||
EmitSel(context, srcA, srcB, srcPred, op.Dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SelI(EmitterContext context)
|
|
||||||
{
|
|
||||||
InstSelI op = context.GetOp<InstSelI>();
|
|
||||||
|
|
||||||
Operand srcA = GetSrcReg(context, op.SrcA);
|
|
||||||
Operand srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20));
|
|
||||||
Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
|
|
||||||
|
|
||||||
EmitSel(context, srcA, srcB, srcPred, op.Dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SelC(EmitterContext context)
|
|
||||||
{
|
|
||||||
InstSelC op = context.GetOp<InstSelC>();
|
|
||||||
|
|
||||||
Operand srcA = GetSrcReg(context, op.SrcA);
|
|
||||||
Operand srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
|
|
||||||
Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
|
|
||||||
|
|
||||||
EmitSel(context, srcA, srcB, srcPred, op.Dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Operand EmitLoadSubgroupLaneId(EmitterContext context)
|
private static Operand EmitLoadSubgroupLaneId(EmitterContext context)
|
||||||
{
|
{
|
||||||
if (context.TranslatorContext.GpuAccessor.QueryHostSubgroupSize() <= 32)
|
if (context.TranslatorContext.GpuAccessor.QueryHostSubgroupSize() <= 32)
|
||||||
@@ -280,34 +215,37 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitPrmt(EmitterContext context, Operand op1, Operand control, Operand op2, PMode pMode, int rd)
|
public static void SelR(EmitterContext context)
|
||||||
{
|
{
|
||||||
if (pMode == PMode.Idx)
|
InstSelR op = context.GetOp<InstSelR>();
|
||||||
{
|
|
||||||
Operand res = Const(0);
|
|
||||||
|
|
||||||
for (int b = 0; b < 4; b++)
|
Operand srcA = GetSrcReg(context, op.SrcA);
|
||||||
{
|
Operand srcB = GetSrcReg(context, op.SrcB);
|
||||||
Operand sel = context.ShiftRightU32(control, Const(b * 4));
|
Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
|
||||||
Operand byteSel = context.BitwiseAnd(sel, Const(7));
|
|
||||||
Operand copySign = context.BitwiseAnd(sel, Const(8));
|
|
||||||
|
|
||||||
Operand srcOp = context.ConditionalSelect(context.BitwiseAnd(byteSel, Const(4)), op2, op1);
|
EmitSel(context, srcA, srcB, srcPred, op.Dest);
|
||||||
Operand srcValue = context.ShiftRightU32(srcOp, context.ShiftLeft(context.BitwiseAnd(byteSel, Const(3)), Const(3)));
|
}
|
||||||
Operand srcSign = context.ShiftRightS32(context.ShiftLeft(srcValue, Const(24)), Const(31));
|
|
||||||
|
|
||||||
srcValue = context.ConditionalSelect(copySign, srcSign, srcValue);
|
public static void SelI(EmitterContext context)
|
||||||
srcValue = context.BitwiseAnd(srcValue, Const(0xff));
|
{
|
||||||
|
InstSelI op = context.GetOp<InstSelI>();
|
||||||
|
|
||||||
res = context.BitfieldInsert(res, srcValue, Const(b * 8), Const(8));
|
Operand srcA = GetSrcReg(context, op.SrcA);
|
||||||
}
|
Operand srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20));
|
||||||
|
Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
|
||||||
|
|
||||||
context.Copy(GetDest(rd), res);
|
EmitSel(context, srcA, srcB, srcPred, op.Dest);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
public static void SelC(EmitterContext context)
|
||||||
throw new NotImplementedException(pMode.ToString());
|
{
|
||||||
}
|
InstSelC op = context.GetOp<InstSelC>();
|
||||||
|
|
||||||
|
Operand srcA = GetSrcReg(context, op.SrcA);
|
||||||
|
Operand srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
|
||||||
|
Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
|
||||||
|
|
||||||
|
EmitSel(context, srcA, srcB, srcPred, op.Dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitR2p(EmitterContext context, Operand value, Operand mask, ByteSel byteSel, bool ccpr)
|
private static void EmitR2p(EmitterContext context, Operand value, Operand mask, ByteSel byteSel, bool ccpr)
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
|||||||
set => _branch = AddSuccessor(_branch, value);
|
set => _branch = AddSuccessor(_branch, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasSuccessor => _branch != null || _next != null;
|
|
||||||
public bool HasBranch => _branch != null;
|
public bool HasBranch => _branch != null;
|
||||||
public bool Reachable => Index == 0 || Predecessors.Count != 0;
|
public bool Reachable => Index == 0 || Predecessors.Count != 0;
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
public bool UsesInstanceId { get; }
|
public bool UsesInstanceId { get; }
|
||||||
public bool UsesDrawParameters { get; }
|
public bool UsesDrawParameters { get; }
|
||||||
public bool UsesRtLayer { get; }
|
public bool UsesRtLayer { get; }
|
||||||
public bool HasUnconditionalDiscard { get; }
|
|
||||||
public byte ClipDistancesWritten { get; }
|
public byte ClipDistancesWritten { get; }
|
||||||
public int FragmentOutputMap { get; }
|
public int FragmentOutputMap { get; }
|
||||||
|
|
||||||
@@ -35,7 +34,6 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
bool usesInstanceId,
|
bool usesInstanceId,
|
||||||
bool usesDrawParameters,
|
bool usesDrawParameters,
|
||||||
bool usesRtLayer,
|
bool usesRtLayer,
|
||||||
bool hasUnconditionalDiscard,
|
|
||||||
byte clipDistancesWritten,
|
byte clipDistancesWritten,
|
||||||
int fragmentOutputMap)
|
int fragmentOutputMap)
|
||||||
{
|
{
|
||||||
@@ -52,7 +50,6 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
UsesInstanceId = usesInstanceId;
|
UsesInstanceId = usesInstanceId;
|
||||||
UsesDrawParameters = usesDrawParameters;
|
UsesDrawParameters = usesDrawParameters;
|
||||||
UsesRtLayer = usesRtLayer;
|
UsesRtLayer = usesRtLayer;
|
||||||
HasUnconditionalDiscard = hasUnconditionalDiscard;
|
|
||||||
ClipDistancesWritten = clipDistancesWritten;
|
ClipDistancesWritten = clipDistancesWritten;
|
||||||
FragmentOutputMap = fragmentOutputMap;
|
FragmentOutputMap = fragmentOutputMap;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
RenderScale,
|
RenderScale,
|
||||||
TfeOffset,
|
TfeOffset,
|
||||||
TfeVertexCount,
|
TfeVertexCount,
|
||||||
BufferTextureOffset,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct SupportBuffer
|
public struct SupportBuffer
|
||||||
@@ -43,13 +42,10 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
public static readonly int ComputeRenderScaleOffset;
|
public static readonly int ComputeRenderScaleOffset;
|
||||||
public static readonly int TfeOffsetOffset;
|
public static readonly int TfeOffsetOffset;
|
||||||
public static readonly int TfeVertexCountOffset;
|
public static readonly int TfeVertexCountOffset;
|
||||||
public static readonly int BufferTextureOffsetOffset;
|
|
||||||
|
|
||||||
public const int FragmentIsBgraCount = 8;
|
public const int FragmentIsBgraCount = 8;
|
||||||
public const int TextureCount = 64;
|
|
||||||
|
|
||||||
// One for the render target, 64 for the textures, and 8 for the images.
|
// One for the render target, 64 for the textures, and 8 for the images.
|
||||||
public const int RenderScaleMaxCount = 1 + TextureCount + 8;
|
public const int RenderScaleMaxCount = 1 + 64 + 8;
|
||||||
|
|
||||||
private static int OffsetOf<T>(ref SupportBuffer storage, ref T target)
|
private static int OffsetOf<T>(ref SupportBuffer storage, ref T target)
|
||||||
{
|
{
|
||||||
@@ -72,7 +68,6 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
ComputeRenderScaleOffset = GraphicsRenderScaleOffset + FieldSize;
|
ComputeRenderScaleOffset = GraphicsRenderScaleOffset + FieldSize;
|
||||||
TfeOffsetOffset = OffsetOf(ref instance, ref instance.TfeOffset);
|
TfeOffsetOffset = OffsetOf(ref instance, ref instance.TfeOffset);
|
||||||
TfeVertexCountOffset = OffsetOf(ref instance, ref instance.TfeVertexCount);
|
TfeVertexCountOffset = OffsetOf(ref instance, ref instance.TfeVertexCount);
|
||||||
BufferTextureOffsetOffset = OffsetOf(ref instance, ref instance.BufferTextureOffset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static StructureType GetStructureType()
|
internal static StructureType GetStructureType()
|
||||||
@@ -85,8 +80,7 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
new StructureField(AggregateType.S32, "frag_scale_count"),
|
new StructureField(AggregateType.S32, "frag_scale_count"),
|
||||||
new StructureField(AggregateType.Array | AggregateType.FP32, "render_scale", RenderScaleMaxCount),
|
new StructureField(AggregateType.Array | AggregateType.FP32, "render_scale", RenderScaleMaxCount),
|
||||||
new StructureField(AggregateType.Vector4 | AggregateType.S32, "tfe_offset"),
|
new StructureField(AggregateType.Vector4 | AggregateType.S32, "tfe_offset"),
|
||||||
new StructureField(AggregateType.S32, "tfe_vertex_count"),
|
new StructureField(AggregateType.S32, "tfe_vertex_count")
|
||||||
new StructureField(AggregateType.Array | AggregateType.Vector2 | AggregateType.S32, "buffer_texture_offset")
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +95,5 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
|
|
||||||
public Vector4<int> TfeOffset;
|
public Vector4<int> TfeOffset;
|
||||||
public Vector4<int> TfeVertexCount;
|
public Vector4<int> TfeVertexCount;
|
||||||
|
|
||||||
public Array5<Array64<Vector4<int>>> BufferTextureOffset;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,5 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
SharedMemory = 1 << 11,
|
SharedMemory = 1 << 11,
|
||||||
Store = 1 << 12,
|
Store = 1 << 12,
|
||||||
VtgAsCompute = 1 << 13,
|
VtgAsCompute = 1 << 13,
|
||||||
UnconditionalDiscard = 1 << 14,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Shader.Translation
|
|
||||||
{
|
|
||||||
static class FeatureIdentification
|
|
||||||
{
|
|
||||||
public static void RunPass(BasicBlock[] blocks, ShaderStage stage, ref FeatureFlags usedFeatures)
|
|
||||||
{
|
|
||||||
if (stage == ShaderStage.Fragment)
|
|
||||||
{
|
|
||||||
bool endsWithDiscardOnly = true;
|
|
||||||
|
|
||||||
for (int blockIndex = 0; blockIndex < blocks.Length; blockIndex++)
|
|
||||||
{
|
|
||||||
BasicBlock block = blocks[blockIndex];
|
|
||||||
|
|
||||||
if (block.HasSuccessor)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (block.Operations.Count == 0 ||
|
|
||||||
block.Operations.Last.Value is not Operation operation ||
|
|
||||||
operation.Inst != Instruction.Discard)
|
|
||||||
{
|
|
||||||
endsWithDiscardOnly = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endsWithDiscardOnly)
|
|
||||||
{
|
|
||||||
usedFeatures |= FeatureFlags.UnconditionalDiscard;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -43,11 +43,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
private readonly Dictionary<TextureInfo, TextureMeta> _usedTextures;
|
private readonly Dictionary<TextureInfo, TextureMeta> _usedTextures;
|
||||||
private readonly Dictionary<TextureInfo, TextureMeta> _usedImages;
|
private readonly Dictionary<TextureInfo, TextureMeta> _usedImages;
|
||||||
|
|
||||||
private readonly List<BufferDefinition> _vacConstantBuffers;
|
|
||||||
private readonly List<BufferDefinition> _vacStorageBuffers;
|
|
||||||
private readonly List<TextureDefinition> _vacTextures;
|
|
||||||
private readonly List<TextureDefinition> _vacImages;
|
|
||||||
|
|
||||||
public int LocalMemoryId { get; private set; }
|
public int LocalMemoryId { get; private set; }
|
||||||
public int SharedMemoryId { get; private set; }
|
public int SharedMemoryId { get; private set; }
|
||||||
|
|
||||||
@@ -83,11 +78,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
_usedTextures = new();
|
_usedTextures = new();
|
||||||
_usedImages = new();
|
_usedImages = new();
|
||||||
|
|
||||||
_vacConstantBuffers = new();
|
|
||||||
_vacStorageBuffers = new();
|
|
||||||
_vacTextures = new();
|
|
||||||
_vacImages = new();
|
|
||||||
|
|
||||||
Properties.AddOrUpdateConstantBuffer(new(BufferLayout.Std140, 0, SupportBuffer.Binding, "support_buffer", SupportBuffer.GetStructureType()));
|
Properties.AddOrUpdateConstantBuffer(new(BufferLayout.Std140, 0, SupportBuffer.Binding, "support_buffer", SupportBuffer.GetStructureType()));
|
||||||
|
|
||||||
LocalMemoryId = -1;
|
LocalMemoryId = -1;
|
||||||
@@ -573,76 +563,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
return descriptors.ToArray();
|
return descriptors.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderProgramInfo GetVertexAsComputeInfo(bool isVertex = false)
|
|
||||||
{
|
|
||||||
var cbDescriptors = new BufferDescriptor[_vacConstantBuffers.Count];
|
|
||||||
int cbDescriptorIndex = 0;
|
|
||||||
|
|
||||||
foreach (BufferDefinition definition in _vacConstantBuffers)
|
|
||||||
{
|
|
||||||
cbDescriptors[cbDescriptorIndex++] = new BufferDescriptor(definition.Set, definition.Binding, 0, 0, 0, BufferUsageFlags.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
var sbDescriptors = new BufferDescriptor[_vacStorageBuffers.Count];
|
|
||||||
int sbDescriptorIndex = 0;
|
|
||||||
|
|
||||||
foreach (BufferDefinition definition in _vacStorageBuffers)
|
|
||||||
{
|
|
||||||
sbDescriptors[sbDescriptorIndex++] = new BufferDescriptor(definition.Set, definition.Binding, 0, 0, 0, BufferUsageFlags.Write);
|
|
||||||
}
|
|
||||||
|
|
||||||
var tDescriptors = new TextureDescriptor[_vacTextures.Count];
|
|
||||||
int tDescriptorIndex = 0;
|
|
||||||
|
|
||||||
foreach (TextureDefinition definition in _vacTextures)
|
|
||||||
{
|
|
||||||
tDescriptors[tDescriptorIndex++] = new TextureDescriptor(
|
|
||||||
definition.Set,
|
|
||||||
definition.Binding,
|
|
||||||
definition.Type,
|
|
||||||
definition.Format,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
definition.ArrayLength,
|
|
||||||
definition.Separate,
|
|
||||||
definition.Flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
var iDescriptors = new TextureDescriptor[_vacImages.Count];
|
|
||||||
int iDescriptorIndex = 0;
|
|
||||||
|
|
||||||
foreach (TextureDefinition definition in _vacImages)
|
|
||||||
{
|
|
||||||
iDescriptors[iDescriptorIndex++] = new TextureDescriptor(
|
|
||||||
definition.Set,
|
|
||||||
definition.Binding,
|
|
||||||
definition.Type,
|
|
||||||
definition.Format,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
definition.ArrayLength,
|
|
||||||
definition.Separate,
|
|
||||||
definition.Flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ShaderProgramInfo(
|
|
||||||
cbDescriptors,
|
|
||||||
sbDescriptors,
|
|
||||||
tDescriptors,
|
|
||||||
iDescriptors,
|
|
||||||
isVertex ? ShaderStage.Vertex : ShaderStage.Compute,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
0,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetCbufSlotAndHandleForTexture(int binding, out int cbufSlot, out int handle)
|
public bool TryGetCbufSlotAndHandleForTexture(int binding, out int cbufSlot, out int handle)
|
||||||
{
|
{
|
||||||
foreach ((TextureInfo info, TextureMeta meta) in _usedTextures)
|
foreach ((TextureInfo info, TextureMeta meta) in _usedTextures)
|
||||||
@@ -707,30 +627,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
Properties.AddOrUpdateStorageBuffer(new(BufferLayout.Std430, setIndex, binding, name, type));
|
Properties.AddOrUpdateStorageBuffer(new(BufferLayout.Std430, setIndex, binding, name, type));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddVertexAsComputeConstantBuffer(BufferDefinition definition)
|
|
||||||
{
|
|
||||||
_vacConstantBuffers.Add(definition);
|
|
||||||
Properties.AddOrUpdateConstantBuffer(definition);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddVertexAsComputeStorageBuffer(BufferDefinition definition)
|
|
||||||
{
|
|
||||||
_vacStorageBuffers.Add(definition);
|
|
||||||
Properties.AddOrUpdateStorageBuffer(definition);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddVertexAsComputeTexture(TextureDefinition definition)
|
|
||||||
{
|
|
||||||
_vacTextures.Add(definition);
|
|
||||||
Properties.AddOrUpdateTexture(definition);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddVertexAsComputeImage(TextureDefinition definition)
|
|
||||||
{
|
|
||||||
_vacImages.Add(definition);
|
|
||||||
Properties.AddOrUpdateImage(definition);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetShaderStagePrefix(ShaderStage stage)
|
public static string GetShaderStagePrefix(ShaderStage stage)
|
||||||
{
|
{
|
||||||
uint index = (uint)stage;
|
uint index = (uint)stage;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
using Ryujinx.Graphics.Shader.Translation.Optimizations;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||||
@@ -28,19 +27,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
|||||||
|
|
||||||
if (texOp.Type == SamplerType.TextureBuffer && !context.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat())
|
if (texOp.Type == SamplerType.TextureBuffer && !context.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat())
|
||||||
{
|
{
|
||||||
if (!context.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat())
|
node = InsertSnormNormalization(node, context.ResourceManager, context.GpuAccessor);
|
||||||
{
|
|
||||||
node = InsertSnormNormalization(node, context.ResourceManager, context.GpuAccessor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!context.GpuAccessor.QueryHostSupportsBufferTexturePixelAlignment())
|
|
||||||
{
|
|
||||||
node = InsertCoordOffset(node, context.ResourceManager, context.Stage, isImage: false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!context.GpuAccessor.QueryHostSupportsBufferTexturePixelAlignment() && texOp.Inst.IsImage())
|
|
||||||
{
|
|
||||||
node = InsertCoordOffset(node, context.ResourceManager, context.Stage, isImage: true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -291,87 +278,6 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LinkedListNode<INode> InsertCoordOffset(LinkedListNode<INode> node, ResourceManager resourceManager, ShaderStage stage, bool isImage)
|
|
||||||
{
|
|
||||||
// Some GPUs have fixed alignment requirements for buffer textures.
|
|
||||||
// For those cases, we bind the aligned buffer offset, and apply the remaining offset on the shader.
|
|
||||||
|
|
||||||
TextureOperation texOp = (TextureOperation)node.Value;
|
|
||||||
|
|
||||||
if ((texOp.Type & SamplerType.Mask) != SamplerType.TextureBuffer)
|
|
||||||
{
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand[] sources = new Operand[texOp.SourcesCount];
|
|
||||||
|
|
||||||
for (int i = 0; i < texOp.SourcesCount; i++)
|
|
||||||
{
|
|
||||||
sources[i] = texOp.GetSource(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
|
|
||||||
bool isIndexed = resourceManager.IsArrayOfTexturesOrImages(texOp.Binding, isImage);
|
|
||||||
|
|
||||||
int coordsIndex = isBindless || isIndexed ? 1 : 0;
|
|
||||||
|
|
||||||
Operand[] dests = new Operand[texOp.DestsCount];
|
|
||||||
|
|
||||||
for (int i = 0; i < texOp.DestsCount; i++)
|
|
||||||
{
|
|
||||||
dests[i] = texOp.GetDest(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
LinkedListNode<INode> oldNode = node;
|
|
||||||
|
|
||||||
Operand source = sources[coordsIndex];
|
|
||||||
Operand offset = Local();
|
|
||||||
Operand coordPlusOffset = Local();
|
|
||||||
|
|
||||||
int stageIndex = stage switch
|
|
||||||
{
|
|
||||||
ShaderStage.TessellationControl => 1,
|
|
||||||
ShaderStage.TessellationEvaluation => 2,
|
|
||||||
ShaderStage.Geometry => 3,
|
|
||||||
ShaderStage.Fragment => 4,
|
|
||||||
_ => 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
int bindingIndex = isImage
|
|
||||||
? resourceManager.FindImageDescriptorIndex(texOp.Binding)
|
|
||||||
: resourceManager.FindTextureDescriptorIndex(texOp.Binding);
|
|
||||||
|
|
||||||
node.List.AddBefore(node, new Operation(
|
|
||||||
Instruction.Load,
|
|
||||||
StorageKind.ConstantBuffer,
|
|
||||||
offset,
|
|
||||||
Const(SupportBuffer.Binding),
|
|
||||||
Const((int)SupportBufferField.BufferTextureOffset),
|
|
||||||
Const(stageIndex * SupportBuffer.TextureCount + bindingIndex),
|
|
||||||
Const(isImage ? 1 : 0)));
|
|
||||||
|
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Add, coordPlusOffset, source, offset));
|
|
||||||
|
|
||||||
sources[coordsIndex] = coordPlusOffset;
|
|
||||||
|
|
||||||
TextureOperation newTexOp = new(
|
|
||||||
texOp.Inst,
|
|
||||||
texOp.Type,
|
|
||||||
texOp.Format,
|
|
||||||
texOp.Flags,
|
|
||||||
texOp.Set,
|
|
||||||
texOp.Binding,
|
|
||||||
texOp.Index,
|
|
||||||
dests,
|
|
||||||
sources);
|
|
||||||
|
|
||||||
node = node.List.AddBefore(node, newTexOp);
|
|
||||||
|
|
||||||
Utils.DeleteNode(oldNode, texOp);
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static LinkedListNode<INode> InsertConstOffsets(LinkedListNode<INode> node, ResourceManager resourceManager, IGpuAccessor gpuAccessor, ShaderStage stage)
|
private static LinkedListNode<INode> InsertConstOffsets(LinkedListNode<INode> node, ResourceManager resourceManager, IGpuAccessor gpuAccessor, ShaderStage stage)
|
||||||
{
|
{
|
||||||
// Non-constant texture offsets are not allowed (according to the spec),
|
// Non-constant texture offsets are not allowed (according to the spec),
|
||||||
|
|||||||
@@ -301,11 +301,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
Optimizer.RunPass(context);
|
Optimizer.RunPass(context);
|
||||||
TransformPasses.RunPass(context);
|
TransformPasses.RunPass(context);
|
||||||
|
|
||||||
if (i == 0)
|
|
||||||
{
|
|
||||||
FeatureIdentification.RunPass(cfg.Blocks, Definitions.Stage, ref usedFeatures);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
funcs[i] = new Function(cfg.Blocks, $"fun{i}", false, inArgumentsCount, outArgumentsCount);
|
funcs[i] = new Function(cfg.Blocks, $"fun{i}", false, inArgumentsCount, outArgumentsCount);
|
||||||
@@ -358,7 +353,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
usedFeatures.HasFlag(FeatureFlags.InstanceId),
|
usedFeatures.HasFlag(FeatureFlags.InstanceId),
|
||||||
usedFeatures.HasFlag(FeatureFlags.DrawParameters),
|
usedFeatures.HasFlag(FeatureFlags.DrawParameters),
|
||||||
usedFeatures.HasFlag(FeatureFlags.RtLayer),
|
usedFeatures.HasFlag(FeatureFlags.RtLayer),
|
||||||
usedFeatures.HasFlag(FeatureFlags.UnconditionalDiscard),
|
|
||||||
clipDistancesWritten,
|
clipDistancesWritten,
|
||||||
originalDefinitions.OmapTargets);
|
originalDefinitions.OmapTargets);
|
||||||
|
|
||||||
@@ -399,7 +393,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
{
|
{
|
||||||
int binding = resourceManager.Reservations.GetTfeBufferStorageBufferBinding(i);
|
int binding = resourceManager.Reservations.GetTfeBufferStorageBufferBinding(i);
|
||||||
BufferDefinition tfeDataBuffer = new(BufferLayout.Std430, 1, binding, $"tfe_data{i}", tfeDataStruct);
|
BufferDefinition tfeDataBuffer = new(BufferLayout.Std430, 1, binding, $"tfe_data{i}", tfeDataStruct);
|
||||||
resourceManager.AddVertexAsComputeStorageBuffer(tfeDataBuffer);
|
resourceManager.Properties.AddOrUpdateStorageBuffer(tfeDataBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,7 +401,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
{
|
{
|
||||||
int vertexInfoCbBinding = resourceManager.Reservations.VertexInfoConstantBufferBinding;
|
int vertexInfoCbBinding = resourceManager.Reservations.VertexInfoConstantBufferBinding;
|
||||||
BufferDefinition vertexInfoBuffer = new(BufferLayout.Std140, 0, vertexInfoCbBinding, "vb_info", VertexInfoBuffer.GetStructureType());
|
BufferDefinition vertexInfoBuffer = new(BufferLayout.Std140, 0, vertexInfoCbBinding, "vb_info", VertexInfoBuffer.GetStructureType());
|
||||||
resourceManager.AddVertexAsComputeConstantBuffer(vertexInfoBuffer);
|
resourceManager.Properties.AddOrUpdateConstantBuffer(vertexInfoBuffer);
|
||||||
|
|
||||||
StructureType vertexOutputStruct = new([
|
StructureType vertexOutputStruct = new([
|
||||||
new StructureField(AggregateType.Array | AggregateType.FP32, "data", 0)
|
new StructureField(AggregateType.Array | AggregateType.FP32, "data", 0)
|
||||||
@@ -415,13 +409,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
int vertexOutputSbBinding = resourceManager.Reservations.VertexOutputStorageBufferBinding;
|
int vertexOutputSbBinding = resourceManager.Reservations.VertexOutputStorageBufferBinding;
|
||||||
BufferDefinition vertexOutputBuffer = new(BufferLayout.Std430, 1, vertexOutputSbBinding, "vertex_output", vertexOutputStruct);
|
BufferDefinition vertexOutputBuffer = new(BufferLayout.Std430, 1, vertexOutputSbBinding, "vertex_output", vertexOutputStruct);
|
||||||
resourceManager.AddVertexAsComputeStorageBuffer(vertexOutputBuffer);
|
resourceManager.Properties.AddOrUpdateStorageBuffer(vertexOutputBuffer);
|
||||||
|
|
||||||
if (Stage == ShaderStage.Vertex)
|
if (Stage == ShaderStage.Vertex)
|
||||||
{
|
{
|
||||||
SetBindingPair ibSetAndBinding = resourceManager.Reservations.GetIndexBufferTextureSetAndBinding();
|
SetBindingPair ibSetAndBinding = resourceManager.Reservations.GetIndexBufferTextureSetAndBinding();
|
||||||
TextureDefinition indexBuffer = new(ibSetAndBinding.SetIndex, ibSetAndBinding.Binding, "ib_data", SamplerType.TextureBuffer);
|
TextureDefinition indexBuffer = new(ibSetAndBinding.SetIndex, ibSetAndBinding.Binding, "ib_data", SamplerType.TextureBuffer);
|
||||||
resourceManager.AddVertexAsComputeTexture(indexBuffer);
|
resourceManager.Properties.AddOrUpdateTexture(indexBuffer);
|
||||||
|
|
||||||
int inputMap = _program.AttributeUsage.UsedInputAttributes;
|
int inputMap = _program.AttributeUsage.UsedInputAttributes;
|
||||||
|
|
||||||
@@ -430,7 +424,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
int location = BitOperations.TrailingZeroCount(inputMap);
|
int location = BitOperations.TrailingZeroCount(inputMap);
|
||||||
SetBindingPair setAndBinding = resourceManager.Reservations.GetVertexBufferTextureSetAndBinding(location);
|
SetBindingPair setAndBinding = resourceManager.Reservations.GetVertexBufferTextureSetAndBinding(location);
|
||||||
TextureDefinition vaBuffer = new(setAndBinding.SetIndex, setAndBinding.Binding, $"vb_data{location}", SamplerType.TextureBuffer);
|
TextureDefinition vaBuffer = new(setAndBinding.SetIndex, setAndBinding.Binding, $"vb_data{location}", SamplerType.TextureBuffer);
|
||||||
resourceManager.AddVertexAsComputeTexture(vaBuffer);
|
resourceManager.Properties.AddOrUpdateTexture(vaBuffer);
|
||||||
|
|
||||||
inputMap &= ~(1 << location);
|
inputMap &= ~(1 << location);
|
||||||
}
|
}
|
||||||
@@ -439,11 +433,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
{
|
{
|
||||||
SetBindingPair trbSetAndBinding = resourceManager.Reservations.GetTopologyRemapBufferTextureSetAndBinding();
|
SetBindingPair trbSetAndBinding = resourceManager.Reservations.GetTopologyRemapBufferTextureSetAndBinding();
|
||||||
TextureDefinition remapBuffer = new(trbSetAndBinding.SetIndex, trbSetAndBinding.Binding, "trb_data", SamplerType.TextureBuffer);
|
TextureDefinition remapBuffer = new(trbSetAndBinding.SetIndex, trbSetAndBinding.Binding, "trb_data", SamplerType.TextureBuffer);
|
||||||
resourceManager.AddVertexAsComputeTexture(remapBuffer);
|
resourceManager.Properties.AddOrUpdateTexture(remapBuffer);
|
||||||
|
|
||||||
int geometryVbOutputSbBinding = resourceManager.Reservations.GeometryVertexOutputStorageBufferBinding;
|
int geometryVbOutputSbBinding = resourceManager.Reservations.GeometryVertexOutputStorageBufferBinding;
|
||||||
BufferDefinition geometryVbOutputBuffer = new(BufferLayout.Std430, 1, geometryVbOutputSbBinding, "geometry_vb_output", vertexOutputStruct);
|
BufferDefinition geometryVbOutputBuffer = new(BufferLayout.Std430, 1, geometryVbOutputSbBinding, "geometry_vb_output", vertexOutputStruct);
|
||||||
resourceManager.AddVertexAsComputeStorageBuffer(geometryVbOutputBuffer);
|
resourceManager.Properties.AddOrUpdateStorageBuffer(geometryVbOutputBuffer);
|
||||||
|
|
||||||
StructureType geometryIbOutputStruct = new([
|
StructureType geometryIbOutputStruct = new([
|
||||||
new StructureField(AggregateType.Array | AggregateType.U32, "data", 0)
|
new StructureField(AggregateType.Array | AggregateType.U32, "data", 0)
|
||||||
@@ -451,7 +445,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
int geometryIbOutputSbBinding = resourceManager.Reservations.GeometryIndexOutputStorageBufferBinding;
|
int geometryIbOutputSbBinding = resourceManager.Reservations.GeometryIndexOutputStorageBufferBinding;
|
||||||
BufferDefinition geometryIbOutputBuffer = new(BufferLayout.Std430, 1, geometryIbOutputSbBinding, "geometry_ib_output", geometryIbOutputStruct);
|
BufferDefinition geometryIbOutputBuffer = new(BufferLayout.Std430, 1, geometryIbOutputSbBinding, "geometry_ib_output", geometryIbOutputStruct);
|
||||||
resourceManager.AddVertexAsComputeStorageBuffer(geometryIbOutputBuffer);
|
resourceManager.Properties.AddOrUpdateStorageBuffer(geometryIbOutputBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceManager.SetVertexAsComputeLocalMemories(Definitions.Stage, Definitions.InputTopology);
|
resourceManager.SetVertexAsComputeLocalMemories(Definitions.Stage, Definitions.InputTopology);
|
||||||
@@ -484,17 +478,12 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
return new ResourceReservations(GpuAccessor, IsTransformFeedbackEmulated, vertexAsCompute: true, _vertexOutput, ioUsage);
|
return new ResourceReservations(GpuAccessor, IsTransformFeedbackEmulated, vertexAsCompute: true, _vertexOutput, ioUsage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderProgramInfo GetVertexAsComputeInfo()
|
|
||||||
{
|
|
||||||
return CreateResourceManager(true).GetVertexAsComputeInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetVertexOutputMapForGeometryAsCompute(TranslatorContext vertexContext)
|
public void SetVertexOutputMapForGeometryAsCompute(TranslatorContext vertexContext)
|
||||||
{
|
{
|
||||||
_vertexOutput = vertexContext._program.GetIoUsage();
|
_vertexOutput = vertexContext._program.GetIoUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
public (ShaderProgram, ShaderProgramInfo) GenerateVertexPassthroughForCompute()
|
public ShaderProgram GenerateVertexPassthroughForCompute()
|
||||||
{
|
{
|
||||||
AttributeUsage attributeUsage = new(GpuAccessor);
|
AttributeUsage attributeUsage = new(GpuAccessor);
|
||||||
ResourceManager resourceManager = new(ShaderStage.Vertex, GpuAccessor);
|
ResourceManager resourceManager = new(ShaderStage.Vertex, GpuAccessor);
|
||||||
@@ -506,7 +495,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
if (Stage == ShaderStage.Vertex)
|
if (Stage == ShaderStage.Vertex)
|
||||||
{
|
{
|
||||||
BufferDefinition vertexInfoBuffer = new(BufferLayout.Std140, 0, vertexInfoCbBinding, "vb_info", VertexInfoBuffer.GetStructureType());
|
BufferDefinition vertexInfoBuffer = new(BufferLayout.Std140, 0, vertexInfoCbBinding, "vb_info", VertexInfoBuffer.GetStructureType());
|
||||||
resourceManager.AddVertexAsComputeConstantBuffer(vertexInfoBuffer);
|
resourceManager.Properties.AddOrUpdateConstantBuffer(vertexInfoBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
StructureType vertexInputStruct = new([
|
StructureType vertexInputStruct = new([
|
||||||
@@ -515,7 +504,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
int vertexDataSbBinding = reservations.VertexOutputStorageBufferBinding;
|
int vertexDataSbBinding = reservations.VertexOutputStorageBufferBinding;
|
||||||
BufferDefinition vertexOutputBuffer = new(BufferLayout.Std430, 1, vertexDataSbBinding, "vb_input", vertexInputStruct);
|
BufferDefinition vertexOutputBuffer = new(BufferLayout.Std430, 1, vertexDataSbBinding, "vb_input", vertexInputStruct);
|
||||||
resourceManager.AddVertexAsComputeStorageBuffer(vertexOutputBuffer);
|
resourceManager.Properties.AddOrUpdateStorageBuffer(vertexOutputBuffer);
|
||||||
|
|
||||||
EmitterContext context = new();
|
EmitterContext context = new();
|
||||||
|
|
||||||
@@ -573,14 +562,14 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
LastInVertexPipeline = true
|
LastInVertexPipeline = true
|
||||||
};
|
};
|
||||||
|
|
||||||
return (Generate(
|
return Generate(
|
||||||
[function],
|
[function],
|
||||||
attributeUsage,
|
attributeUsage,
|
||||||
definitions,
|
definitions,
|
||||||
definitions,
|
definitions,
|
||||||
resourceManager,
|
resourceManager,
|
||||||
FeatureFlags.None,
|
FeatureFlags.None,
|
||||||
0), resourceManager.GetVertexAsComputeInfo(isVertex: true));
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderProgram GenerateGeometryPassthrough()
|
public ShaderProgram GenerateGeometryPassthrough()
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
queueLock,
|
queueLock,
|
||||||
_gd.QueueFamilyIndex,
|
_gd.QueueFamilyIndex,
|
||||||
_gd.IsQualcommProprietary,
|
_gd.IsQualcommProprietary,
|
||||||
_gd.IsTurnip,
|
|
||||||
isLight: true);
|
isLight: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private readonly Queue _queue;
|
private readonly Queue _queue;
|
||||||
private readonly Lock _queueLock;
|
private readonly Lock _queueLock;
|
||||||
private readonly bool _concurrentFenceWaitUnsupported;
|
private readonly bool _concurrentFenceWaitUnsupported;
|
||||||
private readonly bool _fenceAlwaysWaits;
|
|
||||||
private readonly CommandPool _pool;
|
private readonly CommandPool _pool;
|
||||||
private readonly Thread _owner;
|
private readonly Thread _owner;
|
||||||
|
|
||||||
@@ -67,7 +66,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Lock queueLock,
|
Lock queueLock,
|
||||||
uint queueFamilyIndex,
|
uint queueFamilyIndex,
|
||||||
bool concurrentFenceWaitUnsupported,
|
bool concurrentFenceWaitUnsupported,
|
||||||
bool fenceAlwaysWaits,
|
|
||||||
bool isLight = false)
|
bool isLight = false)
|
||||||
{
|
{
|
||||||
_api = api;
|
_api = api;
|
||||||
@@ -75,7 +73,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_queue = queue;
|
_queue = queue;
|
||||||
_queueLock = queueLock;
|
_queueLock = queueLock;
|
||||||
_concurrentFenceWaitUnsupported = concurrentFenceWaitUnsupported;
|
_concurrentFenceWaitUnsupported = concurrentFenceWaitUnsupported;
|
||||||
_fenceAlwaysWaits = fenceAlwaysWaits;
|
|
||||||
_owner = Thread.CurrentThread;
|
_owner = Thread.CurrentThread;
|
||||||
|
|
||||||
CommandPoolCreateInfo commandPoolCreateInfo = new()
|
CommandPoolCreateInfo commandPoolCreateInfo = new()
|
||||||
@@ -210,7 +207,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
ref ReservedCommandBuffer entry = ref _commandBuffers[index];
|
ref ReservedCommandBuffer entry = ref _commandBuffers[index];
|
||||||
|
|
||||||
if (wait || !entry.InConsumption || entry.Fence.IsSignaledLazy())
|
if (wait || !entry.InConsumption || entry.Fence.IsSignaled())
|
||||||
{
|
{
|
||||||
WaitAndDecrementRef(index);
|
WaitAndDecrementRef(index);
|
||||||
|
|
||||||
@@ -352,7 +349,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
if (refreshFence)
|
if (refreshFence)
|
||||||
{
|
{
|
||||||
entry.Fence = new FenceHolder(_api, _device, _concurrentFenceWaitUnsupported, _fenceAlwaysWaits);
|
entry.Fence = new FenceHolder(_api, _device, _concurrentFenceWaitUnsupported);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,15 +12,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private int _referenceCount;
|
private int _referenceCount;
|
||||||
private int _lock;
|
private int _lock;
|
||||||
private readonly bool _concurrentWaitUnsupported;
|
private readonly bool _concurrentWaitUnsupported;
|
||||||
private readonly bool _alwaysWaits;
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
public unsafe FenceHolder(Vk api, Device device, bool concurrentWaitUnsupported, bool alwaysWaits)
|
public unsafe FenceHolder(Vk api, Device device, bool concurrentWaitUnsupported)
|
||||||
{
|
{
|
||||||
_api = api;
|
_api = api;
|
||||||
_device = device;
|
_device = device;
|
||||||
_concurrentWaitUnsupported = concurrentWaitUnsupported;
|
_concurrentWaitUnsupported = concurrentWaitUnsupported;
|
||||||
_alwaysWaits = alwaysWaits;
|
|
||||||
|
|
||||||
FenceCreateInfo fenceCreateInfo = new()
|
FenceCreateInfo fenceCreateInfo = new()
|
||||||
{
|
{
|
||||||
@@ -125,16 +123,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsSignaledLazy()
|
|
||||||
{
|
|
||||||
if (_alwaysWaits)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return IsSignaled();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSignaled()
|
public bool IsSignaled()
|
||||||
{
|
{
|
||||||
if (_concurrentWaitUnsupported)
|
if (_concurrentWaitUnsupported)
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private ProgramPipelineState _state;
|
private ProgramPipelineState _state;
|
||||||
private DisposableRenderPass _dummyRenderPass;
|
private DisposableRenderPass _dummyRenderPass;
|
||||||
private ShaderCompilationRequest _compileRequest;
|
private readonly Task _compileTask;
|
||||||
private bool _firstBackgroundUse;
|
private bool _firstBackgroundUse;
|
||||||
|
|
||||||
public ShaderCollection(
|
public ShaderCollection(
|
||||||
@@ -139,7 +139,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
// Updating buffer texture bindings using template updates crashes the Adreno driver on Windows.
|
// Updating buffer texture bindings using template updates crashes the Adreno driver on Windows.
|
||||||
UpdateTexturesWithoutTemplate = gd.IsQualcommProprietary && usesBufferTextures;
|
UpdateTexturesWithoutTemplate = gd.IsQualcommProprietary && usesBufferTextures;
|
||||||
|
|
||||||
_compileRequest = new ShaderCompilationRequest(Task.CompletedTask);
|
_compileTask = Task.CompletedTask;
|
||||||
_firstBackgroundUse = false;
|
_firstBackgroundUse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,9 +153,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
_state = state;
|
_state = state;
|
||||||
|
|
||||||
_compileRequest = gd.ShaderCompilationQueue != null
|
_compileTask = BackgroundCompilation();
|
||||||
? gd.ShaderCompilationQueue.Add(BackgroundCompilation)
|
|
||||||
: new ShaderCompilationRequest(BackgroundCompilationAsync());
|
|
||||||
_firstBackgroundUse = !fromCache;
|
_firstBackgroundUse = !fromCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,25 +458,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return (buffer, texture);
|
return (buffer, texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task BackgroundCompilationAsync()
|
private async Task BackgroundCompilation()
|
||||||
{
|
{
|
||||||
await Task.WhenAll(_shaders.Select(shader => shader.CompileTask));
|
await Task.WhenAll(_shaders.Select(shader => shader.CompileTask));
|
||||||
|
|
||||||
BackgroundCompilationImpl();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BackgroundCompilation()
|
|
||||||
{
|
|
||||||
foreach (var shader in _shaders)
|
|
||||||
{
|
|
||||||
shader.CompileTask.Wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
BackgroundCompilationImpl();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BackgroundCompilationImpl()
|
|
||||||
{
|
|
||||||
if (Array.Exists(_shaders, shader => shader.CompileStatus == ProgramLinkStatus.Failure))
|
if (Array.Exists(_shaders, shader => shader.CompileStatus == ProgramLinkStatus.Failure))
|
||||||
{
|
{
|
||||||
LinkStatus = ProgramLinkStatus.Failure;
|
LinkStatus = ProgramLinkStatus.Failure;
|
||||||
@@ -621,11 +604,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_compileRequest.IsCompleted)
|
if (!_compileTask.IsCompleted)
|
||||||
{
|
{
|
||||||
if (blocking)
|
if (blocking)
|
||||||
{
|
{
|
||||||
_compileRequest.Wait();
|
_compileTask.Wait();
|
||||||
|
|
||||||
if (LinkStatus == ProgramLinkStatus.Failure)
|
if (LinkStatus == ProgramLinkStatus.Failure)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,131 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
|
||||||
{
|
|
||||||
class ShaderCompilationQueue
|
|
||||||
{
|
|
||||||
private const int MaxParallelCompilations = 8;
|
|
||||||
private const int MaxThreadStackSize = 2 * 1024 * 1024; // MB
|
|
||||||
|
|
||||||
private struct Request
|
|
||||||
{
|
|
||||||
public readonly ulong Id;
|
|
||||||
public readonly Action Callback;
|
|
||||||
|
|
||||||
public Request(ulong id, Action callback)
|
|
||||||
{
|
|
||||||
Id = id;
|
|
||||||
Callback = callback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Thread[] _workerThreads;
|
|
||||||
private readonly CancellationTokenSource _cts;
|
|
||||||
private readonly BlockingCollection<Request>[] _queues;
|
|
||||||
private readonly ulong[] _finishedIds;
|
|
||||||
private ulong _currentId;
|
|
||||||
private int _currentQueueIndex;
|
|
||||||
|
|
||||||
public ShaderCompilationQueue()
|
|
||||||
{
|
|
||||||
_workerThreads = new Thread[MaxParallelCompilations];
|
|
||||||
_queues = new BlockingCollection<Request>[MaxParallelCompilations];
|
|
||||||
_finishedIds = new ulong[MaxParallelCompilations];
|
|
||||||
|
|
||||||
_cts = new CancellationTokenSource();
|
|
||||||
|
|
||||||
for (int i = 0; i < MaxParallelCompilations; i++)
|
|
||||||
{
|
|
||||||
_queues[i] = new BlockingCollection<Request>();
|
|
||||||
|
|
||||||
Thread thread = new Thread(DoWork, MaxThreadStackSize) { Name = $"BackgroundShaderCompiler.{i}" };
|
|
||||||
thread.IsBackground = true;
|
|
||||||
thread.Start(i);
|
|
||||||
|
|
||||||
_workerThreads[i] = thread;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DoWork(object threadId)
|
|
||||||
{
|
|
||||||
int queueIndex = (int)threadId;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var queue = _queues[queueIndex];
|
|
||||||
|
|
||||||
foreach (var request in queue.GetConsumingEnumerable(_cts.Token))
|
|
||||||
{
|
|
||||||
request.Callback();
|
|
||||||
|
|
||||||
lock (queue)
|
|
||||||
{
|
|
||||||
_finishedIds[queueIndex] = request.Id;
|
|
||||||
|
|
||||||
Monitor.PulseAll(queue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderCompilationRequest Add(Action callback)
|
|
||||||
{
|
|
||||||
ulong newId = Interlocked.Increment(ref _currentId);
|
|
||||||
|
|
||||||
// Let's keep rotating between the queues to increase the chances
|
|
||||||
// that the selected queue thread is currently idle.
|
|
||||||
int queueIndex = Interlocked.Increment(ref _currentQueueIndex) % MaxParallelCompilations;
|
|
||||||
|
|
||||||
_queues[queueIndex].Add(new Request(newId, callback));
|
|
||||||
|
|
||||||
return new ShaderCompilationRequest(this, queueIndex, newId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Wait(int queueIndex, ulong id)
|
|
||||||
{
|
|
||||||
var queue = _queues[queueIndex];
|
|
||||||
|
|
||||||
lock (queue)
|
|
||||||
{
|
|
||||||
while (_finishedIds[queueIndex] < id)
|
|
||||||
{
|
|
||||||
Monitor.Wait(queue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsCompleted(int queueIndex, ulong id)
|
|
||||||
{
|
|
||||||
var queue = _queues[queueIndex];
|
|
||||||
|
|
||||||
lock (queue)
|
|
||||||
{
|
|
||||||
return _finishedIds[queueIndex] >= id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < MaxParallelCompilations; i++)
|
|
||||||
{
|
|
||||||
_queues[i].CompleteAdding();
|
|
||||||
}
|
|
||||||
|
|
||||||
_cts.Cancel();
|
|
||||||
|
|
||||||
for (int i = 0; i < MaxParallelCompilations; i++)
|
|
||||||
{
|
|
||||||
_workerThreads[i].Join();
|
|
||||||
|
|
||||||
_queues[i].Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
_cts.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
|
||||||
{
|
|
||||||
struct ShaderCompilationRequest
|
|
||||||
{
|
|
||||||
private readonly Task _task;
|
|
||||||
private readonly ShaderCompilationQueue _queue;
|
|
||||||
private readonly int _queueIndex;
|
|
||||||
private readonly ulong _requestId;
|
|
||||||
|
|
||||||
public bool IsCompleted
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_task != null)
|
|
||||||
{
|
|
||||||
return _task.IsCompleted;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return _queue.IsCompleted(_queueIndex, _requestId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderCompilationRequest(Task task)
|
|
||||||
{
|
|
||||||
_task = task;
|
|
||||||
_queue = null;
|
|
||||||
_queueIndex = 0;
|
|
||||||
_requestId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderCompilationRequest(ShaderCompilationQueue queue, int queueIndex, ulong requestId)
|
|
||||||
{
|
|
||||||
_task = null;
|
|
||||||
_queue = queue;
|
|
||||||
_queueIndex = queueIndex;
|
|
||||||
_requestId = requestId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Wait()
|
|
||||||
{
|
|
||||||
if (_task != null)
|
|
||||||
{
|
|
||||||
_task.Wait();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_queue.Wait(_queueIndex, _requestId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -266,7 +266,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
public void FreeCompleted()
|
public void FreeCompleted()
|
||||||
{
|
{
|
||||||
FenceHolder signalledFence = null;
|
FenceHolder signalledFence = null;
|
||||||
while (_pendingCopies.TryPeek(out PendingCopy pc) && pc.Fence != null && (pc.Fence == signalledFence || pc.Fence.IsSignaledLazy()))
|
while (_pendingCopies.TryPeek(out PendingCopy pc) && pc.Fence != null && (pc.Fence == signalledFence || pc.Fence.IsSignaled()))
|
||||||
{
|
{
|
||||||
signalledFence = pc.Fence; // Already checked - don't need to do it again.
|
signalledFence = pc.Fence; // Already checked - don't need to do it again.
|
||||||
PendingCopy dequeued = _pendingCopies.Dequeue();
|
PendingCopy dequeued = _pendingCopies.Dequeue();
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
internal CommandBufferPool CommandBufferPool { get; private set; }
|
internal CommandBufferPool CommandBufferPool { get; private set; }
|
||||||
internal PipelineLayoutCache PipelineLayoutCache { get; private set; }
|
internal PipelineLayoutCache PipelineLayoutCache { get; private set; }
|
||||||
internal BackgroundResources BackgroundResources { get; private set; }
|
internal BackgroundResources BackgroundResources { get; private set; }
|
||||||
internal ShaderCompilationQueue ShaderCompilationQueue { get; private set; }
|
|
||||||
internal Action<Action> InterruptAction { get; private set; }
|
internal Action<Action> InterruptAction { get; private set; }
|
||||||
internal SyncManager SyncManager { get; private set; }
|
internal SyncManager SyncManager { get; private set; }
|
||||||
|
|
||||||
@@ -97,7 +96,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
internal bool IsNvidiaPreTuring { get; private set; }
|
internal bool IsNvidiaPreTuring { get; private set; }
|
||||||
internal bool IsIntelArc { get; private set; }
|
internal bool IsIntelArc { get; private set; }
|
||||||
internal bool IsQualcommProprietary { get; private set; }
|
internal bool IsQualcommProprietary { get; private set; }
|
||||||
internal bool IsTurnip { get; private set; }
|
|
||||||
internal bool IsMoltenVk { get; private set; }
|
internal bool IsMoltenVk { get; private set; }
|
||||||
internal bool SupportsMTL31 { get; private set; }
|
internal bool SupportsMTL31 { get; private set; }
|
||||||
internal bool IsTBDR { get; private set; }
|
internal bool IsTBDR { get; private set; }
|
||||||
@@ -129,12 +127,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
// Any device running on MacOS is using MoltenVK, even Intel and AMD vendors.
|
// Any device running on MacOS is using MoltenVK, even Intel and AMD vendors.
|
||||||
IsMoltenVk = true;
|
IsMoltenVk = true;
|
||||||
|
|
||||||
// The default thread stack size on MacOS is low, and can cause stack overflow
|
|
||||||
// on SPIR-V Cross during shader compilation.
|
|
||||||
// As a workaround, we use this custom queue which allows us to specify the stack
|
|
||||||
// size of the threads used for compilation.
|
|
||||||
ShaderCompilationQueue = new ShaderCompilationQueue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SupportsMTL31 = OperatingSystem.IsMacOSVersionAtLeast(14);
|
SupportsMTL31 = OperatingSystem.IsMacOSVersionAtLeast(14);
|
||||||
@@ -404,8 +396,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
IsFeedbackLoopDevice = IsAmdRdna3;
|
IsFeedbackLoopDevice = IsAmdRdna3;
|
||||||
|
|
||||||
IsTurnip = GpuRenderer.StartsWith("Turnip");
|
|
||||||
|
|
||||||
if (Vendor == Vendor.Nvidia)
|
if (Vendor == Vendor.Nvidia)
|
||||||
{
|
{
|
||||||
Match match = VendorUtils.NvidiaConsumerClassRegex().Match(GpuRenderer);
|
Match match = VendorUtils.NvidiaConsumerClassRegex().Match(GpuRenderer);
|
||||||
@@ -486,7 +476,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtExternalMemoryHost hostMemoryApi);
|
Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtExternalMemoryHost hostMemoryApi);
|
||||||
HostMemoryAllocator = new HostMemoryAllocator(MemoryAllocator, Api, hostMemoryApi, _device);
|
HostMemoryAllocator = new HostMemoryAllocator(MemoryAllocator, Api, hostMemoryApi, _device);
|
||||||
|
|
||||||
CommandBufferPool = new CommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex, IsQualcommProprietary, IsTurnip);
|
CommandBufferPool = new CommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex, IsQualcommProprietary);
|
||||||
|
|
||||||
PipelineLayoutCache = new PipelineLayoutCache();
|
PipelineLayoutCache = new PipelineLayoutCache();
|
||||||
|
|
||||||
@@ -787,7 +777,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
supportsGeometryShader: Capabilities.SupportsGeometryShader,
|
supportsGeometryShader: Capabilities.SupportsGeometryShader,
|
||||||
supportsGeometryShaderPassthrough: Capabilities.SupportsGeometryShaderPassthrough,
|
supportsGeometryShaderPassthrough: Capabilities.SupportsGeometryShaderPassthrough,
|
||||||
supportsTransformFeedback: Capabilities.SupportsTransformFeedback,
|
supportsTransformFeedback: Capabilities.SupportsTransformFeedback,
|
||||||
supportsImageBufferPixelAlignment: false,
|
|
||||||
supportsImageLoadFormatted: features2.Features.ShaderStorageImageReadWithoutFormat,
|
supportsImageLoadFormatted: features2.Features.ShaderStorageImageReadWithoutFormat,
|
||||||
supportsLayerVertexTessellation: featuresVk12.ShaderOutputLayer,
|
supportsLayerVertexTessellation: featuresVk12.ShaderOutputLayer,
|
||||||
supportsMismatchingViewFormat: true,
|
supportsMismatchingViewFormat: true,
|
||||||
@@ -801,7 +790,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
supportsShaderNonUniformIndexing:
|
supportsShaderNonUniformIndexing:
|
||||||
featuresVk12.ShaderSampledImageArrayNonUniformIndexing &&
|
featuresVk12.ShaderSampledImageArrayNonUniformIndexing &&
|
||||||
featuresVk12.ShaderStorageImageArrayNonUniformIndexing,
|
featuresVk12.ShaderStorageImageArrayNonUniformIndexing,
|
||||||
supportsTextureBufferPixelAlignment: false,
|
|
||||||
supportsTextureGatherOffsets: features2.Features.ShaderImageGatherExtended,
|
supportsTextureGatherOffsets: features2.Features.ShaderImageGatherExtended,
|
||||||
supportsTextureShadowLod: false,
|
supportsTextureShadowLod: false,
|
||||||
supportsVertexStoreAndAtomics: features2.Features.VertexPipelineStoresAndAtomics,
|
supportsVertexStoreAndAtomics: features2.Features.VertexPipelineStoresAndAtomics,
|
||||||
@@ -1124,8 +1112,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
SurfaceApi.DestroySurface(_instance.Instance, _surface, null);
|
SurfaceApi.DestroySurface(_instance.Instance, _surface, null);
|
||||||
|
|
||||||
ShaderCompilationQueue?.Dispose();
|
|
||||||
|
|
||||||
Api.DestroyDevice(_device, null);
|
Api.DestroyDevice(_device, null);
|
||||||
|
|
||||||
_debugMessenger.Dispose();
|
_debugMessenger.Dispose();
|
||||||
|
|||||||
@@ -166,15 +166,13 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
|
|
||||||
string[] buttons = GetButtonsText(module, description, "DlgBtn");
|
string[] buttons = GetButtonsText(module, description, "DlgBtn");
|
||||||
|
|
||||||
(uint Module, uint Description) errorCodeTuple = (module, uint.Parse(description.ToString("0000")));
|
bool showDetails = _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Error Code: {module}-{description:0000}", "\n" + message, buttons);
|
||||||
|
|
||||||
bool showDetails = _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Error Code: {module}-{description:0000}", "\n" + message, buttons, errorCodeTuple);
|
|
||||||
if (showDetails)
|
if (showDetails)
|
||||||
{
|
{
|
||||||
message = GetMessageText(module, description, "FlvMsg");
|
message = GetMessageText(module, description, "FlvMsg");
|
||||||
buttons = GetButtonsText(module, description, "FlvBtn");
|
buttons = GetButtonsText(module, description, "FlvBtn");
|
||||||
|
|
||||||
_horizon.Device.UIHandler.DisplayErrorAppletDialog($"Details: {module}-{description:0000}", "\n" + message, buttons, errorCodeTuple);
|
_horizon.Device.UIHandler.DisplayErrorAppletDialog($"Details: {module}-{description:0000}", "\n" + message, buttons);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,19 +27,9 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
_normalSession = normalSession;
|
_normalSession = normalSession;
|
||||||
_interactiveSession = interactiveSession;
|
_interactiveSession = interactiveSession;
|
||||||
|
|
||||||
UserProfile selected = _system.Device.UIHandler.ShowPlayerSelectDialog();
|
// TODO(jduncanator): Parse PlayerSelectConfig from input data
|
||||||
if (selected == null)
|
_normalSession.Push(BuildResponse());
|
||||||
{
|
|
||||||
_normalSession.Push(BuildResponse());
|
|
||||||
}
|
|
||||||
else if (selected.UserId == new UserId("00000000000000000000000000000080"))
|
|
||||||
{
|
|
||||||
_normalSession.Push(BuildGuestResponse());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_normalSession.Push(BuildResponse(selected));
|
|
||||||
}
|
|
||||||
AppletStateChanged?.Invoke(this, null);
|
AppletStateChanged?.Invoke(this, null);
|
||||||
|
|
||||||
_system.ReturnFocus();
|
_system.ReturnFocus();
|
||||||
@@ -47,34 +37,16 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] BuildResponse(UserProfile selectedUser)
|
private byte[] BuildResponse()
|
||||||
{
|
{
|
||||||
|
UserProfile currentUser = _system.AccountManager.LastOpenedUser;
|
||||||
|
|
||||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||||
using BinaryWriter writer = new(stream);
|
using BinaryWriter writer = new(stream);
|
||||||
|
|
||||||
writer.Write((ulong)PlayerSelectResult.Success);
|
writer.Write((ulong)PlayerSelectResult.Success);
|
||||||
|
|
||||||
selectedUser.UserId.Write(writer);
|
currentUser.UserId.Write(writer);
|
||||||
|
|
||||||
return stream.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] BuildGuestResponse()
|
|
||||||
{
|
|
||||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
|
||||||
using BinaryWriter writer = new(stream);
|
|
||||||
|
|
||||||
writer.Write(new byte());
|
|
||||||
|
|
||||||
return stream.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] BuildResponse()
|
|
||||||
{
|
|
||||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
|
||||||
using BinaryWriter writer = new(stream);
|
|
||||||
|
|
||||||
writer.Write((ulong)PlayerSelectResult.Failure);
|
|
||||||
|
|
||||||
return stream.ToArray();
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.8 KiB |
@@ -59,7 +59,6 @@
|
|||||||
<EmbeddedResource Include="HOS\Applets\SoftwareKeyboard\Resources\Icon_BtnB.png" />
|
<EmbeddedResource Include="HOS\Applets\SoftwareKeyboard\Resources\Icon_BtnB.png" />
|
||||||
<EmbeddedResource Include="HOS\Applets\SoftwareKeyboard\Resources\Icon_KeyF6.png" />
|
<EmbeddedResource Include="HOS\Applets\SoftwareKeyboard\Resources\Icon_KeyF6.png" />
|
||||||
<EmbeddedResource Include="HOS\Services\Account\Acc\DefaultUserImage.jpg" />
|
<EmbeddedResource Include="HOS\Services\Account\Acc\DefaultUserImage.jpg" />
|
||||||
<EmbeddedResource Include="HOS\Services\Account\Acc\GuestUserImage.jpg" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ryujinx.HLE.HOS.Applets;
|
using Ryujinx.HLE.HOS.Applets;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.UI
|
namespace Ryujinx.HLE.UI
|
||||||
@@ -49,8 +48,7 @@ namespace Ryujinx.HLE.UI
|
|||||||
/// Displays a Message Dialog box specific to Error Applet and blocks until it is closed.
|
/// Displays a Message Dialog box specific to Error Applet and blocks until it is closed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>False when OK is pressed, True when another button (Details) is pressed.</returns>
|
/// <returns>False when OK is pressed, True when another button (Details) is pressed.</returns>
|
||||||
// ReSharper disable once UnusedParameter.Global
|
bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText);
|
||||||
bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText, (uint Module, uint Description)? errorCode = null);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a handler to process keyboard inputs into text strings.
|
/// Creates a handler to process keyboard inputs into text strings.
|
||||||
@@ -67,10 +65,5 @@ namespace Ryujinx.HLE.UI
|
|||||||
/// Takes a screenshot from the current renderer and saves it in the screenshots folder.
|
/// Takes a screenshot from the current renderer and saves it in the screenshots folder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void TakeScreenshot();
|
void TakeScreenshot();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Displays the player select dialog and returns the selected profile.
|
|
||||||
/// </summary>
|
|
||||||
UserProfile ShowPlayerSelectDialog();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ namespace Ryujinx.ShaderTools
|
|||||||
|
|
||||||
if (options.VertexPassthrough)
|
if (options.VertexPassthrough)
|
||||||
{
|
{
|
||||||
(program, _) = translatorContext.GenerateVertexPassthroughForCompute();
|
program = translatorContext.GenerateVertexPassthroughForCompute();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ using Ryujinx.Graphics.GAL.Multithreading;
|
|||||||
using Ryujinx.Graphics.Gpu;
|
using Ryujinx.Graphics.Gpu;
|
||||||
using Ryujinx.Graphics.OpenGL;
|
using Ryujinx.Graphics.OpenGL;
|
||||||
using Ryujinx.HLE.HOS.Applets;
|
using Ryujinx.HLE.HOS.Applets;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||||
using Ryujinx.HLE.Loaders.Processes;
|
using Ryujinx.HLE.Loaders.Processes;
|
||||||
using Ryujinx.HLE.UI;
|
using Ryujinx.HLE.UI;
|
||||||
@@ -29,7 +28,6 @@ using static SDL.SDL3;
|
|||||||
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
|
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
|
||||||
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
|
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
|
||||||
using Switch = Ryujinx.HLE.Switch;
|
using Switch = Ryujinx.HLE.Switch;
|
||||||
using UserProfile = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile;
|
|
||||||
|
|
||||||
namespace Ryujinx.Headless
|
namespace Ryujinx.Headless
|
||||||
{
|
{
|
||||||
@@ -533,7 +531,7 @@ namespace Ryujinx.Headless
|
|||||||
Exit();
|
Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText, (uint Module, uint Description)? errorCode = null)
|
public bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText)
|
||||||
{
|
{
|
||||||
SDL_MessageBoxButtonData[] buttons = new SDL_MessageBoxButtonData[buttonsText.Length];
|
SDL_MessageBoxButtonData[] buttons = new SDL_MessageBoxButtonData[buttonsText.Length];
|
||||||
|
|
||||||
@@ -592,10 +590,5 @@ namespace Ryujinx.Headless
|
|||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserProfile ShowPlayerSelectDialog()
|
|
||||||
{
|
|
||||||
return AccountSaveDataManager.GetLastUsedUser();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,10 +169,4 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<TrimmerRootDescriptor Include="TrimmerRootDescriptor.xml" />
|
<TrimmerRootDescriptor Include="TrimmerRootDescriptor.xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Compile Update="UI\Applet\UserSelectorDialog.axaml.cs">
|
|
||||||
<DependentUpon>UserSelectorDialog.axaml</DependentUpon>
|
|
||||||
<SubType>Code</SubType>
|
|
||||||
</Compile>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,23 +1,17 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using Gommon;
|
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.Controls;
|
using Ryujinx.Ava.UI.Controls;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
|
||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.Common;
|
|
||||||
using Ryujinx.HLE;
|
using Ryujinx.HLE;
|
||||||
using Ryujinx.HLE.HOS.Applets;
|
using Ryujinx.HLE.HOS.Applets;
|
||||||
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||||
using Ryujinx.HLE.UI;
|
using Ryujinx.HLE.UI;
|
||||||
using Ryujinx.UI.Common.Configuration;
|
using Ryujinx.UI.Common.Configuration;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Applet
|
namespace Ryujinx.Ava.UI.Applet
|
||||||
@@ -221,7 +215,7 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
_parent.ViewModel.AppHost?.Stop();
|
_parent.ViewModel.AppHost?.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DisplayErrorAppletDialog(string title, string message, string[] buttons, (uint Module, uint Description)? errorCode = null)
|
public bool DisplayErrorAppletDialog(string title, string message, string[] buttons)
|
||||||
{
|
{
|
||||||
ManualResetEvent dialogCloseEvent = new(false);
|
ManualResetEvent dialogCloseEvent = new(false);
|
||||||
|
|
||||||
@@ -262,59 +256,9 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
return showDetails;
|
return showDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDynamicTextInputHandler CreateDynamicTextInputHandler() => new AvaloniaDynamicTextInputHandler(_parent);
|
public IDynamicTextInputHandler CreateDynamicTextInputHandler()
|
||||||
|
|
||||||
public UserProfile ShowPlayerSelectDialog()
|
|
||||||
{
|
{
|
||||||
UserId selected = UserId.Null;
|
return new AvaloniaDynamicTextInputHandler(_parent);
|
||||||
byte[] defaultGuestImage = EmbeddedResources.Read("Ryujinx.HLE/HOS/Services/Account/Acc/GuestUserImage.jpg");
|
|
||||||
UserProfile guest = new UserProfile(new UserId("00000000000000000000000000000080"), "Guest", defaultGuestImage);
|
|
||||||
|
|
||||||
ManualResetEvent dialogCloseEvent = new(false);
|
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
|
||||||
{
|
|
||||||
ObservableCollection<BaseModel> profiles = [];
|
|
||||||
NavigationDialogHost nav = new();
|
|
||||||
|
|
||||||
_parent.AccountManager.GetAllUsers()
|
|
||||||
.OrderBy(x => x.Name)
|
|
||||||
.ForEach(profile => profiles.Add(new Models.UserProfile(profile, nav)));
|
|
||||||
|
|
||||||
profiles.Add(new Models.UserProfile(guest, nav));
|
|
||||||
ProfileSelectorDialogViewModel viewModel = new()
|
|
||||||
{
|
|
||||||
Profiles = profiles,
|
|
||||||
SelectedUserId = _parent.AccountManager.LastOpenedUser.UserId
|
|
||||||
};
|
|
||||||
(selected, _) = await ProfileSelectorDialog.ShowInputDialog(viewModel);
|
|
||||||
|
|
||||||
dialogCloseEvent.Set();
|
|
||||||
});
|
|
||||||
|
|
||||||
dialogCloseEvent.WaitOne();
|
|
||||||
|
|
||||||
UserProfile profile = _parent.AccountManager.LastOpenedUser;
|
|
||||||
if (selected == guest.UserId)
|
|
||||||
{
|
|
||||||
profile = guest;
|
|
||||||
}
|
|
||||||
else if (selected == UserId.Null)
|
|
||||||
{
|
|
||||||
profile = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (UserProfile p in _parent.AccountManager.GetAllUsers())
|
|
||||||
{
|
|
||||||
if (p.UserId == selected)
|
|
||||||
{
|
|
||||||
profile = p;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return profile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TakeScreenshot()
|
public void TakeScreenshot()
|
||||||
|
|||||||
@@ -1,121 +0,0 @@
|
|||||||
<UserControl
|
|
||||||
x:Class="Ryujinx.Ava.UI.Applet.ProfileSelectorDialog"
|
|
||||||
xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
|
||||||
xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models"
|
|
||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
|
||||||
d:DesignHeight="450"
|
|
||||||
MinWidth="500"
|
|
||||||
d:DesignWidth="800"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Focusable="True"
|
|
||||||
x:DataType="viewModels:ProfileSelectorDialogViewModel">
|
|
||||||
|
|
||||||
<UserControl.Resources>
|
|
||||||
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<Design.DataContext>
|
|
||||||
<viewModels:ProfileSelectorDialogViewModel />
|
|
||||||
</Design.DataContext>
|
|
||||||
|
|
||||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<Border
|
|
||||||
CornerRadius="5"
|
|
||||||
BorderBrush="{DynamicResource AppListHoverBackgroundColor}"
|
|
||||||
BorderThickness="1">
|
|
||||||
|
|
||||||
<ListBox
|
|
||||||
MaxHeight="300"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Background="Transparent"
|
|
||||||
ItemsSource="{Binding Profiles}"
|
|
||||||
SelectionChanged="ProfilesList_SelectionChanged">
|
|
||||||
|
|
||||||
<ListBox.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<WrapPanel
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Orientation="Horizontal" />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ListBox.ItemsPanel>
|
|
||||||
|
|
||||||
<ListBox.Styles>
|
|
||||||
<Style Selector="ListBoxItem">
|
|
||||||
<Setter Property="Margin" Value="5 5 0 5" />
|
|
||||||
<Setter Property="CornerRadius" Value="5" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="Rectangle#SelectionIndicator">
|
|
||||||
<Setter Property="Opacity" Value="0" />
|
|
||||||
</Style>
|
|
||||||
</ListBox.Styles>
|
|
||||||
|
|
||||||
<ListBox.DataTemplates>
|
|
||||||
<DataTemplate
|
|
||||||
DataType="models:UserProfile">
|
|
||||||
<Grid
|
|
||||||
PointerEntered="Grid_PointerEntered"
|
|
||||||
PointerExited="Grid_OnPointerExited">
|
|
||||||
<Border
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
ClipToBounds="True"
|
|
||||||
CornerRadius="5"
|
|
||||||
Background="{Binding BackgroundColor}">
|
|
||||||
<StackPanel
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch">
|
|
||||||
<Image
|
|
||||||
Width="96"
|
|
||||||
Height="96"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
Source="{Binding Image, Converter={StaticResource ByteImage}}" />
|
|
||||||
<TextBlock
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
MaxWidth="90"
|
|
||||||
Text="{Binding Name}"
|
|
||||||
TextAlignment="Center"
|
|
||||||
TextWrapping="Wrap"
|
|
||||||
TextTrimming="CharacterEllipsis"
|
|
||||||
MaxLines="2"
|
|
||||||
Margin="5" />
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</Grid>
|
|
||||||
</DataTemplate>
|
|
||||||
<DataTemplate
|
|
||||||
DataType="viewModels:BaseModel">
|
|
||||||
<Panel
|
|
||||||
Height="118"
|
|
||||||
Width="96">
|
|
||||||
<Panel.Styles>
|
|
||||||
<Style Selector="Panel">
|
|
||||||
<Setter Property="Background" Value="{DynamicResource ListBoxBackground}" />
|
|
||||||
</Style>
|
|
||||||
</Panel.Styles>
|
|
||||||
</Panel>
|
|
||||||
</DataTemplate>
|
|
||||||
</ListBox.DataTemplates>
|
|
||||||
</ListBox>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<StackPanel
|
|
||||||
Grid.Row="1"
|
|
||||||
Margin="0 24 0 0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Orientation="Horizontal"
|
|
||||||
Spacing="10">
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</UserControl>
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Input;
|
|
||||||
using FluentAvalonia.UI.Controls;
|
|
||||||
using Ryujinx.Ava.Common.Locale;
|
|
||||||
using Ryujinx.Ava.UI.Controls;
|
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
|
||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|
||||||
using Ryujinx.UI.Common.Configuration;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
|
|
||||||
using UserProfileSft = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Applet
|
|
||||||
{
|
|
||||||
public partial class ProfileSelectorDialog : UserControl
|
|
||||||
{
|
|
||||||
public ProfileSelectorDialogViewModel ViewModel { get; set; }
|
|
||||||
|
|
||||||
public ProfileSelectorDialog(ProfileSelectorDialogViewModel viewModel)
|
|
||||||
{
|
|
||||||
DataContext = ViewModel = viewModel;
|
|
||||||
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Grid_PointerEntered(object sender, PointerEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is Grid { DataContext: UserProfile profile })
|
|
||||||
{
|
|
||||||
profile.IsPointerOver = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Grid_OnPointerExited(object sender, PointerEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is Grid { DataContext: UserProfile profile })
|
|
||||||
{
|
|
||||||
profile.IsPointerOver = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ProfilesList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is ListBox listBox)
|
|
||||||
{
|
|
||||||
int selectedIndex = listBox.SelectedIndex;
|
|
||||||
|
|
||||||
if (selectedIndex >= 0 && selectedIndex < ViewModel.Profiles.Count)
|
|
||||||
{
|
|
||||||
if (ViewModel.Profiles[selectedIndex] is UserProfile userProfile)
|
|
||||||
{
|
|
||||||
ViewModel.SelectedUserId = userProfile.UserId;
|
|
||||||
Logger.Info?.Print(LogClass.UI, $"Selected: {userProfile.UserId}", "ProfileSelector");
|
|
||||||
|
|
||||||
ObservableCollection<BaseModel> newProfiles = [];
|
|
||||||
|
|
||||||
foreach (BaseModel item in ViewModel.Profiles)
|
|
||||||
{
|
|
||||||
if (item is UserProfile originalItem)
|
|
||||||
{
|
|
||||||
UserProfileSft profile = new(originalItem.UserId, originalItem.Name, originalItem.Image);
|
|
||||||
|
|
||||||
if (profile.UserId == ViewModel.SelectedUserId)
|
|
||||||
{
|
|
||||||
profile.AccountState = AccountState.Open;
|
|
||||||
}
|
|
||||||
|
|
||||||
newProfiles.Add(new UserProfile(profile, new NavigationDialogHost()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewModel.Profiles = newProfiles;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<(UserId Id, bool Result)> ShowInputDialog(ProfileSelectorDialogViewModel viewModel)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (ConfigurationState.Instance.System.SkipUserProfilesManager)
|
|
||||||
{
|
|
||||||
UserId defaultId = viewModel.SelectedUserId;
|
|
||||||
return (defaultId, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
FAContentDialog contentDialog = new()
|
|
||||||
{
|
|
||||||
Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle],
|
|
||||||
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.Continue],
|
|
||||||
SecondaryButtonText = string.Empty,
|
|
||||||
CloseButtonText = LocaleManager.Instance[LocaleKeys.Cancel],
|
|
||||||
Content = new ProfileSelectorDialog(viewModel),
|
|
||||||
Padding = new Thickness(0)
|
|
||||||
};
|
|
||||||
|
|
||||||
UserId result = UserId.Null;
|
|
||||||
bool input = false;
|
|
||||||
|
|
||||||
contentDialog.Closed += Handler;
|
|
||||||
|
|
||||||
await ContentDialogHelper.ShowAsync(contentDialog);
|
|
||||||
|
|
||||||
return (result, input);
|
|
||||||
|
|
||||||
void Handler(FAContentDialog sender, FAContentDialogClosedEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
if (eventArgs.Result == FAContentDialogResult.Primary)
|
|
||||||
{
|
|
||||||
result = viewModel.SelectedUserId;
|
|
||||||
input = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = UserId.Null;
|
|
||||||
input = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.ViewModels
|
|
||||||
{
|
|
||||||
public partial class ProfileSelectorDialogViewModel : BaseModel
|
|
||||||
{
|
|
||||||
|
|
||||||
[ObservableProperty] private UserId _selectedUserId;
|
|
||||||
|
|
||||||
[ObservableProperty] private ObservableCollection<BaseModel> _profiles = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user