mirror of
https://git.ryujinx.app/kenji-nx/ryujinx.git
synced 2025-12-14 07:37:04 +00:00
misc: chore: Fix numerous NullReferenceExceptions, InvalidOperationExceptions
This commit is contained in:
parent
a90db3464d
commit
d2a532f971
90 changed files with 667 additions and 533 deletions
|
|
@ -59,7 +59,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
|
|
||||||
for (int y = 0; y < context.SampleCount; y++)
|
for (int y = 0; y < context.SampleCount; y++)
|
||||||
{
|
{
|
||||||
context.MemoryManager.Write(targetOffset + (ulong)y * TargetChannelCount, PcmHelper.Saturate(inputBuffer[y]));
|
if (inputBuffer != null)
|
||||||
|
{
|
||||||
|
context.MemoryManager.Write(targetOffset + (ulong)y * TargetChannelCount,
|
||||||
|
PcmHelper.Saturate(inputBuffer[y]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentOffset += context.SampleCount * TargetChannelCount;
|
currentOffset += context.SampleCount * TargetChannelCount;
|
||||||
|
|
|
||||||
|
|
@ -318,14 +318,17 @@ namespace Ryujinx.Common.Collections
|
||||||
{
|
{
|
||||||
Root = newNode;
|
Root = newNode;
|
||||||
}
|
}
|
||||||
else if (start.CompareTo(parent.Start) < 0)
|
else if (parent != null && start.CompareTo(parent.Start) < 0)
|
||||||
{
|
{
|
||||||
parent.Left = newNode;
|
parent.Left = newNode;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (parent != null)
|
||||||
{
|
{
|
||||||
parent.Right = newNode;
|
parent.Right = newNode;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PropagateIncrease(newNode);
|
PropagateIncrease(newNode);
|
||||||
Count++;
|
Count++;
|
||||||
|
|
|
||||||
|
|
@ -279,14 +279,17 @@ namespace Ryujinx.Common.Collections
|
||||||
{
|
{
|
||||||
Root = newNode;
|
Root = newNode;
|
||||||
}
|
}
|
||||||
else if (key.CompareTo(parent.Key) < 0)
|
else if (parent != null && key.CompareTo(parent.Key) < 0)
|
||||||
{
|
{
|
||||||
parent.Left = newNode;
|
parent.Left = newNode;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (parent != null)
|
||||||
{
|
{
|
||||||
parent.Right = newNode;
|
parent.Right = newNode;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Count++;
|
Count++;
|
||||||
return newNode;
|
return newNode;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -273,7 +273,7 @@ namespace Ryujinx.Common.Configuration
|
||||||
{
|
{
|
||||||
FileSystemInfo resolvedDirectoryInfo =
|
FileSystemInfo resolvedDirectoryInfo =
|
||||||
Directory.ResolveLinkTarget(correctApplicationDataDirectoryPath, true);
|
Directory.ResolveLinkTarget(correctApplicationDataDirectoryPath, true);
|
||||||
string resolvedPath = resolvedDirectoryInfo.FullName;
|
string resolvedPath = resolvedDirectoryInfo?.FullName;
|
||||||
Logger.Error?.Print(LogClass.Application, $"Please manually move your Ryujinx data from {resolvedPath} to {correctApplicationDataDirectoryPath}, and remove the symlink.");
|
Logger.Error?.Print(LogClass.Application, $"Please manually move your Ryujinx data from {resolvedPath} to {correctApplicationDataDirectoryPath}, and remove the symlink.");
|
||||||
}
|
}
|
||||||
catch (Exception symlinkException)
|
catch (Exception symlinkException)
|
||||||
|
|
@ -297,7 +297,7 @@ namespace Ryujinx.Common.Configuration
|
||||||
{
|
{
|
||||||
FileSystemInfo resolvedDirectoryInfo =
|
FileSystemInfo resolvedDirectoryInfo =
|
||||||
Directory.ResolveLinkTarget(correctApplicationDataDirectoryPath, true);
|
Directory.ResolveLinkTarget(correctApplicationDataDirectoryPath, true);
|
||||||
string resolvedPath = resolvedDirectoryInfo.FullName;
|
string resolvedPath = resolvedDirectoryInfo?.FullName;
|
||||||
Logger.Error?.Print(LogClass.Application, $"Please manually move your Ryujinx data from {resolvedPath} to {correctApplicationDataDirectoryPath}, and remove the symlink.");
|
Logger.Error?.Print(LogClass.Application, $"Please manually move your Ryujinx data from {resolvedPath} to {correctApplicationDataDirectoryPath}, and remove the symlink.");
|
||||||
}
|
}
|
||||||
catch (Exception symlinkException)
|
catch (Exception symlinkException)
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
||||||
{
|
{
|
||||||
string propertyName = tempReader.GetString();
|
string propertyName = tempReader.GetString();
|
||||||
|
|
||||||
if (propertyName.Equals("motion_backend"))
|
if (propertyName is "motion_backend")
|
||||||
{
|
{
|
||||||
tempReader.Read();
|
tempReader.Read();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ namespace Ryujinx.Common.Configuration.Hid
|
||||||
{
|
{
|
||||||
string propertyName = tempReader.GetString();
|
string propertyName = tempReader.GetString();
|
||||||
|
|
||||||
if (propertyName.Equals("backend"))
|
if (propertyName is "backend")
|
||||||
{
|
{
|
||||||
tempReader.Read();
|
tempReader.Read();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ namespace Ryujinx.Common.Logging
|
||||||
public readonly struct Log
|
public readonly struct Log
|
||||||
{
|
{
|
||||||
private static readonly string _homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
private static readonly string _homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||||
private static readonly string _homeDirRedacted = Path.Combine(Directory.GetParent(_homeDir).FullName, "[redacted]");
|
private static readonly string _homeDirRedacted = Path.Combine(Directory.GetParent(_homeDir)?.FullName ?? string.Empty, "[redacted]");
|
||||||
|
|
||||||
internal readonly LogLevel Level;
|
internal readonly LogLevel Level;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -258,6 +258,8 @@ namespace ARMeilleure.Common
|
||||||
for (int i = 0; i < Levels.Length - 1; i++)
|
for (int i = 0; i < Levels.Length - 1; i++)
|
||||||
{
|
{
|
||||||
ref AddressTableLevel level = ref Levels[i];
|
ref AddressTableLevel level = ref Levels[i];
|
||||||
|
if (page != null)
|
||||||
|
{
|
||||||
ref TEntry* nextPage = ref page[level.GetValue(address)];
|
ref TEntry* nextPage = ref page[level.GetValue(address)];
|
||||||
|
|
||||||
if (nextPage == null || nextPage == _fillBottomLevelPtr)
|
if (nextPage == null || nextPage == _fillBottomLevelPtr)
|
||||||
|
|
@ -276,6 +278,7 @@ namespace ARMeilleure.Common
|
||||||
|
|
||||||
page = (TEntry**)nextPage;
|
page = (TEntry**)nextPage;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (TEntry*)page;
|
return (TEntry*)page;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -388,9 +388,14 @@ namespace Ryujinx.Cpu.Jit.HostTracked
|
||||||
_treeLock.ExitReadLock();
|
_treeLock.ExitReadLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_firstPagePa != null)
|
||||||
|
{
|
||||||
return (_backingMemory, _firstPagePa.Value);
|
return (_backingMemory, _firstPagePa.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (null, 0);
|
||||||
|
}
|
||||||
|
|
||||||
public PrivateRange GetPrivateAllocation(ulong va)
|
public PrivateRange GetPrivateAllocation(ulong va)
|
||||||
{
|
{
|
||||||
_treeLock.EnterReadLock();
|
_treeLock.EnterReadLock();
|
||||||
|
|
|
||||||
|
|
@ -135,8 +135,11 @@ namespace Ryujinx.Cpu.Jit
|
||||||
offset += (int)copySize;
|
offset += (int)copySize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (last != null)
|
||||||
|
{
|
||||||
return new ReadOnlySequence<byte>(first, 0, last, (int)(size - last.RunningIndex));
|
return new ReadOnlySequence<byte>(first, 0, last, (int)(size - last.RunningIndex));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (InvalidMemoryRegionException)
|
catch (InvalidMemoryRegionException)
|
||||||
{
|
{
|
||||||
if (_invalidAccessHandler == null || !_invalidAccessHandler(va))
|
if (_invalidAccessHandler == null || !_invalidAccessHandler(va))
|
||||||
|
|
@ -146,6 +149,8 @@ namespace Ryujinx.Cpu.Jit
|
||||||
|
|
||||||
return ReadOnlySequence<byte>.Empty;
|
return ReadOnlySequence<byte>.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|
|
||||||
|
|
@ -872,7 +872,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
||||||
|
|
||||||
if (unscaled)
|
if (unscaled)
|
||||||
{
|
{
|
||||||
writeInstUnscaled(rt, tempRegister.Operand, offs);
|
writeInstUnscaled?.Invoke(rt, tempRegister.Operand, offs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||||
|
|
||||||
if (Volatile.Read(ref _interruptAction) != null)
|
if (Volatile.Read(ref _interruptAction) != null)
|
||||||
{
|
{
|
||||||
_interruptAction();
|
_interruptAction?.Invoke();
|
||||||
_interruptRun.Set();
|
_interruptRun.Set();
|
||||||
|
|
||||||
Interlocked.Exchange(ref _interruptAction, null);
|
Interlocked.Exchange(ref _interruptAction, null);
|
||||||
|
|
|
||||||
|
|
@ -297,7 +297,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||||
EmitLoadGprA(opCode);
|
EmitLoadGprA(opCode);
|
||||||
EmitLoadImm(opCode);
|
EmitLoadImm(opCode);
|
||||||
_ilGen.Emit(OpCodes.Add);
|
_ilGen.Emit(OpCodes.Add);
|
||||||
_ilGen.Emit(OpCodes.Call, typeof(MacroJitContext).GetMethod(nameof(MacroJitContext.Read)));
|
_ilGen.Emit(OpCodes.Call, typeof(MacroJitContext).GetMethod(nameof(MacroJitContext.Read))!);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -457,7 +457,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||||
private void EmitFetchParam()
|
private void EmitFetchParam()
|
||||||
{
|
{
|
||||||
_ilGen.Emit(OpCodes.Ldarg_0);
|
_ilGen.Emit(OpCodes.Ldarg_0);
|
||||||
_ilGen.Emit(OpCodes.Call, typeof(MacroJitContext).GetMethod(nameof(MacroJitContext.FetchParam)));
|
_ilGen.Emit(OpCodes.Call, typeof(MacroJitContext).GetMethod(nameof(MacroJitContext.FetchParam))!);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -508,7 +508,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||||
{
|
{
|
||||||
_ilGen.Emit(OpCodes.Ldarg_1);
|
_ilGen.Emit(OpCodes.Ldarg_1);
|
||||||
_ilGen.Emit(OpCodes.Ldloc_S, _methAddr);
|
_ilGen.Emit(OpCodes.Ldloc_S, _methAddr);
|
||||||
_ilGen.Emit(OpCodes.Call, typeof(MacroJitContext).GetMethod(nameof(MacroJitContext.Send)));
|
_ilGen.Emit(OpCodes.Call, typeof(MacroJitContext).GetMethod(nameof(MacroJitContext.Send))!);
|
||||||
_ilGen.Emit(OpCodes.Ldloc_S, _methAddr);
|
_ilGen.Emit(OpCodes.Ldloc_S, _methAddr);
|
||||||
_ilGen.Emit(OpCodes.Ldloc_S, _methIncr);
|
_ilGen.Emit(OpCodes.Ldloc_S, _methIncr);
|
||||||
_ilGen.Emit(OpCodes.Add);
|
_ilGen.Emit(OpCodes.Add);
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// Removes the least used texture from the cache.
|
/// Removes the least used texture from the cache.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void RemoveLeastUsedTexture()
|
private void RemoveLeastUsedTexture()
|
||||||
|
{
|
||||||
|
if (_textures.First != null)
|
||||||
{
|
{
|
||||||
Texture oldestTexture = _textures.First.Value;
|
Texture oldestTexture = _textures.First.Value;
|
||||||
|
|
||||||
|
|
@ -192,6 +194,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
oldestTexture.DecrementReferenceCount();
|
oldestTexture.DecrementReferenceCount();
|
||||||
oldestTexture.CacheNode = null;
|
oldestTexture.CacheNode = null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes a texture from the cache.
|
/// Removes a texture from the cache.
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
public T FindOrCreate(GpuChannel channel, ulong address, int maximumId, TextureBindingsArrayCache bindingsArrayCache)
|
public T FindOrCreate(GpuChannel channel, ulong address, int maximumId, TextureBindingsArrayCache bindingsArrayCache)
|
||||||
{
|
{
|
||||||
// Remove old entries from the cache, if possible.
|
// Remove old entries from the cache, if possible.
|
||||||
while (_pools.Count > MaxCapacity && (_currentTimestamp - _pools.First.Value.CacheTimestamp) >= MinDeltaForRemoval)
|
while (_pools.Count > MaxCapacity && _pools.First != null &&
|
||||||
|
(_currentTimestamp - _pools.First.Value.CacheTimestamp) >= MinDeltaForRemoval)
|
||||||
{
|
{
|
||||||
T oldestPool = _pools.First.Value;
|
T oldestPool = _pools.First.Value;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -372,7 +372,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
if (rangeCount == -1)
|
if (rangeCount == -1)
|
||||||
{
|
{
|
||||||
_migrationTarget.WaitForAndFlushRanges(address, size);
|
_migrationTarget?.WaitForAndFlushRanges(address, size);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -481,7 +481,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = Unsafe.SizeOf<TocHeader>() + programIndex * Unsafe.SizeOf<OffsetAndSize>();
|
int offset = Unsafe.SizeOf<TocHeader>() + programIndex * Unsafe.SizeOf<OffsetAndSize>();
|
||||||
if (offset + Unsafe.SizeOf<OffsetAndSize>() > tocFileStream.Length)
|
if (tocFileStream != null && offset + Unsafe.SizeOf<OffsetAndSize>() > tocFileStream.Length)
|
||||||
{
|
{
|
||||||
return (null, null);
|
return (null, null);
|
||||||
}
|
}
|
||||||
|
|
@ -491,7 +491,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||||
throw new DiskCacheLoadException(DiskCacheLoadResult.FileCorruptedGeneric);
|
throw new DiskCacheLoadException(DiskCacheLoadResult.FileCorruptedGeneric);
|
||||||
}
|
}
|
||||||
|
|
||||||
tocFileStream.Seek(offset, SeekOrigin.Begin);
|
tocFileStream?.Seek(offset, SeekOrigin.Begin);
|
||||||
|
|
||||||
BinarySerializer tocReader = new(tocFileStream);
|
BinarySerializer tocReader = new(tocFileStream);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -990,10 +990,13 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
dataWriter.Write(ref hasPipelineState);
|
dataWriter.Write(ref hasPipelineState);
|
||||||
|
|
||||||
if (hasPipelineState)
|
if (hasPipelineState)
|
||||||
|
{
|
||||||
|
if (PipelineState != null)
|
||||||
{
|
{
|
||||||
ProgramPipelineState pipelineState = PipelineState.Value;
|
ProgramPipelineState pipelineState = PipelineState.Value;
|
||||||
dataWriter.WriteWithMagicAndSize(ref pipelineState, PgpsMagic);
|
dataWriter.WriteWithMagicAndSize(ref pipelineState, PgpsMagic);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_queriedState.HasFlag(QueriedStateFlags.TransformFeedback))
|
if (_queriedState.HasFlag(QueriedStateFlags.TransformFeedback))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
|
||||||
|
|
||||||
FFmpegApi.av_log_format_line(ptr, level, format, vl, lineBuffer, lineSize, &printPrefix);
|
FFmpegApi.av_log_format_line(ptr, level, format, vl, lineBuffer, lineSize, &printPrefix);
|
||||||
|
|
||||||
string line = Marshal.PtrToStringAnsi((IntPtr)lineBuffer).Trim();
|
string line = Marshal.PtrToStringAnsi((IntPtr)lineBuffer)?.Trim();
|
||||||
|
|
||||||
switch (level)
|
switch (level)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
IntPtr message,
|
IntPtr message,
|
||||||
IntPtr userParam)
|
IntPtr userParam)
|
||||||
{
|
{
|
||||||
string msg = Marshal.PtrToStringUTF8(message).Replace('\n', ' ');
|
string msg = Marshal.PtrToStringUTF8(message)?.Replace('\n', ' ');
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
||||||
GL.UseProgram(previousProgram);
|
GL.UseProgram(previousProgram);
|
||||||
GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
|
GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
|
||||||
|
|
||||||
(_renderer.Pipeline as Pipeline).RestoreImages1And2();
|
(_renderer.Pipeline as Pipeline)?.RestoreImages1And2();
|
||||||
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
GL.ActiveTexture(TextureUnit.Texture0);
|
||||||
GL.BindTexture(TextureTarget.Texture2D, previousTextureBinding);
|
GL.BindTexture(TextureTarget.Texture2D, previousTextureBinding);
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,10 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
GL.ActiveTexture(TextureUnit.Texture0);
|
||||||
int previousTextureBinding = GL.GetInteger(GetPName.TextureBinding2D);
|
int previousTextureBinding = GL.GetInteger(GetPName.TextureBinding2D);
|
||||||
|
|
||||||
GL.BindImageTexture(0, textureView.Handle, 0, false, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
|
if (textureView != null)
|
||||||
|
{
|
||||||
|
GL.BindImageTexture(0, textureView.Handle, 0, false, 0, TextureAccess.ReadWrite,
|
||||||
|
SizedInternalFormat.Rgba8);
|
||||||
|
|
||||||
int threadGroupWorkRegionDim = 16;
|
int threadGroupWorkRegionDim = 16;
|
||||||
int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||||
|
|
@ -156,17 +159,19 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
||||||
|
|
||||||
// Sharpening Pass
|
// Sharpening Pass
|
||||||
GL.UseProgram(_sharpeningShaderProgram);
|
GL.UseProgram(_sharpeningShaderProgram);
|
||||||
GL.BindImageTexture(0, destinationTexture.Handle, 0, false, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
|
GL.BindImageTexture(0, destinationTexture.Handle, 0, false, 0, TextureAccess.ReadWrite,
|
||||||
|
SizedInternalFormat.Rgba8);
|
||||||
textureView.Bind(0);
|
textureView.Bind(0);
|
||||||
GL.Uniform1(_inputUniform, 0);
|
GL.Uniform1(_inputUniform, 0);
|
||||||
GL.Uniform1(_outputUniform, 0);
|
GL.Uniform1(_outputUniform, 0);
|
||||||
GL.Uniform1(_sharpeningUniform, 1.5f - (Level * 0.01f * 1.5f));
|
GL.Uniform1(_sharpeningUniform, 1.5f - (Level * 0.01f * 1.5f));
|
||||||
GL.DispatchCompute(dispatchX, dispatchY, 1);
|
GL.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
|
}
|
||||||
|
|
||||||
GL.UseProgram(previousProgram);
|
GL.UseProgram(previousProgram);
|
||||||
GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
|
GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
|
||||||
|
|
||||||
(_renderer.Pipeline as Pipeline).RestoreImages1And2();
|
(_renderer.Pipeline as Pipeline)?.RestoreImages1And2();
|
||||||
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
GL.ActiveTexture(TextureUnit.Texture0);
|
||||||
GL.BindTexture(TextureTarget.Texture2D, previousTextureBinding);
|
GL.BindTexture(TextureTarget.Texture2D, previousTextureBinding);
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
||||||
GL.UseProgram(previousProgram);
|
GL.UseProgram(previousProgram);
|
||||||
GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
|
GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
|
||||||
|
|
||||||
(_renderer.Pipeline as Pipeline).RestoreImages1And2();
|
(_renderer.Pipeline as Pipeline)?.RestoreImages1And2();
|
||||||
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
GL.ActiveTexture(TextureUnit.Texture0);
|
||||||
GL.BindTexture(TextureTarget.Texture2D, previousTextureBinding);
|
GL.BindTexture(TextureTarget.Texture2D, previousTextureBinding);
|
||||||
|
|
|
||||||
|
|
@ -222,8 +222,8 @@ namespace Ryujinx.Graphics.OpenGL.Effects.Smaa
|
||||||
GL.BindImageTexture(0, blendOutput.Handle, 0, false, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
|
GL.BindImageTexture(0, blendOutput.Handle, 0, false, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
|
||||||
GL.UseProgram(_blendShaderPrograms[Quality]);
|
GL.UseProgram(_blendShaderPrograms[Quality]);
|
||||||
edgeOutput.Bind(0);
|
edgeOutput.Bind(0);
|
||||||
areaTexture.Bind(1);
|
areaTexture?.Bind(1);
|
||||||
searchTexture.Bind(2);
|
searchTexture?.Bind(2);
|
||||||
GL.Uniform1(_inputUniform, 0);
|
GL.Uniform1(_inputUniform, 0);
|
||||||
GL.Uniform1(_outputUniform, 0);
|
GL.Uniform1(_outputUniform, 0);
|
||||||
GL.Uniform1(_samplerAreaUniform, 1);
|
GL.Uniform1(_samplerAreaUniform, 1);
|
||||||
|
|
@ -243,7 +243,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects.Smaa
|
||||||
GL.DispatchCompute(dispatchX, dispatchY, 1);
|
GL.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
|
GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
|
||||||
|
|
||||||
(_renderer.Pipeline as Pipeline).RestoreImages1And2();
|
(_renderer.Pipeline as Pipeline)?.RestoreImages1And2();
|
||||||
|
|
||||||
GL.UseProgram(previousProgram);
|
GL.UseProgram(previousProgram);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,9 +64,12 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||||
INode lastOp = GetLastOp();
|
INode lastOp = GetLastOp();
|
||||||
|
|
||||||
if (lastOp is Operation operation && IsControlFlowInst(operation.Inst))
|
if (lastOp is Operation operation && IsControlFlowInst(operation.Inst))
|
||||||
|
{
|
||||||
|
if (Operations.Last != null)
|
||||||
{
|
{
|
||||||
Operations.AddBefore(Operations.Last, node);
|
Operations.AddBefore(Operations.Last, node);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Operations.AddLast(node);
|
Operations.AddLast(node);
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handleAsgOp.Inst != Instruction.Load ||
|
if (handleAsgOp is not { Inst: Instruction.Load } ||
|
||||||
handleAsgOp.StorageKind != StorageKind.ConstantBuffer ||
|
handleAsgOp.StorageKind != StorageKind.ConstantBuffer ||
|
||||||
handleAsgOp.SourcesCount != 4)
|
handleAsgOp.SourcesCount != 4)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
|
|
||||||
operation.Dest = null;
|
operation.Dest = null;
|
||||||
|
|
||||||
LinkedListNode<INode> newNode = node.List.AddBefore(node, new Operation(Instruction.Call, 0, floatValue, callArgs));
|
LinkedListNode<INode> newNode = node.List?.AddBefore(node, new Operation(Instruction.Call, 0, floatValue, callArgs));
|
||||||
|
|
||||||
Utils.DeleteNode(node, operation);
|
Utils.DeleteNode(node, operation);
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
|
|
||||||
Operand[] callArgs = [Const(functionId), operation.GetSource(0), resultLow, resultHigh];
|
Operand[] callArgs = [Const(functionId), operation.GetSource(0), resultLow, resultHigh];
|
||||||
|
|
||||||
LinkedListNode<INode> newNode = node.List.AddBefore(node, new Operation(Instruction.Call, 0, (Operand)null, callArgs));
|
LinkedListNode<INode> newNode = node.List?.AddBefore(node, new Operation(Instruction.Call, 0, (Operand)null, callArgs));
|
||||||
|
|
||||||
Utils.DeleteNode(node, operation);
|
Utils.DeleteNode(node, operation);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -305,7 +305,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
LinkedListNode<INode> node)
|
LinkedListNode<INode> node)
|
||||||
{
|
{
|
||||||
Operation operation = node.Value as Operation;
|
Operation operation = node.Value as Operation;
|
||||||
Operand globalAddress = operation.GetSource(0);
|
Operand globalAddress = operation?.GetSource(0);
|
||||||
SearchResult result = FindUniqueBaseAddressCb(gtsContext, block, globalAddress, needsOffset: true);
|
SearchResult result = FindUniqueBaseAddressCb(gtsContext, block, globalAddress, needsOffset: true);
|
||||||
|
|
||||||
if (result.Found)
|
if (result.Found)
|
||||||
|
|
@ -331,8 +331,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
Operation maskOp = new(Instruction.BitwiseAnd, baseAddressMasked, baseAddress, Const(-alignment));
|
Operation maskOp = new(Instruction.BitwiseAnd, baseAddressMasked, baseAddress, Const(-alignment));
|
||||||
Operation subOp = new(Instruction.Subtract, hostOffset, globalAddress, baseAddressMasked);
|
Operation subOp = new(Instruction.Subtract, hostOffset, globalAddress, baseAddressMasked);
|
||||||
|
|
||||||
node.List.AddBefore(node, maskOp);
|
node.List?.AddBefore(node, maskOp);
|
||||||
node.List.AddBefore(node, subOp);
|
node.List?.AddBefore(node, subOp);
|
||||||
|
|
||||||
offset = hostOffset;
|
offset = hostOffset;
|
||||||
}
|
}
|
||||||
|
|
@ -342,7 +342,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
|
|
||||||
Operation addOp = new(Instruction.Add, newOffset, offset, Const(result.ConstOffset));
|
Operation addOp = new(Instruction.Add, newOffset, offset, Const(result.ConstOffset));
|
||||||
|
|
||||||
node.List.AddBefore(node, addOp);
|
node.List?.AddBefore(node, addOp);
|
||||||
|
|
||||||
offset = newOffset;
|
offset = newOffset;
|
||||||
}
|
}
|
||||||
|
|
@ -441,8 +441,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
Operation shiftOp = new(Instruction.ShiftRightU32, wordOffset, offset, Const(2));
|
Operation shiftOp = new(Instruction.ShiftRightU32, wordOffset, offset, Const(2));
|
||||||
Operation storageOp = new(operation.Inst, StorageKind.StorageBuffer, operation.Dest, sources);
|
Operation storageOp = new(operation.Inst, StorageKind.StorageBuffer, operation.Dest, sources);
|
||||||
|
|
||||||
node.List.AddBefore(node, shiftOp);
|
node.List?.AddBefore(node, shiftOp);
|
||||||
LinkedListNode<INode> newNode = node.List.AddBefore(node, storageOp);
|
LinkedListNode<INode> newNode = node.List?.AddBefore(node, storageOp);
|
||||||
|
|
||||||
Utils.DeleteNode(node, operation);
|
Utils.DeleteNode(node, operation);
|
||||||
|
|
||||||
|
|
@ -483,7 +483,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
|
|
||||||
Operation callOp = new(Instruction.Call, returnValue, sources);
|
Operation callOp = new(Instruction.Call, returnValue, sources);
|
||||||
|
|
||||||
LinkedListNode<INode> newNode = node.List.AddBefore(node, callOp);
|
LinkedListNode<INode> newNode = node.List?.AddBefore(node, callOp);
|
||||||
|
|
||||||
if (returnsValue)
|
if (returnsValue)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
|
|
||||||
public static void DeleteNode(LinkedListNode<INode> node, Operation operation)
|
public static void DeleteNode(LinkedListNode<INode> node, Operation operation)
|
||||||
{
|
{
|
||||||
node.List.Remove(node);
|
node.List?.Remove(node);
|
||||||
|
|
||||||
for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++)
|
for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
{
|
{
|
||||||
Operation operation = node.Value as Operation;
|
Operation operation = node.Value as Operation;
|
||||||
|
|
||||||
for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++)
|
for (int srcIndex = 0; srcIndex < operation?.SourcesCount; srcIndex++)
|
||||||
{
|
{
|
||||||
Operand source = operation.GetSource(srcIndex);
|
Operand source = operation.GetSource(srcIndex);
|
||||||
|
|
||||||
|
|
@ -155,7 +155,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
localInputs[block.Index] |= GetMask(register) & ~localOutputs[block.Index];
|
localInputs[block.Index] |= GetMask(register) & ~localOutputs[block.Index];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int dstIndex = 0; dstIndex < operation.DestsCount; dstIndex++)
|
for (int dstIndex = 0; dstIndex < operation?.DestsCount; dstIndex++)
|
||||||
{
|
{
|
||||||
Operand dest = operation.GetDest(dstIndex);
|
Operand dest = operation.GetDest(dstIndex);
|
||||||
|
|
||||||
|
|
@ -296,7 +296,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
{
|
{
|
||||||
Operation operation = node.Value as Operation;
|
Operation operation = node.Value as Operation;
|
||||||
|
|
||||||
if (operation.Inst == Instruction.Call)
|
if (operation?.Inst == Instruction.Call)
|
||||||
{
|
{
|
||||||
Operand funcId = operation.GetSource(0);
|
Operand funcId = operation.GetSource(0);
|
||||||
|
|
||||||
|
|
@ -333,7 +333,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return block.Operations.First.Value is Operation operation && operation.Inst == inst;
|
return block.Operations.First?.Value is Operation operation && operation.Inst == inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool EndsWith(BasicBlock block, Instruction inst)
|
private static bool EndsWith(BasicBlock block, Instruction inst)
|
||||||
|
|
@ -343,7 +343,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return block.Operations.Last.Value is Operation operation && operation.Inst == inst;
|
return block.Operations.Last?.Value is Operation operation && operation.Inst == inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RegisterMask GetMask(Register register)
|
private static RegisterMask GetMask(Register register)
|
||||||
|
|
@ -444,9 +444,12 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
Operation copyOp = new(Instruction.Copy, OperandHelper.Argument(argIndex++), OperandHelper.Register(register));
|
Operation copyOp = new(Instruction.Copy, OperandHelper.Argument(argIndex++), OperandHelper.Register(register));
|
||||||
|
|
||||||
if (node == null)
|
if (node == null)
|
||||||
|
{
|
||||||
|
if (block.Operations.Last != null)
|
||||||
{
|
{
|
||||||
node = block.Operations.AddBefore(block.Operations.Last, copyOp);
|
node = block.Operations.AddBefore(block.Operations.Last, copyOp);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
node = block.Operations.AddAfter(node, copyOp);
|
node = block.Operations.AddAfter(node, copyOp);
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
Operand GenerateLoad(IoVariable ioVariable)
|
Operand GenerateLoad(IoVariable ioVariable)
|
||||||
{
|
{
|
||||||
Operand value = Local();
|
Operand value = Local();
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Load, StorageKind.Input, value, Const((int)ioVariable)));
|
node.List?.AddBefore(node, new Operation(Instruction.Load, StorageKind.Input, value, Const((int)ioVariable)));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
|
|
||||||
Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, inputOffset, primVertex);
|
Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, inputOffset, primVertex);
|
||||||
|
|
||||||
newNode = node.List.AddBefore(node, new Operation(
|
newNode = node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.StorageBuffer,
|
StorageKind.StorageBuffer,
|
||||||
operation.Dest,
|
operation.Dest,
|
||||||
|
|
@ -80,7 +80,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
{
|
{
|
||||||
if (TryGetOffset(context.ResourceManager, operation, StorageKind.Output, out int outputOffset))
|
if (TryGetOffset(context.ResourceManager, operation, StorageKind.Output, out int outputOffset))
|
||||||
{
|
{
|
||||||
newNode = node.List.AddBefore(node, new Operation(
|
newNode = node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.LocalMemory,
|
StorageKind.LocalMemory,
|
||||||
operation.Dest,
|
operation.Dest,
|
||||||
|
|
@ -99,7 +99,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
{
|
{
|
||||||
Operand value = operation.GetSource(operation.SourcesCount - 1);
|
Operand value = operation.GetSource(operation.SourcesCount - 1);
|
||||||
|
|
||||||
newNode = node.List.AddBefore(node, new Operation(
|
newNode = node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Store,
|
Instruction.Store,
|
||||||
StorageKind.LocalMemory,
|
StorageKind.LocalMemory,
|
||||||
(Operand)null,
|
(Operand)null,
|
||||||
|
|
@ -134,7 +134,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
definitions.MaxOutputVertices * definitions.ThreadsPerInputPrimitive,
|
definitions.MaxOutputVertices * definitions.ThreadsPerInputPrimitive,
|
||||||
definitions.ThreadsPerInputPrimitive);
|
definitions.ThreadsPerInputPrimitive);
|
||||||
Operand outputBaseVertex = Local();
|
Operand outputBaseVertex = Local();
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Add, outputBaseVertex, new[] { baseVertexOffset, outputPrimVertex }));
|
node.List?.AddBefore(node, new Operation(Instruction.Add, outputBaseVertex, new[] { baseVertexOffset, outputPrimVertex }));
|
||||||
|
|
||||||
Operand outputPrimIndex = IncrementLocalMemory(node, resourceManager.LocalGeometryOutputIndexCountMemoryId);
|
Operand outputPrimIndex = IncrementLocalMemory(node, resourceManager.LocalGeometryOutputIndexCountMemoryId);
|
||||||
Operand baseIndexOffset = GenerateBaseOffset(
|
Operand baseIndexOffset = GenerateBaseOffset(
|
||||||
|
|
@ -143,16 +143,16 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
definitions.GetGeometryOutputIndexBufferStride(),
|
definitions.GetGeometryOutputIndexBufferStride(),
|
||||||
definitions.ThreadsPerInputPrimitive);
|
definitions.ThreadsPerInputPrimitive);
|
||||||
Operand outputBaseIndex = Local();
|
Operand outputBaseIndex = Local();
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Add, outputBaseIndex, new[] { baseIndexOffset, outputPrimIndex }));
|
node.List?.AddBefore(node, new Operation(Instruction.Add, outputBaseIndex, new[] { baseIndexOffset, outputPrimIndex }));
|
||||||
|
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Store,
|
Instruction.Store,
|
||||||
StorageKind.StorageBuffer,
|
StorageKind.StorageBuffer,
|
||||||
null,
|
null,
|
||||||
new[] { Const(ibOutputBinding), Const(0), outputBaseIndex, outputBaseVertex }));
|
new[] { Const(ibOutputBinding), Const(0), outputBaseIndex, outputBaseVertex }));
|
||||||
|
|
||||||
Operand baseOffset = Local();
|
Operand baseOffset = Local();
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Multiply, baseOffset, new[] { outputBaseVertex, Const(stride) }));
|
node.List?.AddBefore(node, new Operation(Instruction.Multiply, baseOffset, new[] { outputBaseVertex, Const(stride) }));
|
||||||
|
|
||||||
LinkedListNode<INode> newNode = node;
|
LinkedListNode<INode> newNode = node;
|
||||||
|
|
||||||
|
|
@ -163,7 +163,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
if (offset > 0)
|
if (offset > 0)
|
||||||
{
|
{
|
||||||
vertexOffset = Local();
|
vertexOffset = Local();
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Add, vertexOffset, new[] { baseOffset, Const(offset) }));
|
node.List?.AddBefore(node, new Operation(Instruction.Add, vertexOffset, new[] { baseOffset, Const(offset) }));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -171,13 +171,13 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
}
|
}
|
||||||
|
|
||||||
Operand value = Local();
|
Operand value = Local();
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.LocalMemory,
|
StorageKind.LocalMemory,
|
||||||
value,
|
value,
|
||||||
new[] { Const(resourceManager.LocalVertexDataMemoryId), Const(offset) }));
|
new[] { Const(resourceManager.LocalVertexDataMemoryId), Const(offset) }));
|
||||||
|
|
||||||
newNode = node.List.AddBefore(node, new Operation(
|
newNode = node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Store,
|
Instruction.Store,
|
||||||
StorageKind.StorageBuffer,
|
StorageKind.StorageBuffer,
|
||||||
null,
|
null,
|
||||||
|
|
@ -198,9 +198,9 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
definitions.GetGeometryOutputIndexBufferStride(),
|
definitions.GetGeometryOutputIndexBufferStride(),
|
||||||
definitions.ThreadsPerInputPrimitive);
|
definitions.ThreadsPerInputPrimitive);
|
||||||
Operand outputBaseIndex = Local();
|
Operand outputBaseIndex = Local();
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Add, outputBaseIndex, new[] { baseIndexOffset, outputPrimIndex }));
|
node.List?.AddBefore(node, new Operation(Instruction.Add, outputBaseIndex, new[] { baseIndexOffset, outputPrimIndex }));
|
||||||
|
|
||||||
return node.List.AddBefore(node, new Operation(
|
return node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Store,
|
Instruction.Store,
|
||||||
StorageKind.StorageBuffer,
|
StorageKind.StorageBuffer,
|
||||||
null,
|
null,
|
||||||
|
|
@ -213,16 +213,16 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
GeneratePrimitiveId(resourceManager, node, primitiveId);
|
GeneratePrimitiveId(resourceManager, node, primitiveId);
|
||||||
|
|
||||||
Operand baseOffset = Local();
|
Operand baseOffset = Local();
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Multiply, baseOffset, new[] { primitiveId, Const(stride) }));
|
node.List?.AddBefore(node, new Operation(Instruction.Multiply, baseOffset, new[] { primitiveId, Const(stride) }));
|
||||||
|
|
||||||
Operand invocationId = Local();
|
Operand invocationId = Local();
|
||||||
GenerateInvocationId(node, invocationId);
|
GenerateInvocationId(node, invocationId);
|
||||||
|
|
||||||
Operand invocationOffset = Local();
|
Operand invocationOffset = Local();
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Multiply, invocationOffset, new[] { invocationId, Const(stride / threadsPerInputPrimitive) }));
|
node.List?.AddBefore(node, new Operation(Instruction.Multiply, invocationOffset, new[] { invocationId, Const(stride / threadsPerInputPrimitive) }));
|
||||||
|
|
||||||
Operand combinedOffset = Local();
|
Operand combinedOffset = Local();
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Add, combinedOffset, new[] { baseOffset, invocationOffset }));
|
node.List?.AddBefore(node, new Operation(Instruction.Add, combinedOffset, new[] { baseOffset, invocationOffset }));
|
||||||
|
|
||||||
return combinedOffset;
|
return combinedOffset;
|
||||||
}
|
}
|
||||||
|
|
@ -230,16 +230,16 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
private static Operand IncrementLocalMemory(LinkedListNode<INode> node, int memoryId)
|
private static Operand IncrementLocalMemory(LinkedListNode<INode> node, int memoryId)
|
||||||
{
|
{
|
||||||
Operand oldValue = Local();
|
Operand oldValue = Local();
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.LocalMemory,
|
StorageKind.LocalMemory,
|
||||||
oldValue,
|
oldValue,
|
||||||
new[] { Const(memoryId) }));
|
new[] { Const(memoryId) }));
|
||||||
|
|
||||||
Operand newValue = Local();
|
Operand newValue = Local();
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Add, newValue, new[] { oldValue, Const(1) }));
|
node.List?.AddBefore(node, new Operation(Instruction.Add, newValue, new[] { oldValue, Const(1) }));
|
||||||
|
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Store, StorageKind.LocalMemory, null, new[] { Const(memoryId), newValue }));
|
node.List?.AddBefore(node, new Operation(Instruction.Store, StorageKind.LocalMemory, null, new[] { Const(memoryId), newValue }));
|
||||||
|
|
||||||
return oldValue;
|
return oldValue;
|
||||||
}
|
}
|
||||||
|
|
@ -253,34 +253,34 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
int vertexInfoCbBinding = resourceManager.Reservations.VertexInfoConstantBufferBinding;
|
int vertexInfoCbBinding = resourceManager.Reservations.VertexInfoConstantBufferBinding;
|
||||||
|
|
||||||
Operand vertexCount = Local();
|
Operand vertexCount = Local();
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.ConstantBuffer,
|
StorageKind.ConstantBuffer,
|
||||||
vertexCount,
|
vertexCount,
|
||||||
new[] { Const(vertexInfoCbBinding), Const((int)VertexInfoBufferField.VertexCounts), Const(0) }));
|
new[] { Const(vertexInfoCbBinding), Const((int)VertexInfoBufferField.VertexCounts), Const(0) }));
|
||||||
|
|
||||||
Operand primInputVertex = Local();
|
Operand primInputVertex = Local();
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.LocalMemory,
|
StorageKind.LocalMemory,
|
||||||
primInputVertex,
|
primInputVertex,
|
||||||
new[] { Const(resourceManager.LocalTopologyRemapMemoryId), primVertex }));
|
new[] { Const(resourceManager.LocalTopologyRemapMemoryId), primVertex }));
|
||||||
|
|
||||||
Operand instanceIndex = Local();
|
Operand instanceIndex = Local();
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.Input,
|
StorageKind.Input,
|
||||||
instanceIndex,
|
instanceIndex,
|
||||||
new[] { Const((int)IoVariable.GlobalId), Const(1) }));
|
new[] { Const((int)IoVariable.GlobalId), Const(1) }));
|
||||||
|
|
||||||
Operand baseVertex = Local();
|
Operand baseVertex = Local();
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Multiply, baseVertex, new[] { instanceIndex, vertexCount }));
|
node.List?.AddBefore(node, new Operation(Instruction.Multiply, baseVertex, new[] { instanceIndex, vertexCount }));
|
||||||
|
|
||||||
Operand vertexIndex = Local();
|
Operand vertexIndex = Local();
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Add, vertexIndex, new[] { baseVertex, primInputVertex }));
|
node.List?.AddBefore(node, new Operation(Instruction.Add, vertexIndex, new[] { baseVertex, primInputVertex }));
|
||||||
|
|
||||||
Operand vertexBaseOffset = Local();
|
Operand vertexBaseOffset = Local();
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Multiply,
|
Instruction.Multiply,
|
||||||
vertexBaseOffset,
|
vertexBaseOffset,
|
||||||
new[] { vertexIndex, Const(resourceManager.Reservations.InputSizePerInvocation) }));
|
new[] { vertexIndex, Const(resourceManager.Reservations.InputSizePerInvocation) }));
|
||||||
|
|
@ -291,7 +291,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
{
|
{
|
||||||
vertexElemOffset = Local();
|
vertexElemOffset = Local();
|
||||||
|
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Add, vertexElemOffset, new[] { vertexBaseOffset, Const(elementOffset) }));
|
node.List?.AddBefore(node, new Operation(Instruction.Add, vertexElemOffset, new[] { vertexBaseOffset, Const(elementOffset) }));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -306,35 +306,35 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
int vertexInfoCbBinding = resourceManager.Reservations.VertexInfoConstantBufferBinding;
|
int vertexInfoCbBinding = resourceManager.Reservations.VertexInfoConstantBufferBinding;
|
||||||
|
|
||||||
Operand vertexCount = Local();
|
Operand vertexCount = Local();
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.ConstantBuffer,
|
StorageKind.ConstantBuffer,
|
||||||
vertexCount,
|
vertexCount,
|
||||||
new[] { Const(vertexInfoCbBinding), Const((int)VertexInfoBufferField.VertexCounts), Const(0) }));
|
new[] { Const(vertexInfoCbBinding), Const((int)VertexInfoBufferField.VertexCounts), Const(0) }));
|
||||||
|
|
||||||
Operand vertexIndex = Local();
|
Operand vertexIndex = Local();
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.Input,
|
StorageKind.Input,
|
||||||
vertexIndex,
|
vertexIndex,
|
||||||
new[] { Const((int)IoVariable.GlobalId), Const(0) }));
|
new[] { Const((int)IoVariable.GlobalId), Const(0) }));
|
||||||
|
|
||||||
Operand instanceIndex = Local();
|
Operand instanceIndex = Local();
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.Input,
|
StorageKind.Input,
|
||||||
instanceIndex,
|
instanceIndex,
|
||||||
new[] { Const((int)IoVariable.GlobalId), Const(1) }));
|
new[] { Const((int)IoVariable.GlobalId), Const(1) }));
|
||||||
|
|
||||||
Operand baseVertex = Local();
|
Operand baseVertex = Local();
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Multiply, baseVertex, new[] { instanceIndex, vertexCount }));
|
node.List?.AddBefore(node, new Operation(Instruction.Multiply, baseVertex, new[] { instanceIndex, vertexCount }));
|
||||||
|
|
||||||
return node.List.AddBefore(node, new Operation(Instruction.Add, dest, new[] { baseVertex, vertexIndex }));
|
return node.List?.AddBefore(node, new Operation(Instruction.Add, dest, new[] { baseVertex, vertexIndex }));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LinkedListNode<INode> GenerateInvocationId(LinkedListNode<INode> node, Operand dest)
|
private static LinkedListNode<INode> GenerateInvocationId(LinkedListNode<INode> node, Operand dest)
|
||||||
{
|
{
|
||||||
return node.List.AddBefore(node, new Operation(
|
return node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.Input,
|
StorageKind.Input,
|
||||||
dest,
|
dest,
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
|
|
||||||
Operand[] callArgs = [Const(functionId), byteOffset, value];
|
Operand[] callArgs = [Const(functionId), byteOffset, value];
|
||||||
|
|
||||||
LinkedListNode<INode> newNode = node.List.AddBefore(node, new Operation(Instruction.Call, 0, result, callArgs));
|
LinkedListNode<INode> newNode = node.List?.AddBefore(node, new Operation(Instruction.Call, 0, result, callArgs));
|
||||||
|
|
||||||
Utils.DeleteNode(node, operation);
|
Utils.DeleteNode(node, operation);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
|
|
||||||
Operand[] callArgs = [Const(functionId), byteOffset, value];
|
Operand[] callArgs = [Const(functionId), byteOffset, value];
|
||||||
|
|
||||||
LinkedListNode<INode> newNode = node.List.AddBefore(node, new Operation(Instruction.Call, 0, (Operand)null, callArgs));
|
LinkedListNode<INode> newNode = node.List?.AddBefore(node, new Operation(Instruction.Call, 0, (Operand)null, callArgs));
|
||||||
|
|
||||||
Utils.DeleteNode(node, operation);
|
Utils.DeleteNode(node, operation);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
|
|
||||||
Operand[] callArgs = [Const(functionId), value, index, mask, valid];
|
Operand[] callArgs = [Const(functionId), value, index, mask, valid];
|
||||||
|
|
||||||
LinkedListNode<INode> newNode = node.List.AddBefore(node, new Operation(Instruction.Call, 0, result, callArgs));
|
LinkedListNode<INode> newNode = node.List?.AddBefore(node, new Operation(Instruction.Call, 0, result, callArgs));
|
||||||
|
|
||||||
Utils.DeleteNode(node, operation);
|
Utils.DeleteNode(node, operation);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
callArgs = [Const(functionId), texOp.GetSource(coordsIndex + index), Const(samplerIndex)];
|
callArgs = [Const(functionId), texOp.GetSource(coordsIndex + index), Const(samplerIndex)];
|
||||||
}
|
}
|
||||||
|
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Call, 0, scaledCoord, callArgs));
|
node.List?.AddBefore(node, new Operation(Instruction.Call, 0, scaledCoord, callArgs));
|
||||||
|
|
||||||
texOp.SetSource(coordsIndex + index, scaledCoord);
|
texOp.SetSource(coordsIndex + index, scaledCoord);
|
||||||
}
|
}
|
||||||
|
|
@ -130,7 +130,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
|
|
||||||
Operand[] callArgs = [Const(functionId), dest, Const(samplerIndex)];
|
Operand[] callArgs = [Const(functionId), dest, Const(samplerIndex)];
|
||||||
|
|
||||||
node.List.AddAfter(node, new Operation(Instruction.Call, 0, unscaledSize, callArgs));
|
node.List?.AddAfter(node, new Operation(Instruction.Call, 0, unscaledSize, callArgs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -178,7 +178,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
|
|
||||||
Operand[] texSizeSources = [Const(0)];
|
Operand[] texSizeSources = [Const(0)];
|
||||||
|
|
||||||
LinkedListNode<INode> textureSizeNode = node.List.AddBefore(node, new TextureOperation(
|
LinkedListNode<INode> textureSizeNode = node.List?.AddBefore(node, new TextureOperation(
|
||||||
Instruction.TextureQuerySize,
|
Instruction.TextureQuerySize,
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
|
|
@ -195,7 +195,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
|
|
||||||
Operand coordNormalized = Local();
|
Operand coordNormalized = Local();
|
||||||
|
|
||||||
node.List.AddBefore(node, new Operation(Instruction.FP32 | Instruction.Divide, coordNormalized, source, GenerateI2f(node, coordSize)));
|
node.List?.AddBefore(node, new Operation(Instruction.FP32 | Instruction.Divide, coordNormalized, source, GenerateI2f(node, coordSize)));
|
||||||
|
|
||||||
texOp.SetSource(index, coordNormalized);
|
texOp.SetSource(index, coordNormalized);
|
||||||
|
|
||||||
|
|
@ -248,7 +248,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
texSizeSources = [Const(0)];
|
texSizeSources = [Const(0)];
|
||||||
}
|
}
|
||||||
|
|
||||||
node.List.AddBefore(node, new TextureOperation(
|
node.List?.AddBefore(node, new TextureOperation(
|
||||||
Instruction.TextureQuerySize,
|
Instruction.TextureQuerySize,
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
|
|
@ -259,18 +259,18 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
[coordSize],
|
[coordSize],
|
||||||
texSizeSources));
|
texSizeSources));
|
||||||
|
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.FP32 | Instruction.Multiply,
|
Instruction.FP32 | Instruction.Multiply,
|
||||||
scaledSize,
|
scaledSize,
|
||||||
GenerateI2f(node, coordSize),
|
GenerateI2f(node, coordSize),
|
||||||
ConstF((float)(1 << (gatherBiasPrecision + 1)))));
|
ConstF((float)(1 << (gatherBiasPrecision + 1)))));
|
||||||
node.List.AddBefore(node, new Operation(Instruction.FP32 | Instruction.Divide, bias, ConstF(1f), scaledSize));
|
node.List?.AddBefore(node, new Operation(Instruction.FP32 | Instruction.Divide, bias, ConstF(1f), scaledSize));
|
||||||
|
|
||||||
Operand source = texOp.GetSource(coordsIndex + index);
|
Operand source = texOp.GetSource(coordsIndex + index);
|
||||||
|
|
||||||
Operand coordBiased = Local();
|
Operand coordBiased = Local();
|
||||||
|
|
||||||
node.List.AddBefore(node, new Operation(Instruction.FP32 | Instruction.Add, coordBiased, source, bias));
|
node.List?.AddBefore(node, new Operation(Instruction.FP32 | Instruction.Add, coordBiased, source, bias));
|
||||||
|
|
||||||
texOp.SetSource(coordsIndex + index, coordBiased);
|
texOp.SetSource(coordsIndex + index, coordBiased);
|
||||||
}
|
}
|
||||||
|
|
@ -573,7 +573,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
texSizeSources = [Const(0)];
|
texSizeSources = [Const(0)];
|
||||||
}
|
}
|
||||||
|
|
||||||
node.List.AddBefore(node, new TextureOperation(
|
node.List?.AddBefore(node, new TextureOperation(
|
||||||
Instruction.TextureQuerySize,
|
Instruction.TextureQuerySize,
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
|
|
@ -604,7 +604,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
{
|
{
|
||||||
lod = Local();
|
lod = Local();
|
||||||
|
|
||||||
node.List.AddBefore(node, new TextureOperation(
|
node.List?.AddBefore(node, new TextureOperation(
|
||||||
Instruction.Lod,
|
Instruction.Lod,
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
|
|
@ -635,7 +635,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
texSizeSources = [GenerateF2i(node, lod)];
|
texSizeSources = [GenerateF2i(node, lod)];
|
||||||
}
|
}
|
||||||
|
|
||||||
node.List.AddBefore(node, new TextureOperation(
|
node.List?.AddBefore(node, new TextureOperation(
|
||||||
Instruction.TextureQuerySize,
|
Instruction.TextureQuerySize,
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
|
|
@ -692,8 +692,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
Operation convOp = new(Instruction.ConvertS32ToFP32, Local(), dest);
|
Operation convOp = new(Instruction.ConvertS32ToFP32, Local(), dest);
|
||||||
Operation normOp = new(Instruction.FP32 | Instruction.Multiply, Local(), convOp.Dest, ConstF(1f / maxPositive));
|
Operation normOp = new(Instruction.FP32 | Instruction.Multiply, Local(), convOp.Dest, ConstF(1f / maxPositive));
|
||||||
|
|
||||||
node = node.List.AddAfter(node, convOp);
|
node = node?.List?.AddAfter(node, convOp);
|
||||||
node = node.List.AddAfter(node, normOp);
|
node = node?.List?.AddAfter(node, normOp);
|
||||||
|
|
||||||
foreach (INode useOp in uses)
|
foreach (INode useOp in uses)
|
||||||
{
|
{
|
||||||
|
|
@ -720,7 +720,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
{
|
{
|
||||||
Operand res = Local();
|
Operand res = Local();
|
||||||
|
|
||||||
node.List.AddBefore(node, new Operation(Instruction.ConvertS32ToFP32, res, value));
|
node.List?.AddBefore(node, new Operation(Instruction.ConvertS32ToFP32, res, value));
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
@ -729,7 +729,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
{
|
{
|
||||||
Operand res = Local();
|
Operand res = Local();
|
||||||
|
|
||||||
node.List.AddBefore(node, new Operation(Instruction.ConvertFP32ToS32, res, value));
|
node.List?.AddBefore(node, new Operation(Instruction.ConvertFP32ToS32, res, value));
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
|
|
||||||
Operation loadOp = new(Instruction.Load, StorageKind.ConstantBuffer, value, inputs);
|
Operation loadOp = new(Instruction.Load, StorageKind.ConstantBuffer, value, inputs);
|
||||||
|
|
||||||
node.List.AddBefore(node, loadOp);
|
node.List?.AddBefore(node, loadOp);
|
||||||
|
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -81,8 +81,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
Operation compareOp = new(Instruction.CompareEqual, isCurrentIndex, new Operand[] { elemIndex, Const(i) });
|
Operation compareOp = new(Instruction.CompareEqual, isCurrentIndex, new Operand[] { elemIndex, Const(i) });
|
||||||
Operation selectOp = new(Instruction.ConditionalSelect, selection, new Operand[] { isCurrentIndex, value, result });
|
Operation selectOp = new(Instruction.ConditionalSelect, selection, new Operand[] { isCurrentIndex, value, result });
|
||||||
|
|
||||||
node.List.AddBefore(node, compareOp);
|
node.List?.AddBefore(node, compareOp);
|
||||||
node.List.AddBefore(node, selectOp);
|
node.List?.AddBefore(node, selectOp);
|
||||||
|
|
||||||
result = selection;
|
result = selection;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
Operand temp = needsSextNorm ? Local() : dest;
|
Operand temp = needsSextNorm ? Local() : dest;
|
||||||
Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, location, 0);
|
Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, location, 0);
|
||||||
|
|
||||||
newNode = node.List.AddBefore(node, new TextureOperation(
|
newNode = node.List?.AddBefore(node, new TextureOperation(
|
||||||
Instruction.TextureSample,
|
Instruction.TextureSample,
|
||||||
SamplerType.TextureBuffer,
|
SamplerType.TextureBuffer,
|
||||||
TextureFormat.Unknown,
|
TextureFormat.Unknown,
|
||||||
|
|
@ -81,7 +81,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
Operand temp = component > 0 ? Local() : dest;
|
Operand temp = component > 0 ? Local() : dest;
|
||||||
Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, location, component);
|
Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, location, component);
|
||||||
|
|
||||||
newNode = node.List.AddBefore(node, new TextureOperation(
|
newNode = node.List?.AddBefore(node, new TextureOperation(
|
||||||
Instruction.TextureSample,
|
Instruction.TextureSample,
|
||||||
SamplerType.TextureBuffer,
|
SamplerType.TextureBuffer,
|
||||||
TextureFormat.Unknown,
|
TextureFormat.Unknown,
|
||||||
|
|
@ -116,7 +116,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
{
|
{
|
||||||
if (TryGetOutputOffset(context.ResourceManager, operation, out int outputOffset))
|
if (TryGetOutputOffset(context.ResourceManager, operation, out int outputOffset))
|
||||||
{
|
{
|
||||||
newNode = node.List.AddBefore(node, new Operation(
|
newNode = node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.LocalMemory,
|
StorageKind.LocalMemory,
|
||||||
operation.Dest,
|
operation.Dest,
|
||||||
|
|
@ -133,7 +133,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
{
|
{
|
||||||
Operand value = operation.GetSource(operation.SourcesCount - 1);
|
Operand value = operation.GetSource(operation.SourcesCount - 1);
|
||||||
|
|
||||||
newNode = node.List.AddBefore(node, new Operation(
|
newNode = node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Store,
|
Instruction.Store,
|
||||||
StorageKind.LocalMemory,
|
StorageKind.LocalMemory,
|
||||||
(Operand)null,
|
(Operand)null,
|
||||||
|
|
@ -164,37 +164,37 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
GenerateVertexIdInstanceRateLoad(resourceManager, node, vertexIdIr);
|
GenerateVertexIdInstanceRateLoad(resourceManager, node, vertexIdIr);
|
||||||
|
|
||||||
Operand attributeOffset = Local();
|
Operand attributeOffset = Local();
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.ConstantBuffer,
|
StorageKind.ConstantBuffer,
|
||||||
attributeOffset,
|
attributeOffset,
|
||||||
new[] { Const(vertexInfoCbBinding), Const((int)VertexInfoBufferField.VertexOffsets), Const(location), Const(0) }));
|
new[] { Const(vertexInfoCbBinding), Const((int)VertexInfoBufferField.VertexOffsets), Const(location), Const(0) }));
|
||||||
|
|
||||||
Operand isInstanceRate = Local();
|
Operand isInstanceRate = Local();
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.ConstantBuffer,
|
StorageKind.ConstantBuffer,
|
||||||
isInstanceRate,
|
isInstanceRate,
|
||||||
new[] { Const(vertexInfoCbBinding), Const((int)VertexInfoBufferField.VertexOffsets), Const(location), Const(1) }));
|
new[] { Const(vertexInfoCbBinding), Const((int)VertexInfoBufferField.VertexOffsets), Const(location), Const(1) }));
|
||||||
|
|
||||||
Operand vertexId = Local();
|
Operand vertexId = Local();
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.ConditionalSelect,
|
Instruction.ConditionalSelect,
|
||||||
vertexId,
|
vertexId,
|
||||||
new[] { isInstanceRate, vertexIdIr, vertexIdVr }));
|
new[] { isInstanceRate, vertexIdIr, vertexIdVr }));
|
||||||
|
|
||||||
Operand vertexStride = Local();
|
Operand vertexStride = Local();
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.ConstantBuffer,
|
StorageKind.ConstantBuffer,
|
||||||
vertexStride,
|
vertexStride,
|
||||||
new[] { Const(vertexInfoCbBinding), Const((int)VertexInfoBufferField.VertexStrides), Const(location), Const(0) }));
|
new[] { Const(vertexInfoCbBinding), Const((int)VertexInfoBufferField.VertexStrides), Const(location), Const(0) }));
|
||||||
|
|
||||||
Operand vertexBaseOffset = Local();
|
Operand vertexBaseOffset = Local();
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Multiply, vertexBaseOffset, new[] { vertexId, vertexStride }));
|
node.List?.AddBefore(node, new Operation(Instruction.Multiply, vertexBaseOffset, new[] { vertexId, vertexStride }));
|
||||||
|
|
||||||
Operand vertexOffset = Local();
|
Operand vertexOffset = Local();
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Add, vertexOffset, new[] { attributeOffset, vertexBaseOffset }));
|
node.List?.AddBefore(node, new Operation(Instruction.Add, vertexOffset, new[] { attributeOffset, vertexBaseOffset }));
|
||||||
|
|
||||||
Operand vertexElemOffset;
|
Operand vertexElemOffset;
|
||||||
|
|
||||||
|
|
@ -202,7 +202,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
{
|
{
|
||||||
vertexElemOffset = Local();
|
vertexElemOffset = Local();
|
||||||
|
|
||||||
node.List.AddBefore(node, new Operation(Instruction.Add, vertexElemOffset, new[] { vertexOffset, Const(component) }));
|
node.List?.AddBefore(node, new Operation(Instruction.Add, vertexElemOffset, new[] { vertexOffset, Const(component) }));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -215,13 +215,13 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
private static LinkedListNode<INode> CopySignExtendedNormalized(LinkedListNode<INode> node, int bits, bool normalize, Operand dest, Operand src)
|
private static LinkedListNode<INode> CopySignExtendedNormalized(LinkedListNode<INode> node, int bits, bool normalize, Operand dest, Operand src)
|
||||||
{
|
{
|
||||||
Operand leftShifted = Local();
|
Operand leftShifted = Local();
|
||||||
node = node.List.AddAfter(node, new Operation(
|
node = node.List?.AddAfter(node, new Operation(
|
||||||
Instruction.ShiftLeft,
|
Instruction.ShiftLeft,
|
||||||
leftShifted,
|
leftShifted,
|
||||||
new[] { src, Const(32 - bits) }));
|
new[] { src, Const(32 - bits) }));
|
||||||
|
|
||||||
Operand rightShifted = normalize ? Local() : dest;
|
Operand rightShifted = normalize ? Local() : dest;
|
||||||
node = node.List.AddAfter(node, new Operation(
|
node = node?.List?.AddAfter(node, new Operation(
|
||||||
Instruction.ShiftRightS32,
|
Instruction.ShiftRightS32,
|
||||||
rightShifted,
|
rightShifted,
|
||||||
new[] { leftShifted, Const(32 - bits) }));
|
new[] { leftShifted, Const(32 - bits) }));
|
||||||
|
|
@ -229,8 +229,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
if (normalize)
|
if (normalize)
|
||||||
{
|
{
|
||||||
Operand asFloat = Local();
|
Operand asFloat = Local();
|
||||||
node = node.List.AddAfter(node, new Operation(Instruction.ConvertS32ToFP32, asFloat, new[] { rightShifted }));
|
node = node?.List?.AddAfter(node, new Operation(Instruction.ConvertS32ToFP32, asFloat, new[] { rightShifted }));
|
||||||
node = node.List.AddAfter(node, new Operation(
|
node = node?.List?.AddAfter(node, new Operation(
|
||||||
Instruction.FP32 | Instruction.Multiply,
|
Instruction.FP32 | Instruction.Multiply,
|
||||||
dest,
|
dest,
|
||||||
new[] { asFloat, ConstF(1f / (1 << (bits - 1))) }));
|
new[] { asFloat, ConstF(1f / (1 << (bits - 1))) }));
|
||||||
|
|
@ -249,13 +249,13 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
{
|
{
|
||||||
Operand componentExists = Local();
|
Operand componentExists = Local();
|
||||||
int vertexInfoCbBinding = resourceManager.Reservations.VertexInfoConstantBufferBinding;
|
int vertexInfoCbBinding = resourceManager.Reservations.VertexInfoConstantBufferBinding;
|
||||||
node = node.List.AddAfter(node, new Operation(
|
node = node.List?.AddAfter(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.ConstantBuffer,
|
StorageKind.ConstantBuffer,
|
||||||
componentExists,
|
componentExists,
|
||||||
new[] { Const(vertexInfoCbBinding), Const((int)VertexInfoBufferField.VertexStrides), Const(location), Const(component) }));
|
new[] { Const(vertexInfoCbBinding), Const((int)VertexInfoBufferField.VertexStrides), Const(location), Const(component) }));
|
||||||
|
|
||||||
return node.List.AddAfter(node, new Operation(
|
return node?.List?.AddAfter(node, new Operation(
|
||||||
Instruction.ConditionalSelect,
|
Instruction.ConditionalSelect,
|
||||||
dest,
|
dest,
|
||||||
new[] { componentExists, src, ConstF(component == 3 ? 1f : 0f) }));
|
new[] { componentExists, src, ConstF(component == 3 ? 1f : 0f) }));
|
||||||
|
|
@ -265,7 +265,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
{
|
{
|
||||||
int vertexInfoCbBinding = resourceManager.Reservations.VertexInfoConstantBufferBinding;
|
int vertexInfoCbBinding = resourceManager.Reservations.VertexInfoConstantBufferBinding;
|
||||||
|
|
||||||
return node.List.AddBefore(node, new Operation(
|
return node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.ConstantBuffer,
|
StorageKind.ConstantBuffer,
|
||||||
dest,
|
dest,
|
||||||
|
|
@ -276,7 +276,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
{
|
{
|
||||||
int vertexInfoCbBinding = resourceManager.Reservations.VertexInfoConstantBufferBinding;
|
int vertexInfoCbBinding = resourceManager.Reservations.VertexInfoConstantBufferBinding;
|
||||||
|
|
||||||
return node.List.AddBefore(node, new Operation(
|
return node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.ConstantBuffer,
|
StorageKind.ConstantBuffer,
|
||||||
dest,
|
dest,
|
||||||
|
|
@ -291,7 +291,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
GenerateBaseVertexLoad(resourceManager, node, baseVertex);
|
GenerateBaseVertexLoad(resourceManager, node, baseVertex);
|
||||||
GenerateVertexIdVertexRateLoad(resourceManager, node, vertexId);
|
GenerateVertexIdVertexRateLoad(resourceManager, node, vertexId);
|
||||||
|
|
||||||
return node.List.AddBefore(node, new Operation(Instruction.Add, dest, new[] { baseVertex, vertexId }));
|
return node.List?.AddBefore(node, new Operation(Instruction.Add, dest, new[] { baseVertex, vertexId }));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LinkedListNode<INode> GenerateInstanceIndexLoad(ResourceManager resourceManager, LinkedListNode<INode> node, Operand dest)
|
private static LinkedListNode<INode> GenerateInstanceIndexLoad(ResourceManager resourceManager, LinkedListNode<INode> node, Operand dest)
|
||||||
|
|
@ -301,34 +301,34 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
|
|
||||||
GenerateBaseInstanceLoad(resourceManager, node, baseInstance);
|
GenerateBaseInstanceLoad(resourceManager, node, baseInstance);
|
||||||
|
|
||||||
node.List.AddBefore(node, new Operation(
|
node.List?.AddBefore(node, new Operation(
|
||||||
Instruction.Load,
|
Instruction.Load,
|
||||||
StorageKind.Input,
|
StorageKind.Input,
|
||||||
instanceId,
|
instanceId,
|
||||||
new[] { Const((int)IoVariable.GlobalId), Const(1) }));
|
new[] { Const((int)IoVariable.GlobalId), Const(1) }));
|
||||||
|
|
||||||
return node.List.AddBefore(node, new Operation(Instruction.Add, dest, new[] { baseInstance, instanceId }));
|
return node.List?.AddBefore(node, new Operation(Instruction.Add, dest, new[] { baseInstance, instanceId }));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LinkedListNode<INode> GenerateVertexIdVertexRateLoad(ResourceManager resourceManager, LinkedListNode<INode> node, Operand dest)
|
private static LinkedListNode<INode> GenerateVertexIdVertexRateLoad(ResourceManager resourceManager, LinkedListNode<INode> node, Operand dest)
|
||||||
{
|
{
|
||||||
Operand[] sources = [Const(resourceManager.LocalVertexIndexVertexRateMemoryId)];
|
Operand[] sources = [Const(resourceManager.LocalVertexIndexVertexRateMemoryId)];
|
||||||
|
|
||||||
return node.List.AddBefore(node, new Operation(Instruction.Load, StorageKind.LocalMemory, dest, sources));
|
return node.List?.AddBefore(node, new Operation(Instruction.Load, StorageKind.LocalMemory, dest, sources));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LinkedListNode<INode> GenerateVertexIdInstanceRateLoad(ResourceManager resourceManager, LinkedListNode<INode> node, Operand dest)
|
private static LinkedListNode<INode> GenerateVertexIdInstanceRateLoad(ResourceManager resourceManager, LinkedListNode<INode> node, Operand dest)
|
||||||
{
|
{
|
||||||
Operand[] sources = [Const(resourceManager.LocalVertexIndexInstanceRateMemoryId)];
|
Operand[] sources = [Const(resourceManager.LocalVertexIndexInstanceRateMemoryId)];
|
||||||
|
|
||||||
return node.List.AddBefore(node, new Operation(Instruction.Load, StorageKind.LocalMemory, dest, sources));
|
return node.List?.AddBefore(node, new Operation(Instruction.Load, StorageKind.LocalMemory, dest, sources));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LinkedListNode<INode> GenerateInstanceIdLoad(LinkedListNode<INode> node, Operand dest)
|
private static LinkedListNode<INode> GenerateInstanceIdLoad(LinkedListNode<INode> node, Operand dest)
|
||||||
{
|
{
|
||||||
Operand[] sources = [Const((int)IoVariable.GlobalId), Const(1)];
|
Operand[] sources = [Const((int)IoVariable.GlobalId), Const(1)];
|
||||||
|
|
||||||
return node.List.AddBefore(node, new Operation(Instruction.Load, StorageKind.Input, dest, sources));
|
return node.List?.AddBefore(node, new Operation(Instruction.Load, StorageKind.Input, dest, sources));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryGetOutputOffset(ResourceManager resourceManager, Operation operation, out int outputOffset)
|
private static bool TryGetOutputOffset(ResourceManager resourceManager, Operation operation, out int outputOffset)
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||||
|
|
||||||
_pipeline.SetUniformBuffers([new BufferAssignment(2, buffer.Range)]);
|
_pipeline.SetUniformBuffers([new BufferAssignment(2, buffer.Range)]);
|
||||||
_pipeline.SetImage(ShaderStage.Compute, 0, _intermediaryTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
|
_pipeline.SetImage(ShaderStage.Compute, 0, _intermediaryTexture?.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
|
var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
|
||||||
var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
|
var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
|
||||||
|
|
||||||
_pipeline.SetImage(ShaderStage.Compute, 0, _texture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
|
_pipeline.SetImage(ShaderStage.Compute, 0, _texture?.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
|
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
|
|
||||||
|
|
@ -177,8 +177,8 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
_areaTexture = _renderer.CreateTexture(areaInfo) as TextureView;
|
_areaTexture = _renderer.CreateTexture(areaInfo) as TextureView;
|
||||||
_searchTexture = _renderer.CreateTexture(searchInfo) as TextureView;
|
_searchTexture = _renderer.CreateTexture(searchInfo) as TextureView;
|
||||||
|
|
||||||
_areaTexture.SetData(areaTexture);
|
_areaTexture?.SetData(areaTexture);
|
||||||
_searchTexture.SetData(searchTexture);
|
_searchTexture?.SetData(searchTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextureView Run(TextureView view, CommandBufferScoped cbs, int width, int height)
|
public TextureView Run(TextureView view, CommandBufferScoped cbs, int width, int height)
|
||||||
|
|
@ -216,7 +216,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
|
|
||||||
buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer);
|
buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer);
|
||||||
_pipeline.SetUniformBuffers([new BufferAssignment(2, buffer.Range)]);
|
_pipeline.SetUniformBuffers([new BufferAssignment(2, buffer.Range)]);
|
||||||
_pipeline.SetImage(ShaderStage.Compute, 0, _edgeOutputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
|
_pipeline.SetImage(ShaderStage.Compute, 0, _edgeOutputTexture?.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
|
||||||
|
|
@ -226,7 +226,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _edgeOutputTexture, _samplerLinear);
|
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _edgeOutputTexture, _samplerLinear);
|
||||||
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _areaTexture, _samplerLinear);
|
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _areaTexture, _samplerLinear);
|
||||||
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 4, _searchTexture, _samplerLinear);
|
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 4, _searchTexture, _samplerLinear);
|
||||||
_pipeline.SetImage(ShaderStage.Compute, 0, _blendOutputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
|
_pipeline.SetImage(ShaderStage.Compute, 0, _blendOutputTexture?.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
|
||||||
|
|
@ -235,7 +235,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
||||||
_pipeline.Specialize(_specConstants);
|
_pipeline.Specialize(_specConstants);
|
||||||
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _blendOutputTexture, _samplerLinear);
|
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _blendOutputTexture, _samplerLinear);
|
||||||
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _samplerLinear);
|
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _samplerLinear);
|
||||||
_pipeline.SetImage(ShaderStage.Compute, 0, _outputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
|
_pipeline.SetImage(ShaderStage.Compute, 0, _outputTexture?.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,15 +28,15 @@ namespace Ryujinx.HLE.Generators
|
||||||
continue;
|
continue;
|
||||||
var constructors = className.ChildNodes().Where(x => x.IsKind(SyntaxKind.ConstructorDeclaration)).Select(y => y as ConstructorDeclarationSyntax);
|
var constructors = className.ChildNodes().Where(x => x.IsKind(SyntaxKind.ConstructorDeclaration)).Select(y => y as ConstructorDeclarationSyntax);
|
||||||
|
|
||||||
if (!constructors.Any(x => x.ParameterList.Parameters.Count >= 1))
|
if (!constructors.Any(x => x != null && x.ParameterList.Parameters.Count >= 1))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (constructors.Where(x => x.ParameterList.Parameters.Count >= 1).FirstOrDefault().ParameterList.Parameters[0].Type.ToString() == "ServiceCtx")
|
if (constructors.FirstOrDefault(x => x != null && x.ParameterList.Parameters.Count >= 1).ParameterList.Parameters[0].Type.ToString() == "ServiceCtx")
|
||||||
{
|
{
|
||||||
generator.EnterScope($"if (type == typeof({GetFullName(className, context)}))");
|
generator.EnterScope($"if (type == typeof({GetFullName(className, context)}))");
|
||||||
if (constructors.Any(x => x.ParameterList.Parameters.Count == 2))
|
if (constructors.Any(x => x != null && x.ParameterList.Parameters.Count == 2))
|
||||||
{
|
{
|
||||||
var type = constructors.Where(x => x.ParameterList.Parameters.Count == 2).FirstOrDefault().ParameterList.Parameters[1].Type;
|
var type = constructors.FirstOrDefault(x => x != null && x.ParameterList.Parameters.Count == 2).ParameterList.Parameters[1].Type;
|
||||||
var model = context.Compilation.GetSemanticModel(type.SyntaxTree);
|
var model = context.Compilation.GetSemanticModel(type.SyntaxTree);
|
||||||
var typeSymbol = model.GetSymbolInfo(type).Symbol as INamedTypeSymbol;
|
var typeSymbol = model.GetSymbolInfo(type).Symbol as INamedTypeSymbol;
|
||||||
var fullName = typeSymbol?.ToString();
|
var fullName = typeSymbol?.ToString();
|
||||||
|
|
@ -45,7 +45,7 @@ namespace Ryujinx.HLE.Generators
|
||||||
generator.LeaveScope();
|
generator.LeaveScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (constructors.Any(x => x.ParameterList.Parameters.Count == 1))
|
if (constructors.Any(x => x != null && x.ParameterList.Parameters.Count == 1))
|
||||||
{
|
{
|
||||||
generator.AppendLine($"return new {GetFullName(className, context)}(context);");
|
generator.AppendLine($"return new {GetFullName(className, context)}(context);");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,7 @@ namespace Ryujinx.HLE.Exceptions
|
||||||
while ((frame = trace.GetFrame(i++)) != null)
|
while ((frame = trace.GetFrame(i++)) != null)
|
||||||
{
|
{
|
||||||
var method = frame.GetMethod();
|
var method = frame.GetMethod();
|
||||||
var declType = method.DeclaringType;
|
var declType = method?.DeclaringType;
|
||||||
|
|
||||||
if (typeof(IpcService).IsAssignableFrom(declType))
|
if (typeof(IpcService).IsAssignableFrom(declType))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -551,7 +551,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||||
new DirectoryInfo(registeredDirectory).Delete(true);
|
new DirectoryInfo(registeredDirectory).Delete(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.Move(temporaryDirectory, registeredDirectory);
|
Directory.Move(temporaryDirectory, registeredDirectory ?? string.Empty);
|
||||||
|
|
||||||
LoadEntries();
|
LoadEntries();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,12 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bytes != null)
|
||||||
|
{
|
||||||
writer.Write(bytes);
|
writer.Write(bytes);
|
||||||
writer.Seek((int)maxSize - bytes.Length, SeekOrigin.Current);
|
writer.Seek((int)maxSize - bytes.Length, SeekOrigin.Current);
|
||||||
|
}
|
||||||
|
|
||||||
writer.Write((uint)text.Length); // String size
|
writer.Write((uint)text.Length); // String size
|
||||||
|
|
||||||
return (uint)text.Length; // Return the cursor position at the end of the text
|
return (uint)text.Length; // Return the cursor position at the end of the text
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||||
KernelContext.CriticalSection.Enter();
|
KernelContext.CriticalSection.Enter();
|
||||||
|
|
||||||
if (list.Count != 0)
|
if (list.Count != 0)
|
||||||
|
{
|
||||||
|
if (list.First != null)
|
||||||
{
|
{
|
||||||
session = list.First.Value;
|
session = list.First.Value;
|
||||||
|
}
|
||||||
|
|
||||||
list.RemoveFirst();
|
list.RemoveFirst();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1369,6 +1369,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
LinkedListNode<KPageNode> pageListNode = pageList.Nodes.First;
|
LinkedListNode<KPageNode> pageListNode = pageList.Nodes.First;
|
||||||
|
|
||||||
|
if (pageListNode != null)
|
||||||
|
{
|
||||||
KPageNode pageNode = pageListNode.Value;
|
KPageNode pageNode = pageListNode.Value;
|
||||||
|
|
||||||
ulong srcPa = pageNode.Address;
|
ulong srcPa = pageNode.Address;
|
||||||
|
|
@ -1391,9 +1393,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
{
|
{
|
||||||
if (srcPaPages == 0)
|
if (srcPaPages == 0)
|
||||||
{
|
{
|
||||||
pageListNode = pageListNode.Next;
|
pageListNode = pageListNode?.Next;
|
||||||
|
|
||||||
|
if (pageListNode != null)
|
||||||
|
{
|
||||||
pageNode = pageListNode.Value;
|
pageNode = pageListNode.Value;
|
||||||
|
}
|
||||||
|
|
||||||
srcPa = pageNode.Address;
|
srcPa = pageNode.Address;
|
||||||
srcPaPages = pageNode.PagesCount;
|
srcPaPages = pageNode.PagesCount;
|
||||||
|
|
@ -1409,6 +1414,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
dstVaPages -= currentPagesCount;
|
dstVaPages -= currentPagesCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PhysicalMemoryUsage += remainingSize;
|
PhysicalMemoryUsage += remainingSize;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
public ref T GetRef<T>(ulong offset) where T : unmanaged
|
public ref T GetRef<T>(ulong offset) where T : unmanaged
|
||||||
{
|
{
|
||||||
if (_pageList.Nodes.Count == 1)
|
if (_pageList.Nodes.Count == 1)
|
||||||
|
{
|
||||||
|
if (_pageList.Nodes.First != null)
|
||||||
{
|
{
|
||||||
ulong address = _pageList.Nodes.First.Value.Address - DramMemoryMap.DramBase;
|
ulong address = _pageList.Nodes.First.Value.Address - DramMemoryMap.DramBase;
|
||||||
return ref _context.Memory.GetRef<T>(address + offset);
|
return ref _context.Memory.GetRef<T>(address + offset);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
throw new NotImplementedException("Non-contiguous shared memory is not yet supported.");
|
throw new NotImplementedException("Non-contiguous shared memory is not yet supported.");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -253,7 +253,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
|
|
||||||
thread.SiblingsPerCore[core] = queue.AddLast(thread);
|
thread.SiblingsPerCore[core] = queue.AddLast(thread);
|
||||||
|
|
||||||
return queue.First.Value;
|
return queue.First?.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Unschedule(int prio, int core, KThread thread)
|
public void Unschedule(int prio, int core, KThread thread)
|
||||||
|
|
|
||||||
|
|
@ -1302,7 +1302,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
{
|
{
|
||||||
Owner?.RemoveThread(this);
|
Owner?.RemoveThread(this);
|
||||||
|
|
||||||
if (_tlsAddress != 0 && Owner.FreeThreadLocalStorage(_tlsAddress) != Result.Success)
|
if (_tlsAddress != 0 && Owner?.FreeThreadLocalStorage(_tlsAddress) != Result.Success)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Unexpected failure freeing thread local storage.");
|
throw new InvalidOperationException("Unexpected failure freeing thread local storage.");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,8 @@ namespace Ryujinx.Horizon.Generators.Hipc
|
||||||
{
|
{
|
||||||
HipcSyntaxReceiver syntaxReceiver = (HipcSyntaxReceiver)context.SyntaxReceiver;
|
HipcSyntaxReceiver syntaxReceiver = (HipcSyntaxReceiver)context.SyntaxReceiver;
|
||||||
|
|
||||||
|
if (syntaxReceiver?.CommandInterfaces != null)
|
||||||
|
{
|
||||||
foreach (var commandInterface in syntaxReceiver.CommandInterfaces)
|
foreach (var commandInterface in syntaxReceiver.CommandInterfaces)
|
||||||
{
|
{
|
||||||
if (!NeedsIServiceObjectImplementation(context.Compilation, commandInterface.ClassDeclarationSyntax))
|
if (!NeedsIServiceObjectImplementation(context.Compilation, commandInterface.ClassDeclarationSyntax))
|
||||||
|
|
@ -99,6 +101,7 @@ namespace Ryujinx.Horizon.Generators.Hipc
|
||||||
context.AddSource($"{GetNamespaceName(commandInterface.ClassDeclarationSyntax)}.{className}.g.cs", generator.ToString());
|
context.AddSource($"{GetNamespaceName(commandInterface.ClassDeclarationSyntax)}.{className}.g.cs", generator.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetNamespaceName(SyntaxNode syntaxNode)
|
private static string GetNamespaceName(SyntaxNode syntaxNode)
|
||||||
{
|
{
|
||||||
|
|
@ -191,14 +194,18 @@ namespace Ryujinx.Horizon.Generators.Hipc
|
||||||
{
|
{
|
||||||
ISymbol symbol = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetDeclaredSymbol(syntaxNode);
|
ISymbol symbol = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetDeclaredSymbol(syntaxNode);
|
||||||
|
|
||||||
|
if (symbol != null)
|
||||||
|
{
|
||||||
foreach (var attribute in symbol.GetAttributes())
|
foreach (var attribute in symbol.GetAttributes())
|
||||||
{
|
{
|
||||||
if (attribute.AttributeClass.ToDisplayString() == attributeName && (uint)argIndex < (uint)attribute.ConstructorArguments.Length)
|
if (attribute.AttributeClass?.ToDisplayString() == attributeName &&
|
||||||
|
(uint)argIndex < (uint)attribute.ConstructorArguments.Length)
|
||||||
{
|
{
|
||||||
yield return attribute.ConstructorArguments[argIndex].ToCSharpString();
|
yield return attribute.ConstructorArguments[argIndex].ToCSharpString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetFirstAttributeArgument(Compilation compilation, SyntaxNode syntaxNode, string attributeName, int argIndex)
|
private static string GetFirstAttributeArgument(Compilation compilation, SyntaxNode syntaxNode, string attributeName, int argIndex)
|
||||||
{
|
{
|
||||||
|
|
@ -507,19 +514,22 @@ namespace Ryujinx.Horizon.Generators.Hipc
|
||||||
{
|
{
|
||||||
TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
|
TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
|
||||||
|
|
||||||
return typeInfo.Type.ToDisplayString();
|
return typeInfo.Type?.ToDisplayString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetCanonicalTypeName(Compilation compilation, SyntaxNode syntaxNode)
|
private static string GetCanonicalTypeName(Compilation compilation, SyntaxNode syntaxNode)
|
||||||
{
|
{
|
||||||
TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
|
TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
|
||||||
string typeName = typeInfo.Type.ToDisplayString();
|
string typeName = typeInfo.Type?.ToDisplayString();
|
||||||
|
|
||||||
|
if (typeName != null)
|
||||||
|
{
|
||||||
int genericArgsStartIndex = typeName.IndexOf('<');
|
int genericArgsStartIndex = typeName.IndexOf('<');
|
||||||
if (genericArgsStartIndex >= 0)
|
if (genericArgsStartIndex >= 0)
|
||||||
{
|
{
|
||||||
return typeName.Substring(0, genericArgsStartIndex);
|
return typeName.Substring(0, genericArgsStartIndex);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return typeName;
|
return typeName;
|
||||||
}
|
}
|
||||||
|
|
@ -528,7 +538,7 @@ namespace Ryujinx.Horizon.Generators.Hipc
|
||||||
{
|
{
|
||||||
TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
|
TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
|
||||||
|
|
||||||
return typeInfo.Type.SpecialType;
|
return typeInfo.Type?.SpecialType ?? SpecialType.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetTypeAlignmentExpression(Compilation compilation, SyntaxNode syntaxNode)
|
private static string GetTypeAlignmentExpression(Compilation compilation, SyntaxNode syntaxNode)
|
||||||
|
|
@ -539,7 +549,7 @@ namespace Ryujinx.Horizon.Generators.Hipc
|
||||||
// "special" types are primitive types aligned to their own length.
|
// "special" types are primitive types aligned to their own length.
|
||||||
// Otherwise, assume that the type is a custom struct, that either defines an explicit alignment
|
// Otherwise, assume that the type is a custom struct, that either defines an explicit alignment
|
||||||
// or has an alignment of 1 which is the lowest possible value.
|
// or has an alignment of 1 which is the lowest possible value.
|
||||||
if (typeInfo.Type.SpecialType == SpecialType.None)
|
if (typeInfo.Type is { SpecialType: SpecialType.None })
|
||||||
{
|
{
|
||||||
string pack = GetTypeFirstNamedAttributeAgument(compilation, syntaxNode, TypeStructLayoutAttribute, "Pack");
|
string pack = GetTypeFirstNamedAttributeAgument(compilation, syntaxNode, TypeStructLayoutAttribute, "Pack");
|
||||||
|
|
||||||
|
|
@ -547,7 +557,7 @@ namespace Ryujinx.Horizon.Generators.Hipc
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return $"Unsafe.SizeOf<{typeInfo.Type.ToDisplayString()}>()";
|
return $"Unsafe.SizeOf<{typeInfo.Type?.ToDisplayString()}>()";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -555,13 +565,13 @@ namespace Ryujinx.Horizon.Generators.Hipc
|
||||||
{
|
{
|
||||||
ISymbol symbol = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode).Type;
|
ISymbol symbol = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode).Type;
|
||||||
|
|
||||||
|
if (symbol != null)
|
||||||
|
{
|
||||||
foreach (var attribute in symbol.GetAttributes())
|
foreach (var attribute in symbol.GetAttributes())
|
||||||
{
|
{
|
||||||
if (attribute.AttributeClass.ToDisplayString() == attributeName)
|
if (attribute.AttributeClass?.ToDisplayString() == attributeName)
|
||||||
{
|
{
|
||||||
foreach (var kv in attribute.NamedArguments)
|
foreach (var kv in attribute.NamedArguments.Where(kv => kv.Key == argName))
|
||||||
{
|
|
||||||
if (kv.Key == argName)
|
|
||||||
{
|
{
|
||||||
return kv.Value.ToCSharpString();
|
return kv.Value.ToCSharpString();
|
||||||
}
|
}
|
||||||
|
|
@ -664,7 +674,7 @@ namespace Ryujinx.Horizon.Generators.Hipc
|
||||||
{
|
{
|
||||||
TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
|
TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
|
||||||
|
|
||||||
return typeInfo.Type.IsUnmanagedType;
|
return typeInfo.Type is { IsUnmanagedType: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsMemory(Compilation compilation, ParameterSyntax parameter)
|
private static bool IsMemory(Compilation compilation, ParameterSyntax parameter)
|
||||||
|
|
@ -707,10 +717,11 @@ namespace Ryujinx.Horizon.Generators.Hipc
|
||||||
private static bool IsObject(Compilation compilation, ParameterSyntax parameter)
|
private static bool IsObject(Compilation compilation, ParameterSyntax parameter)
|
||||||
{
|
{
|
||||||
SyntaxNode syntaxNode = parameter.Type;
|
SyntaxNode syntaxNode = parameter.Type;
|
||||||
TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
|
TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode!.SyntaxTree).GetTypeInfo(syntaxNode);
|
||||||
|
|
||||||
return typeInfo.Type.ToDisplayString() == TypeIServiceObject ||
|
return typeInfo.Type != null &&
|
||||||
typeInfo.Type.AllInterfaces.Any(x => x.ToDisplayString() == TypeIServiceObject);
|
(typeInfo.Type.ToDisplayString() == TypeIServiceObject ||
|
||||||
|
typeInfo.Type.AllInterfaces.Any(x => x.ToDisplayString() == TypeIServiceObject));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsProcessId(Compilation compilation, ParameterSyntax parameter)
|
private static bool IsProcessId(Compilation compilation, ParameterSyntax parameter)
|
||||||
|
|
@ -781,7 +792,7 @@ namespace Ryujinx.Horizon.Generators.Hipc
|
||||||
private static bool NeedsIServiceObjectImplementation(Compilation compilation, ClassDeclarationSyntax classDeclarationSyntax)
|
private static bool NeedsIServiceObjectImplementation(Compilation compilation, ClassDeclarationSyntax classDeclarationSyntax)
|
||||||
{
|
{
|
||||||
ITypeSymbol type = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree).GetDeclaredSymbol(classDeclarationSyntax);
|
ITypeSymbol type = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree).GetDeclaredSymbol(classDeclarationSyntax);
|
||||||
var serviceObjectInterface = type.AllInterfaces.FirstOrDefault(x => x.ToDisplayString() == TypeIServiceObject);
|
var serviceObjectInterface = type?.AllInterfaces.FirstOrDefault(x => x.ToDisplayString() == TypeIServiceObject);
|
||||||
var interfaceMember = serviceObjectInterface?.GetMembers().FirstOrDefault(x => x.Name == "GetCommandHandlers");
|
var interfaceMember = serviceObjectInterface?.GetMembers().FirstOrDefault(x => x.Name == "GetCommandHandlers");
|
||||||
|
|
||||||
// Return true only if the class implements IServiceObject but does not actually implement the method
|
// Return true only if the class implements IServiceObject but does not actually implement the method
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,8 @@ namespace Ryujinx.Horizon.Kernel.Generators
|
||||||
|
|
||||||
List<SyscallIdAndName> syscalls = [];
|
List<SyscallIdAndName> syscalls = [];
|
||||||
|
|
||||||
|
if (syntaxReceiver != null)
|
||||||
|
{
|
||||||
foreach (var method in syntaxReceiver.SvcImplementations)
|
foreach (var method in syntaxReceiver.SvcImplementations)
|
||||||
{
|
{
|
||||||
GenerateMethod32(generator, context.Compilation, method);
|
GenerateMethod32(generator, context.Compilation, method);
|
||||||
|
|
@ -155,6 +157,8 @@ namespace Ryujinx.Horizon.Kernel.Generators
|
||||||
foreach (AttributeSyntax attribute in method.AttributeLists.SelectMany(attributeList =>
|
foreach (AttributeSyntax attribute in method.AttributeLists.SelectMany(attributeList =>
|
||||||
attributeList.Attributes.Where(attribute =>
|
attributeList.Attributes.Where(attribute =>
|
||||||
GetCanonicalTypeName(context.Compilation, attribute) == TypeSvcAttribute)))
|
GetCanonicalTypeName(context.Compilation, attribute) == TypeSvcAttribute)))
|
||||||
|
{
|
||||||
|
if (attribute.ArgumentList != null)
|
||||||
{
|
{
|
||||||
syscalls.AddRange(from attributeArg in attribute.ArgumentList.Arguments
|
syscalls.AddRange(from attributeArg in attribute.ArgumentList.Arguments
|
||||||
where attributeArg.Expression.Kind() == SyntaxKind.NumericLiteralExpression
|
where attributeArg.Expression.Kind() == SyntaxKind.NumericLiteralExpression
|
||||||
|
|
@ -163,6 +167,8 @@ namespace Ryujinx.Horizon.Kernel.Generators
|
||||||
select new SyscallIdAndName((int)numericLiteral.Token.Value, method.Identifier.Text));
|
select new SyscallIdAndName((int)numericLiteral.Token.Value, method.Identifier.Text));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
syscalls.Sort();
|
syscalls.Sort();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,11 @@ namespace Ryujinx.Horizon.Arp.Ipc
|
||||||
return ArpResult.InvalidInstanceId;
|
return ArpResult.InvalidInstanceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
applicationCertificate = _applicationInstanceManager.Entries[applicationInstanceId].Certificate.Value;
|
ApplicationCertificate? certificate = _applicationInstanceManager.Entries[applicationInstanceId].Certificate;
|
||||||
|
if (certificate != null)
|
||||||
|
{
|
||||||
|
applicationCertificate = certificate.Value;
|
||||||
|
}
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -510,7 +510,7 @@ namespace Ryujinx.Input.HLE
|
||||||
{
|
{
|
||||||
var keyboard = KeyboardDriver.GetGamepad("0") as IKeyboard;
|
var keyboard = KeyboardDriver.GetGamepad("0") as IKeyboard;
|
||||||
|
|
||||||
KeyboardStateSnapshot keyboardState = keyboard.GetKeyboardStateSnapshot();
|
KeyboardStateSnapshot keyboardState = keyboard?.GetKeyboardStateSnapshot();
|
||||||
|
|
||||||
KeyboardInput hidKeyboard = new()
|
KeyboardInput hidKeyboard = new()
|
||||||
{
|
{
|
||||||
|
|
@ -520,14 +520,14 @@ namespace Ryujinx.Input.HLE
|
||||||
|
|
||||||
foreach (HLEKeyboardMappingEntry entry in _keyMapping)
|
foreach (HLEKeyboardMappingEntry entry in _keyMapping)
|
||||||
{
|
{
|
||||||
ulong value = keyboardState.IsPressed(entry.TargetKey) ? 1UL : 0UL;
|
ulong value = keyboardState != null && keyboardState.IsPressed(entry.TargetKey) ? 1UL : 0UL;
|
||||||
|
|
||||||
hidKeyboard.Keys[entry.Target / 0x40] |= (value << (entry.Target % 0x40));
|
hidKeyboard.Keys[entry.Target / 0x40] |= (value << (entry.Target % 0x40));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (HLEKeyboardMappingEntry entry in _keyModifierMapping)
|
foreach (HLEKeyboardMappingEntry entry in _keyModifierMapping)
|
||||||
{
|
{
|
||||||
int value = keyboardState.IsPressed(entry.TargetKey) ? 1 : 0;
|
int value = keyboardState != null && keyboardState.IsPressed(entry.TargetKey) ? 1 : 0;
|
||||||
|
|
||||||
hidKeyboard.Modifier |= value << entry.Target;
|
hidKeyboard.Modifier |= value << entry.Target;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -304,10 +304,13 @@ namespace Ryujinx.Input.HLE
|
||||||
buttons |= 1 << 4;
|
buttons |= 1 << 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mouse != null)
|
||||||
|
{
|
||||||
var position = IMouse.GetScreenPosition(mouseInput.Position, mouse.ClientSize, aspectRatio);
|
var position = IMouse.GetScreenPosition(mouseInput.Position, mouse.ClientSize, aspectRatio);
|
||||||
|
|
||||||
_device.Hid.Mouse.Update((int)position.X, (int)position.Y, buttons, (int)mouseInput.Scroll.X, (int)mouseInput.Scroll.Y, true);
|
_device.Hid.Mouse.Update((int)position.X, (int)position.Y, buttons, (int)mouseInput.Scroll.X, (int)mouseInput.Scroll.Y, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_device.Hid.Mouse.Update(0, 0);
|
_device.Hid.Mouse.Update(0, 0);
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,8 @@ namespace Ryujinx.UI.App.Common
|
||||||
private static byte[] GetResourceBytes(string resourceName)
|
private static byte[] GetResourceBytes(string resourceName)
|
||||||
{
|
{
|
||||||
Stream resourceStream = Assembly.GetCallingAssembly().GetManifestResourceStream(resourceName);
|
Stream resourceStream = Assembly.GetCallingAssembly().GetManifestResourceStream(resourceName);
|
||||||
|
if (resourceStream != null)
|
||||||
|
{
|
||||||
byte[] resourceByteArray = new byte[resourceStream.Length];
|
byte[] resourceByteArray = new byte[resourceStream.Length];
|
||||||
|
|
||||||
resourceStream.ReadExactly(resourceByteArray);
|
resourceStream.ReadExactly(resourceByteArray);
|
||||||
|
|
@ -95,6 +97,9 @@ namespace Ryujinx.UI.App.Common
|
||||||
return resourceByteArray;
|
return resourceByteArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
/// <exception cref="Ryujinx.HLE.Exceptions.InvalidNpdmException">The npdm file doesn't contain valid data.</exception>
|
/// <exception cref="Ryujinx.HLE.Exceptions.InvalidNpdmException">The npdm file doesn't contain valid data.</exception>
|
||||||
/// <exception cref="NotImplementedException">The FsAccessHeader.ContentOwnerId section is not implemented.</exception>
|
/// <exception cref="NotImplementedException">The FsAccessHeader.ContentOwnerId section is not implemented.</exception>
|
||||||
/// <exception cref="ArgumentException">An error occured while reading bytes from the stream.</exception>
|
/// <exception cref="ArgumentException">An error occured while reading bytes from the stream.</exception>
|
||||||
|
|
@ -1178,7 +1183,7 @@ namespace Ryujinx.UI.App.Common
|
||||||
{
|
{
|
||||||
string extension = Path.GetExtension(applicationPath)?.ToLower();
|
string extension = Path.GetExtension(applicationPath)?.ToLower();
|
||||||
|
|
||||||
using FileStream file = new(applicationPath, FileMode.Open, FileAccess.Read);
|
using FileStream file = new(applicationPath ?? string.Empty, FileMode.Open, FileAccess.Read);
|
||||||
|
|
||||||
if (extension == ".nsp" || extension == ".pfs0" || extension == ".xci")
|
if (extension == ".nsp" || extension == ".pfs0" || extension == ".xci")
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ namespace Ryujinx.UI.Common.Helper
|
||||||
|
|
||||||
Logger.Debug?.Print(LogClass.Application, $"Adding type association {ext}");
|
Logger.Debug?.Print(LogClass.Application, $"Adding type association {ext}");
|
||||||
using var openCmd = key.CreateSubKey(@"shell\open\command");
|
using var openCmd = key.CreateSubKey(@"shell\open\command");
|
||||||
openCmd.SetValue("", $"\"{Environment.ProcessPath}\" \"%1\"");
|
openCmd?.SetValue("", $"\"{Environment.ProcessPath}\" \"%1\"");
|
||||||
Logger.Debug?.Print(LogClass.Application, $"Added type association {ext}");
|
Logger.Debug?.Print(LogClass.Application, $"Added type association {ext}");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,11 @@ namespace Ryujinx.UI.Common.SystemInfo
|
||||||
{
|
{
|
||||||
foreach (var cpuObj in cpuObjs)
|
foreach (var cpuObj in cpuObjs)
|
||||||
{
|
{
|
||||||
return cpuObj["Name"].ToString().Trim();
|
return cpuObj["Name"].ToString()?.Trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Environment.GetEnvironmentVariable("PROCESSOR_IDENTIFIER").Trim();
|
return Environment.GetEnvironmentVariable("PROCESSOR_IDENTIFIER")?.Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ namespace Ryujinx.Ava
|
||||||
if (result == UserResult.Yes)
|
if (result == UserResult.Yes)
|
||||||
{
|
{
|
||||||
var path = Environment.ProcessPath;
|
var path = Environment.ProcessPath;
|
||||||
var proc = Process.Start(path, CommandLineState.Arguments);
|
var proc = Process.Start(path ?? string.Empty, CommandLineState.Arguments);
|
||||||
desktop.Shutdown();
|
desktop.Shutdown();
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +144,7 @@ namespace Ryujinx.Ava
|
||||||
|
|
||||||
public static ThemeVariant DetectSystemTheme()
|
public static ThemeVariant DetectSystemTheme()
|
||||||
{
|
{
|
||||||
if (Current is App app)
|
if (Current is App { PlatformSettings: not null } app)
|
||||||
{
|
{
|
||||||
var colorValues = app.PlatformSettings.GetColorValues();
|
var colorValues = app.PlatformSettings.GetColorValues();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -192,8 +192,11 @@ namespace Ryujinx.Modules
|
||||||
|
|
||||||
HttpResponseMessage message = await buildSizeClient.GetAsync(new Uri(_buildUrl), HttpCompletionOption.ResponseHeadersRead);
|
HttpResponseMessage message = await buildSizeClient.GetAsync(new Uri(_buildUrl), HttpCompletionOption.ResponseHeadersRead);
|
||||||
|
|
||||||
|
if (message.Content.Headers.ContentRange?.Length != null)
|
||||||
|
{
|
||||||
_buildSize = message.Content.Headers.ContentRange.Length.Value;
|
_buildSize = message.Content.Headers.ContentRange.Length.Value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, ex.Message);
|
Logger.Warning?.Print(LogClass.Application, ex.Message);
|
||||||
|
|
@ -375,17 +378,23 @@ namespace Ryujinx.Modules
|
||||||
}
|
}
|
||||||
|
|
||||||
client.DownloadProgressChanged += (_, args) =>
|
client.DownloadProgressChanged += (_, args) =>
|
||||||
|
{
|
||||||
|
if (args.UserState != null)
|
||||||
{
|
{
|
||||||
int index = (int)args.UserState;
|
int index = (int)args.UserState;
|
||||||
|
|
||||||
Interlocked.Add(ref totalProgressPercentage, -1 * progressPercentage[index]);
|
Interlocked.Add(ref totalProgressPercentage, -1 * progressPercentage[index]);
|
||||||
Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage);
|
Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage);
|
||||||
|
}
|
||||||
|
|
||||||
Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage);
|
Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage);
|
||||||
|
|
||||||
taskDialog.SetProgressBarState(totalProgressPercentage / ConnectionCount, TaskDialogProgressState.Normal);
|
taskDialog.SetProgressBarState(totalProgressPercentage / ConnectionCount, TaskDialogProgressState.Normal);
|
||||||
};
|
};
|
||||||
|
|
||||||
client.DownloadDataCompleted += (_, args) =>
|
client.DownloadDataCompleted += (_, args) =>
|
||||||
|
{
|
||||||
|
if (args.UserState != null)
|
||||||
{
|
{
|
||||||
int index = (int)args.UserState;
|
int index = (int)args.UserState;
|
||||||
|
|
||||||
|
|
@ -399,6 +408,8 @@ namespace Ryujinx.Modules
|
||||||
}
|
}
|
||||||
|
|
||||||
list[index] = args.Result;
|
list[index] = args.Result;
|
||||||
|
}
|
||||||
|
|
||||||
Interlocked.Increment(ref completedRequests);
|
Interlocked.Increment(ref completedRequests);
|
||||||
|
|
||||||
if (Equals(completedRequests, ConnectionCount))
|
if (Equals(completedRequests, ConnectionCount))
|
||||||
|
|
@ -465,6 +476,8 @@ namespace Ryujinx.Modules
|
||||||
using Stream remoteFileStream = response.Content.ReadAsStreamAsync().Result;
|
using Stream remoteFileStream = response.Content.ReadAsStreamAsync().Result;
|
||||||
using Stream updateFileStream = File.Open(updateFile, FileMode.Create);
|
using Stream updateFileStream = File.Open(updateFile, FileMode.Create);
|
||||||
|
|
||||||
|
if (response.Content.Headers.ContentLength != null)
|
||||||
|
{
|
||||||
long totalBytes = response.Content.Headers.ContentLength.Value;
|
long totalBytes = response.Content.Headers.ContentLength.Value;
|
||||||
long byteWritten = 0;
|
long byteWritten = 0;
|
||||||
|
|
||||||
|
|
@ -485,6 +498,7 @@ namespace Ryujinx.Modules
|
||||||
|
|
||||||
updateFileStream.Write(buffer, 0, readSize);
|
updateFileStream.Write(buffer, 0, readSize);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
InstallUpdate(taskDialog, updateFile);
|
InstallUpdate(taskDialog, updateFile);
|
||||||
}
|
}
|
||||||
|
|
@ -524,7 +538,7 @@ namespace Ryujinx.Modules
|
||||||
|
|
||||||
string outPath = Path.Combine(outputDirectoryPath, tarEntry.Name);
|
string outPath = Path.Combine(outputDirectoryPath, tarEntry.Name);
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
Directory.CreateDirectory(Path.GetDirectoryName(outPath) ?? string.Empty);
|
||||||
|
|
||||||
using FileStream outStream = File.OpenWrite(outPath);
|
using FileStream outStream = File.OpenWrite(outPath);
|
||||||
tarStream.CopyEntryContents(outStream);
|
tarStream.CopyEntryContents(outStream);
|
||||||
|
|
@ -560,7 +574,7 @@ namespace Ryujinx.Modules
|
||||||
|
|
||||||
string outPath = Path.Combine(outputDirectoryPath, zipEntry.Name);
|
string outPath = Path.Combine(outputDirectoryPath, zipEntry.Name);
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
Directory.CreateDirectory(Path.GetDirectoryName(outPath) ?? string.Empty);
|
||||||
|
|
||||||
using Stream zipStream = zipFile.GetInputStream(zipEntry);
|
using Stream zipStream = zipFile.GetInputStream(zipEntry);
|
||||||
using FileStream outStream = File.OpenWrite(outPath);
|
using FileStream outStream = File.OpenWrite(outPath);
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,9 @@ namespace Ryujinx.Ava.UI.Applet
|
||||||
{
|
{
|
||||||
_parent = parent;
|
_parent = parent;
|
||||||
|
|
||||||
(_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyPressed += AvaloniaDynamicTextInputHandler_KeyPressed;
|
((AvaloniaKeyboardDriver)_parent.InputManager.KeyboardDriver).KeyPressed += AvaloniaDynamicTextInputHandler_KeyPressed;
|
||||||
(_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyRelease += AvaloniaDynamicTextInputHandler_KeyRelease;
|
((AvaloniaKeyboardDriver)_parent.InputManager.KeyboardDriver).KeyRelease += AvaloniaDynamicTextInputHandler_KeyRelease;
|
||||||
(_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).TextInput += AvaloniaDynamicTextInputHandler_TextInput;
|
((AvaloniaKeyboardDriver)_parent.InputManager.KeyboardDriver).TextInput += AvaloniaDynamicTextInputHandler_TextInput;
|
||||||
|
|
||||||
_hiddenTextBox = _parent.HiddenTextBox;
|
_hiddenTextBox = _parent.HiddenTextBox;
|
||||||
|
|
||||||
|
|
@ -118,9 +118,9 @@ namespace Ryujinx.Ava.UI.Applet
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
(_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyPressed -= AvaloniaDynamicTextInputHandler_KeyPressed;
|
((AvaloniaKeyboardDriver)_parent.InputManager.KeyboardDriver).KeyPressed -= AvaloniaDynamicTextInputHandler_KeyPressed;
|
||||||
(_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyRelease -= AvaloniaDynamicTextInputHandler_KeyRelease;
|
((AvaloniaKeyboardDriver)_parent.InputManager.KeyboardDriver).KeyRelease -= AvaloniaDynamicTextInputHandler_KeyRelease;
|
||||||
(_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).TextInput -= AvaloniaDynamicTextInputHandler_TextInput;
|
((AvaloniaKeyboardDriver)_parent.InputManager.KeyboardDriver).TextInput -= AvaloniaDynamicTextInputHandler_TextInput;
|
||||||
|
|
||||||
_textChangedSubscription?.Dispose();
|
_textChangedSubscription?.Dispose();
|
||||||
_selectionStartChangedSubscription?.Dispose();
|
_selectionStartChangedSubscription?.Dispose();
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ namespace Ryujinx.Ava.UI.Controls
|
||||||
viewModel.VirtualFileSystem,
|
viewModel.VirtualFileSystem,
|
||||||
viewModel.SelectedApplication.IdString,
|
viewModel.SelectedApplication.IdString,
|
||||||
viewModel.SelectedApplication.Name,
|
viewModel.SelectedApplication.Name,
|
||||||
viewModel.SelectedApplication.Path).ShowDialog(viewModel.TopLevel as Window);
|
viewModel.SelectedApplication.Path).ShowDialog((Window)viewModel.TopLevel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -396,11 +396,14 @@ namespace Ryujinx.Ava.UI.Controls
|
||||||
viewModel.SelectedApplication.Name);
|
viewModel.SelectedApplication.Name);
|
||||||
|
|
||||||
var iconFile = await result[0].CreateFileAsync(selectedApp.IdString + ".png");
|
var iconFile = await result[0].CreateFileAsync(selectedApp.IdString + ".png");
|
||||||
|
if (iconFile != null)
|
||||||
|
{
|
||||||
await using var fileStream = await iconFile.OpenWriteAsync();
|
await using var fileStream = await iconFile.OpenWriteAsync();
|
||||||
|
|
||||||
fileStream.Write(selectedApp.Icon);
|
fileStream.Write(selectedApp.Icon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void CreateApplicationShortcut_Click(object sender, RoutedEventArgs args)
|
public void CreateApplicationShortcut_Click(object sender, RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ namespace Ryujinx.Ava.UI.Controls
|
||||||
|
|
||||||
private void SearchBox_OnKeyUp(object sender, KeyEventArgs args)
|
private void SearchBox_OnKeyUp(object sender, KeyEventArgs args)
|
||||||
{
|
{
|
||||||
(DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
|
(DataContext as MainWindowViewModel).SearchText = (sender as TextBox)?.Text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ namespace Ryujinx.Ava.UI.Controls
|
||||||
|
|
||||||
private void SearchBox_OnKeyUp(object sender, KeyEventArgs args)
|
private void SearchBox_OnKeyUp(object sender, KeyEventArgs args)
|
||||||
{
|
{
|
||||||
(DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
|
(DataContext as MainWindowViewModel).SearchText = (sender as TextBox)?.Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void IdString_OnClick(object sender, RoutedEventArgs e)
|
private async void IdString_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,8 @@ namespace Ryujinx.Ava.UI.Models
|
||||||
|
|
||||||
if (InGameList)
|
if (InGameList)
|
||||||
{
|
{
|
||||||
Icon = appData.Icon;
|
Icon = appData?.Icon;
|
||||||
Title = appData.Name;
|
Title = appData?.Name;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ namespace Ryujinx.Ava.UI.Models
|
||||||
private void UpdateBackground()
|
private void UpdateBackground()
|
||||||
{
|
{
|
||||||
var currentApplication = Avalonia.Application.Current;
|
var currentApplication = Avalonia.Application.Current;
|
||||||
currentApplication.Styles.TryGetResource("ControlFillColorSecondary", currentApplication.ActualThemeVariant, out object color);
|
currentApplication!.Styles.TryGetResource("ControlFillColorSecondary", currentApplication.ActualThemeVariant, out object color);
|
||||||
|
|
||||||
if (color is not null)
|
if (color is not null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -127,8 +127,11 @@ namespace Ryujinx.Ava.UI.Renderer
|
||||||
X11Window = PlatformHelper.CreateOpenGLWindow(new FramebufferFormat(new ColorFormat(8, 8, 8, 0), 16, 0, ColorFormat.Zero, 0, 2, false), 0, 0, 100, 100) as GLXWindow;
|
X11Window = PlatformHelper.CreateOpenGLWindow(new FramebufferFormat(new ColorFormat(8, 8, 8, 0), 16, 0, ColorFormat.Zero, 0, 2, false), 0, 0, 100, 100) as GLXWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (X11Window != null)
|
||||||
|
{
|
||||||
WindowHandle = X11Window.WindowHandle.RawHandle;
|
WindowHandle = X11Window.WindowHandle.RawHandle;
|
||||||
X11Display = X11Window.DisplayHandle.RawHandle;
|
X11Display = X11Window.DisplayHandle.RawHandle;
|
||||||
|
}
|
||||||
|
|
||||||
return new PlatformHandle(WindowHandle, "X11");
|
return new PlatformHandle(WindowHandle, "X11");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
return app.Favorite ? -1 : 1;
|
return app.Favorite ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new InvalidCastException($"Cannot cast {o.GetType()} to {nameof(AppListFavoriteComparable)}");
|
throw new InvalidCastException($"Cannot cast {o?.GetType()} to {nameof(AppListFavoriteComparable)}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,9 +92,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
|
||||||
_applicationData = applicationData;
|
_applicationData = applicationData;
|
||||||
|
|
||||||
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
{
|
{
|
||||||
_storageProvider = desktop.MainWindow.StorageProvider;
|
_storageProvider = desktop.MainWindow?.StorageProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadDownloadableContents();
|
LoadDownloadableContents();
|
||||||
|
|
|
||||||
|
|
@ -254,10 +254,13 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||||
|
|
||||||
AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(owner);
|
AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(owner);
|
||||||
|
|
||||||
|
if (_mainWindow != null)
|
||||||
|
{
|
||||||
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
|
_mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
|
||||||
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
|
_mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
|
||||||
|
|
||||||
_mainWindow.ViewModel.AppHost?.NpadManager.BlockInputUpdates();
|
_mainWindow.ViewModel.AppHost?.NpadManager.BlockInputUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
_isLoaded = false;
|
_isLoaded = false;
|
||||||
|
|
||||||
|
|
@ -783,11 +786,14 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||||
config = (ConfigViewModel as ControllerInputViewModel)?.Config.GetConfig();
|
config = (ConfigViewModel as ControllerInputViewModel)?.Config.GetConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config != null)
|
||||||
|
{
|
||||||
config.ControllerType = Controllers[_controller].Type;
|
config.ControllerType = Controllers[_controller].Type;
|
||||||
|
|
||||||
string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig);
|
string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig);
|
||||||
|
|
||||||
await File.WriteAllTextAsync(path, jsonString);
|
await File.WriteAllTextAsync(path, jsonString);
|
||||||
|
}
|
||||||
|
|
||||||
LoadProfiles();
|
LoadProfiles();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1332,7 +1332,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
}
|
}
|
||||||
catch (MissingKeyException ex)
|
catch (MissingKeyException ex)
|
||||||
{
|
{
|
||||||
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Application, ex.ToString());
|
Logger.Error?.Print(LogClass.Application, ex.ToString());
|
||||||
|
|
||||||
|
|
@ -1553,7 +1553,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.InvokeAsync(() =>
|
Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
Application.Current.Styles.TryGetResource(args.VSyncMode,
|
Application.Current!.Styles.TryGetResource(args.VSyncMode,
|
||||||
Application.Current.ActualThemeVariant,
|
Application.Current.ActualThemeVariant,
|
||||||
out object color);
|
out object color);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -279,7 +279,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
|
||||||
foreach (var dir in directories)
|
foreach (var dir in directories)
|
||||||
{
|
{
|
||||||
string dirToCreate = dir.Replace(directory.Parent.ToString(), destinationDir);
|
string dirToCreate = dir.Replace(directory.Parent?.ToString() ?? string.Empty, destinationDir);
|
||||||
|
|
||||||
// Mod already exists
|
// Mod already exists
|
||||||
if (Directory.Exists(dirToCreate))
|
if (Directory.Exists(dirToCreate))
|
||||||
|
|
@ -302,7 +302,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
|
||||||
foreach (var file in files)
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
File.Copy(file, file.Replace(directory.Parent.ToString(), destinationDir), true);
|
File.Copy(file, file.Replace(directory.Parent?.ToString() ?? string.Empty, destinationDir), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadMods(_applicationId, _installedDlcIds);
|
LoadMods(_applicationId, _installedDlcIds);
|
||||||
|
|
|
||||||
|
|
@ -75,9 +75,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
|
||||||
ApplicationData = applicationData;
|
ApplicationData = applicationData;
|
||||||
|
|
||||||
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
{
|
{
|
||||||
StorageProvider = desktop.MainWindow.StorageProvider;
|
StorageProvider = desktop.MainWindow?.StorageProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadUpdates();
|
LoadUpdates();
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
result = String.Compare(x?.Name, y?.Name, StringComparison.Ordinal);
|
result = String.Compare(x?.Name, y?.Name, StringComparison.Ordinal);
|
||||||
break;
|
break;
|
||||||
case SortField.Saved:
|
case SortField.Saved:
|
||||||
|
if (x != null && y != null)
|
||||||
|
{
|
||||||
result = x.PotentialSavingsB.CompareTo(y.PotentialSavingsB);
|
result = x.PotentialSavingsB.CompareTo(y.PotentialSavingsB);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,11 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||||
{
|
{
|
||||||
|
|
||||||
var viewModel = (DataContext as ControllerInputViewModel);
|
var viewModel = (DataContext as ControllerInputViewModel);
|
||||||
|
if (viewModel != null)
|
||||||
|
{
|
||||||
viewModel.ParentModel.IsModified = true;
|
viewModel.ParentModel.IsModified = true;
|
||||||
|
}
|
||||||
|
|
||||||
_changeSlider = (float)check.Value;
|
_changeSlider = (float)check.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -82,9 +86,11 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||||
{
|
{
|
||||||
if ((bool)check.IsPointerOver)
|
if ((bool)check.IsPointerOver)
|
||||||
{
|
{
|
||||||
|
if (DataContext is ControllerInputViewModel viewModel)
|
||||||
var viewModel = (DataContext as ControllerInputViewModel);
|
{
|
||||||
viewModel.ParentModel.IsModified = true;
|
viewModel.ParentModel.IsModified = true;
|
||||||
|
}
|
||||||
|
|
||||||
_currentAssigner?.Cancel();
|
_currentAssigner?.Cancel();
|
||||||
_currentAssigner = null;
|
_currentAssigner = null;
|
||||||
}
|
}
|
||||||
|
|
@ -96,7 +102,7 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||||
{
|
{
|
||||||
if (sender is ToggleButton button )
|
if (sender is ToggleButton button )
|
||||||
{
|
{
|
||||||
if ((bool)button.IsChecked)
|
if (button.IsChecked != null && (bool)button.IsChecked)
|
||||||
{
|
{
|
||||||
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
|
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
|
||||||
{
|
{
|
||||||
|
|
@ -233,7 +239,7 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||||
var controllerInputViewModel = DataContext as ControllerInputViewModel;
|
var controllerInputViewModel = DataContext as ControllerInputViewModel;
|
||||||
|
|
||||||
assigner = new GamepadButtonAssigner(
|
assigner = new GamepadButtonAssigner(
|
||||||
controllerInputViewModel.ParentModel.SelectedGamepad,
|
controllerInputViewModel?.ParentModel.SelectedGamepad,
|
||||||
(controllerInputViewModel.ParentModel.Config as StandardControllerInputConfig).TriggerThreshold,
|
(controllerInputViewModel.ParentModel.Config as StandardControllerInputConfig).TriggerThreshold,
|
||||||
forStick);
|
forStick);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,10 +72,13 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||||
{
|
{
|
||||||
ViewModel.IsModified = true;
|
ViewModel.IsModified = true;
|
||||||
var player = (PlayerModel)e.AddedItems[0];
|
var player = (PlayerModel)e.AddedItems[0];
|
||||||
|
if (player != null)
|
||||||
|
{
|
||||||
ViewModel.PlayerId = player.Id;
|
ViewModel.PlayerId = player.Id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||||
{
|
{
|
||||||
if (sender is ToggleButton button)
|
if (sender is ToggleButton button)
|
||||||
{
|
{
|
||||||
if ((bool)button.IsChecked)
|
if (button.IsChecked != null && (bool)button.IsChecked)
|
||||||
{
|
{
|
||||||
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
|
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
|
||||||
{
|
{
|
||||||
|
|
@ -60,6 +60,8 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||||
|
|
||||||
var viewModel = (DataContext as KeyboardInputViewModel);
|
var viewModel = (DataContext as KeyboardInputViewModel);
|
||||||
|
|
||||||
|
if (viewModel != null)
|
||||||
|
{
|
||||||
IKeyboard keyboard = (IKeyboard)viewModel.ParentModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
|
IKeyboard keyboard = (IKeyboard)viewModel.ParentModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
|
||||||
IButtonAssigner assigner = CreateButtonAssigner();
|
IButtonAssigner assigner = CreateButtonAssigner();
|
||||||
|
|
||||||
|
|
@ -162,6 +164,7 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||||
|
|
||||||
_currentAssigner.GetInputAndAssign(assigner, keyboard);
|
_currentAssigner.GetInputAndAssign(assigner, keyboard);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_currentAssigner != null)
|
if (_currentAssigner != null)
|
||||||
|
|
@ -193,7 +196,7 @@ namespace Ryujinx.Ava.UI.Views.Input
|
||||||
{
|
{
|
||||||
IButtonAssigner assigner;
|
IButtonAssigner assigner;
|
||||||
|
|
||||||
assigner = new KeyboardKeyAssigner((IKeyboard)(DataContext as KeyboardInputViewModel).ParentModel.SelectedGamepad);
|
assigner = new KeyboardKeyAssigner((IKeyboard)(DataContext as KeyboardInputViewModel)?.ParentModel.SelectedGamepad);
|
||||||
|
|
||||||
return assigner;
|
return assigner;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||||
{
|
{
|
||||||
if (sender is RadioButton button)
|
if (sender is RadioButton button)
|
||||||
{
|
{
|
||||||
ViewModel.Sort(Enum.Parse<ApplicationSort>(button.Tag.ToString()));
|
ViewModel.Sort(Enum.Parse<ApplicationSort>(button.Tag?.ToString() ?? string.Empty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||||
{
|
{
|
||||||
if (sender is RadioButton button)
|
if (sender is RadioButton button)
|
||||||
{
|
{
|
||||||
ViewModel.Sort(button.Tag.ToString() != "Descending");
|
ViewModel.Sort(button.Tag?.ToString() != "Descending");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ namespace Ryujinx.Ava.UI.Views.Settings
|
||||||
{
|
{
|
||||||
if (sender is ToggleButton button)
|
if (sender is ToggleButton button)
|
||||||
{
|
{
|
||||||
if ((bool)button.IsChecked)
|
if (button.IsChecked != null && (bool)button.IsChecked)
|
||||||
{
|
{
|
||||||
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
|
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
|
||||||
{
|
{
|
||||||
|
|
@ -69,6 +69,8 @@ namespace Ryujinx.Ava.UI.Views.Settings
|
||||||
var viewModel = (DataContext) as SettingsViewModel;
|
var viewModel = (DataContext) as SettingsViewModel;
|
||||||
var buttonValue = e.ButtonValue.Value;
|
var buttonValue = e.ButtonValue.Value;
|
||||||
|
|
||||||
|
if (viewModel != null)
|
||||||
|
{
|
||||||
switch (button.Name)
|
switch (button.Name)
|
||||||
{
|
{
|
||||||
case "ToggleVSyncMode":
|
case "ToggleVSyncMode":
|
||||||
|
|
@ -106,6 +108,7 @@ namespace Ryujinx.Ava.UI.Views.Settings
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_currentAssigner.GetInputAndAssign(assigner, keyboard);
|
_currentAssigner.GetInputAndAssign(assigner, keyboard);
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ namespace Ryujinx.Ava.UI.Views.User
|
||||||
private async void Import_OnClick(object sender, RoutedEventArgs e)
|
private async void Import_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var window = this.GetVisualRoot() as Window;
|
var window = this.GetVisualRoot() as Window;
|
||||||
var result = await window.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
var result = await window?.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||||
{
|
{
|
||||||
AllowMultiple = false,
|
AllowMultiple = false,
|
||||||
FileTypeFilter = new List<FilePickerFileType>
|
FileTypeFilter = new List<FilePickerFileType>
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ namespace Ryujinx.Ava.UI.Views.User
|
||||||
|
|
||||||
private void Close(object sender, RoutedEventArgs e)
|
private void Close(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
((ContentDialog)_parent.Parent).Hide();
|
((ContentDialog)_parent.Parent)?.Hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(_enabledCheatsPath));
|
Directory.CreateDirectory(Path.GetDirectoryName(_enabledCheatsPath) ?? string.Empty);
|
||||||
|
|
||||||
File.WriteAllLines(_enabledCheatsPath, enabledCheats);
|
File.WriteAllLines(_enabledCheatsPath, enabledCheats);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,12 +53,12 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
private void SaveAndClose(object sender, RoutedEventArgs routedEventArgs)
|
private void SaveAndClose(object sender, RoutedEventArgs routedEventArgs)
|
||||||
{
|
{
|
||||||
ViewModel.Save();
|
ViewModel.Save();
|
||||||
((ContentDialog)Parent).Hide();
|
((ContentDialog)Parent)?.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Close(object sender, RoutedEventArgs e)
|
private void Close(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
((ContentDialog)Parent).Hide();
|
((ContentDialog)Parent)?.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveDLC(object sender, RoutedEventArgs e)
|
private void RemoveDLC(object sender, RoutedEventArgs e)
|
||||||
|
|
|
||||||
|
|
@ -494,7 +494,10 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Subscribe to the ColorValuesChanged event
|
/// Subscribe to the ColorValuesChanged event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
if (PlatformSettings != null)
|
||||||
|
{
|
||||||
PlatformSettings.ColorValuesChanged += OnPlatformColorValuesChanged;
|
PlatformSettings.ColorValuesChanged += OnPlatformColorValuesChanged;
|
||||||
|
}
|
||||||
|
|
||||||
ViewModel.Initialize(
|
ViewModel.Initialize(
|
||||||
ContentManager,
|
ContentManager,
|
||||||
|
|
@ -578,7 +581,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
var volumeSplitButton = sender as ToggleSplitButton;
|
var volumeSplitButton = sender as ToggleSplitButton;
|
||||||
if (ViewModel.IsGameRunning)
|
if (ViewModel.IsGameRunning)
|
||||||
{
|
{
|
||||||
if (!volumeSplitButton.IsChecked)
|
if (volumeSplitButton is not { IsChecked: true })
|
||||||
{
|
{
|
||||||
ViewModel.AppHost.Device.SetVolume(ViewModel.VolumeBeforeMute);
|
ViewModel.AppHost.Device.SetVolume(ViewModel.VolumeBeforeMute);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,12 +53,12 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
private void SaveAndClose(object sender, RoutedEventArgs e)
|
private void SaveAndClose(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.Save();
|
ViewModel.Save();
|
||||||
((ContentDialog)Parent).Hide();
|
((ContentDialog)Parent)?.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Close(object sender, RoutedEventArgs e)
|
private void Close(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
((ContentDialog)Parent).Hide();
|
((ContentDialog)Parent)?.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void DeleteMod(object sender, RoutedEventArgs e)
|
private async void DeleteMod(object sender, RoutedEventArgs e)
|
||||||
|
|
|
||||||
|
|
@ -50,14 +50,14 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
|
|
||||||
private void Close(object sender, RoutedEventArgs e)
|
private void Close(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
((ContentDialog)Parent).Hide();
|
((ContentDialog)Parent)?.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save(object sender, RoutedEventArgs e)
|
public void Save(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.Save();
|
ViewModel.Save();
|
||||||
|
|
||||||
((ContentDialog)Parent).Hide();
|
((ContentDialog)Parent)?.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenLocation(object sender, RoutedEventArgs e)
|
private void OpenLocation(object sender, RoutedEventArgs e)
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
|
|
||||||
private void Close(object sender, RoutedEventArgs e)
|
private void Close(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
((ContentDialog)Parent).Hide();
|
((ContentDialog)Parent)?.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Cancel(Object sender, RoutedEventArgs e)
|
private void Cancel(Object sender, RoutedEventArgs e)
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ namespace Spv.Generator
|
||||||
|
|
||||||
public bool Equals(Instruction cmpObj)
|
public bool Equals(Instruction cmpObj)
|
||||||
{
|
{
|
||||||
bool result = Type == cmpObj.Type && Id == cmpObj.Id;
|
bool result = cmpObj != null && Type == cmpObj.Type && Id == cmpObj.Id;
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ namespace Spv.Generator
|
||||||
|
|
||||||
public bool Equals(LiteralInteger cmpObj)
|
public bool Equals(LiteralInteger cmpObj)
|
||||||
{
|
{
|
||||||
return Type == cmpObj.Type && _integerType == cmpObj._integerType && _data == cmpObj._data;
|
return cmpObj != null && Type == cmpObj.Type && _integerType == cmpObj._integerType && _data == cmpObj._data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ namespace Spv.Generator
|
||||||
|
|
||||||
public bool Equals(LiteralString cmpObj)
|
public bool Equals(LiteralString cmpObj)
|
||||||
{
|
{
|
||||||
return Type == cmpObj.Type && _value.Equals(cmpObj._value);
|
return cmpObj != null && Type == cmpObj.Type && _value.Equals(cmpObj._value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue