Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
3d1a0bf374 | ||
|
c20f3fbebd | ||
|
0d3b82477e | ||
|
470be03c2f | ||
|
c963b3c804 | ||
|
a4fdfb5f94 | ||
|
37d27c4c99 | ||
|
f906eb06c2 | ||
|
219f63ff4e | ||
|
1cca3e99ab | ||
|
55a23e5ec8 | ||
|
479d1fd8b0 | ||
|
cb70e7bb30 | ||
|
c200a7b7c6 | ||
|
6268170a10 | ||
|
ee0f9b03a4 | ||
|
f93c5f006a | ||
|
295fbd0542 | ||
|
d7310d7a1c | ||
|
8c50943a2e | ||
|
ec4cd57ccf | ||
|
5a085cba0f | ||
|
1a1d33a018 | ||
|
0fbcd630bc | ||
|
f4d731ae20 | ||
|
8ac53c66b4 | ||
|
0f50de72be | ||
|
df758eddd1 | ||
|
5f32a8ed94 | ||
|
535fbec675 | ||
|
6fe88115a3 | ||
|
475fa4d390 | ||
|
edf7e628ca | ||
|
ba5c0cf5d8 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -125,6 +125,9 @@ ClientBin/
|
||||
packages/*
|
||||
*.config
|
||||
|
||||
# Include nuget.config
|
||||
!nuget.config
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
|
@@ -1587,6 +1587,12 @@ namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
|
||||
|
||||
// We can eliminate the move if source is already 32-bit and the registers are the same.
|
||||
if (dest.Value == source.Value && source.Type == OperandType.I32)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
context.Assembler.Mov(dest, source, OperandType.I32);
|
||||
}
|
||||
|
||||
|
@@ -80,10 +80,7 @@ namespace ARMeilleure.Common
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(null);
|
||||
}
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
lock (_pages)
|
||||
{
|
||||
@@ -100,10 +97,7 @@ namespace ARMeilleure.Common
|
||||
/// <exception cref="ArgumentException">Length of <paramref name="levels"/> is less than 2</exception>
|
||||
public AddressTable(Level[] levels)
|
||||
{
|
||||
if (levels == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(levels));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(levels);
|
||||
|
||||
if (levels.Length < 2)
|
||||
{
|
||||
@@ -141,10 +135,7 @@ namespace ARMeilleure.Common
|
||||
/// <exception cref="ArgumentException"><paramref name="address"/> is not mapped</exception>
|
||||
public ref TEntry GetValue(ulong address)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(null);
|
||||
}
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
if (!IsValid(address))
|
||||
{
|
||||
|
@@ -49,10 +49,7 @@ namespace ARMeilleure.Common
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(null);
|
||||
}
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
return ref _countTable.GetValue(_index);
|
||||
}
|
||||
|
@@ -53,10 +53,7 @@ namespace ARMeilleure.Common
|
||||
/// <exception cref="ObjectDisposedException"><see cref="EntryTable{TEntry}"/> instance was disposed</exception>
|
||||
public int Allocate()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(null);
|
||||
}
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
lock (_allocated)
|
||||
{
|
||||
@@ -83,10 +80,7 @@ namespace ARMeilleure.Common
|
||||
/// <exception cref="ObjectDisposedException"><see cref="EntryTable{TEntry}"/> instance was disposed</exception>
|
||||
public void Free(int index)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(null);
|
||||
}
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
lock (_allocated)
|
||||
{
|
||||
@@ -108,10 +102,7 @@ namespace ARMeilleure.Common
|
||||
/// <exception cref="ArgumentException">Entry at <paramref name="index"/> is not allocated</exception>
|
||||
public ref TEntry GetValue(int index)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(null);
|
||||
}
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
lock (_allocated)
|
||||
{
|
||||
|
@@ -381,7 +381,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
Operand ne = context.VectorExtract(type, GetVec(op.Rn), 0);
|
||||
Operand ne = context.VectorExtract(type, GetVec(op.Rn), index);
|
||||
|
||||
if (sizeF == 0)
|
||||
{
|
||||
@@ -389,8 +389,6 @@ namespace ARMeilleure.Instructions
|
||||
Operand e = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
|
||||
context.LoadFromContext();
|
||||
|
||||
e = context.ZeroExtend16(OperandType.I64, e);
|
||||
|
||||
res = EmitVectorInsert(context, res, e, part + index, 1);
|
||||
}
|
||||
else /* if (sizeF == 1) */
|
||||
|
@@ -48,10 +48,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
|
||||
public void AddSuccessor(BasicBlock block)
|
||||
{
|
||||
if (block == null)
|
||||
{
|
||||
ThrowNull(nameof(block));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(block);
|
||||
|
||||
if ((uint)_succCount + 1 > MaxSuccessors)
|
||||
{
|
||||
@@ -100,10 +97,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
|
||||
public void SetSuccessor(int index, BasicBlock block)
|
||||
{
|
||||
if (block == null)
|
||||
{
|
||||
ThrowNull(nameof(block));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(block);
|
||||
|
||||
if ((uint)index >= (uint)_succCount)
|
||||
{
|
||||
@@ -144,7 +138,6 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
}
|
||||
}
|
||||
|
||||
private static void ThrowNull(string name) => throw new ArgumentNullException(name);
|
||||
private static void ThrowOutOfRange(string name) => throw new ArgumentOutOfRangeException(name);
|
||||
private static void ThrowSuccessorOverflow() => throw new OverflowException($"BasicBlock can only have {MaxSuccessors} successors.");
|
||||
|
||||
|
@@ -378,14 +378,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
if (Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)Value ^ ((int)Kind << 16) ^ ((int)Type << 20);
|
||||
}
|
||||
return ((ulong)_data).GetHashCode();
|
||||
}
|
||||
|
||||
public bool Equals(Operand operand)
|
||||
|
@@ -18,17 +18,17 @@ namespace ARMeilleure.Signal
|
||||
public IntPtr sa_restorer;
|
||||
}
|
||||
|
||||
static class UnixSignalHandlerRegistration
|
||||
static partial class UnixSignalHandlerRegistration
|
||||
{
|
||||
private const int SIGSEGV = 11;
|
||||
private const int SIGBUS = 10;
|
||||
private const int SA_SIGINFO = 0x00000004;
|
||||
|
||||
[DllImport("libc", SetLastError = true)]
|
||||
private static extern int sigaction(int signum, ref SigAction sigAction, out SigAction oldAction);
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int sigaction(int signum, ref SigAction sigAction, out SigAction oldAction);
|
||||
|
||||
[DllImport("libc", SetLastError = true)]
|
||||
private static extern int sigemptyset(ref SigSet set);
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int sigemptyset(ref SigSet set);
|
||||
|
||||
public static SigAction RegisterExceptionHandler(IntPtr action)
|
||||
{
|
||||
|
@@ -3,19 +3,19 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Signal
|
||||
{
|
||||
unsafe class WindowsSignalHandlerRegistration
|
||||
unsafe partial class WindowsSignalHandlerRegistration
|
||||
{
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler);
|
||||
[LibraryImport("kernel32.dll")]
|
||||
private static partial IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern ulong RemoveVectoredExceptionHandler(IntPtr handle);
|
||||
[LibraryImport("kernel32.dll")]
|
||||
private static partial ulong RemoveVectoredExceptionHandler(IntPtr handle);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
|
||||
static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
|
||||
[LibraryImport("kernel32.dll", SetLastError = true, EntryPoint = "LoadLibraryA")]
|
||||
private static partial IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
|
||||
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
private static partial IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
|
||||
|
||||
private static IntPtr _getCurrentThreadIdPtr;
|
||||
|
||||
|
@@ -7,7 +7,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Translation.Cache
|
||||
{
|
||||
static class JitUnwindWindows
|
||||
static partial class JitUnwindWindows
|
||||
{
|
||||
private const int MaxUnwindCodesArraySize = 32; // Must be an even value.
|
||||
|
||||
@@ -42,14 +42,15 @@ namespace ARMeilleure.Translation.Cache
|
||||
|
||||
private unsafe delegate RuntimeFunction* GetRuntimeFunctionCallback(ulong controlPc, IntPtr context);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
private static unsafe extern bool RtlInstallFunctionTableCallback(
|
||||
[LibraryImport("kernel32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static unsafe partial bool RtlInstallFunctionTableCallback(
|
||||
ulong tableIdentifier,
|
||||
ulong baseAddress,
|
||||
uint length,
|
||||
GetRuntimeFunctionCallback callback,
|
||||
IntPtr context,
|
||||
string outOfProcessCallbackDll);
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string outOfProcessCallbackDll);
|
||||
|
||||
private static GetRuntimeFunctionCallback _getRuntimeFunctionCallback;
|
||||
|
||||
|
@@ -25,10 +25,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
public static Delegate GetDelegate(MethodInfo info)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(info));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(info);
|
||||
|
||||
Type[] parameters = info.GetParameters().Select(pI => pI.ParameterType).ToArray();
|
||||
Type returnType = info.ReturnType;
|
||||
|
@@ -35,10 +35,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
public static IntPtr GetDelegateFuncPtr(MethodInfo info)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(info));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(info);
|
||||
|
||||
string key = GetKey(info);
|
||||
|
||||
@@ -52,10 +49,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
public static int GetDelegateIndex(MethodInfo info)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(info));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(info);
|
||||
|
||||
string key = GetKey(info);
|
||||
|
||||
|
@@ -67,10 +67,7 @@ namespace ARMeilleure.Translation
|
||||
/// <returns>True if the value was added, false if the start key was already in the dictionary</returns>
|
||||
public bool AddOrUpdate(K start, K end, V value, Func<K, V, V> updateFactoryCallback)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
|
||||
return BSTInsert(start, end, value, updateFactoryCallback, out IntervalTreeNode<K, V> node);
|
||||
}
|
||||
@@ -85,10 +82,7 @@ namespace ARMeilleure.Translation
|
||||
/// <returns><paramref name="value"/> if <paramref name="start"/> is not yet on the tree, or the existing value otherwise</returns>
|
||||
public V GetOrAdd(K start, K end, V value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
|
||||
BSTInsert(start, end, value, null, out IntervalTreeNode<K, V> node);
|
||||
return node.Value;
|
||||
@@ -152,10 +146,7 @@ namespace ARMeilleure.Translation
|
||||
/// <returns>Node reference in the tree</returns>
|
||||
private IntervalTreeNode<K, V> GetNode(K key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
IntervalTreeNode<K, V> node = _root;
|
||||
while (node != null)
|
||||
|
@@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||
|
||||
private const uint InternalVersion = 3713; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
private const uint InternalVersion = 4159; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const string ActualDir = "0";
|
||||
private const string BackupDir = "1";
|
||||
|
@@ -140,7 +140,7 @@ namespace ARMeilleure.Translation
|
||||
}
|
||||
}
|
||||
|
||||
Array.Clear(localDefs, 0, localDefs.Length);
|
||||
Array.Clear(localDefs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -30,10 +30,7 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(null);
|
||||
}
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
return _dispatchStub.Value;
|
||||
}
|
||||
@@ -47,10 +44,7 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(null);
|
||||
}
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
return _slowDispatchStub.Value;
|
||||
}
|
||||
@@ -64,10 +58,7 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(null);
|
||||
}
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
return _dispatchLoop.Value;
|
||||
}
|
||||
@@ -81,7 +72,9 @@ namespace ARMeilleure.Translation
|
||||
/// <exception cref="ArgumentNullException"><paramref name="translator"/> is null</exception>
|
||||
public TranslatorStubs(Translator translator)
|
||||
{
|
||||
_translator = translator ?? throw new ArgumentNullException(nameof(translator));
|
||||
ArgumentNullException.ThrowIfNull(translator);
|
||||
|
||||
_translator = translator;
|
||||
_dispatchStub = new(GenerateDispatchStub, isThreadSafe: true);
|
||||
_dispatchLoop = new(GenerateDispatchLoop, isThreadSafe: true);
|
||||
}
|
||||
|
54
Directory.Packages.props
Normal file
54
Directory.Packages.props
Normal file
@@ -0,0 +1,54 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Avalonia" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="Concentus" Version="1.1.7" />
|
||||
<PackageVersion Include="Crc32.NET" Version="1.2.0" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.1.3.18" />
|
||||
<PackageVersion Include="DynamicData" Version="7.12.11" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="1.4.5" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
|
||||
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
|
||||
<PackageVersion Include="LibHac" Version="0.17.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
<PackageVersion Include="NUnit" Version="3.13.3" />
|
||||
<PackageVersion Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
<PackageVersion Include="OpenTK.Core" Version="4.7.5" />
|
||||
<PackageVersion Include="OpenTK.Graphics" Version="4.7.5" />
|
||||
<PackageVersion Include="OpenTK.OpenAL" Version="4.7.5" />
|
||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.7.5" />
|
||||
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.24.2-build21" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.1" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
|
||||
<PackageVersion Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
||||
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.25.1" />
|
||||
<PackageVersion Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageVersion Include="System.Management" Version="7.0.0" />
|
||||
<PackageVersion Include="System.Net.NameResolution" Version="4.3.0" />
|
||||
<PackageVersion Include="System.Threading.ThreadPool" Version="4.3.0" />
|
||||
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.5.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@@ -1,11 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OpenTK.OpenAL" Version="4.7.5" />
|
||||
<PackageReference Include="OpenTK.OpenAL" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -51,6 +51,40 @@ namespace Ryujinx.Audio.Backends.CompatLayer
|
||||
};
|
||||
}
|
||||
|
||||
private SampleFormat SelectHardwareSampleFormat(SampleFormat targetSampleFormat)
|
||||
{
|
||||
if (_realDriver.SupportsSampleFormat(targetSampleFormat))
|
||||
{
|
||||
return targetSampleFormat;
|
||||
}
|
||||
|
||||
// Attempt conversion from PCM16.
|
||||
if (targetSampleFormat == SampleFormat.PcmInt16)
|
||||
{
|
||||
// Prefer PCM32 if we need to convert.
|
||||
if (_realDriver.SupportsSampleFormat(SampleFormat.PcmInt32))
|
||||
{
|
||||
return SampleFormat.PcmInt32;
|
||||
}
|
||||
|
||||
// If not supported, PCM float provides the best quality with a cost lower than PCM24.
|
||||
if (_realDriver.SupportsSampleFormat(SampleFormat.PcmFloat))
|
||||
{
|
||||
return SampleFormat.PcmFloat;
|
||||
}
|
||||
|
||||
// TODO: Implement PCM24 conversion.
|
||||
|
||||
// If nothing is truly supported, attempt PCM8 at the cost of loosing quality.
|
||||
if (_realDriver.SupportsSampleFormat(SampleFormat.PcmInt8))
|
||||
{
|
||||
return SampleFormat.PcmInt8;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentException("No valid sample format configuration found!");
|
||||
}
|
||||
|
||||
public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume)
|
||||
{
|
||||
if (channelCount == 0)
|
||||
@@ -77,15 +111,26 @@ namespace Ryujinx.Audio.Backends.CompatLayer
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
SampleFormat hardwareSampleFormat = SelectHardwareSampleFormat(sampleFormat);
|
||||
uint hardwareChannelCount = SelectHardwareChannelCount(channelCount);
|
||||
|
||||
IHardwareDeviceSession realSession = _realDriver.OpenDeviceSession(direction, memoryManager, sampleFormat, sampleRate, hardwareChannelCount, volume);
|
||||
IHardwareDeviceSession realSession = _realDriver.OpenDeviceSession(direction, memoryManager, hardwareSampleFormat, sampleRate, hardwareChannelCount, volume);
|
||||
|
||||
if (hardwareChannelCount == channelCount)
|
||||
if (hardwareChannelCount == channelCount && hardwareSampleFormat == sampleFormat)
|
||||
{
|
||||
return realSession;
|
||||
}
|
||||
|
||||
if (hardwareSampleFormat != sampleFormat)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Audio, $"{sampleFormat} isn't supported by the audio device, conversion to {hardwareSampleFormat} will happen.");
|
||||
|
||||
if (hardwareSampleFormat < sampleFormat)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Audio, $"{hardwareSampleFormat} has lower quality than {sampleFormat}, expect some loss in audio fidelity.");
|
||||
}
|
||||
}
|
||||
|
||||
if (direction == Direction.Input)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Audio, $"The selected audio backend doesn't support the requested audio input configuration, fallback to dummy...");
|
||||
@@ -103,7 +148,7 @@ namespace Ryujinx.Audio.Backends.CompatLayer
|
||||
}
|
||||
|
||||
// If we need to do post processing before sending to the hardware device, wrap around it.
|
||||
return new CompatLayerHardwareDeviceSession(realSessionOutputBase, channelCount);
|
||||
return new CompatLayerHardwareDeviceSession(realSessionOutputBase, sampleFormat, channelCount);
|
||||
}
|
||||
|
||||
public bool SupportsChannelCount(uint channelCount)
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Audio.Backends.Common;
|
||||
using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Audio.Renderer.Dsp;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@@ -8,11 +9,13 @@ namespace Ryujinx.Audio.Backends.CompatLayer
|
||||
class CompatLayerHardwareDeviceSession : HardwareDeviceSessionOutputBase
|
||||
{
|
||||
private HardwareDeviceSessionOutputBase _realSession;
|
||||
private SampleFormat _userSampleFormat;
|
||||
private uint _userChannelCount;
|
||||
|
||||
public CompatLayerHardwareDeviceSession(HardwareDeviceSessionOutputBase realSession, uint userChannelCount) : base(realSession.MemoryManager, realSession.RequestedSampleFormat, realSession.RequestedSampleRate, userChannelCount)
|
||||
public CompatLayerHardwareDeviceSession(HardwareDeviceSessionOutputBase realSession, SampleFormat userSampleFormat, uint userChannelCount) : base(realSession.MemoryManager, realSession.RequestedSampleFormat, realSession.RequestedSampleRate, userChannelCount)
|
||||
{
|
||||
_realSession = realSession;
|
||||
_userSampleFormat = userSampleFormat;
|
||||
_userChannelCount = userChannelCount;
|
||||
}
|
||||
|
||||
@@ -38,53 +41,86 @@ namespace Ryujinx.Audio.Backends.CompatLayer
|
||||
|
||||
public override void QueueBuffer(AudioBuffer buffer)
|
||||
{
|
||||
SampleFormat realSampleFormat = _realSession.RequestedSampleFormat;
|
||||
|
||||
if (_userSampleFormat != realSampleFormat)
|
||||
{
|
||||
if (_userSampleFormat != SampleFormat.PcmInt16)
|
||||
{
|
||||
throw new NotImplementedException("Converting formats other than PCM16 is not supported.");
|
||||
}
|
||||
|
||||
int userSampleCount = buffer.Data.Length / BackendHelper.GetSampleSize(_userSampleFormat);
|
||||
|
||||
ReadOnlySpan<short> samples = MemoryMarshal.Cast<byte, short>(buffer.Data);
|
||||
byte[] convertedSamples = new byte[BackendHelper.GetSampleSize(realSampleFormat) * userSampleCount];
|
||||
|
||||
switch (realSampleFormat)
|
||||
{
|
||||
case SampleFormat.PcmInt8:
|
||||
PcmHelper.Convert(MemoryMarshal.Cast<byte, sbyte>(convertedSamples), samples);
|
||||
break;
|
||||
case SampleFormat.PcmInt32:
|
||||
PcmHelper.Convert(MemoryMarshal.Cast<byte, int>(convertedSamples), samples);
|
||||
break;
|
||||
case SampleFormat.PcmFloat:
|
||||
PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast<byte, float>(convertedSamples), samples);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException($"Sample format conversion from {_userSampleFormat} to {realSampleFormat} not implemented.");
|
||||
}
|
||||
|
||||
buffer.Data = convertedSamples;
|
||||
}
|
||||
|
||||
_realSession.QueueBuffer(buffer);
|
||||
}
|
||||
|
||||
public override bool RegisterBuffer(AudioBuffer buffer, byte[] samples)
|
||||
{
|
||||
if (RequestedSampleFormat != SampleFormat.PcmInt16)
|
||||
{
|
||||
throw new NotImplementedException("Downmixing formats other than PCM16 is not supported.");
|
||||
}
|
||||
|
||||
if (samples == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
short[] downmixedBufferPCM16;
|
||||
|
||||
ReadOnlySpan<short> samplesPCM16 = MemoryMarshal.Cast<byte, short>(samples);
|
||||
|
||||
if (_userChannelCount == 6)
|
||||
if (_userChannelCount != _realSession.RequestedChannelCount)
|
||||
{
|
||||
downmixedBufferPCM16 = Downmixing.DownMixSurroundToStereo(samplesPCM16);
|
||||
|
||||
if (_realSession.RequestedChannelCount == 1)
|
||||
if (_userSampleFormat != SampleFormat.PcmInt16)
|
||||
{
|
||||
downmixedBufferPCM16 = Downmixing.DownMixStereoToMono(downmixedBufferPCM16);
|
||||
throw new NotImplementedException("Downmixing formats other than PCM16 is not supported.");
|
||||
}
|
||||
}
|
||||
else if (_userChannelCount == 2 && _realSession.RequestedChannelCount == 1)
|
||||
{
|
||||
downmixedBufferPCM16 = Downmixing.DownMixStereoToMono(samplesPCM16);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException($"Downmixing from {_userChannelCount} to {_realSession.RequestedChannelCount} not implemented.");
|
||||
}
|
||||
|
||||
byte[] downmixedBuffer = MemoryMarshal.Cast<short, byte>(downmixedBufferPCM16).ToArray();
|
||||
ReadOnlySpan<short> samplesPCM16 = MemoryMarshal.Cast<byte, short>(samples);
|
||||
|
||||
if (_userChannelCount == 6)
|
||||
{
|
||||
samplesPCM16 = Downmixing.DownMixSurroundToStereo(samplesPCM16);
|
||||
|
||||
if (_realSession.RequestedChannelCount == 1)
|
||||
{
|
||||
samplesPCM16 = Downmixing.DownMixStereoToMono(samplesPCM16);
|
||||
}
|
||||
}
|
||||
else if (_userChannelCount == 2 && _realSession.RequestedChannelCount == 1)
|
||||
{
|
||||
samplesPCM16 = Downmixing.DownMixStereoToMono(samplesPCM16);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException($"Downmixing from {_userChannelCount} to {_realSession.RequestedChannelCount} not implemented.");
|
||||
}
|
||||
|
||||
samples = MemoryMarshal.Cast<short, byte>(samplesPCM16).ToArray();
|
||||
}
|
||||
|
||||
AudioBuffer fakeBuffer = new AudioBuffer
|
||||
{
|
||||
BufferTag = buffer.BufferTag,
|
||||
DataPointer = buffer.DataPointer,
|
||||
DataSize = (ulong)downmixedBuffer.Length
|
||||
DataSize = (ulong)samples.Length
|
||||
};
|
||||
|
||||
bool result = _realSession.RegisterBuffer(fakeBuffer, downmixedBuffer);
|
||||
bool result = _realSession.RegisterBuffer(fakeBuffer, samples);
|
||||
|
||||
if (result)
|
||||
{
|
||||
|
@@ -23,7 +23,7 @@ namespace Ryujinx.Audio.Renderer.Common
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
ulong alignedOffset = BitUtils.AlignUp(Offset, align);
|
||||
ulong alignedOffset = BitUtils.AlignUp<ulong>(Offset, (ulong)align);
|
||||
|
||||
if (alignedOffset + size <= (ulong)BackingMemory.Length)
|
||||
{
|
||||
@@ -55,7 +55,7 @@ namespace Ryujinx.Audio.Renderer.Common
|
||||
|
||||
public static ulong GetTargetSize<T>(ulong currentSize, ulong count, int align) where T : unmanaged
|
||||
{
|
||||
return BitUtils.AlignUp(currentSize, align) + (ulong)Unsafe.SizeOf<T>() * count;
|
||||
return BitUtils.AlignUp<ulong>(currentSize, (ulong)align) + (ulong)Unsafe.SizeOf<T>() * count;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp
|
||||
@@ -23,6 +24,44 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
return GetCountToDecode(startSampleOffset, endSampleOffset, offset, count) * Unsafe.SizeOf<T>();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float ConvertSampleToPcmFloat(short sample)
|
||||
{
|
||||
return (float)sample / short.MaxValue;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static short ConvertSampleToPcmInt16(float sample)
|
||||
{
|
||||
return Saturate(sample * short.MaxValue);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static TOutput ConvertSample<TInput, TOutput>(TInput value) where TInput: INumber<TInput>, IMinMaxValue<TInput> where TOutput : INumber<TOutput>, IMinMaxValue<TOutput>
|
||||
{
|
||||
TInput conversionRate = TInput.CreateSaturating(TOutput.MaxValue / TOutput.CreateSaturating(TInput.MaxValue));
|
||||
|
||||
return TOutput.CreateSaturating(value * conversionRate);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Convert<TInput, TOutput>(Span<TOutput> output, ReadOnlySpan<TInput> input) where TInput : INumber<TInput>, IMinMaxValue<TInput> where TOutput : INumber<TOutput>, IMinMaxValue<TOutput>
|
||||
{
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
{
|
||||
output[i] = ConvertSample<TInput, TOutput>(input[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void ConvertSampleToPcmFloat(Span<float> output, ReadOnlySpan<short> input)
|
||||
{
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
{
|
||||
output[i] = ConvertSampleToPcmFloat(input[i]);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int Decode(Span<short> output, ReadOnlySpan<short> input, int startSampleOffset, int endSampleOffset, int channelIndex, int channelCount)
|
||||
{
|
||||
@@ -53,7 +92,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
|
||||
for (int i = 0; i < decodedCount; i++)
|
||||
{
|
||||
output[i] = (short)(input[i * channelCount + channelIndex] * short.MaxValue);
|
||||
output[i] = ConvertSampleToPcmInt16(input[i * channelCount + channelIndex]);
|
||||
}
|
||||
|
||||
return decodedCount;
|
||||
|
@@ -167,7 +167,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
return ResultCode.WorkBufferTooSmall;
|
||||
}
|
||||
|
||||
_depopBuffer = workBufferAllocator.Allocate<float>((ulong)BitUtils.AlignUp(parameter.MixBufferCount, Constants.BufferAlignment), Constants.BufferAlignment);
|
||||
_depopBuffer = workBufferAllocator.Allocate<float>(BitUtils.AlignUp<ulong>(parameter.MixBufferCount, Constants.BufferAlignment), Constants.BufferAlignment);
|
||||
|
||||
if (_depopBuffer.IsEmpty)
|
||||
{
|
||||
@@ -772,7 +772,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
size = WorkBufferAllocator.GetTargetSize<float>(size, Constants.TargetSampleCount * (Constants.VoiceChannelCountMax + parameter.MixBufferCount) * (parameter.SinkCount + parameter.SubMixBufferCount), 0x10);
|
||||
|
||||
// Depop buffer
|
||||
size = WorkBufferAllocator.GetTargetSize<float>(size, (ulong)BitUtils.AlignUp(parameter.MixBufferCount, Constants.BufferAlignment), Constants.BufferAlignment);
|
||||
size = WorkBufferAllocator.GetTargetSize<float>(size, BitUtils.AlignUp<ulong>(parameter.MixBufferCount, Constants.BufferAlignment), Constants.BufferAlignment);
|
||||
|
||||
// Voice
|
||||
size = WorkBufferAllocator.GetTargetSize<VoiceState>(size, parameter.VoiceCount, VoiceState.Alignment);
|
||||
@@ -804,10 +804,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
ulong performanceMetricsPerFramesSize = PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter, ref behaviourContext) * (parameter.PerformanceMetricFramesCount + 1) + 0xC;
|
||||
|
||||
size += BitUtils.AlignUp(performanceMetricsPerFramesSize, Constants.PerformanceMetricsPerFramesSizeAlignment);
|
||||
size += BitUtils.AlignUp<ulong>(performanceMetricsPerFramesSize, Constants.PerformanceMetricsPerFramesSizeAlignment);
|
||||
}
|
||||
|
||||
return BitUtils.AlignUp(size, Constants.WorkBufferAlignment);
|
||||
return BitUtils.AlignUp<ulong>(size, Constants.WorkBufferAlignment);
|
||||
}
|
||||
|
||||
public ResultCode QuerySystemEvent(out IWritableEvent systemEvent)
|
||||
|
@@ -17,7 +17,7 @@ using Ryujinx.Ava.Ui.Windows;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.System;
|
||||
using Ryujinx.Common.SystemInterop;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.GAL.Multithreading;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
|
@@ -280,7 +280,7 @@
|
||||
"ControllerSettingsRemoveProfileToolTip": "Remove Profile",
|
||||
"ControllerSettingsSaveProfileToolTip": "Save Profile",
|
||||
"MenuBarFileToolsTakeScreenshot": "Take Screenshot",
|
||||
"MenuBarFileToolsHideUi": "Hide Ui",
|
||||
"MenuBarFileToolsHideUi": "Hide UI",
|
||||
"GameListContextMenuToggleFavorite": "Toggle Favorite",
|
||||
"GameListContextMenuToggleFavoriteToolTip": "Toggle Favorite status of Game",
|
||||
"SettingsTabGeneralTheme": "Theme",
|
||||
|
@@ -8,7 +8,7 @@ namespace Ryujinx.Ava.Ui.Helper
|
||||
public delegate void UpdateBoundsCallbackDelegate(Rect rect);
|
||||
|
||||
[SupportedOSPlatform("macos")]
|
||||
static class MetalHelper
|
||||
static partial class MetalHelper
|
||||
{
|
||||
private const string LibObjCImport = "/usr/lib/libobjc.A.dylib";
|
||||
|
||||
@@ -100,28 +100,28 @@ namespace Ryujinx.Ava.Ui.Helper
|
||||
// TODO
|
||||
}
|
||||
|
||||
[DllImport(LibObjCImport)]
|
||||
private static unsafe extern IntPtr sel_registerName(byte* data);
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static unsafe partial IntPtr sel_registerName(byte* data);
|
||||
|
||||
[DllImport(LibObjCImport)]
|
||||
private static unsafe extern IntPtr objc_getClass(byte* data);
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static unsafe partial IntPtr objc_getClass(byte* data);
|
||||
|
||||
[DllImport(LibObjCImport)]
|
||||
private static extern void objc_msgSend(IntPtr receiver, Selector selector);
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector);
|
||||
|
||||
[DllImport(LibObjCImport)]
|
||||
private static extern void objc_msgSend(IntPtr receiver, Selector selector, byte value);
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector, byte value);
|
||||
|
||||
[DllImport(LibObjCImport)]
|
||||
private static extern void objc_msgSend(IntPtr receiver, Selector selector, IntPtr value);
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector, IntPtr value);
|
||||
|
||||
[DllImport(LibObjCImport)]
|
||||
private static extern void objc_msgSend(IntPtr receiver, Selector selector, NSRect point);
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector, NSRect point);
|
||||
|
||||
[DllImport(LibObjCImport)]
|
||||
private static extern void objc_msgSend(IntPtr receiver, Selector selector, double value);
|
||||
[LibraryImport(LibObjCImport)]
|
||||
private static partial void objc_msgSend(IntPtr receiver, Selector selector, double value);
|
||||
|
||||
[DllImport(LibObjCImport, EntryPoint = "objc_msgSend")]
|
||||
private static extern IntPtr IntPtr_objc_msgSend(IntPtr receiver, Selector selector);
|
||||
[LibraryImport(LibObjCImport, EntryPoint = "objc_msgSend")]
|
||||
private static partial IntPtr IntPtr_objc_msgSend(IntPtr receiver, Selector selector);
|
||||
}
|
||||
}
|
@@ -7,8 +7,7 @@ namespace Ryujinx.Ava.Input
|
||||
{
|
||||
internal static class AvaloniaKeyboardMappingHelper
|
||||
{
|
||||
private static readonly AvaKey[] _keyMapping = new AvaKey[(int)Key.Count]
|
||||
{
|
||||
private static readonly AvaKey[] _keyMapping = {
|
||||
// NOTE: Invalid
|
||||
AvaKey.None,
|
||||
|
||||
@@ -151,16 +150,16 @@ namespace Ryujinx.Ava.Input
|
||||
|
||||
static AvaloniaKeyboardMappingHelper()
|
||||
{
|
||||
var inputKeys = Enum.GetValues(typeof(Key));
|
||||
var inputKeys = Enum.GetValues<Key>();
|
||||
|
||||
// NOTE: Avalonia.Input.Key is not contiguous and quite large, so use a dictionary instead of an array.
|
||||
_avaKeyMapping = new Dictionary<AvaKey, Key>();
|
||||
|
||||
foreach (var key in inputKeys)
|
||||
{
|
||||
if (TryGetAvaKey((Key)key, out var index))
|
||||
if (TryGetAvaKey(key, out var index))
|
||||
{
|
||||
_avaKeyMapping[index] = (Key)key;
|
||||
_avaKeyMapping[index] = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@ using Ryujinx.Ava.Ui.Controls;
|
||||
using Ryujinx.Ava.Ui.Windows;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Ui.Common.Helper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@@ -278,14 +279,15 @@ namespace Ryujinx.Modules
|
||||
{
|
||||
string ryuName = Path.GetFileName(Environment.ProcessPath);
|
||||
string ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ryuName);
|
||||
var ryuArg = Environment.GetCommandLineArgs().Skip(1);
|
||||
|
||||
if (!OperatingSystem.IsWindows())
|
||||
if (!Path.Exists(ryuExe))
|
||||
{
|
||||
chmod(ryuExe, Convert.ToUInt32("0777", 8));
|
||||
ryuExe = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, OperatingSystem.IsWindows() ? "Ryujinx.exe" : "Ryujinx");
|
||||
}
|
||||
|
||||
Process.Start(ryuExe, ryuArg);
|
||||
SetFileExecutable(ryuExe);
|
||||
|
||||
Process.Start(ryuExe, CommandLineState.Arguments);
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
@@ -456,16 +458,19 @@ namespace Ryujinx.Modules
|
||||
worker.Start();
|
||||
}
|
||||
|
||||
[DllImport("libc", SetLastError = true)]
|
||||
private static extern int chmod(string path, uint mode);
|
||||
|
||||
private static void SetUnixPermissions()
|
||||
private static void SetFileExecutable(string path)
|
||||
{
|
||||
string ryuBin = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx");
|
||||
const UnixFileMode ExecutableFileMode = UnixFileMode.UserExecute |
|
||||
UnixFileMode.UserWrite |
|
||||
UnixFileMode.UserRead |
|
||||
UnixFileMode.GroupRead |
|
||||
UnixFileMode.GroupWrite |
|
||||
UnixFileMode.OtherRead |
|
||||
UnixFileMode.OtherWrite;
|
||||
|
||||
if (!OperatingSystem.IsWindows())
|
||||
if (!OperatingSystem.IsWindows() && File.Exists(path))
|
||||
{
|
||||
chmod(ryuBin, 493);
|
||||
File.SetUnixFileMode(path, ExecutableFileMode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,7 +591,7 @@ namespace Ryujinx.Modules
|
||||
|
||||
Directory.Delete(UpdateDir, true);
|
||||
|
||||
SetUnixPermissions();
|
||||
SetFileExecutable(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx"));
|
||||
|
||||
UpdateSuccessful = true;
|
||||
|
||||
|
@@ -6,7 +6,7 @@ using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.GraphicsDriver;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.System;
|
||||
using Ryujinx.Common.SystemInterop;
|
||||
using Ryujinx.Common.SystemInfo;
|
||||
using Ryujinx.Modules;
|
||||
using Ryujinx.SDL2.Common;
|
||||
@@ -20,7 +20,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava
|
||||
{
|
||||
internal class Program
|
||||
internal partial class Program
|
||||
{
|
||||
public static double WindowScaleFactor { get; set; }
|
||||
public static double DesktopScaleFactor { get; set; } = 1.0;
|
||||
@@ -28,8 +28,8 @@ namespace Ryujinx.Ava
|
||||
public static string ConfigurationPath { get; private set; }
|
||||
public static bool PreviewerDetached { get; private set; }
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern int MessageBoxA(IntPtr hWnd, string text, string caption, uint type);
|
||||
[LibraryImport("user32.dll", SetLastError = true)]
|
||||
public static partial int MessageBoxA(IntPtr hWnd, [MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string caption, uint type);
|
||||
|
||||
private const uint MB_ICONWARNING = 0x30;
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||
@@ -18,31 +18,31 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia.Svg" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
||||
<PackageReference Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
|
||||
<PackageReference Include="DynamicData" Version="7.12.11" />
|
||||
<PackageReference Include="FluentAvaloniaUI" Version="1.4.5" />
|
||||
<PackageReference Include="XamlNameReferenceGenerator" Version="1.5.1" />
|
||||
<PackageReference Include="Avalonia" />
|
||||
<PackageReference Include="Avalonia.Desktop" />
|
||||
<PackageReference Include="Avalonia.Diagnostics" />
|
||||
<PackageReference Include="Avalonia.Controls.DataGrid" />
|
||||
<PackageReference Include="Avalonia.Markup.Xaml.Loader" />
|
||||
<PackageReference Include="Avalonia.Svg" />
|
||||
<PackageReference Include="Avalonia.Svg.Skia" />
|
||||
<PackageReference Include="jp2masa.Avalonia.Flexbox" />
|
||||
<PackageReference Include="DynamicData" />
|
||||
<PackageReference Include="FluentAvaloniaUI" />
|
||||
<PackageReference Include="XamlNameReferenceGenerator" />
|
||||
|
||||
<PackageReference Include="OpenTK.Core" Version="4.7.5" />
|
||||
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
|
||||
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build12" />
|
||||
<PackageReference Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'win10-x64'" />
|
||||
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
|
||||
<PackageReference Include="SPB" Version="0.0.4-build28" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.4.1" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||
<PackageReference Include="OpenTK.Core" />
|
||||
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
|
||||
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" />
|
||||
<PackageReference Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'win10-x64'" />
|
||||
<PackageReference Include="Silk.NET.Vulkan" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
|
||||
<PackageReference Include="SPB" />
|
||||
<PackageReference Include="SharpZipLib" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" />
|
||||
|
||||
<!--NOTE: DO NOT REMOVE, THIS IS REQUIRED AS A RESULT OF A TRIMMING ISSUE IN AVALONIA -->
|
||||
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
||||
<PackageReference Include="System.Drawing.Common" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -45,7 +45,7 @@
|
||||
TextWrapping="Wrap" />
|
||||
<TextBox
|
||||
Name="Input"
|
||||
Grid.Row="2"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
|
@@ -111,7 +111,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||
|
||||
overlay.Position = window.PointToScreen(new Point());
|
||||
|
||||
await contentDialog.ShowAsync();
|
||||
await contentDialog.ShowAsync(overlay);
|
||||
contentDialog.Closed -= handler;
|
||||
overlay.Close();
|
||||
};
|
||||
|
@@ -125,9 +125,9 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
cbSize = Marshal.SizeOf<WNDCLASSEX>(),
|
||||
hInstance = GetModuleHandle(null),
|
||||
lpfnWndProc = _wndProcDelegate,
|
||||
lpfnWndProc = Marshal.GetFunctionPointerForDelegate(_wndProcDelegate),
|
||||
style = ClassStyles.CS_OWNDC,
|
||||
lpszClassName = _className,
|
||||
lpszClassName = Marshal.StringToHGlobalUni(_className),
|
||||
hCursor = LoadCursor(IntPtr.Zero, (IntPtr)Cursors.IDC_ARROW)
|
||||
};
|
||||
|
||||
@@ -148,7 +148,9 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||
IntPtr.Zero);
|
||||
|
||||
WindowHandle = handle;
|
||||
|
||||
|
||||
Marshal.FreeHGlobal(wndClassEx.lpszClassName);
|
||||
|
||||
return new PlatformHandle(WindowHandle, "HWND");
|
||||
}
|
||||
|
||||
|
@@ -5,7 +5,7 @@ using System.Runtime.Versioning;
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
internal class Win32NativeInterop
|
||||
internal partial class Win32NativeInterop
|
||||
{
|
||||
[Flags]
|
||||
public enum ClassStyles : uint
|
||||
@@ -48,58 +48,52 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
internal delegate IntPtr WindowProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct WNDCLASSEX
|
||||
{
|
||||
public int cbSize;
|
||||
public ClassStyles style;
|
||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
public WindowProc lpfnWndProc; // not WndProc
|
||||
public IntPtr lpfnWndProc; // not WndProc
|
||||
public int cbClsExtra;
|
||||
public int cbWndExtra;
|
||||
public IntPtr hInstance;
|
||||
public IntPtr hIcon;
|
||||
public IntPtr hCursor;
|
||||
public IntPtr hbrBackground;
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string lpszMenuName;
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string lpszClassName;
|
||||
public IntPtr lpszMenuName;
|
||||
public IntPtr lpszClassName;
|
||||
public IntPtr hIconSm;
|
||||
|
||||
public static WNDCLASSEX Create()
|
||||
public WNDCLASSEX()
|
||||
{
|
||||
return new WNDCLASSEX
|
||||
{
|
||||
cbSize = Marshal.SizeOf<WNDCLASSEX>()
|
||||
};
|
||||
cbSize = Marshal.SizeOf<WNDCLASSEX>();
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern ushort RegisterClassEx(ref WNDCLASSEX param);
|
||||
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")]
|
||||
public static partial ushort RegisterClassEx(ref WNDCLASSEX param);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern short UnregisterClass([MarshalAs(UnmanagedType.LPWStr)] string lpClassName, IntPtr instance);
|
||||
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "UnregisterClassW")]
|
||||
public static partial short UnregisterClass([MarshalAs(UnmanagedType.LPWStr)] string lpClassName, IntPtr instance);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr DefWindowProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam);
|
||||
[LibraryImport("user32.dll", EntryPoint = "DefWindowProcW")]
|
||||
public static partial IntPtr DefWindowProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||
[LibraryImport("kernel32.dll", EntryPoint = "GetModuleHandleA")]
|
||||
public static partial IntPtr GetModuleHandle([MarshalAs(UnmanagedType.LPStr)] string lpModuleName);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
[LibraryImport("user32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool DestroyWindow(IntPtr hwnd);
|
||||
public static partial bool DestroyWindow(IntPtr hwnd);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern IntPtr LoadCursor(IntPtr hInstance, IntPtr lpCursorName);
|
||||
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "LoadCursorA")]
|
||||
public static partial IntPtr LoadCursor(IntPtr hInstance, IntPtr lpCursorName);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr CreateWindowEx(
|
||||
[LibraryImport("user32.dll", SetLastError = true, EntryPoint = "CreateWindowExW")]
|
||||
public static partial IntPtr CreateWindowEx(
|
||||
uint dwExStyle,
|
||||
string lpClassName,
|
||||
string lpWindowName,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string lpClassName,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string lpWindowName,
|
||||
WindowStyles dwStyle,
|
||||
int x,
|
||||
int y,
|
||||
|
@@ -24,10 +24,7 @@ namespace Ryujinx.Common.Collections
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
public int Get(K key, ref V[] overlaps)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
IntervalTreeNode<K, V> node = GetNode(key);
|
||||
|
||||
@@ -61,15 +58,8 @@ namespace Ryujinx.Common.Collections
|
||||
/// <exception cref="ArgumentNullException"><paramref name="start"/> or <paramref name="end"/> is null</exception>
|
||||
public int Get(K start, K end, ref V[] overlaps, int overlapCount = 0)
|
||||
{
|
||||
if (start == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(start));
|
||||
}
|
||||
|
||||
if (end == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(end));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(start);
|
||||
ArgumentNullException.ThrowIfNull(end);
|
||||
|
||||
GetValues(Root, start, end, ref overlaps, ref overlapCount);
|
||||
|
||||
@@ -85,20 +75,9 @@ namespace Ryujinx.Common.Collections
|
||||
/// <exception cref="ArgumentNullException"><paramref name="start"/>, <paramref name="end"/> or <paramref name="value"/> are null</exception>
|
||||
public void Add(K start, K end, V value)
|
||||
{
|
||||
if (start == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(start));
|
||||
}
|
||||
|
||||
if (end == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(end));
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(start);
|
||||
ArgumentNullException.ThrowIfNull(end);
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
|
||||
Insert(start, end, value);
|
||||
}
|
||||
@@ -112,10 +91,7 @@ namespace Ryujinx.Common.Collections
|
||||
/// <returns>Number of deleted values</returns>
|
||||
public int Remove(K key, V value)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
int removed = Delete(key, value);
|
||||
|
||||
@@ -168,10 +144,7 @@ namespace Ryujinx.Common.Collections
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
private IntervalTreeNode<K, V> GetNode(K key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
IntervalTreeNode<K, V> node = Root;
|
||||
while (node != null)
|
||||
@@ -462,10 +435,8 @@ namespace Ryujinx.Common.Collections
|
||||
|
||||
public bool ContainsKey(K key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
return GetNode(key) != null;
|
||||
}
|
||||
}
|
||||
|
@@ -17,10 +17,7 @@ namespace Ryujinx.Common.Collections
|
||||
/// <exception cref="ArgumentNullException"><paramref name="node"/> is null</exception>
|
||||
public void Add(T node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(node));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(node);
|
||||
|
||||
Insert(node);
|
||||
}
|
||||
@@ -32,10 +29,8 @@ namespace Ryujinx.Common.Collections
|
||||
/// <exception cref="ArgumentNullException"><paramref name="node"/> is null</exception>
|
||||
public void Remove(T node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(node));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(node);
|
||||
|
||||
if (Delete(node) != null)
|
||||
{
|
||||
Count--;
|
||||
@@ -50,10 +45,7 @@ namespace Ryujinx.Common.Collections
|
||||
/// <exception cref="ArgumentNullException"><paramref name="searchNode"/> is null</exception>
|
||||
public T GetNode(T searchNode)
|
||||
{
|
||||
if (searchNode == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(searchNode));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(searchNode);
|
||||
|
||||
T node = Root;
|
||||
while (node != null)
|
||||
|
@@ -92,10 +92,8 @@ namespace Ryujinx.Common.Collections
|
||||
/// <exception cref="ArgumentNullException"><paramref name="node"/> is null</exception>
|
||||
protected static T Minimum(T node)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(node));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(node);
|
||||
|
||||
T tmp = node;
|
||||
while (tmp.Left != null)
|
||||
{
|
||||
|
@@ -22,10 +22,7 @@ namespace Ryujinx.Common.Collections
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
public V Get(K key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
Node<K, V> node = GetNode(key);
|
||||
|
||||
@@ -47,14 +44,8 @@ namespace Ryujinx.Common.Collections
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> or <paramref name="value"/> are null</exception>
|
||||
public void Add(K key, V value)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
|
||||
Insert(key, value);
|
||||
}
|
||||
@@ -66,10 +57,8 @@ namespace Ryujinx.Common.Collections
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
public void Remove(K key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
if (Delete(key) != null)
|
||||
{
|
||||
Count--;
|
||||
@@ -217,10 +206,7 @@ namespace Ryujinx.Common.Collections
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
private Node<K, V> GetNode(K key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
Node<K, V> node = Root;
|
||||
while (node != null)
|
||||
@@ -370,10 +356,8 @@ namespace Ryujinx.Common.Collections
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
private Node<K, V> FloorNode(K key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
Node<K, V> tmp = Root;
|
||||
|
||||
while (tmp != null)
|
||||
@@ -424,10 +408,8 @@ namespace Ryujinx.Common.Collections
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
private Node<K, V> CeilingNode(K key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
Node<K, V> tmp = Root;
|
||||
|
||||
while (tmp != null)
|
||||
@@ -477,10 +459,8 @@ namespace Ryujinx.Common.Collections
|
||||
// Method descriptions are not provided as they are already included as part of the interface.
|
||||
public bool ContainsKey(K key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
return GetNode(key) != null;
|
||||
}
|
||||
|
||||
@@ -493,10 +473,8 @@ namespace Ryujinx.Common.Collections
|
||||
|
||||
public bool TryGetValue(K key, [MaybeNullWhen(false)] out V value)
|
||||
{
|
||||
if (null == key)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
Node<K, V> node = GetNode(key);
|
||||
value = node != null ? node.Value : default;
|
||||
return node != null;
|
||||
@@ -504,10 +482,7 @@ namespace Ryujinx.Common.Collections
|
||||
|
||||
public void Add(KeyValuePair<K, V> item)
|
||||
{
|
||||
if (item.Key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(item.Key));
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(item.Key);
|
||||
|
||||
Add(item.Key, item.Value);
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Common.GraphicsDriver
|
||||
{
|
||||
static class NVThreadedOptimization
|
||||
static partial class NVThreadedOptimization
|
||||
{
|
||||
private const string ProfileName = "Ryujinx Nvidia Profile";
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace Ryujinx.Common.GraphicsDriver
|
||||
private const uint NvAPI_DRS_SaveSettings_ID = 0xFCBC7E14;
|
||||
private const uint NvAPI_DRS_DestroySession_ID = 0x0DAD9CFF8;
|
||||
|
||||
[DllImport("nvapi64")]
|
||||
private static extern IntPtr nvapi_QueryInterface(uint id);
|
||||
[LibraryImport("nvapi64")]
|
||||
private static partial IntPtr nvapi_QueryInterface(uint id);
|
||||
|
||||
private delegate int NvAPI_InitializeDelegate();
|
||||
private static NvAPI_InitializeDelegate NvAPI_Initialize;
|
||||
@@ -152,7 +152,7 @@ namespace Ryujinx.Common.GraphicsDriver
|
||||
|
||||
if (ptr != IntPtr.Zero)
|
||||
{
|
||||
return Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)) as T;
|
||||
return Marshal.GetDelegateForFunctionPointer<T>(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
|
||||
@@ -12,7 +13,7 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||
/// State for partial unmaps. Intended to be used on Windows.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct PartialUnmapState
|
||||
public partial struct PartialUnmapState
|
||||
{
|
||||
public NativeReaderWriterLock PartialUnmapLock;
|
||||
public int PartialUnmapsCount;
|
||||
@@ -25,20 +26,22 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||
public readonly static IntPtr GlobalState;
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern int GetCurrentThreadId();
|
||||
[LibraryImport("kernel32.dll")]
|
||||
public static partial int GetCurrentThreadId();
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern IntPtr OpenThread(int dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
private static partial IntPtr OpenThread(int dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwThreadId);
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool CloseHandle(IntPtr hObject);
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs (UnmanagedType.Bool)]
|
||||
public static partial bool CloseHandle(IntPtr hObject);
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern bool GetExitCodeThread(IntPtr hThread, out uint lpExitCode);
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static partial bool GetExitCodeThread(IntPtr hThread, out uint lpExitCode);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a global static PartialUnmapState and populates the field offsets.
|
||||
|
@@ -6,8 +6,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MsgPack.Cli" Version="1.0.1" />
|
||||
<PackageReference Include="System.Management" Version="7.0.0" />
|
||||
<PackageReference Include="MsgPack.Cli" />
|
||||
<PackageReference Include="System.Management" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@@ -8,7 +8,7 @@ using Ryujinx.Common.Logging;
|
||||
namespace Ryujinx.Common.SystemInfo
|
||||
{
|
||||
[SupportedOSPlatform("macos")]
|
||||
class MacOSSystemInfo : SystemInfo
|
||||
partial class MacOSSystemInfo : SystemInfo
|
||||
{
|
||||
internal MacOSSystemInfo()
|
||||
{
|
||||
@@ -60,8 +60,8 @@ namespace Ryujinx.Common.SystemInfo
|
||||
|
||||
private const string SystemLibraryName = "libSystem.dylib";
|
||||
|
||||
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
private static extern int sysctlbyname(string name, IntPtr oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
|
||||
[LibraryImport(SystemLibraryName, SetLastError = true)]
|
||||
private static partial int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string name, IntPtr oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
|
||||
|
||||
private static int sysctlbyname(string name, IntPtr oldValue, ref ulong oldSize)
|
||||
{
|
||||
@@ -116,11 +116,11 @@ namespace Ryujinx.Common.SystemInfo
|
||||
return res;
|
||||
}
|
||||
|
||||
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
private static extern uint mach_host_self();
|
||||
[LibraryImport(SystemLibraryName, SetLastError = true)]
|
||||
private static partial uint mach_host_self();
|
||||
|
||||
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
private static extern int host_page_size(uint host, ref uint out_page_size);
|
||||
[LibraryImport(SystemLibraryName, SetLastError = true)]
|
||||
private static partial int host_page_size(uint host, ref uint out_page_size);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
struct VMStatistics64
|
||||
@@ -151,7 +151,7 @@ namespace Ryujinx.Common.SystemInfo
|
||||
public ulong TotalUncompressedPagesInCompressor;
|
||||
}
|
||||
|
||||
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
private static extern int host_statistics64(uint host_priv, int host_flavor, ref VMStatistics64 host_info64_out, ref uint host_info64_outCnt);
|
||||
[LibraryImport(SystemLibraryName, SetLastError = true)]
|
||||
private static partial int host_statistics64(uint host_priv, int host_flavor, ref VMStatistics64 host_info64_out, ref uint host_info64_outCnt);
|
||||
}
|
||||
}
|
@@ -7,7 +7,7 @@ using Ryujinx.Common.Logging;
|
||||
namespace Ryujinx.Common.SystemInfo
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
class WindowsSystemInfo : SystemInfo
|
||||
partial class WindowsSystemInfo : SystemInfo
|
||||
{
|
||||
internal WindowsSystemInfo()
|
||||
{
|
||||
@@ -18,7 +18,7 @@ namespace Ryujinx.Common.SystemInfo
|
||||
private static (ulong Total, ulong Available) GetMemoryStats()
|
||||
{
|
||||
MemoryStatusEx memStatus = new MemoryStatusEx();
|
||||
if (GlobalMemoryStatusEx(memStatus))
|
||||
if (GlobalMemoryStatusEx(ref memStatus))
|
||||
{
|
||||
return (memStatus.TotalPhys, memStatus.AvailPhys); // Bytes
|
||||
}
|
||||
@@ -45,8 +45,8 @@ namespace Ryujinx.Common.SystemInfo
|
||||
return Environment.GetEnvironmentVariable("PROCESSOR_IDENTIFIER").Trim();
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
private class MemoryStatusEx
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct MemoryStatusEx
|
||||
{
|
||||
public uint Length;
|
||||
public uint MemoryLoad;
|
||||
@@ -60,13 +60,13 @@ namespace Ryujinx.Common.SystemInfo
|
||||
|
||||
public MemoryStatusEx()
|
||||
{
|
||||
Length = (uint)Marshal.SizeOf(typeof(MemoryStatusEx));
|
||||
Length = (uint)Marshal.SizeOf<MemoryStatusEx>();
|
||||
}
|
||||
}
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern bool GlobalMemoryStatusEx([In, Out] MemoryStatusEx lpBuffer);
|
||||
private static partial bool GlobalMemoryStatusEx(ref MemoryStatusEx lpBuffer);
|
||||
|
||||
private static ManagementObjectCollection GetWMIObjects(string scope, string query)
|
||||
{
|
||||
|
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Common.System
|
||||
namespace Ryujinx.Common.SystemInterop
|
||||
{
|
||||
public class DisplaySleep
|
||||
public partial class DisplaySleep
|
||||
{
|
||||
[Flags]
|
||||
enum EXECUTION_STATE : uint
|
||||
@@ -13,8 +13,8 @@ namespace Ryujinx.Common.System
|
||||
ES_SYSTEM_REQUIRED = 0x00000001
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
private static partial EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
|
||||
|
||||
static public void Prevent()
|
||||
{
|
@@ -3,29 +3,30 @@ using System;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Common.System
|
||||
namespace Ryujinx.Common.SystemInterop
|
||||
{
|
||||
public static class ForceDpiAware
|
||||
public static partial class ForceDpiAware
|
||||
{
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool SetProcessDPIAware();
|
||||
[LibraryImport("user32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static partial bool SetProcessDPIAware();
|
||||
|
||||
private const string X11LibraryName = "libX11.so.6";
|
||||
|
||||
[DllImport(X11LibraryName)]
|
||||
private static extern IntPtr XOpenDisplay(string display);
|
||||
[LibraryImport(X11LibraryName)]
|
||||
private static partial IntPtr XOpenDisplay([MarshalAs(UnmanagedType.LPStr)] string display);
|
||||
|
||||
[DllImport(X11LibraryName)]
|
||||
private static extern IntPtr XGetDefault(IntPtr display, string program, string option);
|
||||
[LibraryImport(X11LibraryName)]
|
||||
private static partial IntPtr XGetDefault(IntPtr display, [MarshalAs(UnmanagedType.LPStr)] string program, [MarshalAs(UnmanagedType.LPStr)] string option);
|
||||
|
||||
[DllImport(X11LibraryName)]
|
||||
private static extern int XDisplayWidth(IntPtr display, int screenNumber);
|
||||
[LibraryImport(X11LibraryName)]
|
||||
private static partial int XDisplayWidth(IntPtr display, int screenNumber);
|
||||
|
||||
[DllImport(X11LibraryName)]
|
||||
private static extern int XDisplayWidthMM(IntPtr display, int screenNumber);
|
||||
[LibraryImport(X11LibraryName)]
|
||||
private static partial int XDisplayWidthMM(IntPtr display, int screenNumber);
|
||||
|
||||
[DllImport(X11LibraryName)]
|
||||
private static extern int XCloseDisplay(IntPtr display);
|
||||
[LibraryImport(X11LibraryName)]
|
||||
private static partial int XCloseDisplay(IntPtr display);
|
||||
|
||||
private static readonly double _standardDpiScale = 96.0;
|
||||
private static readonly double _maxScaleFactor = 1.25;
|
@@ -2,10 +2,10 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Common.System
|
||||
namespace Ryujinx.Common.SystemInterop
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class GdiPlusHelper
|
||||
public static partial class GdiPlusHelper
|
||||
{
|
||||
private const string LibraryName = "gdiplus.dll";
|
||||
|
||||
@@ -52,17 +52,17 @@ namespace Ryujinx.Common.System
|
||||
public IntPtr NotificationUnhook;
|
||||
}
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
private static extern int GdiplusStartup(out IntPtr token, in StartupInputEx input, out StartupOutput output);
|
||||
[LibraryImport(LibraryName)]
|
||||
private static partial int GdiplusStartup(out IntPtr token, in StartupInputEx input, out StartupOutput output);
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
private static extern int GdipCreateFromHWND(IntPtr hwnd, out IntPtr graphics);
|
||||
[LibraryImport(LibraryName)]
|
||||
private static partial int GdipCreateFromHWND(IntPtr hwnd, out IntPtr graphics);
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
private static extern int GdipDeleteGraphics(IntPtr graphics);
|
||||
[LibraryImport(LibraryName)]
|
||||
private static partial int GdipDeleteGraphics(IntPtr graphics);
|
||||
|
||||
[DllImport(LibraryName)]
|
||||
private static extern int GdipGetDpiX(IntPtr graphics, out float dpi);
|
||||
[LibraryImport(LibraryName)]
|
||||
private static partial int GdipGetDpiX(IntPtr graphics, out float dpi);
|
||||
|
||||
public static float GetDpiX(IntPtr hwnd)
|
||||
{
|
@@ -4,13 +4,13 @@ using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Common.System
|
||||
namespace Ryujinx.Common.SystemInterop
|
||||
{
|
||||
/// <summary>
|
||||
/// Handle Windows Multimedia timer resolution.
|
||||
/// </summary>
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class WindowsMultimediaTimerResolution : IDisposable
|
||||
public partial class WindowsMultimediaTimerResolution : IDisposable
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct TimeCaps
|
||||
@@ -19,14 +19,14 @@ namespace Ryujinx.Common.System
|
||||
public uint wPeriodMax;
|
||||
};
|
||||
|
||||
[DllImport("winmm.dll", EntryPoint = "timeGetDevCaps", SetLastError = true)]
|
||||
private static extern uint TimeGetDevCaps(ref TimeCaps timeCaps, uint sizeTimeCaps);
|
||||
[LibraryImport("winmm.dll", EntryPoint = "timeGetDevCaps", SetLastError = true)]
|
||||
private static partial uint TimeGetDevCaps(ref TimeCaps timeCaps, uint sizeTimeCaps);
|
||||
|
||||
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
|
||||
private static extern uint TimeBeginPeriod(uint uMilliseconds);
|
||||
[LibraryImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
|
||||
private static partial uint TimeBeginPeriod(uint uMilliseconds);
|
||||
|
||||
[DllImport("winmm.dll", EntryPoint = "timeEndPeriod")]
|
||||
private static extern uint TimeEndPeriod(uint uMilliseconds);
|
||||
[LibraryImport("winmm.dll", EntryPoint = "timeEndPeriod")]
|
||||
private static partial uint TimeEndPeriod(uint uMilliseconds);
|
||||
|
||||
private uint _targetResolutionInMilliseconds;
|
||||
private bool _isActive;
|
@@ -1,82 +1,26 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
public static class BitUtils
|
||||
{
|
||||
public static uint AlignUp(uint value, int size)
|
||||
public static T AlignUp<T>(T value, T size)
|
||||
where T : IBinaryInteger<T>
|
||||
{
|
||||
return (uint)AlignUp((int)value, size);
|
||||
return (value + (size - T.One)) & -size;
|
||||
}
|
||||
|
||||
public static int AlignUp(int value, int size)
|
||||
{
|
||||
return (value + (size - 1)) & -size;
|
||||
}
|
||||
|
||||
public static ulong AlignUp(ulong value, int size)
|
||||
{
|
||||
return (ulong)AlignUp((long)value, size);
|
||||
}
|
||||
|
||||
public static long AlignUp(long value, int size)
|
||||
{
|
||||
return AlignUp(value, (long)size);
|
||||
}
|
||||
|
||||
public static ulong AlignUp(ulong value, ulong size)
|
||||
{
|
||||
return (ulong)AlignUp((long)value, (long)size);
|
||||
}
|
||||
|
||||
public static long AlignUp(long value, long size)
|
||||
{
|
||||
return (value + (size - 1)) & -size;
|
||||
}
|
||||
|
||||
public static uint AlignDown(uint value, int size)
|
||||
{
|
||||
return (uint)AlignDown((int)value, size);
|
||||
}
|
||||
|
||||
public static int AlignDown(int value, int size)
|
||||
public static T AlignDown<T>(T value, T size)
|
||||
where T : IBinaryInteger<T>
|
||||
{
|
||||
return value & -size;
|
||||
}
|
||||
|
||||
public static ulong AlignDown(ulong value, int size)
|
||||
public static T DivRoundUp<T>(T value, T dividend)
|
||||
where T : IBinaryInteger<T>
|
||||
{
|
||||
return (ulong)AlignDown((long)value, size);
|
||||
}
|
||||
|
||||
public static long AlignDown(long value, int size)
|
||||
{
|
||||
return AlignDown(value, (long)size);
|
||||
}
|
||||
|
||||
public static ulong AlignDown(ulong value, ulong size)
|
||||
{
|
||||
return (ulong)AlignDown((long)value, (long)size);
|
||||
}
|
||||
|
||||
public static long AlignDown(long value, long size)
|
||||
{
|
||||
return value & -size;
|
||||
}
|
||||
|
||||
public static int DivRoundUp(int value, int dividend)
|
||||
{
|
||||
return (value + dividend - 1) / dividend;
|
||||
}
|
||||
|
||||
public static ulong DivRoundUp(ulong value, uint dividend)
|
||||
{
|
||||
return (value + dividend - 1) / dividend;
|
||||
}
|
||||
|
||||
public static long DivRoundUp(long value, int dividend)
|
||||
{
|
||||
return (value + dividend - 1) / dividend;
|
||||
return (value + (dividend - T.One)) / dividend;
|
||||
}
|
||||
|
||||
public static int Pow2RoundUp(int value)
|
||||
|
@@ -1,12 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Device
|
||||
{
|
||||
public class DeviceState<TState> : IDeviceState where TState : unmanaged
|
||||
public class DeviceState<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState> : IDeviceState where TState : unmanaged
|
||||
{
|
||||
private const int RegisterSize = sizeof(int);
|
||||
|
||||
|
@@ -14,10 +14,13 @@ namespace Ryujinx.Graphics.GAL
|
||||
public readonly bool SupportsBc123Compression;
|
||||
public readonly bool SupportsBc45Compression;
|
||||
public readonly bool SupportsBc67Compression;
|
||||
public readonly bool SupportsEtc2Compression;
|
||||
public readonly bool Supports3DTextureCompression;
|
||||
public readonly bool SupportsBgraFormat;
|
||||
public readonly bool SupportsR4G4Format;
|
||||
public readonly bool SupportsR4G4B4A4Format;
|
||||
public readonly bool SupportsSnormBufferTextureFormat;
|
||||
public readonly bool Supports5BitComponentFormat;
|
||||
public readonly bool SupportsFragmentShaderInterlock;
|
||||
public readonly bool SupportsFragmentShaderOrderingIntel;
|
||||
public readonly bool SupportsGeometryShaderPassthrough;
|
||||
@@ -50,10 +53,13 @@ namespace Ryujinx.Graphics.GAL
|
||||
bool supportsBc123Compression,
|
||||
bool supportsBc45Compression,
|
||||
bool supportsBc67Compression,
|
||||
bool supportsEtc2Compression,
|
||||
bool supports3DTextureCompression,
|
||||
bool supportsBgraFormat,
|
||||
bool supportsR4G4Format,
|
||||
bool supportsR4G4B4A4Format,
|
||||
bool supportsSnormBufferTextureFormat,
|
||||
bool supports5BitComponentFormat,
|
||||
bool supportsFragmentShaderInterlock,
|
||||
bool supportsFragmentShaderOrderingIntel,
|
||||
bool supportsGeometryShaderPassthrough,
|
||||
@@ -83,10 +89,13 @@ namespace Ryujinx.Graphics.GAL
|
||||
SupportsBc123Compression = supportsBc123Compression;
|
||||
SupportsBc45Compression = supportsBc45Compression;
|
||||
SupportsBc67Compression = supportsBc67Compression;
|
||||
SupportsEtc2Compression = supportsEtc2Compression;
|
||||
Supports3DTextureCompression = supports3DTextureCompression;
|
||||
SupportsBgraFormat = supportsBgraFormat;
|
||||
SupportsR4G4Format = supportsR4G4Format;
|
||||
SupportsR4G4B4A4Format = supportsR4G4B4A4Format;
|
||||
SupportsSnormBufferTextureFormat = supportsSnormBufferTextureFormat;
|
||||
Supports5BitComponentFormat = supports5BitComponentFormat;
|
||||
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
|
||||
SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;
|
||||
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
||||
|
@@ -448,6 +448,27 @@ namespace Ryujinx.Graphics.GAL
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the texture format is 16 bit packed.
|
||||
/// </summary>
|
||||
/// <param name="format">Texture format</param>
|
||||
/// <returns>True if the texture format is 16 bit packed, false otherwise</returns>
|
||||
public static bool Is16BitPacked(this Format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case Format.B5G6R5Unorm:
|
||||
case Format.B5G5R5A1Unorm:
|
||||
case Format.R5G5B5X1Unorm:
|
||||
case Format.R5G5B5A1Unorm:
|
||||
case Format.R5G6B5Unorm:
|
||||
case Format.R4G4B4A4Unorm:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the texture format is an ASTC format.
|
||||
/// </summary>
|
||||
@@ -516,6 +537,27 @@ namespace Ryujinx.Graphics.GAL
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the texture format is an ETC2 format.
|
||||
/// </summary>
|
||||
/// <param name="format">Texture format</param>
|
||||
/// <returns>True if the texture format is an ETC2 format, false otherwise</returns>
|
||||
public static bool IsEtc2(this Format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case Format.Etc2RgbaSrgb:
|
||||
case Format.Etc2RgbaUnorm:
|
||||
case Format.Etc2RgbPtaSrgb:
|
||||
case Format.Etc2RgbPtaUnorm:
|
||||
case Format.Etc2RgbSrgb:
|
||||
case Format.Etc2RgbUnorm:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the texture format is a BGR format.
|
||||
/// </summary>
|
||||
|
@@ -2,6 +2,7 @@ using Ryujinx.Graphics.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
@@ -21,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||
/// Represents a device's state, with a additional shadow state.
|
||||
/// </summary>
|
||||
/// <typeparam name="TState">Type of the state</typeparam>
|
||||
class DeviceStateWithShadow<TState> : IDeviceState where TState : unmanaged, IShadowState
|
||||
class DeviceStateWithShadow<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState> : IDeviceState where TState : unmanaged, IShadowState
|
||||
{
|
||||
private readonly DeviceState<TState> _state;
|
||||
private readonly DeviceState<TState> _shadowState;
|
||||
|
@@ -100,7 +100,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
|
||||
_isLinear = (argument & 1) != 0;
|
||||
|
||||
_offset = 0;
|
||||
_size = (int)(BitUtils.AlignUp(state.LineLengthIn, 4) * state.LineCount);
|
||||
_size = (int)(BitUtils.AlignUp<uint>(state.LineLengthIn, 4) * state.LineCount);
|
||||
|
||||
int count = _size / 4;
|
||||
|
||||
|
@@ -98,7 +98,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawEnd(ThreedClass engine, int argument)
|
||||
{
|
||||
DrawEnd(engine, _state.State.IndexBufferState.First, (int)_state.State.IndexBufferCount);
|
||||
DrawEnd(
|
||||
engine,
|
||||
_state.State.IndexBufferState.First,
|
||||
(int)_state.State.IndexBufferCount,
|
||||
_state.State.VertexBufferDrawState.First,
|
||||
_state.State.VertexBufferDrawState.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -108,7 +113,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="firstIndex">Index of the first index buffer element used on the draw</param>
|
||||
/// <param name="indexCount">Number of index buffer elements used on the draw</param>
|
||||
private void DrawEnd(ThreedClass engine, int firstIndex, int indexCount)
|
||||
/// <param name="drawFirstVertex">Index of the first vertex used on the draw</param>
|
||||
/// <param name="drawVertexCount">Number of vertices used on the draw</param>
|
||||
private void DrawEnd(ThreedClass engine, int firstIndex, int indexCount, int drawFirstVertex, int drawVertexCount)
|
||||
{
|
||||
ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable(
|
||||
_context,
|
||||
@@ -135,6 +142,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_drawState.FirstIndex = firstIndex;
|
||||
_drawState.IndexCount = indexCount;
|
||||
_drawState.DrawFirstVertex = drawFirstVertex;
|
||||
_drawState.DrawVertexCount = drawVertexCount;
|
||||
_currentSpecState.SetHasConstantBufferDrawParameters(false);
|
||||
|
||||
engine.UpdateState();
|
||||
@@ -156,10 +165,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_instancedIndexCount = ibCount != 0 ? ibCount : indexCount;
|
||||
|
||||
var drawState = _state.State.VertexBufferDrawState;
|
||||
|
||||
_instancedDrawStateFirst = drawState.First;
|
||||
_instancedDrawStateCount = drawState.Count;
|
||||
_instancedDrawStateFirst = drawFirstVertex;
|
||||
_instancedDrawStateCount = drawVertexCount;
|
||||
|
||||
_drawState.DrawIndexed = false;
|
||||
|
||||
@@ -195,7 +202,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
var drawState = _state.State.VertexBufferDrawState;
|
||||
|
||||
_context.Renderer.Pipeline.Draw(drawState.Count, 1, drawState.First, firstInstance);
|
||||
_context.Renderer.Pipeline.Draw(drawVertexCount, 1, drawFirstVertex, firstInstance);
|
||||
}
|
||||
|
||||
_drawState.DrawIndexed = false;
|
||||
@@ -216,16 +223,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
bool incrementInstance = (argument & (1 << 26)) != 0;
|
||||
bool resetInstance = (argument & (1 << 27)) == 0;
|
||||
|
||||
if (_state.State.PrimitiveTypeOverrideEnable)
|
||||
{
|
||||
PrimitiveTypeOverride typeOverride = _state.State.PrimitiveTypeOverride;
|
||||
DrawBegin(incrementInstance, resetInstance, typeOverride.Convert());
|
||||
}
|
||||
else
|
||||
{
|
||||
PrimitiveType type = (PrimitiveType)(argument & 0xffff);
|
||||
DrawBegin(incrementInstance, resetInstance, type.Convert());
|
||||
}
|
||||
PrimitiveType type = (PrimitiveType)(argument & 0xffff);
|
||||
DrawBegin(incrementInstance, resetInstance, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -234,8 +233,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
/// <param name="incrementInstance">Indicates if the current instance should be incremented</param>
|
||||
/// <param name="resetInstance">Indicates if the current instance should be set to zero</param>
|
||||
/// <param name="topology">Primitive topology</param>
|
||||
private void DrawBegin(bool incrementInstance, bool resetInstance, PrimitiveTopology topology)
|
||||
/// <param name="primitiveType">Primitive type</param>
|
||||
private void DrawBegin(bool incrementInstance, bool resetInstance, PrimitiveType primitiveType)
|
||||
{
|
||||
if (incrementInstance)
|
||||
{
|
||||
@@ -248,6 +247,18 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_instanceIndex = 0;
|
||||
}
|
||||
|
||||
PrimitiveTopology topology;
|
||||
|
||||
if (_state.State.PrimitiveTypeOverrideEnable)
|
||||
{
|
||||
PrimitiveTypeOverride typeOverride = _state.State.PrimitiveTypeOverride;
|
||||
topology = typeOverride.Convert();
|
||||
}
|
||||
else
|
||||
{
|
||||
topology = primitiveType.Convert();
|
||||
}
|
||||
|
||||
UpdateTopology(topology);
|
||||
}
|
||||
|
||||
@@ -276,46 +287,70 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_drawState.DrawIndexed = true;
|
||||
}
|
||||
|
||||
// TODO: Verify if the index type is implied from the method that is called,
|
||||
// or if it uses the state index type on hardware.
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements.
|
||||
/// Performs a indexed draw with 8-bit index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawIndexedSmall(ThreedClass engine, int argument)
|
||||
public void DrawIndexBuffer8BeginEndInstanceFirst(ThreedClass engine, int argument)
|
||||
{
|
||||
DrawIndexedSmall(engine, argument, false);
|
||||
DrawIndexBufferBeginEndInstance(engine, argument, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements.
|
||||
/// Performs a indexed draw with 16-bit index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawIndexedSmall2(ThreedClass engine, int argument)
|
||||
public void DrawIndexBuffer16BeginEndInstanceFirst(ThreedClass engine, int argument)
|
||||
{
|
||||
DrawIndexedSmall(engine, argument);
|
||||
DrawIndexBufferBeginEndInstance(engine, argument, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements,
|
||||
/// Performs a indexed draw with 32-bit index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawIndexBuffer32BeginEndInstanceFirst(ThreedClass engine, int argument)
|
||||
{
|
||||
DrawIndexBufferBeginEndInstance(engine, argument, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with 8-bit index buffer elements,
|
||||
/// while also pre-incrementing the current instance value.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawIndexedSmallIncInstance(ThreedClass engine, int argument)
|
||||
public void DrawIndexBuffer8BeginEndInstanceSubsequent(ThreedClass engine, int argument)
|
||||
{
|
||||
DrawIndexedSmall(engine, argument, true);
|
||||
DrawIndexBufferBeginEndInstance(engine, argument, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements,
|
||||
/// Performs a indexed draw with 16-bit index buffer elements,
|
||||
/// while also pre-incrementing the current instance value.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawIndexedSmallIncInstance2(ThreedClass engine, int argument)
|
||||
public void DrawIndexBuffer16BeginEndInstanceSubsequent(ThreedClass engine, int argument)
|
||||
{
|
||||
DrawIndexedSmallIncInstance(engine, argument);
|
||||
DrawIndexBufferBeginEndInstance(engine, argument, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with 32-bit index buffer elements,
|
||||
/// while also pre-incrementing the current instance value.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawIndexBuffer32BeginEndInstanceSubsequent(ThreedClass engine, int argument)
|
||||
{
|
||||
DrawIndexBufferBeginEndInstance(engine, argument, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -325,11 +360,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
/// <param name="instanced">True to increment the current instance value, false otherwise</param>
|
||||
private void DrawIndexedSmall(ThreedClass engine, int argument, bool instanced)
|
||||
private void DrawIndexBufferBeginEndInstance(ThreedClass engine, int argument, bool instanced)
|
||||
{
|
||||
PrimitiveTypeOverride typeOverride = _state.State.PrimitiveTypeOverride;
|
||||
|
||||
DrawBegin(instanced, !instanced, typeOverride.Convert());
|
||||
DrawBegin(instanced, !instanced, (PrimitiveType)((argument >> 28) & 0xf));
|
||||
|
||||
int firstIndex = argument & 0xffff;
|
||||
int indexCount = (argument >> 16) & 0xfff;
|
||||
@@ -339,7 +372,52 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_drawState.DrawIndexed = true;
|
||||
engine.ForceStateDirty(IndexBufferCountMethodOffset * 4);
|
||||
|
||||
DrawEnd(engine, firstIndex, indexCount);
|
||||
DrawEnd(engine, firstIndex, indexCount, 0, 0);
|
||||
|
||||
_drawState.DrawIndexed = oldDrawIndexed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a non-indexed draw with the specified topology, index and count.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawVertexArrayBeginEndInstanceFirst(ThreedClass engine, int argument)
|
||||
{
|
||||
DrawVertexArrayBeginEndInstance(engine, argument, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a non-indexed draw with the specified topology, index and count,
|
||||
/// while incrementing the current instance.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawVertexArrayBeginEndInstanceSubsequent(ThreedClass engine, int argument)
|
||||
{
|
||||
DrawVertexArrayBeginEndInstance(engine, argument, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements,
|
||||
/// while optionally also pre-incrementing the current instance value.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
/// <param name="instanced">True to increment the current instance value, false otherwise</param>
|
||||
private void DrawVertexArrayBeginEndInstance(ThreedClass engine, int argument, bool instanced)
|
||||
{
|
||||
DrawBegin(instanced, !instanced, (PrimitiveType)((argument >> 28) & 0xf));
|
||||
|
||||
int firstVertex = argument & 0xffff;
|
||||
int vertexCount = (argument >> 16) & 0xfff;
|
||||
|
||||
bool oldDrawIndexed = _drawState.DrawIndexed;
|
||||
|
||||
_drawState.DrawIndexed = false;
|
||||
engine.ForceStateDirty(VertexBufferFirstMethodOffset * 4);
|
||||
|
||||
DrawEnd(engine, 0, 0, firstVertex, vertexCount);
|
||||
|
||||
_drawState.DrawIndexed = oldDrawIndexed;
|
||||
}
|
||||
@@ -449,8 +527,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
}
|
||||
else
|
||||
{
|
||||
_state.State.VertexBufferDrawState.First = firstVertex;
|
||||
_state.State.VertexBufferDrawState.Count = count;
|
||||
_drawState.DrawFirstVertex = firstVertex;
|
||||
_drawState.DrawVertexCount = count;
|
||||
engine.ForceStateDirty(VertexBufferFirstMethodOffset * 4);
|
||||
}
|
||||
|
||||
|
@@ -17,6 +17,16 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
public int IndexCount;
|
||||
|
||||
/// <summary>
|
||||
/// First vertex used on non-indexed draws. This value is stored somewhere else on indexed draws.
|
||||
/// </summary>
|
||||
public int DrawFirstVertex;
|
||||
|
||||
/// <summary>
|
||||
/// Vertex count used on non-indexed draws. Indexed draws have a index count instead.
|
||||
/// </summary>
|
||||
public int DrawVertexCount;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the next draw will be a indexed draw.
|
||||
/// </summary>
|
||||
|
@@ -2,6 +2,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -39,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// GPU state update tracker.
|
||||
/// </summary>
|
||||
/// <typeparam name="TState">State type</typeparam>
|
||||
class StateUpdateTracker<TState>
|
||||
class StateUpdateTracker<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TState>
|
||||
{
|
||||
private const int BlockSize = 0xe00;
|
||||
private const int RegisterSize = sizeof(uint);
|
||||
|
@@ -1,7 +1,5 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
using Ryujinx.Graphics.Gpu.Shader;
|
||||
@@ -991,6 +989,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
bool drawIndexed = _drawState.DrawIndexed;
|
||||
bool drawIndirect = _drawState.DrawIndirect;
|
||||
int drawFirstVertex = _drawState.DrawFirstVertex;
|
||||
int drawVertexCount = _drawState.DrawVertexCount;
|
||||
uint vbEnableMask = 0;
|
||||
|
||||
for (int index = 0; index < Constants.TotalVertexBuffers; index++)
|
||||
@@ -1052,9 +1052,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
int firstInstance = (int)_state.State.FirstInstance;
|
||||
|
||||
var drawState = _state.State.VertexBufferDrawState;
|
||||
|
||||
size = Math.Min(vbSize, (ulong)((firstInstance + drawState.First + drawState.Count) * stride));
|
||||
size = Math.Min(vbSize, (ulong)((firstInstance + drawFirstVertex + drawVertexCount) * stride));
|
||||
}
|
||||
|
||||
_pipeline.VertexBuffers[index] = new BufferPipelineDescriptor(_channel.MemoryManager.IsMapped(address), stride, divisor);
|
||||
@@ -1295,7 +1293,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
for (int stageIndex = 0; stageIndex < Constants.ShaderStages; stageIndex++)
|
||||
{
|
||||
_currentProgramInfo[stageIndex] = gs.Shaders[stageIndex + 1]?.Info;
|
||||
ShaderProgramInfo info = gs.Shaders[stageIndex + 1]?.Info;
|
||||
|
||||
if (info?.UsesRtLayer == true)
|
||||
{
|
||||
_vtgWritesRtLayer = true;
|
||||
}
|
||||
|
||||
_currentProgramInfo[stageIndex] = info;
|
||||
}
|
||||
|
||||
_context.Renderer.Pipeline.SetProgram(gs.HostProgram);
|
||||
|
@@ -42,6 +42,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{ nameof(ThreedClassState.TextureBarrier), new RwCallback(TextureBarrier, null) },
|
||||
{ nameof(ThreedClassState.TextureBarrierTiled), new RwCallback(TextureBarrierTiled, null) },
|
||||
{ nameof(ThreedClassState.DrawTextureSrcY), new RwCallback(DrawTexture, null) },
|
||||
{ nameof(ThreedClassState.DrawVertexArrayBeginEndInstanceFirst), new RwCallback(DrawVertexArrayBeginEndInstanceFirst, null) },
|
||||
{ nameof(ThreedClassState.DrawVertexArrayBeginEndInstanceSubsequent), new RwCallback(DrawVertexArrayBeginEndInstanceSubsequent, null) },
|
||||
{ nameof(ThreedClassState.VbElementU8), new RwCallback(VbElementU8, null) },
|
||||
{ nameof(ThreedClassState.VbElementU16), new RwCallback(VbElementU16, null) },
|
||||
{ nameof(ThreedClassState.VbElementU32), new RwCallback(VbElementU32, null) },
|
||||
@@ -49,10 +51,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{ nameof(ThreedClassState.RenderEnableCondition), new RwCallback(null, Zero) },
|
||||
{ nameof(ThreedClassState.DrawEnd), new RwCallback(DrawEnd, null) },
|
||||
{ nameof(ThreedClassState.DrawBegin), new RwCallback(DrawBegin, null) },
|
||||
{ nameof(ThreedClassState.DrawIndexedSmall), new RwCallback(DrawIndexedSmall, null) },
|
||||
{ nameof(ThreedClassState.DrawIndexedSmall2), new RwCallback(DrawIndexedSmall2, null) },
|
||||
{ nameof(ThreedClassState.DrawIndexedSmallIncInstance), new RwCallback(DrawIndexedSmallIncInstance, null) },
|
||||
{ nameof(ThreedClassState.DrawIndexedSmallIncInstance2), new RwCallback(DrawIndexedSmallIncInstance2, null) },
|
||||
{ nameof(ThreedClassState.DrawIndexBuffer32BeginEndInstanceFirst), new RwCallback(DrawIndexBuffer32BeginEndInstanceFirst, null) },
|
||||
{ nameof(ThreedClassState.DrawIndexBuffer16BeginEndInstanceFirst), new RwCallback(DrawIndexBuffer16BeginEndInstanceFirst, null) },
|
||||
{ nameof(ThreedClassState.DrawIndexBuffer8BeginEndInstanceFirst), new RwCallback(DrawIndexBuffer8BeginEndInstanceFirst, null) },
|
||||
{ nameof(ThreedClassState.DrawIndexBuffer32BeginEndInstanceSubsequent), new RwCallback(DrawIndexBuffer32BeginEndInstanceSubsequent, null) },
|
||||
{ nameof(ThreedClassState.DrawIndexBuffer16BeginEndInstanceSubsequent), new RwCallback(DrawIndexBuffer16BeginEndInstanceSubsequent, null) },
|
||||
{ nameof(ThreedClassState.DrawIndexBuffer8BeginEndInstanceSubsequent), new RwCallback(DrawIndexBuffer8BeginEndInstanceSubsequent, null) },
|
||||
{ nameof(ThreedClassState.IndexBufferCount), new RwCallback(SetIndexBufferCount, null) },
|
||||
{ nameof(ThreedClassState.Clear), new RwCallback(Clear, null) },
|
||||
{ nameof(ThreedClassState.SemaphoreControl), new RwCallback(Report, null) },
|
||||
@@ -303,6 +307,25 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_drawManager.DrawTexture(this, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a non-indexed draw with the specified topology, index and count.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawVertexArrayBeginEndInstanceFirst(int argument)
|
||||
{
|
||||
_drawManager.DrawVertexArrayBeginEndInstanceFirst(this, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a non-indexed draw with the specified topology, index and count,
|
||||
/// while incrementing the current instance.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawVertexArrayBeginEndInstanceSubsequent(int argument)
|
||||
{
|
||||
_drawManager.DrawVertexArrayBeginEndInstanceSubsequent(this, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes four 8-bit index buffer elements.
|
||||
/// </summary>
|
||||
@@ -370,41 +393,60 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements.
|
||||
/// Performs a indexed draw with 8-bit index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawIndexedSmall(int argument)
|
||||
private void DrawIndexBuffer8BeginEndInstanceFirst(int argument)
|
||||
{
|
||||
_drawManager.DrawIndexedSmall(this, argument);
|
||||
_drawManager.DrawIndexBuffer8BeginEndInstanceFirst(this, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements.
|
||||
/// Performs a indexed draw with 16-bit index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawIndexedSmall2(int argument)
|
||||
private void DrawIndexBuffer16BeginEndInstanceFirst(int argument)
|
||||
{
|
||||
_drawManager.DrawIndexedSmall2(this, argument);
|
||||
_drawManager.DrawIndexBuffer16BeginEndInstanceFirst(this, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements,
|
||||
/// Performs a indexed draw with 32-bit index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawIndexBuffer32BeginEndInstanceFirst(int argument)
|
||||
{
|
||||
_drawManager.DrawIndexBuffer32BeginEndInstanceFirst(this, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with 8-bit index buffer elements,
|
||||
/// while also pre-incrementing the current instance value.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawIndexedSmallIncInstance(int argument)
|
||||
private void DrawIndexBuffer8BeginEndInstanceSubsequent(int argument)
|
||||
{
|
||||
_drawManager.DrawIndexedSmallIncInstance(this, argument);
|
||||
_drawManager.DrawIndexBuffer8BeginEndInstanceSubsequent(this, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements,
|
||||
/// Performs a indexed draw with 16-bit index buffer elements,
|
||||
/// while also pre-incrementing the current instance value.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawIndexedSmallIncInstance2(int argument)
|
||||
private void DrawIndexBuffer16BeginEndInstanceSubsequent(int argument)
|
||||
{
|
||||
_drawManager.DrawIndexedSmallIncInstance2(this, argument);
|
||||
_drawManager.DrawIndexBuffer16BeginEndInstanceSubsequent(this, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with 32-bit index buffer elements,
|
||||
/// while also pre-incrementing the current instance value.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawIndexBuffer32BeginEndInstanceSubsequent(int argument)
|
||||
{
|
||||
_drawManager.DrawIndexBuffer32BeginEndInstanceSubsequent(this, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -813,7 +813,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
public uint ClearFlags;
|
||||
public fixed uint Reserved10FC[25];
|
||||
public Array32<VertexAttribState> VertexAttribState;
|
||||
public fixed uint Reserved11E0[15];
|
||||
public fixed uint Reserved11E0[13];
|
||||
public uint DrawVertexArrayBeginEndInstanceFirst;
|
||||
public uint DrawVertexArrayBeginEndInstanceSubsequent;
|
||||
public RtControl RtControl;
|
||||
public fixed uint Reserved1220[2];
|
||||
public Size3D RtDepthStencilSize;
|
||||
@@ -888,12 +890,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
public fixed uint Reserved164C[95];
|
||||
public IndexBufferState IndexBufferState;
|
||||
public uint IndexBufferCount;
|
||||
public uint DrawIndexedSmall;
|
||||
public uint DrawIndexedSmall2;
|
||||
public uint Reserved17EC;
|
||||
public uint DrawIndexedSmallIncInstance;
|
||||
public uint DrawIndexedSmallIncInstance2;
|
||||
public fixed uint Reserved17F8[33];
|
||||
public uint DrawIndexBuffer32BeginEndInstanceFirst;
|
||||
public uint DrawIndexBuffer16BeginEndInstanceFirst;
|
||||
public uint DrawIndexBuffer8BeginEndInstanceFirst;
|
||||
public uint DrawIndexBuffer32BeginEndInstanceSubsequent;
|
||||
public uint DrawIndexBuffer16BeginEndInstanceSubsequent;
|
||||
public uint DrawIndexBuffer8BeginEndInstanceSubsequent;
|
||||
public fixed uint Reserved17FC[32];
|
||||
public float DepthBiasClamp;
|
||||
public Array16<Boolean32> VertexBufferInstanced;
|
||||
public fixed uint Reserved18C0[20];
|
||||
|
@@ -208,8 +208,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
Bc6HSf16Float = Bc6HSf16 | RFloat | GFloat | BFloat | AFloat, // 0x7ff90
|
||||
Bc6HUf16Float = Bc6HUf16 | RFloat | GFloat | BFloat | AFloat, // 0x7ff91
|
||||
Etc2RgbUnorm = Etc2Rgb | RUnorm | GUnorm | BUnorm | AUnorm, // 0x24906
|
||||
Etc2RgbPtaUnorm = Etc2RgbPta | RUnorm | GUnorm | BUnorm | AUnorm, // 0x2490a
|
||||
Etc2RgbaUnorm = Etc2Rgba | RUnorm | GUnorm | BUnorm | AUnorm, // 0x2490b
|
||||
Etc2RgbUnormSrgb = Etc2Rgb | RUnorm | GUnorm | BUnorm | AUnorm | Srgb, // 0xa4906
|
||||
Etc2RgbPtaUnormSrgb = Etc2RgbPta | RUnorm | GUnorm | BUnorm | AUnorm | Srgb, // 0xa490a
|
||||
Etc2RgbaUnormSrgb = Etc2Rgba | RUnorm | GUnorm | BUnorm | AUnorm | Srgb, // 0xa490b
|
||||
Astc2D4x4Unorm = Astc2D4x4 | RUnorm | GUnorm | BUnorm | AUnorm, // 0x24940
|
||||
Astc2D5x4Unorm = Astc2D5x4 | RUnorm | GUnorm | BUnorm | AUnorm, // 0x24950
|
||||
@@ -429,8 +431,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
{ TextureFormat.Bc6HSf16Float, new FormatInfo(Format.Bc6HSfloat, 4, 4, 16, 4) },
|
||||
{ TextureFormat.Bc6HUf16Float, new FormatInfo(Format.Bc6HUfloat, 4, 4, 16, 4) },
|
||||
{ TextureFormat.Etc2RgbUnorm, new FormatInfo(Format.Etc2RgbUnorm, 4, 4, 8, 3) },
|
||||
{ TextureFormat.Etc2RgbPtaUnorm, new FormatInfo(Format.Etc2RgbPtaUnorm, 4, 4, 8, 4) },
|
||||
{ TextureFormat.Etc2RgbaUnorm, new FormatInfo(Format.Etc2RgbaUnorm, 4, 4, 16, 4) },
|
||||
{ TextureFormat.Etc2RgbUnormSrgb, new FormatInfo(Format.Etc2RgbSrgb, 4, 4, 8, 3) },
|
||||
{ TextureFormat.Etc2RgbPtaUnormSrgb, new FormatInfo(Format.Etc2RgbPtaSrgb, 4, 4, 8, 4) },
|
||||
{ TextureFormat.Etc2RgbaUnormSrgb, new FormatInfo(Format.Etc2RgbaSrgb, 4, 4, 16, 4) },
|
||||
{ TextureFormat.Astc2D4x4Unorm, new FormatInfo(Format.Astc4x4Unorm, 4, 4, 16, 4) },
|
||||
{ TextureFormat.Astc2D5x4Unorm, new FormatInfo(Format.Astc5x4Unorm, 5, 4, 16, 4) },
|
||||
|
@@ -857,9 +857,23 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
result = decoded;
|
||||
}
|
||||
else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm)
|
||||
else if (!_context.Capabilities.SupportsEtc2Compression && Format.IsEtc2())
|
||||
{
|
||||
result = PixelConverter.ConvertR4G4ToR4G4B4A4(result);
|
||||
switch (Format)
|
||||
{
|
||||
case Format.Etc2RgbaSrgb:
|
||||
case Format.Etc2RgbaUnorm:
|
||||
result = ETC2Decoder.DecodeRgba(result, width, height, depth, levels, layers);
|
||||
break;
|
||||
case Format.Etc2RgbPtaSrgb:
|
||||
case Format.Etc2RgbPtaUnorm:
|
||||
result = ETC2Decoder.DecodePta(result, width, height, depth, levels, layers);
|
||||
break;
|
||||
case Format.Etc2RgbSrgb:
|
||||
case Format.Etc2RgbUnorm:
|
||||
result = ETC2Decoder.DecodeRgb(result, width, height, depth, levels, layers);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!TextureCompatibility.HostSupportsBcFormat(Format, Target, _context.Capabilities))
|
||||
{
|
||||
@@ -895,6 +909,43 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm)
|
||||
{
|
||||
result = PixelConverter.ConvertR4G4ToR4G4B4A4(result, width);
|
||||
|
||||
if (!_context.Capabilities.SupportsR4G4B4A4Format)
|
||||
{
|
||||
result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result, width);
|
||||
}
|
||||
}
|
||||
else if (Format == Format.R4G4B4A4Unorm)
|
||||
{
|
||||
if (!_context.Capabilities.SupportsR4G4B4A4Format)
|
||||
{
|
||||
result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result, width);
|
||||
}
|
||||
}
|
||||
else if (!_context.Capabilities.Supports5BitComponentFormat && Format.Is16BitPacked())
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case Format.B5G6R5Unorm:
|
||||
case Format.R5G6B5Unorm:
|
||||
result = PixelConverter.ConvertR5G6B5ToR8G8B8A8(result, width);
|
||||
break;
|
||||
case Format.B5G5R5A1Unorm:
|
||||
case Format.R5G5B5X1Unorm:
|
||||
case Format.R5G5B5A1Unorm:
|
||||
result = PixelConverter.ConvertR5G5B5ToR8G8B8A8(result, width, Format == Format.R5G5B5X1Unorm);
|
||||
break;
|
||||
case Format.A1B5G5R5Unorm:
|
||||
result = PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result, width);
|
||||
break;
|
||||
case Format.R4G4B4A4Unorm:
|
||||
result = PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result, width);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@@ -320,10 +320,15 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
// Check if the texture pool has been modified since bindings were last committed.
|
||||
// If it wasn't, then it's possible to avoid looking up textures again when the handle remains the same.
|
||||
bool poolModified = _cachedTexturePool != texturePool || _cachedSamplerPool != samplerPool;
|
||||
if (_cachedTexturePool != texturePool || _cachedSamplerPool != samplerPool)
|
||||
{
|
||||
Rebind();
|
||||
|
||||
_cachedTexturePool = texturePool;
|
||||
_cachedSamplerPool = samplerPool;
|
||||
_cachedTexturePool = texturePool;
|
||||
_cachedSamplerPool = samplerPool;
|
||||
}
|
||||
|
||||
bool poolModified = false;
|
||||
|
||||
if (texturePool != null)
|
||||
{
|
||||
|
@@ -67,6 +67,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <returns>A host compatible format</returns>
|
||||
public static FormatInfo ToHostCompatibleFormat(TextureInfo info, Capabilities caps)
|
||||
{
|
||||
// The host API does not support those compressed formats.
|
||||
// We assume software decompression will be done for those textures,
|
||||
// and so we adjust the format here to match the decompressor output.
|
||||
|
||||
if (!caps.SupportsAstcCompression)
|
||||
{
|
||||
if (info.FormatInfo.Format.IsAstcUnorm())
|
||||
@@ -83,16 +87,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
}
|
||||
|
||||
if (!caps.SupportsR4G4Format && info.FormatInfo.Format == Format.R4G4Unorm)
|
||||
{
|
||||
return new FormatInfo(Format.R4G4B4A4Unorm, 1, 1, 2, 4);
|
||||
}
|
||||
|
||||
if (!HostSupportsBcFormat(info.FormatInfo.Format, info.Target, caps))
|
||||
{
|
||||
// The host API does not this compressed format.
|
||||
// We assume software decompression will be done for those textures,
|
||||
// and so we adjust the format here to match the decompressor output.
|
||||
switch (info.FormatInfo.Format)
|
||||
{
|
||||
case Format.Bc1RgbaSrgb:
|
||||
@@ -119,6 +115,45 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
}
|
||||
|
||||
if (!caps.SupportsEtc2Compression)
|
||||
{
|
||||
switch (info.FormatInfo.Format)
|
||||
{
|
||||
case Format.Etc2RgbaSrgb:
|
||||
case Format.Etc2RgbPtaSrgb:
|
||||
case Format.Etc2RgbSrgb:
|
||||
return new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4, 4);
|
||||
case Format.Etc2RgbaUnorm:
|
||||
case Format.Etc2RgbPtaUnorm:
|
||||
case Format.Etc2RgbUnorm:
|
||||
return new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4);
|
||||
}
|
||||
}
|
||||
|
||||
if (!caps.SupportsR4G4Format && info.FormatInfo.Format == Format.R4G4Unorm)
|
||||
{
|
||||
if (caps.SupportsR4G4B4A4Format)
|
||||
{
|
||||
return new FormatInfo(Format.R4G4B4A4Unorm, 1, 1, 2, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4);
|
||||
}
|
||||
}
|
||||
|
||||
if (info.FormatInfo.Format == Format.R4G4B4A4Unorm)
|
||||
{
|
||||
if (!caps.SupportsR4G4B4A4Format)
|
||||
{
|
||||
return new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4);
|
||||
}
|
||||
}
|
||||
else if (!caps.Supports5BitComponentFormat && info.FormatInfo.Format.Is16BitPacked())
|
||||
{
|
||||
return new FormatInfo(info.FormatInfo.Format.IsBgr() ? Format.B8G8R8A8Unorm : Format.R8G8B8A8Unorm, 1, 1, 4, 4);
|
||||
}
|
||||
|
||||
return info.FormatInfo;
|
||||
}
|
||||
|
||||
|
@@ -252,7 +252,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
RecordStorageAlignment(_cpStorageBuffers, index, gpuVa);
|
||||
|
||||
gpuVa = BitUtils.AlignDown(gpuVa, _context.Capabilities.StorageBufferOffsetAlignment);
|
||||
gpuVa = BitUtils.AlignDown<ulong>(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment);
|
||||
|
||||
ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
|
||||
|
||||
@@ -276,7 +276,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
RecordStorageAlignment(buffers, index, gpuVa);
|
||||
|
||||
gpuVa = BitUtils.AlignDown(gpuVa, _context.Capabilities.StorageBufferOffsetAlignment);
|
||||
gpuVa = BitUtils.AlignDown<ulong>(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment);
|
||||
|
||||
ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
|
||||
|
||||
|
@@ -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 = 4069;
|
||||
private const uint CodeGenVersion = 4106;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
|
@@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
{
|
||||
CachedShaderStage currentStage = stages[i];
|
||||
|
||||
if (currentStage != null && currentStage.Info.Stage == stage && currentStage.Info != null)
|
||||
if (currentStage?.Info != null && currentStage.Info.Stage == stage)
|
||||
{
|
||||
return ShaderCache.GetBindings(currentStage.Info);
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
||||
{
|
||||
static class FFmpegApi
|
||||
static partial class FFmpegApi
|
||||
{
|
||||
public const string AvCodecLibraryName = "avcodec";
|
||||
public const string AvUtilLibraryName = "avutil";
|
||||
@@ -78,52 +78,52 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
||||
|
||||
public unsafe delegate void av_log_set_callback_callback(void* a0, AVLog level, [MarshalAs(UnmanagedType.LPUTF8Str)] string a2, byte* a3);
|
||||
|
||||
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern AVFrame* av_frame_alloc();
|
||||
[LibraryImport(AvUtilLibraryName)]
|
||||
internal static unsafe partial AVFrame* av_frame_alloc();
|
||||
|
||||
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern void av_frame_unref(AVFrame* frame);
|
||||
[LibraryImport(AvUtilLibraryName)]
|
||||
internal static unsafe partial void av_frame_unref(AVFrame* frame);
|
||||
|
||||
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern void av_free(AVFrame* frame);
|
||||
[LibraryImport(AvUtilLibraryName)]
|
||||
internal static unsafe partial void av_free(AVFrame* frame);
|
||||
|
||||
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern void av_log_set_level(AVLog level);
|
||||
[LibraryImport(AvUtilLibraryName)]
|
||||
internal static unsafe partial void av_log_set_level(AVLog level);
|
||||
|
||||
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern void av_log_set_callback(av_log_set_callback_callback callback);
|
||||
[LibraryImport(AvUtilLibraryName)]
|
||||
internal static unsafe partial void av_log_set_callback(av_log_set_callback_callback callback);
|
||||
|
||||
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern AVLog av_log_get_level();
|
||||
[LibraryImport(AvUtilLibraryName)]
|
||||
internal static unsafe partial AVLog av_log_get_level();
|
||||
|
||||
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern void av_log_format_line(void* ptr, AVLog level, [MarshalAs(UnmanagedType.LPUTF8Str)] string fmt, byte* vl, byte* line, int lineSize, int* printPrefix);
|
||||
[LibraryImport(AvUtilLibraryName)]
|
||||
internal static unsafe partial void av_log_format_line(void* ptr, AVLog level, [MarshalAs(UnmanagedType.LPUTF8Str)] string fmt, byte* vl, byte* line, int lineSize, int* printPrefix);
|
||||
|
||||
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern AVCodec* avcodec_find_decoder(AVCodecID id);
|
||||
[LibraryImport(AvCodecLibraryName)]
|
||||
internal static unsafe partial AVCodec* avcodec_find_decoder(AVCodecID id);
|
||||
|
||||
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern AVCodecContext* avcodec_alloc_context3(AVCodec* codec);
|
||||
[LibraryImport(AvCodecLibraryName)]
|
||||
internal static unsafe partial AVCodecContext* avcodec_alloc_context3(AVCodec* codec);
|
||||
|
||||
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern int avcodec_open2(AVCodecContext* avctx, AVCodec* codec, void **options);
|
||||
[LibraryImport(AvCodecLibraryName)]
|
||||
internal static unsafe partial int avcodec_open2(AVCodecContext* avctx, AVCodec* codec, void **options);
|
||||
|
||||
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern int avcodec_close(AVCodecContext* avctx);
|
||||
[LibraryImport(AvCodecLibraryName)]
|
||||
internal static unsafe partial int avcodec_close(AVCodecContext* avctx);
|
||||
|
||||
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern void avcodec_free_context(AVCodecContext** avctx);
|
||||
[LibraryImport(AvCodecLibraryName)]
|
||||
internal static unsafe partial void avcodec_free_context(AVCodecContext** avctx);
|
||||
|
||||
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern AVPacket* av_packet_alloc();
|
||||
[LibraryImport(AvCodecLibraryName)]
|
||||
internal static unsafe partial AVPacket* av_packet_alloc();
|
||||
|
||||
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern void av_packet_unref(AVPacket* pkt);
|
||||
[LibraryImport(AvCodecLibraryName)]
|
||||
internal static unsafe partial void av_packet_unref(AVPacket* pkt);
|
||||
|
||||
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern void av_packet_free(AVPacket** pkt);
|
||||
[LibraryImport(AvCodecLibraryName)]
|
||||
internal static unsafe partial void av_packet_free(AVPacket** pkt);
|
||||
|
||||
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static unsafe extern int avcodec_version();
|
||||
[LibraryImport(AvCodecLibraryName)]
|
||||
internal static unsafe partial int avcodec_version();
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ using System.Runtime.Versioning;
|
||||
namespace Ryujinx.Graphics.OpenGL.Helper
|
||||
{
|
||||
[SupportedOSPlatform("linux")]
|
||||
internal static class GLXHelper
|
||||
internal static partial class GLXHelper
|
||||
{
|
||||
private const string LibraryName = "glx.dll";
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Ryujinx.Graphics.OpenGL.Helper
|
||||
});
|
||||
}
|
||||
|
||||
[DllImport(LibraryName, EntryPoint = "glXGetCurrentContext")]
|
||||
public static extern IntPtr GetCurrentContext();
|
||||
[LibraryImport(LibraryName, EntryPoint = "glXGetCurrentContext")]
|
||||
public static partial IntPtr GetCurrentContext();
|
||||
}
|
||||
}
|
||||
|
@@ -5,11 +5,11 @@ using System.Runtime.Versioning;
|
||||
namespace Ryujinx.Graphics.OpenGL.Helper
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
internal static class WGLHelper
|
||||
internal static partial class WGLHelper
|
||||
{
|
||||
private const string LibraryName = "OPENGL32.DLL";
|
||||
|
||||
[DllImport(LibraryName, EntryPoint = "wglGetCurrentContext")]
|
||||
public extern static IntPtr GetCurrentContext();
|
||||
[LibraryImport(LibraryName, EntryPoint = "wglGetCurrentContext")]
|
||||
public static partial IntPtr GetCurrentContext();
|
||||
}
|
||||
}
|
||||
|
@@ -110,10 +110,13 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
supportsBc123Compression: HwCapabilities.SupportsTextureCompressionS3tc,
|
||||
supportsBc45Compression: HwCapabilities.SupportsTextureCompressionRgtc,
|
||||
supportsBc67Compression: true, // Should check BPTC extension, but for some reason NVIDIA is not exposing the extension.
|
||||
supportsEtc2Compression: true,
|
||||
supports3DTextureCompression: false,
|
||||
supportsBgraFormat: false,
|
||||
supportsR4G4Format: false,
|
||||
supportsR4G4B4A4Format: true,
|
||||
supportsSnormBufferTextureFormat: false,
|
||||
supports5BitComponentFormat: true,
|
||||
supportsFragmentShaderInterlock: HwCapabilities.SupportsFragmentShaderInterlock,
|
||||
supportsFragmentShaderOrderingIntel: HwCapabilities.SupportsFragmentShaderOrdering,
|
||||
supportsGeometryShaderPassthrough: HwCapabilities.SupportsGeometryShaderPassthrough,
|
||||
|
@@ -6,7 +6,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OpenTK.Graphics" Version="4.7.5" />
|
||||
<PackageReference Include="OpenTK.Graphics" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -262,7 +262,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
|
||||
value = (value >> operation.Index * 16) & 0xffff;
|
||||
|
||||
operation.TurnIntoCopy(ConstF(HalfConversion.HalfToSingle(value)));
|
||||
operation.TurnIntoCopy(ConstF((float)BitConverter.UInt16BitsToHalf((ushort)value)));
|
||||
}
|
||||
|
||||
private static void FPNegate(Operation operation)
|
||||
|
@@ -1,47 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
{
|
||||
static class HalfConversion
|
||||
{
|
||||
public static float HalfToSingle(int value)
|
||||
{
|
||||
int mantissa = (value >> 0) & 0x3ff;
|
||||
int exponent = (value >> 10) & 0x1f;
|
||||
int sign = (value >> 15) & 0x1;
|
||||
|
||||
if (exponent == 0x1f)
|
||||
{
|
||||
// NaN or Infinity.
|
||||
mantissa <<= 13;
|
||||
exponent = 0xff;
|
||||
}
|
||||
else if (exponent != 0 || mantissa != 0 )
|
||||
{
|
||||
if (exponent == 0)
|
||||
{
|
||||
// Denormal.
|
||||
int e = -1;
|
||||
int m = mantissa;
|
||||
|
||||
do
|
||||
{
|
||||
e++;
|
||||
m <<= 1;
|
||||
}
|
||||
while ((m & 0x400) == 0);
|
||||
|
||||
mantissa = m & 0x3ff;
|
||||
exponent = e;
|
||||
}
|
||||
|
||||
mantissa <<= 13;
|
||||
exponent = 127 - 15 + exponent;
|
||||
}
|
||||
|
||||
int output = (sign << 31) | (exponent << 23) | mantissa;
|
||||
|
||||
return BitConverter.Int32BitsToSingle(output);
|
||||
}
|
||||
}
|
||||
}
|
682
Ryujinx.Graphics.Texture/ETC2Decoder.cs
Normal file
682
Ryujinx.Graphics.Texture/ETC2Decoder.cs
Normal file
@@ -0,0 +1,682 @@
|
||||
using Ryujinx.Common;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
public static class ETC2Decoder
|
||||
{
|
||||
private const uint AlphaMask = 0xff000000u;
|
||||
|
||||
private const int BlockWidth = 4;
|
||||
private const int BlockHeight = 4;
|
||||
|
||||
private static readonly int[][] _etc1Lut =
|
||||
{
|
||||
new int[] { 2, 8, -2, -8 },
|
||||
new int[] { 5, 17, -5, -17 },
|
||||
new int[] { 9, 29, -9, -29 },
|
||||
new int[] { 13, 42, -13, -42 },
|
||||
new int[] { 18, 60, -18, -60 },
|
||||
new int[] { 24, 80, -24, -80 },
|
||||
new int[] { 33, 106, -33, -106 },
|
||||
new int[] { 47, 183, -47, -183 }
|
||||
};
|
||||
|
||||
private static readonly int[] _etc2Lut =
|
||||
{
|
||||
3, 6, 11, 16, 23, 32, 41, 64
|
||||
};
|
||||
|
||||
private static readonly int[][] _etc2AlphaLut =
|
||||
{
|
||||
new int[] { -3, -6, -9, -15, 2, 5, 8, 14 },
|
||||
new int[] { -3, -7, -10, -13, 2, 6, 9, 12 },
|
||||
new int[] { -2, -5, -8, -13, 1, 4, 7, 12 },
|
||||
new int[] { -2, -4, -6, -13, 1, 3, 5, 12 },
|
||||
new int[] { -3, -6, -8, -12, 2, 5, 7, 11 },
|
||||
new int[] { -3, -7, -9, -11, 2, 6, 8, 10 },
|
||||
new int[] { -4, -7, -8, -11, 3, 6, 7, 10 },
|
||||
new int[] { -3, -5, -8, -11, 2, 4, 7, 10 },
|
||||
new int[] { -2, -6, -8, -10, 1, 5, 7, 9 },
|
||||
new int[] { -2, -5, -8, -10, 1, 4, 7, 9 },
|
||||
new int[] { -2, -4, -8, -10, 1, 3, 7, 9 },
|
||||
new int[] { -2, -5, -7, -10, 1, 4, 6, 9 },
|
||||
new int[] { -3, -4, -7, -10, 2, 3, 6, 9 },
|
||||
new int[] { -1, -2, -3, -10, 0, 1, 2, 9 },
|
||||
new int[] { -4, -6, -8, -9, 3, 5, 7, 8 },
|
||||
new int[] { -3, -5, -7, -9, 2, 4, 6, 8 }
|
||||
};
|
||||
|
||||
public static byte[] DecodeRgb(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
|
||||
{
|
||||
ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data);
|
||||
|
||||
int inputOffset = 0;
|
||||
|
||||
byte[] output = new byte[CalculateOutputSize(width, height, depth, levels, layers)];
|
||||
|
||||
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output);
|
||||
Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight];
|
||||
|
||||
int imageBaseOOffs = 0;
|
||||
|
||||
for (int l = 0; l < levels; l++)
|
||||
{
|
||||
int wInBlocks = BitUtils.DivRoundUp(width, BlockWidth);
|
||||
int hInBlocks = BitUtils.DivRoundUp(height, BlockHeight);
|
||||
|
||||
for (int l2 = 0; l2 < layers; l2++)
|
||||
{
|
||||
for (int z = 0; z < depth; z++)
|
||||
{
|
||||
for (int y = 0; y < hInBlocks; y++)
|
||||
{
|
||||
int ty = y * BlockHeight;
|
||||
int bh = Math.Min(BlockHeight, height - ty);
|
||||
|
||||
for (int x = 0; x < wInBlocks; x++)
|
||||
{
|
||||
int tx = x * BlockWidth;
|
||||
int bw = Math.Min(BlockWidth, width - tx);
|
||||
|
||||
ulong colorBlock = dataUlong[inputOffset++];
|
||||
|
||||
DecodeBlock(tile, colorBlock);
|
||||
|
||||
for (int py = 0; py < bh; py++)
|
||||
{
|
||||
int oOffsBase = imageBaseOOffs + ((ty + py) * width) + tx;
|
||||
|
||||
for (int px = 0; px < bw; px++)
|
||||
{
|
||||
int oOffs = oOffsBase + px;
|
||||
|
||||
outputUint[oOffs] = tile[py * BlockWidth + px] | AlphaMask;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
imageBaseOOffs += width * height;
|
||||
}
|
||||
}
|
||||
|
||||
width = Math.Max(1, width >> 1);
|
||||
height = Math.Max(1, height >> 1);
|
||||
depth = Math.Max(1, depth >> 1);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public static byte[] DecodePta(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
|
||||
{
|
||||
ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data);
|
||||
|
||||
int inputOffset = 0;
|
||||
|
||||
byte[] output = new byte[CalculateOutputSize(width, height, depth, levels, layers)];
|
||||
|
||||
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output);
|
||||
Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight];
|
||||
|
||||
int imageBaseOOffs = 0;
|
||||
|
||||
for (int l = 0; l < levels; l++)
|
||||
{
|
||||
int wInBlocks = BitUtils.DivRoundUp(width, BlockWidth);
|
||||
int hInBlocks = BitUtils.DivRoundUp(height, BlockHeight);
|
||||
|
||||
for (int l2 = 0; l2 < layers; l2++)
|
||||
{
|
||||
for (int z = 0; z < depth; z++)
|
||||
{
|
||||
for (int y = 0; y < hInBlocks; y++)
|
||||
{
|
||||
int ty = y * BlockHeight;
|
||||
int bh = Math.Min(BlockHeight, height - ty);
|
||||
|
||||
for (int x = 0; x < wInBlocks; x++)
|
||||
{
|
||||
int tx = x * BlockWidth;
|
||||
int bw = Math.Min(BlockWidth, width - tx);
|
||||
|
||||
ulong colorBlock = dataUlong[inputOffset++];
|
||||
|
||||
DecodeBlockPta(tile, colorBlock);
|
||||
|
||||
for (int py = 0; py < bh; py++)
|
||||
{
|
||||
int oOffsBase = imageBaseOOffs + ((ty + py) * width) + tx;
|
||||
|
||||
tile.Slice(py * BlockWidth, bw).CopyTo(outputUint.Slice(oOffsBase, bw));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
imageBaseOOffs += width * height;
|
||||
}
|
||||
}
|
||||
|
||||
width = Math.Max(1, width >> 1);
|
||||
height = Math.Max(1, height >> 1);
|
||||
depth = Math.Max(1, depth >> 1);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public static byte[] DecodeRgba(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
|
||||
{
|
||||
ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data);
|
||||
|
||||
int inputOffset = 0;
|
||||
|
||||
byte[] output = new byte[CalculateOutputSize(width, height, depth, levels, layers)];
|
||||
|
||||
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output);
|
||||
Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight];
|
||||
|
||||
int imageBaseOOffs = 0;
|
||||
|
||||
for (int l = 0; l < levels; l++)
|
||||
{
|
||||
int wInBlocks = BitUtils.DivRoundUp(width, BlockWidth);
|
||||
int hInBlocks = BitUtils.DivRoundUp(height, BlockHeight);
|
||||
|
||||
for (int l2 = 0; l2 < layers; l2++)
|
||||
{
|
||||
for (int z = 0; z < depth; z++)
|
||||
{
|
||||
for (int y = 0; y < hInBlocks; y++)
|
||||
{
|
||||
int ty = y * BlockHeight;
|
||||
int bh = Math.Min(BlockHeight, height - ty);
|
||||
|
||||
for (int x = 0; x < wInBlocks; x++)
|
||||
{
|
||||
int tx = x * BlockWidth;
|
||||
int bw = Math.Min(BlockWidth, width - tx);
|
||||
|
||||
ulong alphaBlock = dataUlong[inputOffset];
|
||||
ulong colorBlock = dataUlong[inputOffset + 1];
|
||||
|
||||
inputOffset += 2;
|
||||
|
||||
DecodeBlock(tile, colorBlock);
|
||||
|
||||
byte alphaBase = (byte)alphaBlock;
|
||||
int[] alphaTable = _etc2AlphaLut[(alphaBlock >> 8) & 0xf];
|
||||
int alphaMultiplier = (int)(alphaBlock >> 12) & 0xf;
|
||||
ulong alphaIndices = BinaryPrimitives.ReverseEndianness(alphaBlock);
|
||||
|
||||
if (alphaMultiplier != 0)
|
||||
{
|
||||
for (int py = 0; py < bh; py++)
|
||||
{
|
||||
int oOffsBase = imageBaseOOffs + ((ty + py) * width) + tx;
|
||||
|
||||
for (int px = 0; px < bw; px++)
|
||||
{
|
||||
int oOffs = oOffsBase + px;
|
||||
int alphaIndex = (int)((alphaIndices >> (((px * BlockHeight + py) ^ 0xf) * 3)) & 7);
|
||||
|
||||
byte a = Saturate(alphaBase + alphaTable[alphaIndex] * alphaMultiplier);
|
||||
|
||||
outputUint[oOffs] = tile[py * BlockWidth + px] | ((uint)a << 24);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint a = (uint)alphaBase << 24;
|
||||
|
||||
for (int py = 0; py < bh; py++)
|
||||
{
|
||||
int oOffsBase = imageBaseOOffs + ((ty + py) * width) + tx;
|
||||
|
||||
for (int px = 0; px < bw; px++)
|
||||
{
|
||||
int oOffs = oOffsBase + px;
|
||||
|
||||
outputUint[oOffs] = tile[py * BlockWidth + px] | a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
imageBaseOOffs += width * height;
|
||||
}
|
||||
}
|
||||
|
||||
width = Math.Max(1, width >> 1);
|
||||
height = Math.Max(1, height >> 1);
|
||||
depth = Math.Max(1, depth >> 1);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private static void DecodeBlock(Span<uint> tile, ulong block)
|
||||
{
|
||||
uint blockLow = (uint)(block >> 0);
|
||||
uint blockHigh = (uint)(block >> 32);
|
||||
|
||||
uint r1, g1, b1;
|
||||
uint r2, g2, b2;
|
||||
|
||||
bool differentialMode = (blockLow & 0x2000000) != 0;
|
||||
|
||||
if (differentialMode)
|
||||
{
|
||||
(r1, g1, b1, r2, g2, b2) = UnpackRgb555DiffEndPoints(blockLow);
|
||||
|
||||
if (r2 > 31)
|
||||
{
|
||||
DecodeBlock59T(tile, blockLow, blockHigh);
|
||||
}
|
||||
else if (g2 > 31)
|
||||
{
|
||||
DecodeBlock58H(tile, blockLow, blockHigh);
|
||||
}
|
||||
else if (b2 > 31)
|
||||
{
|
||||
DecodeBlock57P(tile, block);
|
||||
}
|
||||
else
|
||||
{
|
||||
r1 |= r1 >> 5;
|
||||
g1 |= g1 >> 5;
|
||||
b1 |= b1 >> 5;
|
||||
|
||||
r2 = (r2 << 3) | (r2 >> 2);
|
||||
g2 = (g2 << 3) | (g2 >> 2);
|
||||
b2 = (b2 << 3) | (b2 >> 2);
|
||||
|
||||
DecodeBlockETC1(tile, blockLow, blockHigh, r1, g1, b1, r2, g2, b2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r1 = (blockLow & 0x0000f0) >> 0;
|
||||
g1 = (blockLow & 0x00f000) >> 8;
|
||||
b1 = (blockLow & 0xf00000) >> 16;
|
||||
|
||||
r2 = (blockLow & 0x00000f) << 4;
|
||||
g2 = (blockLow & 0x000f00) >> 4;
|
||||
b2 = (blockLow & 0x0f0000) >> 12;
|
||||
|
||||
r1 |= r1 >> 4;
|
||||
g1 |= g1 >> 4;
|
||||
b1 |= b1 >> 4;
|
||||
|
||||
r2 |= r2 >> 4;
|
||||
g2 |= g2 >> 4;
|
||||
b2 |= b2 >> 4;
|
||||
|
||||
DecodeBlockETC1(tile, blockLow, blockHigh, r1, g1, b1, r2, g2, b2);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DecodeBlockPta(Span<uint> tile, ulong block)
|
||||
{
|
||||
uint blockLow = (uint)(block >> 0);
|
||||
uint blockHigh = (uint)(block >> 32);
|
||||
|
||||
(uint r1, uint g1, uint b1, uint r2, uint g2, uint b2) = UnpackRgb555DiffEndPoints(blockLow);
|
||||
|
||||
bool fullyOpaque = (blockLow & 0x2000000) != 0;
|
||||
|
||||
if (fullyOpaque)
|
||||
{
|
||||
if (r2 > 31)
|
||||
{
|
||||
DecodeBlock59T(tile, blockLow, blockHigh);
|
||||
}
|
||||
else if (g2 > 31)
|
||||
{
|
||||
DecodeBlock58H(tile, blockLow, blockHigh);
|
||||
}
|
||||
else if (b2 > 31)
|
||||
{
|
||||
DecodeBlock57P(tile, block);
|
||||
}
|
||||
else
|
||||
{
|
||||
r1 |= r1 >> 5;
|
||||
g1 |= g1 >> 5;
|
||||
b1 |= b1 >> 5;
|
||||
|
||||
r2 = (r2 << 3) | (r2 >> 2);
|
||||
g2 = (g2 << 3) | (g2 >> 2);
|
||||
b2 = (b2 << 3) | (b2 >> 2);
|
||||
|
||||
DecodeBlockETC1(tile, blockLow, blockHigh, r1, g1, b1, r2, g2, b2);
|
||||
}
|
||||
|
||||
for (int i = 0; i < tile.Length; i++)
|
||||
{
|
||||
tile[i] |= AlphaMask;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r2 > 31)
|
||||
{
|
||||
DecodeBlock59T(tile, blockLow, blockHigh, AlphaMask);
|
||||
}
|
||||
else if (g2 > 31)
|
||||
{
|
||||
DecodeBlock58H(tile, blockLow, blockHigh, AlphaMask);
|
||||
}
|
||||
else if (b2 > 31)
|
||||
{
|
||||
DecodeBlock57P(tile, block);
|
||||
|
||||
for (int i = 0; i < tile.Length; i++)
|
||||
{
|
||||
tile[i] |= AlphaMask;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r1 |= r1 >> 5;
|
||||
g1 |= g1 >> 5;
|
||||
b1 |= b1 >> 5;
|
||||
|
||||
r2 = (r2 << 3) | (r2 >> 2);
|
||||
g2 = (g2 << 3) | (g2 >> 2);
|
||||
b2 = (b2 << 3) | (b2 >> 2);
|
||||
|
||||
DecodeBlockETC1(tile, blockLow, blockHigh, r1, g1, b1, r2, g2, b2, AlphaMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static (uint, uint, uint, uint, uint, uint) UnpackRgb555DiffEndPoints(uint blockLow)
|
||||
{
|
||||
uint r1 = (blockLow & 0x0000f8) >> 0;
|
||||
uint g1 = (blockLow & 0x00f800) >> 8;
|
||||
uint b1 = (blockLow & 0xf80000) >> 16;
|
||||
|
||||
uint r2 = (uint)((sbyte)(r1 >> 3) + ((sbyte)((blockLow & 0x000007) << 5) >> 5));
|
||||
uint g2 = (uint)((sbyte)(g1 >> 3) + ((sbyte)((blockLow & 0x000700) >> 3) >> 5));
|
||||
uint b2 = (uint)((sbyte)(b1 >> 3) + ((sbyte)((blockLow & 0x070000) >> 11) >> 5));
|
||||
|
||||
return (r1, g1, b1, r2, g2, b2);
|
||||
}
|
||||
|
||||
private static void DecodeBlock59T(Span<uint> tile, uint blockLow, uint blockHigh, uint alphaMask = 0)
|
||||
{
|
||||
uint r1 = (blockLow & 3) | ((blockLow >> 1) & 0xc);
|
||||
uint g1 = (blockLow >> 12) & 0xf;
|
||||
uint b1 = (blockLow >> 8) & 0xf;
|
||||
|
||||
uint r2 = (blockLow >> 20) & 0xf;
|
||||
uint g2 = (blockLow >> 16) & 0xf;
|
||||
uint b2 = (blockLow >> 28) & 0xf;
|
||||
|
||||
r1 |= r1 << 4;
|
||||
g1 |= g1 << 4;
|
||||
b1 |= b1 << 4;
|
||||
|
||||
r2 |= r2 << 4;
|
||||
g2 |= g2 << 4;
|
||||
b2 |= b2 << 4;
|
||||
|
||||
int dist = _etc2Lut[((blockLow >> 24) & 1) | ((blockLow >> 25) & 6)];
|
||||
|
||||
Span<uint> palette = stackalloc uint[4];
|
||||
|
||||
palette[0] = Pack(r1, g1, b1);
|
||||
palette[1] = Pack(r2, g2, b2, dist);
|
||||
palette[2] = Pack(r2, g2, b2);
|
||||
palette[3] = Pack(r2, g2, b2, -dist);
|
||||
|
||||
blockHigh = BinaryPrimitives.ReverseEndianness(blockHigh);
|
||||
|
||||
for (int y = 0; y < BlockHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < BlockWidth; x++)
|
||||
{
|
||||
int offset = (y * 4) + x;
|
||||
int index = (x * 4) + y;
|
||||
|
||||
int paletteIndex = (int)((blockHigh >> index) & 1) | (int)((blockHigh >> (index + 15)) & 2);
|
||||
|
||||
tile[offset] = palette[paletteIndex];
|
||||
|
||||
if (alphaMask != 0)
|
||||
{
|
||||
if (paletteIndex == 2)
|
||||
{
|
||||
tile[offset] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tile[offset] |= alphaMask;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DecodeBlock58H(Span<uint> tile, uint blockLow, uint blockHigh, uint alphaMask = 0)
|
||||
{
|
||||
uint r1 = (blockLow >> 3) & 0xf;
|
||||
uint g1 = ((blockLow << 1) & 0xe) | ((blockLow >> 12) & 1);
|
||||
uint b1 = ((blockLow >> 23) & 1) | ((blockLow >> 7) & 6) | ((blockLow >> 8) & 8);
|
||||
|
||||
uint r2 = (blockLow >> 19) & 0xf;
|
||||
uint g2 = ((blockLow >> 31) & 1) | ((blockLow >> 15) & 0xe);
|
||||
uint b2 = (blockLow >> 27) & 0xf;
|
||||
|
||||
uint rgb1 = Pack4Be(r1, g1, b1);
|
||||
uint rgb2 = Pack4Be(r2, g2, b2);
|
||||
|
||||
r1 |= r1 << 4;
|
||||
g1 |= g1 << 4;
|
||||
b1 |= b1 << 4;
|
||||
|
||||
r2 |= r2 << 4;
|
||||
g2 |= g2 << 4;
|
||||
b2 |= b2 << 4;
|
||||
|
||||
int dist = _etc2Lut[(rgb1 >= rgb2 ? 1u : 0u) | ((blockLow >> 23) & 2) | ((blockLow >> 24) & 4)];
|
||||
|
||||
Span<uint> palette = stackalloc uint[4];
|
||||
|
||||
palette[0] = Pack(r1, g1, b1, dist);
|
||||
palette[1] = Pack(r1, g1, b1, -dist);
|
||||
palette[2] = Pack(r2, g2, b2, dist);
|
||||
palette[3] = Pack(r2, g2, b2, -dist);
|
||||
|
||||
blockHigh = BinaryPrimitives.ReverseEndianness(blockHigh);
|
||||
|
||||
for (int y = 0; y < BlockHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < BlockWidth; x++)
|
||||
{
|
||||
int offset = (y * 4) + x;
|
||||
int index = (x * 4) + y;
|
||||
|
||||
int paletteIndex = (int)((blockHigh >> index) & 1) | (int)((blockHigh >> (index + 15)) & 2);
|
||||
|
||||
tile[offset] = palette[paletteIndex];
|
||||
|
||||
if (alphaMask != 0)
|
||||
{
|
||||
if (paletteIndex == 2)
|
||||
{
|
||||
tile[offset] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tile[offset] |= alphaMask;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DecodeBlock57P(Span<uint> tile, ulong block)
|
||||
{
|
||||
int r0 = (int)((block >> 1) & 0x3f);
|
||||
int g0 = (int)(((block >> 9) & 0x3f) | ((block & 1) << 6));
|
||||
int b0 = (int)(((block >> 31) & 1) | ((block >> 15) & 6) | ((block >> 16) & 0x18) | ((block >> 3) & 0x20));
|
||||
|
||||
int rh = (int)(((block >> 24) & 1) | ((block >> 25) & 0x3e));
|
||||
int gh = (int)((block >> 33) & 0x7f);
|
||||
int bh = (int)(((block >> 43) & 0x1f) | ((block >> 27) & 0x20));
|
||||
|
||||
int rv = (int)(((block >> 53) & 7) | ((block >> 37) & 0x38));
|
||||
int gv = (int)(((block >> 62) & 3) | ((block >> 46) & 0x7c));
|
||||
int bv = (int)((block >> 56) & 0x3f);
|
||||
|
||||
r0 = (r0 << 2) | (r0 >> 4);
|
||||
g0 = (g0 << 1) | (g0 >> 6);
|
||||
b0 = (b0 << 2) | (b0 >> 4);
|
||||
|
||||
rh = (rh << 2) | (rh >> 4);
|
||||
gh = (gh << 1) | (gh >> 6);
|
||||
bh = (bh << 2) | (bh >> 4);
|
||||
|
||||
rv = (rv << 2) | (rv >> 4);
|
||||
gv = (gv << 1) | (gv >> 6);
|
||||
bv = (bv << 2) | (bv >> 4);
|
||||
|
||||
for (int y = 0; y < BlockHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < BlockWidth; x++)
|
||||
{
|
||||
int offset = y * BlockWidth + x;
|
||||
|
||||
byte r = Saturate(((x * (rh - r0)) + (y * (rv - r0)) + (r0 * 4) + 2) >> 2);
|
||||
byte g = Saturate(((x * (gh - g0)) + (y * (gv - g0)) + (g0 * 4) + 2) >> 2);
|
||||
byte b = Saturate(((x * (bh - b0)) + (y * (bv - b0)) + (b0 * 4) + 2) >> 2);
|
||||
|
||||
tile[offset] = Pack(r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DecodeBlockETC1(
|
||||
Span<uint> tile,
|
||||
uint blockLow,
|
||||
uint blockHigh,
|
||||
uint r1,
|
||||
uint g1,
|
||||
uint b1,
|
||||
uint r2,
|
||||
uint g2,
|
||||
uint b2,
|
||||
uint alphaMask = 0)
|
||||
{
|
||||
int[] table1 = _etc1Lut[(blockLow >> 29) & 7];
|
||||
int[] table2 = _etc1Lut[(blockLow >> 26) & 7];
|
||||
|
||||
bool flip = (blockLow & 0x1000000) != 0;
|
||||
|
||||
if (!flip)
|
||||
{
|
||||
for (int y = 0; y < BlockHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < BlockWidth / 2; x++)
|
||||
{
|
||||
uint color1 = CalculatePixel(r1, g1, b1, x + 0, y, blockHigh, table1, alphaMask);
|
||||
uint color2 = CalculatePixel(r2, g2, b2, x + 2, y, blockHigh, table2, alphaMask);
|
||||
|
||||
int offset1 = y * BlockWidth + x;
|
||||
int offset2 = y * BlockWidth + x + 2;
|
||||
|
||||
tile[offset1] = color1;
|
||||
tile[offset2] = color2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < BlockHeight / 2; y++)
|
||||
{
|
||||
for (int x = 0; x < BlockWidth; x++)
|
||||
{
|
||||
uint color1 = CalculatePixel(r1, g1, b1, x, y + 0, blockHigh, table1, alphaMask);
|
||||
uint color2 = CalculatePixel(r2, g2, b2, x, y + 2, blockHigh, table2, alphaMask);
|
||||
|
||||
int offset1 = (y * BlockWidth) + x;
|
||||
int offset2 = ((y + 2) * BlockWidth) + x;
|
||||
|
||||
tile[offset1] = color1;
|
||||
tile[offset2] = color2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static uint CalculatePixel(uint r, uint g, uint b, int x, int y, uint block, int[] table, uint alphaMask)
|
||||
{
|
||||
int index = x * BlockHeight + y;
|
||||
uint msb = block << 1;
|
||||
uint tableIndex = index < 8
|
||||
? ((block >> (index + 24)) & 1) + ((msb >> (index + 8)) & 2)
|
||||
: ((block >> (index + 8)) & 1) + ((msb >> (index - 8)) & 2);
|
||||
|
||||
if (alphaMask != 0)
|
||||
{
|
||||
if (tableIndex == 0)
|
||||
{
|
||||
return Pack(r, g, b) | alphaMask;
|
||||
}
|
||||
else if (tableIndex == 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Pack(r, g, b, table[tableIndex]) | alphaMask;
|
||||
}
|
||||
}
|
||||
|
||||
return Pack(r, g, b, table[tableIndex]);
|
||||
}
|
||||
|
||||
private static uint Pack(uint r, uint g, uint b, int offset)
|
||||
{
|
||||
r = Saturate((int)(r + offset));
|
||||
g = Saturate((int)(g + offset));
|
||||
b = Saturate((int)(b + offset));
|
||||
|
||||
return Pack(r, g, b);
|
||||
}
|
||||
|
||||
private static uint Pack(uint r, uint g, uint b)
|
||||
{
|
||||
return r | (g << 8) | (b << 16);
|
||||
}
|
||||
|
||||
private static uint Pack4Be(uint r, uint g, uint b)
|
||||
{
|
||||
return (r << 8) | (g << 4) | b;
|
||||
}
|
||||
|
||||
private static byte Saturate(int value)
|
||||
{
|
||||
return value > byte.MaxValue ? byte.MaxValue : value < byte.MinValue ? byte.MinValue : (byte)value;
|
||||
}
|
||||
|
||||
private static int CalculateOutputSize(int width, int height, int depth, int levels, int layers)
|
||||
{
|
||||
int size = 0;
|
||||
|
||||
for (int l = 0; l < levels; l++)
|
||||
{
|
||||
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
@@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
public static class LayoutConverter
|
||||
{
|
||||
private const int HostStrideAlignment = 4;
|
||||
public const int HostStrideAlignment = 4;
|
||||
|
||||
public static void ConvertBlockLinearToLinear(
|
||||
Span<byte> dst,
|
||||
|
@@ -1,3 +1,4 @@
|
||||
using Ryujinx.Common;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
@@ -7,30 +8,206 @@ namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
public static class PixelConverter
|
||||
{
|
||||
public unsafe static byte[] ConvertR4G4ToR4G4B4A4(ReadOnlySpan<byte> data)
|
||||
private static (int remainder, int outRemainder, int height) GetLineRemainders(int length, int width, int bpp, int outBpp)
|
||||
{
|
||||
int stride = BitUtils.AlignUp(width * bpp, LayoutConverter.HostStrideAlignment);
|
||||
int remainder = stride / bpp - width;
|
||||
|
||||
int outStride = BitUtils.AlignUp(width * outBpp, LayoutConverter.HostStrideAlignment);
|
||||
int outRemainder = outStride / outBpp - width;
|
||||
|
||||
return (remainder, outRemainder, length / stride);
|
||||
}
|
||||
|
||||
public unsafe static byte[] ConvertR4G4ToR4G4B4A4(ReadOnlySpan<byte> data, int width)
|
||||
{
|
||||
byte[] output = new byte[data.Length * 2];
|
||||
int start = 0;
|
||||
|
||||
if (Sse41.IsSupported)
|
||||
{
|
||||
int sizeTrunc = data.Length & ~7;
|
||||
start = sizeTrunc;
|
||||
|
||||
fixed (byte* inputPtr = data, outputPtr = output)
|
||||
{
|
||||
for (ulong offset = 0; offset < (ulong)sizeTrunc; offset += 8)
|
||||
{
|
||||
Sse2.Store(outputPtr + offset * 2, Sse41.ConvertToVector128Int16(inputPtr + offset).AsByte());
|
||||
}
|
||||
}
|
||||
}
|
||||
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 1, 2);
|
||||
|
||||
Span<ushort> outputSpan = MemoryMarshal.Cast<byte, ushort>(output);
|
||||
|
||||
for (int i = start; i < data.Length; i++)
|
||||
if (remainder == 0)
|
||||
{
|
||||
outputSpan[i] = (ushort)data[i];
|
||||
int start = 0;
|
||||
|
||||
if (Sse41.IsSupported)
|
||||
{
|
||||
int sizeTrunc = data.Length & ~7;
|
||||
start = sizeTrunc;
|
||||
|
||||
fixed (byte* inputPtr = data, outputPtr = output)
|
||||
{
|
||||
for (ulong offset = 0; offset < (ulong)sizeTrunc; offset += 8)
|
||||
{
|
||||
Sse2.Store(outputPtr + offset * 2, Sse41.ConvertToVector128Int16(inputPtr + offset).AsByte());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = start; i < data.Length; i++)
|
||||
{
|
||||
outputSpan[i] = (ushort)data[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int offset = 0;
|
||||
int outOffset = 0;
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
outputSpan[outOffset++] = data[offset++];
|
||||
}
|
||||
|
||||
offset += remainder;
|
||||
outOffset += outRemainder;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public unsafe static byte[] ConvertR5G6B5ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
|
||||
{
|
||||
byte[] output = new byte[data.Length * 2];
|
||||
int offset = 0;
|
||||
int outOffset = 0;
|
||||
|
||||
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
|
||||
|
||||
ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
|
||||
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output);
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
uint packed = inputSpan[offset++];
|
||||
|
||||
uint outputPacked = 0xff000000;
|
||||
outputPacked |= (packed << 3) & 0x000000f8;
|
||||
outputPacked |= (packed << 8) & 0x00f80000;
|
||||
|
||||
// Replicate 5 bit components.
|
||||
outputPacked |= (outputPacked >> 5) & 0x00070007;
|
||||
|
||||
// Include and replicate 6 bit component.
|
||||
outputPacked |= ((packed << 5) & 0x0000fc00) | ((packed >> 1) & 0x00000300);
|
||||
|
||||
outputSpan[outOffset++] = outputPacked;
|
||||
}
|
||||
|
||||
offset += remainder;
|
||||
outOffset += outRemainder;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public unsafe static byte[] ConvertR5G5B5ToR8G8B8A8(ReadOnlySpan<byte> data, int width, bool forceAlpha)
|
||||
{
|
||||
byte[] output = new byte[data.Length * 2];
|
||||
int offset = 0;
|
||||
int outOffset = 0;
|
||||
|
||||
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
|
||||
|
||||
ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
|
||||
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output);
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
uint packed = inputSpan[offset++];
|
||||
|
||||
uint a = forceAlpha ? 1 : (packed >> 15);
|
||||
|
||||
uint outputPacked = a * 0xff000000;
|
||||
outputPacked |= (packed << 3) & 0x000000f8;
|
||||
outputPacked |= (packed << 6) & 0x0000f800;
|
||||
outputPacked |= (packed << 9) & 0x00f80000;
|
||||
|
||||
// Replicate 5 bit components.
|
||||
outputPacked |= (outputPacked >> 5) & 0x00070707;
|
||||
|
||||
outputSpan[outOffset++] = outputPacked;
|
||||
}
|
||||
|
||||
offset += remainder;
|
||||
outOffset += outRemainder;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public unsafe static byte[] ConvertA1B5G5R5ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
|
||||
{
|
||||
byte[] output = new byte[data.Length * 2];
|
||||
int offset = 0;
|
||||
int outOffset = 0;
|
||||
|
||||
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
|
||||
|
||||
ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
|
||||
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output);
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
uint packed = inputSpan[offset++];
|
||||
|
||||
uint a = packed >> 15;
|
||||
|
||||
uint outputPacked = a * 0xff000000;
|
||||
outputPacked |= (packed >> 8) & 0x000000f8;
|
||||
outputPacked |= (packed << 5) & 0x0000f800;
|
||||
outputPacked |= (packed << 18) & 0x00f80000;
|
||||
|
||||
// Replicate 5 bit components.
|
||||
outputPacked |= (outputPacked >> 5) & 0x00070707;
|
||||
|
||||
outputSpan[outOffset++] = outputPacked;
|
||||
}
|
||||
|
||||
offset += remainder;
|
||||
outOffset += outRemainder;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public unsafe static byte[] ConvertR4G4B4A4ToR8G8B8A8(ReadOnlySpan<byte> data, int width)
|
||||
{
|
||||
byte[] output = new byte[data.Length * 2];
|
||||
int offset = 0;
|
||||
int outOffset = 0;
|
||||
|
||||
(int remainder, int outRemainder, int height) = GetLineRemainders(data.Length, width, 2, 4);
|
||||
|
||||
ReadOnlySpan<ushort> inputSpan = MemoryMarshal.Cast<byte, ushort>(data);
|
||||
Span<uint> outputSpan = MemoryMarshal.Cast<byte, uint>(output);
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
uint packed = inputSpan[offset++];
|
||||
|
||||
uint outputPacked = packed & 0x0000000f;
|
||||
outputPacked |= (packed << 4) & 0x00000f00;
|
||||
outputPacked |= (packed << 8) & 0x000f0000;
|
||||
outputPacked |= (packed << 12) & 0x0f000000;
|
||||
|
||||
outputSpan[outOffset++] = outputPacked * 0x11;
|
||||
}
|
||||
|
||||
offset += remainder;
|
||||
outOffset += outRemainder;
|
||||
}
|
||||
|
||||
return output;
|
||||
|
@@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
var range = _freeRanges[i];
|
||||
|
||||
ulong alignedOffset = BitUtils.AlignUp(range.Offset, (int)alignment);
|
||||
ulong alignedOffset = BitUtils.AlignUp<ulong>(range.Offset, alignment);
|
||||
ulong sizeDelta = alignedOffset - range.Offset;
|
||||
ulong usableSize = range.Size - sizeDelta;
|
||||
|
||||
@@ -196,7 +196,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
ulong blockAlignedSize = BitUtils.AlignUp(size, _blockAlignment);
|
||||
ulong blockAlignedSize = BitUtils.AlignUp<ulong>(size, (ulong)_blockAlignment);
|
||||
|
||||
var memoryAllocateInfo = new MemoryAllocateInfo()
|
||||
{
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
@@ -13,14 +13,14 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.7.5" />
|
||||
<PackageReference Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
|
||||
<PackageReference Include="System.Threading.ThreadPool" Version="4.3.0" />
|
||||
<PackageReference Include="OpenTK.Windowing.GraphicsLibraryFramework" />
|
||||
<PackageReference Include="shaderc.net" />
|
||||
<PackageReference Include="Silk.NET.Vulkan" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" />
|
||||
<PackageReference Include="System.Net.NameResolution" />
|
||||
<PackageReference Include="System.Threading.ThreadPool" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -374,7 +374,24 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
api.GetPhysicalDeviceProperties(physicalDevice, out var properties);
|
||||
bool useRobustBufferAccess = VendorUtils.FromId(properties.VendorID) == Vendor.Nvidia;
|
||||
|
||||
var supportedFeatures = api.GetPhysicalDeviceFeature(physicalDevice);
|
||||
PhysicalDeviceFeatures2 features2 = new PhysicalDeviceFeatures2()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceFeatures2
|
||||
};
|
||||
|
||||
PhysicalDeviceCustomBorderColorFeaturesEXT featuresCustomBorderColorSupported = new PhysicalDeviceCustomBorderColorFeaturesEXT()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceCustomBorderColorFeaturesExt
|
||||
};
|
||||
|
||||
if (supportedExtensions.Contains("VK_EXT_custom_border_color"))
|
||||
{
|
||||
features2.PNext = &featuresCustomBorderColorSupported;
|
||||
}
|
||||
|
||||
api.GetPhysicalDeviceFeatures2(physicalDevice, &features2);
|
||||
|
||||
var supportedFeatures = features2.Features;
|
||||
|
||||
var features = new PhysicalDeviceFeatures()
|
||||
{
|
||||
@@ -491,6 +508,23 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
pExtendedFeatures = &featuresSubgroupSizeControl;
|
||||
}
|
||||
|
||||
PhysicalDeviceCustomBorderColorFeaturesEXT featuresCustomBorderColor;
|
||||
|
||||
if (supportedExtensions.Contains("VK_EXT_custom_border_color") &&
|
||||
featuresCustomBorderColorSupported.CustomBorderColors &&
|
||||
featuresCustomBorderColorSupported.CustomBorderColorWithoutFormat)
|
||||
{
|
||||
featuresCustomBorderColor = new PhysicalDeviceCustomBorderColorFeaturesEXT()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceCustomBorderColorFeaturesExt,
|
||||
PNext = pExtendedFeatures,
|
||||
CustomBorderColors = true,
|
||||
CustomBorderColorWithoutFormat = true,
|
||||
};
|
||||
|
||||
pExtendedFeatures = &featuresCustomBorderColor;
|
||||
}
|
||||
|
||||
var enabledExtensions = RequiredExtensions.Union(DesirableExtensions.Intersect(supportedExtensions)).ToArray();
|
||||
|
||||
IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length];
|
||||
|
@@ -177,6 +177,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SType = StructureType.PhysicalDeviceShaderFloat16Int8Features
|
||||
};
|
||||
|
||||
PhysicalDeviceCustomBorderColorFeaturesEXT featuresCustomBorderColor = new PhysicalDeviceCustomBorderColorFeaturesEXT()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceCustomBorderColorFeaturesExt
|
||||
};
|
||||
|
||||
if (supportedExtensions.Contains("VK_EXT_robustness2"))
|
||||
{
|
||||
features2.PNext = &featuresRobustness2;
|
||||
@@ -188,8 +193,18 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
features2.PNext = &featuresShaderInt8;
|
||||
}
|
||||
|
||||
if (supportedExtensions.Contains("VK_EXT_custom_border_color"))
|
||||
{
|
||||
featuresCustomBorderColor.PNext = features2.PNext;
|
||||
features2.PNext = &featuresCustomBorderColor;
|
||||
}
|
||||
|
||||
Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2);
|
||||
|
||||
bool customBorderColorSupported = supportedExtensions.Contains("VK_EXT_custom_border_color") &&
|
||||
featuresCustomBorderColor.CustomBorderColors &&
|
||||
featuresCustomBorderColor.CustomBorderColorWithoutFormat;
|
||||
|
||||
ref var properties = ref properties2.Properties;
|
||||
|
||||
SampleCountFlags supportedSampleCounts =
|
||||
@@ -199,7 +214,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
Capabilities = new HardwareCapabilities(
|
||||
supportedExtensions.Contains("VK_EXT_index_type_uint8"),
|
||||
supportedExtensions.Contains("VK_EXT_custom_border_color"),
|
||||
customBorderColorSupported,
|
||||
supportedExtensions.Contains(KhrDrawIndirectCount.ExtensionName),
|
||||
supportedExtensions.Contains("VK_EXT_fragment_shader_interlock"),
|
||||
supportedExtensions.Contains("VK_NV_geometry_shader_passthrough"),
|
||||
@@ -373,6 +388,24 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
GAL.Format.Bc7Srgb,
|
||||
GAL.Format.Bc7Unorm);
|
||||
|
||||
bool supportsEtc2CompressionFormat = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
|
||||
GAL.Format.Etc2RgbaSrgb,
|
||||
GAL.Format.Etc2RgbaUnorm,
|
||||
GAL.Format.Etc2RgbPtaSrgb,
|
||||
GAL.Format.Etc2RgbPtaUnorm,
|
||||
GAL.Format.Etc2RgbSrgb,
|
||||
GAL.Format.Etc2RgbUnorm);
|
||||
|
||||
bool supports5BitComponentFormat = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
|
||||
GAL.Format.R5G6B5Unorm,
|
||||
GAL.Format.R5G5B5A1Unorm,
|
||||
GAL.Format.R5G5B5X1Unorm,
|
||||
GAL.Format.B5G6R5Unorm,
|
||||
GAL.Format.B5G5R5A1Unorm,
|
||||
GAL.Format.A1B5G5R5Unorm);
|
||||
|
||||
bool supportsR4G4B4A4Format = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
|
||||
GAL.Format.R4G4B4A4Unorm);
|
||||
|
||||
PhysicalDeviceVulkan12Features featuresVk12 = new PhysicalDeviceVulkan12Features()
|
||||
{
|
||||
@@ -399,10 +432,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
supportsBc123Compression: supportsBc123CompressionFormat,
|
||||
supportsBc45Compression: supportsBc45CompressionFormat,
|
||||
supportsBc67Compression: supportsBc67CompressionFormat,
|
||||
supportsEtc2Compression: supportsEtc2CompressionFormat,
|
||||
supports3DTextureCompression: true,
|
||||
supportsBgraFormat: true,
|
||||
supportsR4G4Format: false,
|
||||
supportsR4G4B4A4Format: supportsR4G4B4A4Format,
|
||||
supportsSnormBufferTextureFormat: true,
|
||||
supports5BitComponentFormat: supports5BitComponentFormat,
|
||||
supportsFragmentShaderInterlock: Capabilities.SupportsFragmentShaderInterlock,
|
||||
supportsFragmentShaderOrderingIntel: false,
|
||||
supportsGeometryShaderPassthrough: Capabilities.SupportsGeometryShaderPassthrough,
|
||||
|
@@ -47,7 +47,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
||||
|
||||
_errorStorage = _normalSession.Pop();
|
||||
_errorCommonHeader = IApplet.ReadStruct<ErrorCommonHeader>(_errorStorage);
|
||||
_errorStorage = _errorStorage.Skip(Marshal.SizeOf(typeof(ErrorCommonHeader))).ToArray();
|
||||
_errorStorage = _errorStorage.Skip(Marshal.SizeOf<ErrorCommonHeader>()).ToArray();
|
||||
|
||||
switch (_errorCommonHeader.Type)
|
||||
{
|
||||
|
@@ -9,6 +9,7 @@ using Ryujinx.HLE.Ui.Input;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -797,7 +798,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static T ReadStruct<T>(byte[] data)
|
||||
private static T ReadStruct<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>(byte[] data)
|
||||
where T : struct
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
|
@@ -81,8 +81,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
attributeMask |= MemoryAttribute.DeviceMapped;
|
||||
}
|
||||
|
||||
ulong clientAddrTruncated = BitUtils.AlignDown(desc.ClientAddress, KPageTableBase.PageSize);
|
||||
ulong clientAddrRounded = BitUtils.AlignUp (desc.ClientAddress, KPageTableBase.PageSize);
|
||||
ulong clientAddrTruncated = BitUtils.AlignDown<ulong>(desc.ClientAddress, KPageTableBase.PageSize);
|
||||
ulong clientAddrRounded = BitUtils.AlignUp<ulong>(desc.ClientAddress, KPageTableBase.PageSize);
|
||||
|
||||
// Check if address is not aligned, in this case we need to perform 2 copies.
|
||||
if (clientAddrTruncated != clientAddrRounded)
|
||||
@@ -113,9 +113,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
ulong clientEndAddr = desc.ClientAddress + desc.Size;
|
||||
ulong serverEndAddr = desc.ServerAddress + desc.Size;
|
||||
|
||||
ulong clientEndAddrTruncated = BitUtils.AlignDown(clientEndAddr, KPageTableBase.PageSize);
|
||||
ulong clientEndAddrRounded = BitUtils.AlignUp (clientEndAddr, KPageTableBase.PageSize);
|
||||
ulong serverEndAddrTruncated = BitUtils.AlignDown(serverEndAddr, KPageTableBase.PageSize);
|
||||
ulong clientEndAddrTruncated = BitUtils.AlignDown<ulong>(clientEndAddr, (ulong)KPageTableBase.PageSize);
|
||||
ulong clientEndAddrRounded = BitUtils.AlignUp<ulong>(clientEndAddr, KPageTableBase.PageSize);
|
||||
ulong serverEndAddrTruncated = BitUtils.AlignDown<ulong>(serverEndAddr, (ulong)KPageTableBase.PageSize);
|
||||
|
||||
if (clientEndAddrTruncated < clientEndAddrRounded &&
|
||||
(clientAddrTruncated == clientAddrRounded || clientAddrTruncated < clientEndAddrTruncated))
|
||||
|
@@ -1005,7 +1005,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
recvListEndAddr = recvListBaseAddr + size;
|
||||
}
|
||||
|
||||
recvListBufferAddress = BitUtils.AlignUp(recvListBaseAddr + dstOffset, 0x10);
|
||||
recvListBufferAddress = BitUtils.AlignUp<ulong>(recvListBaseAddr + dstOffset, 0x10);
|
||||
|
||||
ulong endAddress = recvListBufferAddress + descriptor.BufferSize;
|
||||
|
||||
|
@@ -44,7 +44,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
|
||||
public KernelResult Map(ulong address, ulong size, KMemoryPermission perm)
|
||||
{
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp(size, KPageTableBase.PageSize))
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, (ulong)KPageTableBase.PageSize))
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
@@ -73,7 +73,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
|
||||
public KernelResult MapToOwner(ulong address, ulong size, KMemoryPermission permission)
|
||||
{
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp(size, KPageTableBase.PageSize))
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, (ulong)KPageTableBase.PageSize))
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
@@ -102,7 +102,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
|
||||
public KernelResult Unmap(ulong address, ulong size)
|
||||
{
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp(size, KPageTableBase.PageSize))
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, (ulong)KPageTableBase.PageSize))
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
@@ -128,7 +128,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
|
||||
public KernelResult UnmapFromOwner(ulong address, ulong size)
|
||||
{
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp(size, KPageTableBase.PageSize))
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, KPageTableBase.PageSize))
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
@@ -101,7 +101,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
for (int depth = HighestDepthIndex; depth >= 0; depth--)
|
||||
{
|
||||
_bitStorages[depth] = storage;
|
||||
size = BitUtils.DivRoundUp(size, UInt64BitSize);
|
||||
size = BitUtils.DivRoundUp<ulong>(size, (ulong)UInt64BitSize);
|
||||
storage = storage.Slice((int)size);
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
|
||||
for (int depth = GetRequiredDepth(regionSize) - 1; depth >= 0; depth--)
|
||||
{
|
||||
regionSize = BitUtils.DivRoundUp(regionSize, UInt64BitSize);
|
||||
regionSize = BitUtils.DivRoundUp<ulong>(regionSize, UInt64BitSize);
|
||||
overheadBits += (int)regionSize;
|
||||
}
|
||||
|
||||
|
@@ -48,7 +48,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
{
|
||||
int diff = 1 << (NextShift - Shift);
|
||||
|
||||
offset = BitUtils.AlignDown(offset, diff);
|
||||
offset = BitUtils.AlignDown(offset, (ulong)diff);
|
||||
|
||||
if (_bitmap.ClearRange(offset, diff))
|
||||
{
|
||||
|
@@ -203,8 +203,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
heapRegion.Size = 0x180000000;
|
||||
stackRegion.Size = 0x80000000;
|
||||
tlsIoRegion.Size = 0x1000000000;
|
||||
CodeRegionStart = BitUtils.AlignDown(address, 0x200000);
|
||||
codeRegionSize = BitUtils.AlignUp(endAddr, 0x200000) - CodeRegionStart;
|
||||
CodeRegionStart = BitUtils.AlignDown<ulong>(address, 0x200000);
|
||||
codeRegionSize = BitUtils.AlignUp<ulong>(endAddr, 0x200000) - CodeRegionStart;
|
||||
stackAndTlsIoStart = 0;
|
||||
stackAndTlsIoEnd = 0;
|
||||
baseAddress = 0x8000000;
|
||||
@@ -1584,8 +1584,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
return KernelResult.OutOfResource;
|
||||
}
|
||||
|
||||
ulong srcMapAddress = BitUtils.AlignUp(src, PageSize);
|
||||
ulong srcMapEndAddr = BitUtils.AlignDown(src + size, PageSize);
|
||||
ulong srcMapAddress = BitUtils.AlignUp<ulong>(src, PageSize);
|
||||
ulong srcMapEndAddr = BitUtils.AlignDown<ulong>(src + size, PageSize);
|
||||
ulong srcMapSize = srcMapEndAddr - srcMapAddress;
|
||||
|
||||
result = MapPagesFromClientProcess(size, src, permission, state, srcPageTable, send, out ulong va);
|
||||
@@ -1659,10 +1659,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
attributeMask |= MemoryAttribute.DeviceMapped;
|
||||
}
|
||||
|
||||
ulong addressRounded = BitUtils.AlignUp(address, PageSize);
|
||||
ulong addressTruncated = BitUtils.AlignDown(address, PageSize);
|
||||
ulong endAddrRounded = BitUtils.AlignUp(endAddr, PageSize);
|
||||
ulong endAddrTruncated = BitUtils.AlignDown(endAddr, PageSize);
|
||||
ulong addressRounded = BitUtils.AlignUp<ulong>(address, PageSize);
|
||||
ulong addressTruncated = BitUtils.AlignDown<ulong>(address, PageSize);
|
||||
ulong endAddrRounded = BitUtils.AlignUp<ulong>(endAddr, PageSize);
|
||||
ulong endAddrTruncated = BitUtils.AlignDown<ulong>(endAddr, PageSize);
|
||||
|
||||
if (!_slabManager.CanAllocate(MaxBlocksNeededForInsertion))
|
||||
{
|
||||
@@ -1769,10 +1769,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
|
||||
ulong endAddr = address + size;
|
||||
|
||||
ulong addressTruncated = BitUtils.AlignDown(address, PageSize);
|
||||
ulong addressRounded = BitUtils.AlignUp(address, PageSize);
|
||||
ulong endAddrTruncated = BitUtils.AlignDown(endAddr, PageSize);
|
||||
ulong endAddrRounded = BitUtils.AlignUp(endAddr, PageSize);
|
||||
ulong addressTruncated = BitUtils.AlignDown<ulong>(address, PageSize);
|
||||
ulong addressRounded = BitUtils.AlignUp<ulong>(address, PageSize);
|
||||
ulong endAddrTruncated = BitUtils.AlignDown<ulong>(endAddr, PageSize);
|
||||
ulong endAddrRounded = BitUtils.AlignUp<ulong>(endAddr, PageSize);
|
||||
|
||||
ulong neededSize = endAddrRounded - addressTruncated;
|
||||
|
||||
@@ -1983,10 +1983,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
return KernelResult.OutOfResource;
|
||||
}
|
||||
|
||||
ulong addressTruncated = BitUtils.AlignDown(address, PageSize);
|
||||
ulong addressRounded = BitUtils.AlignUp(address, PageSize);
|
||||
ulong endAddrTruncated = BitUtils.AlignDown(endAddr, PageSize);
|
||||
ulong endAddrRounded = BitUtils.AlignUp(endAddr, PageSize);
|
||||
ulong addressTruncated = BitUtils.AlignDown<ulong>(address, PageSize);
|
||||
ulong addressRounded = BitUtils.AlignUp<ulong>(address, PageSize);
|
||||
ulong endAddrTruncated = BitUtils.AlignDown<ulong>(endAddr, PageSize);
|
||||
ulong endAddrRounded = BitUtils.AlignUp<ulong>(endAddr, PageSize);
|
||||
|
||||
ulong pagesCount = (endAddrRounded - addressTruncated) / PageSize;
|
||||
|
||||
@@ -2010,10 +2010,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
{
|
||||
ulong endAddr = address + size;
|
||||
|
||||
ulong addressRounded = BitUtils.AlignUp(address, PageSize);
|
||||
ulong addressTruncated = BitUtils.AlignDown(address, PageSize);
|
||||
ulong endAddrRounded = BitUtils.AlignUp(endAddr, PageSize);
|
||||
ulong endAddrTruncated = BitUtils.AlignDown(endAddr, PageSize);
|
||||
ulong addressRounded = BitUtils.AlignUp<ulong>(address, PageSize);
|
||||
ulong addressTruncated = BitUtils.AlignDown<ulong>(address, PageSize);
|
||||
ulong endAddrRounded = BitUtils.AlignUp<ulong>(endAddr, PageSize);
|
||||
ulong endAddrTruncated = BitUtils.AlignDown<ulong>(endAddr, PageSize);
|
||||
|
||||
ulong pagesCount = addressRounded < endAddrTruncated ? (endAddrTruncated - addressRounded) / PageSize : 0;
|
||||
|
||||
@@ -2540,7 +2540,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
|
||||
for (int attempt = 0; attempt < 8; attempt++)
|
||||
{
|
||||
ulong aslrAddress = BitUtils.AlignDown(regionStart + GetRandomValue(0, aslrMaxOffset) * (ulong)alignment, alignment);
|
||||
ulong aslrAddress = BitUtils.AlignDown(regionStart + GetRandomValue(0, aslrMaxOffset) * (ulong)alignment, (ulong)alignment);
|
||||
ulong aslrEndAddr = aslrAddress + totalNeededSize;
|
||||
|
||||
KMemoryInfo info = _blockManager.FindBlock(aslrAddress).GetInfo();
|
||||
@@ -2618,7 +2618,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
|
||||
currBaseAddr += reservedSize;
|
||||
|
||||
ulong address = BitUtils.AlignDown(currBaseAddr, alignment) + reservedStart;
|
||||
ulong address = BitUtils.AlignDown<ulong>(currBaseAddr, (ulong)alignment) + reservedStart;
|
||||
|
||||
if (currBaseAddr > address)
|
||||
{
|
||||
@@ -2834,7 +2834,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
{
|
||||
lock (_blockManager)
|
||||
{
|
||||
return BitUtils.DivRoundUp(GetMmUsedSize(), PageSize);
|
||||
return BitUtils.DivRoundUp<ulong>(GetMmUsedSize(), PageSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
KProcess process,
|
||||
KMemoryPermission permission)
|
||||
{
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp(size, KPageTableBase.PageSize))
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, KPageTableBase.PageSize))
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
|
||||
public KernelResult UnmapFromProcess(KPageTableBase memoryManager, ulong address, ulong size, KProcess process)
|
||||
{
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp(size, KPageTableBase.PageSize))
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, KPageTableBase.PageSize))
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
@@ -67,7 +67,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
KProcess process,
|
||||
KMemoryPermission permission)
|
||||
{
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp(size, KPageTableBase.PageSize))
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, KPageTableBase.PageSize))
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
@@ -95,7 +95,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
ulong size,
|
||||
KProcess process)
|
||||
{
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp(size, KPageTableBase.PageSize))
|
||||
if (_pageList.GetPagesCount() != BitUtils.DivRoundUp<ulong>(size, (ulong)KPageTableBase.PageSize))
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
@@ -472,7 +472,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
|
||||
public KernelResult FreeThreadLocalStorage(ulong tlsSlotAddr)
|
||||
{
|
||||
ulong tlsPageAddr = BitUtils.AlignDown(tlsSlotAddr, KPageTableBase.PageSize);
|
||||
ulong tlsPageAddr = BitUtils.AlignDown<ulong>(tlsSlotAddr, KPageTableBase.PageSize);
|
||||
|
||||
KernelContext.CriticalSection.Enter();
|
||||
|
||||
@@ -554,7 +554,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
throw new InvalidOperationException("Trying to start a process with a invalid state!");
|
||||
}
|
||||
|
||||
ulong stackSizeRounded = BitUtils.AlignUp(stackSize, KPageTableBase.PageSize);
|
||||
ulong stackSizeRounded = BitUtils.AlignUp<ulong>(stackSize, KPageTableBase.PageSize);
|
||||
|
||||
ulong neededSize = stackSizeRounded + _imageSize;
|
||||
|
||||
|
@@ -47,7 +47,7 @@ namespace Ryujinx.HLE.HOS
|
||||
endOffset = kip.BssOffset + kip.BssSize;
|
||||
}
|
||||
|
||||
uint codeSize = BitUtils.AlignUp(kip.TextOffset + endOffset, KPageTableBase.PageSize);
|
||||
uint codeSize = BitUtils.AlignUp<uint>(kip.TextOffset + endOffset, KPageTableBase.PageSize);
|
||||
|
||||
int codePagesCount = (int)(codeSize / KPageTableBase.PageSize);
|
||||
|
||||
@@ -195,7 +195,7 @@ namespace Ryujinx.HLE.HOS
|
||||
nsoSize = dataEnd;
|
||||
}
|
||||
|
||||
nsoSize = BitUtils.AlignUp(nsoSize, KPageTableBase.PageSize);
|
||||
nsoSize = BitUtils.AlignUp<uint>(nsoSize, KPageTableBase.PageSize);
|
||||
|
||||
nsoBase[index] = codeStart + (ulong)codeSize;
|
||||
|
||||
@@ -349,7 +349,7 @@ namespace Ryujinx.HLE.HOS
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
size = BitUtils.AlignUp(size, KPageTableBase.PageSize);
|
||||
size = BitUtils.AlignUp<ulong>(size, KPageTableBase.PageSize);
|
||||
|
||||
return process.MemoryManager.SetProcessMemoryPermission(address, size, permission);
|
||||
}
|
||||
|
@@ -4,8 +4,6 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||
{
|
||||
public class UserProfile
|
||||
{
|
||||
private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
public UserId UserId { get; }
|
||||
|
||||
public long LastModifiedTimestamp { get; set; }
|
||||
@@ -83,7 +81,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||
|
||||
private void UpdateLastModifiedTimestamp()
|
||||
{
|
||||
LastModifiedTimestamp = (long)(DateTime.Now - Epoch).TotalSeconds;
|
||||
LastModifiedTimestamp = (long)(DateTime.Now - DateTime.UnixEpoch).TotalSeconds;
|
||||
}
|
||||
}
|
||||
}
|
@@ -100,27 +100,24 @@ namespace Ryujinx.HLE.HOS.Services.Caps
|
||||
Unknown0x1f = 1
|
||||
};
|
||||
|
||||
using (SHA256 sha256Hash = SHA256.Create())
|
||||
// NOTE: The hex hash is a HMAC-SHA256 (first 32 bytes) using a hardcoded secret key over the titleId, we can simulate it by hashing the titleId instead.
|
||||
string hash = BitConverter.ToString(SHA256.HashData(BitConverter.GetBytes(titleId))).Replace("-", "").Remove(0x20);
|
||||
string folderPath = Path.Combine(_sdCardPath, "Nintendo", "Album", currentDateTime.Year.ToString("00"), currentDateTime.Month.ToString("00"), currentDateTime.Day.ToString("00"));
|
||||
string filePath = GenerateFilePath(folderPath, applicationAlbumEntry, currentDateTime, hash);
|
||||
|
||||
// TODO: Handle that using the FS service implementation and return the right error code instead of throwing exceptions.
|
||||
Directory.CreateDirectory(folderPath);
|
||||
|
||||
while (File.Exists(filePath))
|
||||
{
|
||||
// NOTE: The hex hash is a HMAC-SHA256 (first 32 bytes) using a hardcoded secret key over the titleId, we can simulate it by hashing the titleId instead.
|
||||
string hash = BitConverter.ToString(sha256Hash.ComputeHash(BitConverter.GetBytes(titleId))).Replace("-", "").Remove(0x20);
|
||||
string folderPath = Path.Combine(_sdCardPath, "Nintendo", "Album", currentDateTime.Year.ToString("00"), currentDateTime.Month.ToString("00"), currentDateTime.Day.ToString("00"));
|
||||
string filePath = GenerateFilePath(folderPath, applicationAlbumEntry, currentDateTime, hash);
|
||||
applicationAlbumEntry.AlbumFileDateTime.UniqueId++;
|
||||
|
||||
// TODO: Handle that using the FS service implementation and return the right error code instead of throwing exceptions.
|
||||
Directory.CreateDirectory(folderPath);
|
||||
|
||||
while (File.Exists(filePath))
|
||||
{
|
||||
applicationAlbumEntry.AlbumFileDateTime.UniqueId++;
|
||||
|
||||
filePath = GenerateFilePath(folderPath, applicationAlbumEntry, currentDateTime, hash);
|
||||
}
|
||||
|
||||
// NOTE: The saved JPEG file doesn't have the limitation in the extra EXIF data.
|
||||
Image.LoadPixelData<Rgba32>(screenshotData, 1280, 720).SaveAsJpegAsync(filePath);
|
||||
filePath = GenerateFilePath(folderPath, applicationAlbumEntry, currentDateTime, hash);
|
||||
}
|
||||
|
||||
// NOTE: The saved JPEG file doesn't have the limitation in the extra EXIF data.
|
||||
Image.LoadPixelData<Rgba32>(screenshotData, 1280, 720).SaveAsJpegAsync(filePath);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,6 @@
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
||||
{
|
||||
@@ -29,7 +28,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"UserPresence {{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status}, AppKeyValueStorage: {Encoding.ASCII.GetString(AppKeyValueStorage)} }}";
|
||||
return $"UserPresence {{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status} }}";
|
||||
}
|
||||
}
|
||||
}
|
@@ -589,9 +589,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||
|
||||
ulong outputPosition = context.Request.RecvListBuff[0].Position;
|
||||
|
||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf(typeof(TagInfo)));
|
||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf<TagInfo>());
|
||||
|
||||
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(TagInfo)));
|
||||
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf<TagInfo>());
|
||||
|
||||
uint deviceHandle = (uint)context.RequestData.ReadUInt64();
|
||||
|
||||
@@ -665,9 +665,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||
|
||||
ulong outputPosition = context.Request.RecvListBuff[0].Position;
|
||||
|
||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf(typeof(RegisterInfo)));
|
||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf<RegisterInfo>());
|
||||
|
||||
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(RegisterInfo)));
|
||||
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf<RegisterInfo>());
|
||||
|
||||
uint deviceHandle = (uint)context.RequestData.ReadUInt64();
|
||||
|
||||
@@ -728,9 +728,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||
|
||||
ulong outputPosition = context.Request.RecvListBuff[0].Position;
|
||||
|
||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf(typeof(CommonInfo)));
|
||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf<CommonInfo>());
|
||||
|
||||
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(CommonInfo)));
|
||||
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf<CommonInfo>());
|
||||
|
||||
uint deviceHandle = (uint)context.RequestData.ReadUInt64();
|
||||
|
||||
@@ -788,9 +788,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||
|
||||
ulong outputPosition = context.Request.RecvListBuff[0].Position;
|
||||
|
||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf(typeof(ModelInfo)));
|
||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf<ModelInfo>());
|
||||
|
||||
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf(typeof(ModelInfo)));
|
||||
MemoryHelper.FillWithZeros(context.Memory, outputPosition, Marshal.SizeOf<ModelInfo>());
|
||||
|
||||
uint deviceHandle = (uint)context.RequestData.ReadUInt64();
|
||||
|
||||
|
@@ -8,6 +8,8 @@ using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostDbgGpu;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostProfGpu;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
||||
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
||||
using Ryujinx.Memory;
|
||||
@@ -23,7 +25,13 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
[Service("nvdrv:t")]
|
||||
class INvDrvServices : IpcService
|
||||
{
|
||||
private static Dictionary<string, Type> _deviceFileRegistry = new Dictionary<string, Type>()
|
||||
private static readonly List<string> _deviceFileDebugRegistry = new List<string>()
|
||||
{
|
||||
"/dev/nvhost-dbg-gpu",
|
||||
"/dev/nvhost-prof-gpu"
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, Type> _deviceFileRegistry = new Dictionary<string, Type>()
|
||||
{
|
||||
{ "/dev/nvmap", typeof(NvMapDeviceFile) },
|
||||
{ "/dev/nvhost-ctrl", typeof(NvHostCtrlDeviceFile) },
|
||||
@@ -35,6 +43,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
//{ "/dev/nvhost-nvjpg", typeof(NvHostChannelDeviceFile) },
|
||||
{ "/dev/nvhost-vic", typeof(NvHostChannelDeviceFile) },
|
||||
//{ "/dev/nvhost-display", typeof(NvHostChannelDeviceFile) },
|
||||
{ "/dev/nvhost-dbg-gpu", typeof(NvHostDbgGpuDeviceFile) },
|
||||
{ "/dev/nvhost-prof-gpu", typeof(NvHostProfGpuDeviceFile) },
|
||||
};
|
||||
|
||||
public static IdDictionary DeviceFileIdRegistry = new IdDictionary();
|
||||
@@ -44,13 +54,23 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
|
||||
private bool _transferMemInitialized = false;
|
||||
|
||||
// TODO: This should call set:sys::GetDebugModeFlag
|
||||
private bool _debugModeEnabled = false;
|
||||
|
||||
public INvDrvServices(ServiceCtx context) : base(context.Device.System.NvDrvServer)
|
||||
{
|
||||
_owner = 0;
|
||||
}
|
||||
|
||||
private int Open(ServiceCtx context, string path)
|
||||
private NvResult Open(ServiceCtx context, string path, out int fd)
|
||||
{
|
||||
fd = -1;
|
||||
|
||||
if (!_debugModeEnabled && _deviceFileDebugRegistry.Contains(path))
|
||||
{
|
||||
return NvResult.NotSupported;
|
||||
}
|
||||
|
||||
if (_deviceFileRegistry.TryGetValue(path, out Type deviceFileClass))
|
||||
{
|
||||
ConstructorInfo constructor = deviceFileClass.GetConstructor(new Type[] { typeof(ServiceCtx), typeof(IVirtualMemoryManager), typeof(ulong) });
|
||||
@@ -59,14 +79,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
|
||||
deviceFile.Path = path;
|
||||
|
||||
return DeviceFileIdRegistry.Add(deviceFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceNv, $"Cannot find file device \"{path}\"!");
|
||||
fd = DeviceFileIdRegistry.Add(deviceFile);
|
||||
|
||||
return NvResult.Success;
|
||||
}
|
||||
|
||||
return -1;
|
||||
Logger.Warning?.Print(LogClass.ServiceNv, $"Cannot find file device \"{path}\"!");
|
||||
|
||||
return NvResult.FileOperationFailed;
|
||||
}
|
||||
|
||||
private NvResult GetIoctlArgument(ServiceCtx context, NvIoctl ioctlCommand, out Span<byte> arguments)
|
||||
@@ -229,12 +249,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
||||
|
||||
string path = MemoryHelper.ReadAsciiString(context.Memory, pathPtr, (long)pathSize);
|
||||
|
||||
fd = Open(context, path);
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
errorCode = NvResult.FileOperationFailed;
|
||||
}
|
||||
errorCode = Open(context, path, out fd);
|
||||
}
|
||||
|
||||
context.ResponseData.Write(fd);
|
||||
|
@@ -0,0 +1,11 @@
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostDbgGpu
|
||||
{
|
||||
class NvHostDbgGpuDeviceFile : NvDeviceFile
|
||||
{
|
||||
public NvHostDbgGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, ulong owner) : base(context, owner) { }
|
||||
|
||||
public override void Close() { }
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
using Ryujinx.Memory;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostProfGpu
|
||||
{
|
||||
class NvHostProfGpuDeviceFile : NvDeviceFile
|
||||
{
|
||||
public NvHostProfGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, ulong owner) : base(context, owner) { }
|
||||
|
||||
public override void Close() { }
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user