Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
378080eb87 | |||
e8f5e97fa4 | |||
f3873620a3 | |||
986ac9ff83 | |||
42b9c1e8fe | |||
3b375525fb | |||
e6658c133c | |||
5b42a4d2c4 |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -27,7 +27,7 @@ jobs:
|
||||
build:
|
||||
name: ${{ matrix.OS_NAME }} (${{ matrix.configuration }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 35
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||
@ -110,7 +110,7 @@ jobs:
|
||||
build_macos:
|
||||
name: macOS Universal (${{ matrix.configuration }})
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 35
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [ Debug, Release ]
|
||||
|
2
.github/workflows/flatpak.yml
vendored
2
.github/workflows/flatpak.yml
vendored
@ -12,7 +12,7 @@ concurrency: flatpak-release
|
||||
|
||||
jobs:
|
||||
release:
|
||||
timeout-minutes: 35
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
|
2
.github/workflows/nightly_pr_comment.yml
vendored
2
.github/workflows/nightly_pr_comment.yml
vendored
@ -7,7 +7,7 @@ jobs:
|
||||
pr_comment:
|
||||
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 35
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
steps:
|
||||
- uses: actions/github-script@v6
|
||||
with:
|
||||
|
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@ -46,7 +46,7 @@ jobs:
|
||||
release:
|
||||
name: Release ${{ matrix.OS_NAME }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 35
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
@ -144,7 +144,7 @@ jobs:
|
||||
macos_release:
|
||||
name: Release MacOS universal
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 35
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
@ -207,4 +207,4 @@ jobs:
|
||||
needs: release
|
||||
with:
|
||||
ryujinx_version: "1.1.${{ github.run_number }}"
|
||||
secrets: inherit
|
||||
secrets: inherit
|
@ -31,7 +31,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
private AudioRendererRenderingDevice _renderingDevice;
|
||||
private AudioRendererExecutionMode _executionMode;
|
||||
private IWritableEvent _systemEvent;
|
||||
private ManualResetEvent _terminationEvent;
|
||||
private MemoryPoolState _dspMemoryPoolState;
|
||||
private VoiceContext _voiceContext;
|
||||
private MixContext _mixContext;
|
||||
@ -83,7 +82,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
public AudioRenderSystem(AudioRendererManager manager, IWritableEvent systemEvent)
|
||||
{
|
||||
_manager = manager;
|
||||
_terminationEvent = new ManualResetEvent(false);
|
||||
_dspMemoryPoolState = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp);
|
||||
_voiceContext = new VoiceContext();
|
||||
_mixContext = new MixContext();
|
||||
@ -387,11 +385,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
_isActive = false;
|
||||
}
|
||||
|
||||
if (_executionMode == AudioRendererExecutionMode.Auto)
|
||||
{
|
||||
_terminationEvent.WaitOne();
|
||||
}
|
||||
|
||||
Logger.Info?.Print(LogClass.AudioRenderer, $"Stopped renderer id {_sessionId}");
|
||||
}
|
||||
|
||||
@ -668,8 +661,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
if (_isActive)
|
||||
{
|
||||
_terminationEvent.Reset();
|
||||
|
||||
if (!_manager.Processor.HasRemainingCommands(_sessionId))
|
||||
{
|
||||
GenerateCommandList(out CommandList commands);
|
||||
@ -686,10 +677,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
_isDspRunningBehind = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_terminationEvent.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -857,7 +844,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
|
||||
_manager.Unregister(this);
|
||||
_terminationEvent.Dispose();
|
||||
_workBufferMemoryPin.Dispose();
|
||||
|
||||
if (MemoryManager is IRefCounted rc)
|
||||
|
@ -270,7 +270,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
string directory = AppDataManager.Mode switch
|
||||
{
|
||||
AppDataManager.LaunchMode.Portable => Path.Combine(AppDataManager.BaseDirPath, "screenshots"),
|
||||
AppDataManager.LaunchMode.Portable or AppDataManager.LaunchMode.Custom => Path.Combine(AppDataManager.BaseDirPath, "screenshots"),
|
||||
_ => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Ryujinx")
|
||||
};
|
||||
|
||||
|
@ -3,21 +3,20 @@ using Avalonia.Controls;
|
||||
using Avalonia.Controls.Notifications;
|
||||
using Avalonia.Threading;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Common;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Helpers
|
||||
{
|
||||
public static class NotificationHelper
|
||||
{
|
||||
private const int MaxNotifications = 4;
|
||||
private const int MaxNotifications = 4;
|
||||
private const int NotificationDelayInMs = 5000;
|
||||
|
||||
private static WindowNotificationManager _notificationManager;
|
||||
|
||||
private static readonly ManualResetEvent _templateAppliedEvent = new(false);
|
||||
private static readonly BlockingCollection<Notification> _notifications = new();
|
||||
|
||||
public static void SetNotificationManager(Window host)
|
||||
@ -29,25 +28,31 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
Margin = new Thickness(0, 0, 15, 40)
|
||||
};
|
||||
|
||||
var maybeAsyncWorkQueue = new Lazy<AsyncWorkQueue<Notification>>(
|
||||
() => new AsyncWorkQueue<Notification>(notification =>
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
_notificationManager.Show(notification);
|
||||
});
|
||||
},
|
||||
"UI.NotificationThread",
|
||||
_notifications),
|
||||
LazyThreadSafetyMode.ExecutionAndPublication);
|
||||
|
||||
_notificationManager.TemplateApplied += (sender, args) =>
|
||||
{
|
||||
_templateAppliedEvent.Set();
|
||||
// NOTE: Force creation of the AsyncWorkQueue.
|
||||
_ = maybeAsyncWorkQueue.Value;
|
||||
};
|
||||
|
||||
Task.Run(async () =>
|
||||
host.Closing += (sender, args) =>
|
||||
{
|
||||
_templateAppliedEvent.WaitOne();
|
||||
|
||||
foreach (var notification in _notifications.GetConsumingEnumerable())
|
||||
if (maybeAsyncWorkQueue.IsValueCreated)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
_notificationManager.Show(notification);
|
||||
});
|
||||
|
||||
await Task.Delay(NotificationDelayInMs / MaxNotifications);
|
||||
maybeAsyncWorkQueue.Value.Dispose();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
public static void Show(string title, string text, NotificationType type, bool waitingExit = false, Action onClick = null, Action onClose = null)
|
||||
|
@ -22,9 +22,11 @@ namespace Ryujinx.Common
|
||||
_cts = new CancellationTokenSource();
|
||||
_queue = collection;
|
||||
_workerAction = callback;
|
||||
_workerThread = new Thread(DoWork) { Name = name };
|
||||
|
||||
_workerThread.IsBackground = true;
|
||||
_workerThread = new Thread(DoWork)
|
||||
{
|
||||
Name = name,
|
||||
IsBackground = true
|
||||
};
|
||||
_workerThread.Start();
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
private const ushort FileFormatVersionMajor = 1;
|
||||
private const ushort FileFormatVersionMinor = 2;
|
||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||
private const uint CodeGenVersion = 4714;
|
||||
private const uint CodeGenVersion = 5110;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
|
@ -2245,7 +2245,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
var result = emitF(context.TypeFP64(), context.GetFP64(src1), context.GetFP64(src2));
|
||||
|
||||
if (!context.Config.GpuAccessor.QueryHostReducedPrecision())
|
||||
if (!context.Config.GpuAccessor.QueryHostReducedPrecision() || operation.ForcePrecise)
|
||||
{
|
||||
context.Decorate(result, Decoration.NoContraction);
|
||||
}
|
||||
@ -2256,7 +2256,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
var result = emitF(context.TypeFP32(), context.GetFP32(src1), context.GetFP32(src2));
|
||||
|
||||
if (!context.Config.GpuAccessor.QueryHostReducedPrecision())
|
||||
if (!context.Config.GpuAccessor.QueryHostReducedPrecision() || operation.ForcePrecise)
|
||||
{
|
||||
context.Decorate(result, Decoration.NoContraction);
|
||||
}
|
||||
@ -2316,7 +2316,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
var result = emitF(context.TypeFP64(), context.GetFP64(src1), context.GetFP64(src2), context.GetFP64(src3));
|
||||
|
||||
if (!context.Config.GpuAccessor.QueryHostReducedPrecision())
|
||||
if (!context.Config.GpuAccessor.QueryHostReducedPrecision() || operation.ForcePrecise)
|
||||
{
|
||||
context.Decorate(result, Decoration.NoContraction);
|
||||
}
|
||||
@ -2327,7 +2327,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
var result = emitF(context.TypeFP32(), context.GetFP32(src1), context.GetFP32(src2), context.GetFP32(src3));
|
||||
|
||||
if (!context.Config.GpuAccessor.QueryHostReducedPrecision())
|
||||
if (!context.Config.GpuAccessor.QueryHostReducedPrecision() || operation.ForcePrecise)
|
||||
{
|
||||
context.Decorate(result, Decoration.NoContraction);
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
public Instruction Inst { get; private set; }
|
||||
public StorageKind StorageKind { get; }
|
||||
|
||||
public bool ForcePrecise { get; set; }
|
||||
|
||||
private Operand[] _dests;
|
||||
|
||||
public Operand Dest
|
||||
|
@ -10,6 +10,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
{
|
||||
public Instruction Inst { get; }
|
||||
public StorageKind StorageKind { get; }
|
||||
public bool ForcePrecise { get; }
|
||||
|
||||
public int Index { get; }
|
||||
|
||||
@ -17,10 +18,11 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
|
||||
public int SourcesCount => _sources.Length;
|
||||
|
||||
public AstOperation(Instruction inst, StorageKind storageKind, IAstNode[] sources, int sourcesCount)
|
||||
public AstOperation(Instruction inst, StorageKind storageKind, bool forcePrecise, IAstNode[] sources, int sourcesCount)
|
||||
{
|
||||
Inst = inst;
|
||||
StorageKind = storageKind;
|
||||
ForcePrecise = forcePrecise;
|
||||
_sources = sources;
|
||||
|
||||
for (int index = 0; index < sources.Length; index++)
|
||||
@ -38,12 +40,18 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
Index = 0;
|
||||
}
|
||||
|
||||
public AstOperation(Instruction inst, StorageKind storageKind, int index, IAstNode[] sources, int sourcesCount) : this(inst, storageKind, sources, sourcesCount)
|
||||
public AstOperation(
|
||||
Instruction inst,
|
||||
StorageKind storageKind,
|
||||
bool forcePrecise,
|
||||
int index,
|
||||
IAstNode[] sources,
|
||||
int sourcesCount) : this(inst, storageKind, forcePrecise, sources, sourcesCount)
|
||||
{
|
||||
Index = index;
|
||||
}
|
||||
|
||||
public AstOperation(Instruction inst, params IAstNode[] sources) : this(inst, StorageKind.None, sources, sources.Length)
|
||||
public AstOperation(Instruction inst, params IAstNode[] sources) : this(inst, StorageKind.None, false, sources, sources.Length)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
int cbufSlot,
|
||||
int handle,
|
||||
int index,
|
||||
params IAstNode[] sources) : base(inst, StorageKind.None, index, sources, sources.Length)
|
||||
params IAstNode[] sources) : base(inst, StorageKind.None, false, index, sources, sources.Length)
|
||||
{
|
||||
Type = type;
|
||||
Format = format;
|
||||
|
@ -156,7 +156,13 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
}
|
||||
else
|
||||
{
|
||||
source = new AstOperation(inst, operation.StorageKind, operation.Index, sources, operation.SourcesCount);
|
||||
source = new AstOperation(
|
||||
inst,
|
||||
operation.StorageKind,
|
||||
operation.ForcePrecise,
|
||||
operation.Index,
|
||||
sources,
|
||||
operation.SourcesCount);
|
||||
}
|
||||
|
||||
AggregateType destElemType = destType;
|
||||
@ -179,7 +185,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
|
||||
dest.VarType = destElemType;
|
||||
|
||||
context.AddNode(new AstAssignment(dest, new AstOperation(Instruction.VectorExtract, StorageKind.None, new[] { destVec, index }, 2)));
|
||||
context.AddNode(new AstAssignment(dest, new AstOperation(Instruction.VectorExtract, StorageKind.None, false, new[] { destVec, index }, 2)));
|
||||
}
|
||||
}
|
||||
else if (operation.Dest != null)
|
||||
@ -227,7 +233,13 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
}
|
||||
else if (!isCopy)
|
||||
{
|
||||
source = new AstOperation(inst, operation.StorageKind, operation.Index, sources, operation.SourcesCount);
|
||||
source = new AstOperation(
|
||||
inst,
|
||||
operation.StorageKind,
|
||||
operation.ForcePrecise,
|
||||
operation.Index,
|
||||
sources,
|
||||
operation.SourcesCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -248,7 +260,13 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
}
|
||||
else
|
||||
{
|
||||
context.AddNode(new AstOperation(inst, operation.StorageKind, operation.Index, sources, operation.SourcesCount));
|
||||
context.AddNode(new AstOperation(
|
||||
inst,
|
||||
operation.StorageKind,
|
||||
operation.ForcePrecise,
|
||||
operation.Index,
|
||||
sources,
|
||||
operation.SourcesCount));
|
||||
}
|
||||
|
||||
// Those instructions needs to be emulated by using helper functions,
|
||||
|
@ -319,7 +319,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
new AstOperand(OperandType.Constant, elemIndex)
|
||||
};
|
||||
|
||||
return new AstOperation(Instruction.Load, StorageKind.ConstantBuffer, sources, sources.Length);
|
||||
return new AstOperation(Instruction.Load, StorageKind.ConstantBuffer, false, sources, sources.Length);
|
||||
}
|
||||
|
||||
return GetOperand(operand);
|
||||
|
@ -14,6 +14,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
public static void RunPass(HelperFunctionManager hfm, BasicBlock[] blocks, ShaderConfig config)
|
||||
{
|
||||
bool isVertexShader = config.Stage == ShaderStage.Vertex;
|
||||
bool isImpreciseFragmentShader = config.Stage == ShaderStage.Fragment && config.GpuAccessor.QueryHostReducedPrecision();
|
||||
bool hasConstantBufferDrawParameters = config.GpuAccessor.QueryHasConstantBufferDrawParameters();
|
||||
bool hasVectorIndexingBug = config.GpuAccessor.QueryHostHasVectorIndexingBug();
|
||||
bool supportsSnormBufferTextureFormat = config.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat();
|
||||
@ -45,6 +46,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
}
|
||||
}
|
||||
|
||||
if (isImpreciseFragmentShader)
|
||||
{
|
||||
EnableForcePreciseIfNeeded(operation);
|
||||
}
|
||||
|
||||
if (hasVectorIndexingBug)
|
||||
{
|
||||
InsertVectorComponentSelect(node, config);
|
||||
@ -81,6 +87,25 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnableForcePreciseIfNeeded(Operation operation)
|
||||
{
|
||||
// There are some cases where a small bias is added to values to prevent division by zero.
|
||||
// When operating with reduced precision, it is possible for this bias to get rounded to 0
|
||||
// and cause a division by zero.
|
||||
// To prevent that, we force those operations to be precise even if the host wants
|
||||
// imprecise operations for performance.
|
||||
|
||||
if (operation.Inst == (Instruction.FP32 | Instruction.Divide) &&
|
||||
operation.GetSource(0).Type == OperandType.Constant &&
|
||||
operation.GetSource(0).AsFloat() == 1f &&
|
||||
operation.GetSource(1).AsgOp is Operation addOp &&
|
||||
addOp.Inst == (Instruction.FP32 | Instruction.Add) &&
|
||||
addOp.GetSource(1).Type == OperandType.Constant)
|
||||
{
|
||||
addOp.ForcePrecise = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void InsertVectorComponentSelect(LinkedListNode<INode> node, ShaderConfig config)
|
||||
{
|
||||
Operation operation = (Operation)node.Value;
|
||||
@ -366,7 +391,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
bool isImage = IsImageInstructionWithScale(texOp.Inst);
|
||||
|
||||
if ((texOp.Inst == Instruction.TextureSample || isImage) &&
|
||||
intCoords &&
|
||||
(intCoords || isImage) &&
|
||||
!isBindless &&
|
||||
!isIndexed &&
|
||||
config.Stage.SupportsRenderScale() &&
|
||||
|
@ -167,12 +167,12 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
if (StrEquals(RomfsDir, modDir.Name))
|
||||
{
|
||||
mods.RomfsDirs.Add(mod = new Mod<DirectoryInfo>($"<{titleId} RomFs>", modDir));
|
||||
mods.RomfsDirs.Add(mod = new Mod<DirectoryInfo>(dir.Name, modDir));
|
||||
types.Append('R');
|
||||
}
|
||||
else if (StrEquals(ExefsDir, modDir.Name))
|
||||
{
|
||||
mods.ExefsDirs.Add(mod = new Mod<DirectoryInfo>($"<{titleId} ExeFs>", modDir));
|
||||
mods.ExefsDirs.Add(mod = new Mod<DirectoryInfo>(dir.Name, modDir));
|
||||
types.Append('E');
|
||||
}
|
||||
else if (StrEquals(CheatDir, modDir.Name))
|
||||
|
@ -381,7 +381,7 @@ namespace Ryujinx.Ui
|
||||
string filename = $"ryujinx_capture_{currentTime.Year}-{currentTime.Month:D2}-{currentTime.Day:D2}_{currentTime.Hour:D2}-{currentTime.Minute:D2}-{currentTime.Second:D2}.png";
|
||||
string directory = AppDataManager.Mode switch
|
||||
{
|
||||
AppDataManager.LaunchMode.Portable => System.IO.Path.Combine(AppDataManager.BaseDirPath, "screenshots"),
|
||||
AppDataManager.LaunchMode.Portable or AppDataManager.LaunchMode.Custom => System.IO.Path.Combine(AppDataManager.BaseDirPath, "screenshots"),
|
||||
_ => System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Ryujinx")
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user