Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
70d65d3d8e | ||
|
0b58f46266 | ||
|
aa96dcb1be | ||
|
82a638230e | ||
|
d11fe26aa3 | ||
|
dcf10561b9 | ||
|
cdc8fed64f |
@@ -27,10 +27,10 @@
|
|||||||
<PackageVersion Include="NetCoreServer" Version="7.0.0" />
|
<PackageVersion Include="NetCoreServer" Version="7.0.0" />
|
||||||
<PackageVersion Include="NUnit" Version="3.13.3" />
|
<PackageVersion Include="NUnit" Version="3.13.3" />
|
||||||
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
|
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||||
<PackageVersion Include="OpenTK.Core" Version="4.7.7" />
|
<PackageVersion Include="OpenTK.Core" Version="4.8.1" />
|
||||||
<PackageVersion Include="OpenTK.Graphics" Version="4.7.7" />
|
<PackageVersion Include="OpenTK.Graphics" Version="4.8.1" />
|
||||||
<PackageVersion Include="OpenTK.OpenAL" Version="4.7.7" />
|
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.8.1" />
|
||||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.7.7" />
|
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.8.1" />
|
||||||
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
|
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||||
|
@@ -117,12 +117,11 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
|
|
||||||
int funcOffset = (int)(pointer.ToInt64() - _jitRegion.Pointer.ToInt64());
|
int funcOffset = (int)(pointer.ToInt64() - _jitRegion.Pointer.ToInt64());
|
||||||
|
|
||||||
bool result = TryFind(funcOffset, out CacheEntry entry);
|
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
|
||||||
Debug.Assert(result);
|
{
|
||||||
|
|
||||||
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
|
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
|
||||||
|
_cacheEntries.RemoveAt(entryIndex);
|
||||||
Remove(funcOffset);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,22 +180,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
_cacheEntries.Insert(index, entry);
|
_cacheEntries.Insert(index, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Remove(int offset)
|
public static bool TryFind(int offset, out CacheEntry entry, out int entryIndex)
|
||||||
{
|
|
||||||
int index = _cacheEntries.BinarySearch(new CacheEntry(offset, 0, default));
|
|
||||||
|
|
||||||
if (index < 0)
|
|
||||||
{
|
|
||||||
index = ~index - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index >= 0)
|
|
||||||
{
|
|
||||||
_cacheEntries.RemoveAt(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool TryFind(int offset, out CacheEntry entry)
|
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
@@ -210,11 +194,13 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
{
|
{
|
||||||
entry = _cacheEntries[index];
|
entry = _cacheEntries[index];
|
||||||
|
entryIndex = index;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = default;
|
entry = default;
|
||||||
|
entryIndex = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -95,7 +95,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
{
|
{
|
||||||
int offset = (int)((long)controlPc - context.ToInt64());
|
int offset = (int)((long)controlPc - context.ToInt64());
|
||||||
|
|
||||||
if (!JitCache.TryFind(offset, out CacheEntry funcEntry))
|
if (!JitCache.TryFind(offset, out CacheEntry funcEntry, out _))
|
||||||
{
|
{
|
||||||
return null; // Not found.
|
return null; // Not found.
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="OpenTK.OpenAL" />
|
<PackageReference Include="OpenTK.Audio.OpenAL" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -48,7 +48,7 @@ namespace Ryujinx.Common.Configuration
|
|||||||
string appDataPath;
|
string appDataPath;
|
||||||
if (OperatingSystem.IsMacOS())
|
if (OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Library", "Application Support");
|
appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -211,6 +211,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||||||
int xCount = (int)_state.State.LineLengthIn;
|
int xCount = (int)_state.State.LineLengthIn;
|
||||||
int yCount = (int)_state.State.LineCount;
|
int yCount = (int)_state.State.LineCount;
|
||||||
|
|
||||||
|
_channel.TextureManager.RefreshModifiedTextures();
|
||||||
_3dEngine.CreatePendingSyncs();
|
_3dEngine.CreatePendingSyncs();
|
||||||
_3dEngine.FlushUboDirty();
|
_3dEngine.FlushUboDirty();
|
||||||
|
|
||||||
|
@@ -651,9 +651,35 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// <returns>True if the format is valid, false otherwise</returns>
|
/// <returns>True if the format is valid, false otherwise</returns>
|
||||||
public static bool TryGetTextureFormat(uint encoded, bool isSrgb, out FormatInfo format)
|
public static bool TryGetTextureFormat(uint encoded, bool isSrgb, out FormatInfo format)
|
||||||
{
|
{
|
||||||
encoded |= (isSrgb ? 1u << 19 : 0u);
|
bool isPacked = (encoded & 0x80000000u) != 0;
|
||||||
|
if (isPacked)
|
||||||
|
{
|
||||||
|
encoded &= ~0x80000000u;
|
||||||
|
}
|
||||||
|
|
||||||
return _textureFormats.TryGetValue((TextureFormat)encoded, out format);
|
encoded |= isSrgb ? 1u << 19 : 0u;
|
||||||
|
|
||||||
|
bool found = _textureFormats.TryGetValue((TextureFormat)encoded, out format);
|
||||||
|
|
||||||
|
if (found && isPacked && !format.Format.IsDepthOrStencil())
|
||||||
|
{
|
||||||
|
// If the packed flag is set, then the components of the pixel are tightly packed into the
|
||||||
|
// GPU registers on the shader.
|
||||||
|
// We can get the same behaviour by aliasing the texture as a format with the same amount of
|
||||||
|
// bytes per pixel, but only a single or the lowest possible number of components.
|
||||||
|
|
||||||
|
format = format.BytesPerPixel switch
|
||||||
|
{
|
||||||
|
1 => new FormatInfo(Format.R8Unorm, 1, 1, 1, 1),
|
||||||
|
2 => new FormatInfo(Format.R16Unorm, 1, 1, 2, 1),
|
||||||
|
4 => new FormatInfo(Format.R32Float, 1, 1, 4, 1),
|
||||||
|
8 => new FormatInfo(Format.R32G32Float, 1, 1, 8, 2),
|
||||||
|
16 => new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16, 4),
|
||||||
|
_ => format,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -101,11 +101,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AlwaysFlushOnOverlap { get; private set; }
|
public bool AlwaysFlushOnOverlap { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates that the texture was modified since the last time it was flushed.
|
|
||||||
/// </summary>
|
|
||||||
public bool ModifiedSinceLastFlush { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Increments when the host texture is swapped, or when the texture is removed from all pools.
|
/// Increments when the host texture is swapped, or when the texture is removed from all pools.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1443,7 +1438,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
if (_modifiedStale || Group.HasCopyDependencies || Group.HasFlushBuffer)
|
if (_modifiedStale || Group.HasCopyDependencies || Group.HasFlushBuffer)
|
||||||
{
|
{
|
||||||
_modifiedStale = false;
|
_modifiedStale = false;
|
||||||
Group.SignalModifying(this, bound, bound || ModifiedSinceLastFlush || Group.HasCopyDependencies || Group.HasFlushBuffer);
|
Group.SignalModifying(this, bound);
|
||||||
}
|
}
|
||||||
|
|
||||||
_physicalMemory.TextureCache.Lift(this);
|
_physicalMemory.TextureCache.Lift(this);
|
||||||
|
@@ -2,6 +2,8 @@ using Ryujinx.Common;
|
|||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Texture;
|
using Ryujinx.Graphics.Texture;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Image
|
namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
@@ -339,7 +341,20 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
if (lhs.FormatInfo.BytesPerPixel != rhs.FormatInfo.BytesPerPixel && IsIncompatibleFormatAliasingAllowed(lhs.FormatInfo, rhs.FormatInfo))
|
if (lhs.FormatInfo.BytesPerPixel != rhs.FormatInfo.BytesPerPixel && IsIncompatibleFormatAliasingAllowed(lhs.FormatInfo, rhs.FormatInfo))
|
||||||
{
|
{
|
||||||
alignedWidthMatches = lhsSize.Width * lhs.FormatInfo.BytesPerPixel == rhsSize.Width * rhs.FormatInfo.BytesPerPixel;
|
// If the formats are incompatible, but the texture strides match,
|
||||||
|
// we might allow them to be copy compatible depending on the format.
|
||||||
|
// The strides are aligned because the format with higher bytes per pixel
|
||||||
|
// might need a bit of padding at the end due to one width not being a multiple of the other.
|
||||||
|
|
||||||
|
Debug.Assert((1 << BitOperations.Log2((uint)lhs.FormatInfo.BytesPerPixel)) == lhs.FormatInfo.BytesPerPixel);
|
||||||
|
Debug.Assert((1 << BitOperations.Log2((uint)rhs.FormatInfo.BytesPerPixel)) == rhs.FormatInfo.BytesPerPixel);
|
||||||
|
|
||||||
|
int alignment = Math.Max(lhs.FormatInfo.BytesPerPixel, rhs.FormatInfo.BytesPerPixel);
|
||||||
|
|
||||||
|
int lhsStride = BitUtils.AlignUp(lhsSize.Width * lhs.FormatInfo.BytesPerPixel, alignment);
|
||||||
|
int rhsStride = BitUtils.AlignUp(rhsSize.Width * rhs.FormatInfo.BytesPerPixel, alignment);
|
||||||
|
|
||||||
|
alignedWidthMatches = lhsStride == rhsStride;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureViewCompatibility result = TextureViewCompatibility.Full;
|
TextureViewCompatibility result = TextureViewCompatibility.Full;
|
||||||
@@ -718,7 +733,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
(lhsFormat, rhsFormat) = (rhsFormat, lhsFormat);
|
(lhsFormat, rhsFormat) = (rhsFormat, lhsFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
return lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm;
|
return (lhsFormat.Format == Format.R8G8B8A8Unorm && rhsFormat.Format == Format.R32G32B32A32Float) ||
|
||||||
|
(lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -709,8 +709,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="texture">The texture that has been modified</param>
|
/// <param name="texture">The texture that has been modified</param>
|
||||||
/// <param name="bound">True if this texture is being bound, false if unbound</param>
|
/// <param name="bound">True if this texture is being bound, false if unbound</param>
|
||||||
/// <param name="setModified">Indicates if the modified flag should be set</param>
|
public void SignalModifying(Texture texture, bool bound)
|
||||||
public void SignalModifying(Texture texture, bool bound, bool setModified)
|
|
||||||
{
|
{
|
||||||
ModifiedSequence = _context.GetModifiedSequence();
|
ModifiedSequence = _context.GetModifiedSequence();
|
||||||
|
|
||||||
@@ -722,7 +721,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
{
|
{
|
||||||
TextureGroupHandle group = _handles[baseHandle + i];
|
TextureGroupHandle group = _handles[baseHandle + i];
|
||||||
|
|
||||||
group.SignalModifying(bound, _context, setModified);
|
group.SignalModifying(bound, _context);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -993,26 +992,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The action to perform when a memory tracking handle is flipped to dirty.
|
|
||||||
/// This notifies overlapping textures that the memory needs to be synchronized.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="groupHandle">The handle that a dirty flag was set on</param>
|
|
||||||
private void DirtyAction(TextureGroupHandle groupHandle)
|
|
||||||
{
|
|
||||||
// Notify all textures that belong to this handle.
|
|
||||||
|
|
||||||
Storage.SignalGroupDirty();
|
|
||||||
|
|
||||||
lock (groupHandle.Overlaps)
|
|
||||||
{
|
|
||||||
foreach (Texture overlap in groupHandle.Overlaps)
|
|
||||||
{
|
|
||||||
overlap.SignalGroupDirty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a CpuRegionHandle for a given address and size range in CPU VA.
|
/// Generate a CpuRegionHandle for a given address and size range in CPU VA.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1084,11 +1063,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
views,
|
views,
|
||||||
result.ToArray());
|
result.ToArray());
|
||||||
|
|
||||||
foreach (RegionHandle handle in result)
|
|
||||||
{
|
|
||||||
handle.RegisterDirtyEvent(() => DirtyAction(groupHandle));
|
|
||||||
}
|
|
||||||
|
|
||||||
return groupHandle;
|
return groupHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1360,11 +1334,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
var groupHandle = new TextureGroupHandle(this, 0, Storage.Size, _views, 0, 0, 0, _allOffsets.Length, cpuRegionHandles);
|
var groupHandle = new TextureGroupHandle(this, 0, Storage.Size, _views, 0, 0, 0, _allOffsets.Length, cpuRegionHandles);
|
||||||
|
|
||||||
foreach (RegionHandle handle in cpuRegionHandles)
|
|
||||||
{
|
|
||||||
handle.RegisterDirtyEvent(() => DirtyAction(groupHandle));
|
|
||||||
}
|
|
||||||
|
|
||||||
handles = new TextureGroupHandle[] { groupHandle };
|
handles = new TextureGroupHandle[] { groupHandle };
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1620,6 +1589,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
if ((ignore == null || !handle.HasDependencyTo(ignore)) && handle.Modified)
|
if ((ignore == null || !handle.HasDependencyTo(ignore)) && handle.Modified)
|
||||||
{
|
{
|
||||||
handle.Modified = false;
|
handle.Modified = false;
|
||||||
|
handle.DeferredCopy = null;
|
||||||
Storage.SignalModifiedDirty();
|
Storage.SignalModifiedDirty();
|
||||||
|
|
||||||
lock (handle.Overlaps)
|
lock (handle.Overlaps)
|
||||||
@@ -1666,8 +1636,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Storage.ModifiedSinceLastFlush = false;
|
|
||||||
|
|
||||||
// There is a small gap here where the action is removed but _actionRegistered is still 1.
|
// There is a small gap here where the action is removed but _actionRegistered is still 1.
|
||||||
// In this case it will skip registering the action, but here we are already handling it,
|
// In this case it will skip registering the action, but here we are already handling it,
|
||||||
// so there shouldn't be any issue as it's the same handler for all actions.
|
// so there shouldn't be any issue as it's the same handler for all actions.
|
||||||
|
@@ -152,6 +152,32 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
// Linear textures are presumed to be used for readback initially.
|
// Linear textures are presumed to be used for readback initially.
|
||||||
_flushBalance = FlushBalanceThreshold + FlushBalanceIncrement;
|
_flushBalance = FlushBalanceThreshold + FlushBalanceIncrement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (RegionHandle handle in handles)
|
||||||
|
{
|
||||||
|
handle.RegisterDirtyEvent(DirtyAction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The action to perform when a memory tracking handle is flipped to dirty.
|
||||||
|
/// This notifies overlapping textures that the memory needs to be synchronized.
|
||||||
|
/// </summary>
|
||||||
|
private void DirtyAction()
|
||||||
|
{
|
||||||
|
// Notify all textures that belong to this handle.
|
||||||
|
|
||||||
|
_group.Storage.SignalGroupDirty();
|
||||||
|
|
||||||
|
lock (Overlaps)
|
||||||
|
{
|
||||||
|
foreach (Texture overlap in Overlaps)
|
||||||
|
{
|
||||||
|
overlap.SignalGroupDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeferredCopy = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -304,17 +330,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bound">True if this handle is being bound, false if unbound</param>
|
/// <param name="bound">True if this handle is being bound, false if unbound</param>
|
||||||
/// <param name="context">The GPU context to register a sync action on</param>
|
/// <param name="context">The GPU context to register a sync action on</param>
|
||||||
/// <param name="setModified">Indicates if the modified flag should be set</param>
|
public void SignalModifying(bool bound, GpuContext context)
|
||||||
public void SignalModifying(bool bound, GpuContext context, bool setModified)
|
|
||||||
{
|
|
||||||
if (setModified)
|
|
||||||
{
|
{
|
||||||
SignalModified(context);
|
SignalModified(context);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RegisterSync(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bound && _syncActionRegistered && NextSyncCopies())
|
if (!bound && _syncActionRegistered && NextSyncCopies())
|
||||||
{
|
{
|
||||||
@@ -457,7 +475,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
public void DeferCopy(TextureGroupHandle copyFrom)
|
public void DeferCopy(TextureGroupHandle copyFrom)
|
||||||
{
|
{
|
||||||
Modified = false;
|
Modified = false;
|
||||||
|
|
||||||
DeferredCopy = copyFrom;
|
DeferredCopy = copyFrom;
|
||||||
|
|
||||||
_group.Storage.SignalGroupDirty();
|
_group.Storage.SignalGroupDirty();
|
||||||
@@ -514,7 +531,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
{
|
{
|
||||||
existing.Other.Handle.CreateCopyDependency(this);
|
existing.Other.Handle.CreateCopyDependency(this);
|
||||||
|
|
||||||
if (copyToOther)
|
if (copyToOther && Modified)
|
||||||
{
|
{
|
||||||
existing.Other.Handle.DeferCopy(this);
|
existing.Other.Handle.DeferCopy(this);
|
||||||
}
|
}
|
||||||
@@ -558,10 +575,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
if (fromHandle != null)
|
if (fromHandle != null)
|
||||||
{
|
{
|
||||||
// Only copy if the copy texture is still modified.
|
// Only copy if the copy texture is still modified.
|
||||||
// It will be set as unmodified if new data is written from CPU, as the data previously in the texture will flush.
|
// DeferredCopy will be set to null if new data is written from CPU (see the DirtyAction method).
|
||||||
// It will also set as unmodified if a copy is deferred to it.
|
// It will also set as unmodified if a copy is deferred to it.
|
||||||
|
|
||||||
shouldCopy = fromHandle.Modified;
|
shouldCopy = true;
|
||||||
|
|
||||||
if (fromHandle._bindCount == 0)
|
if (fromHandle._bindCount == 0)
|
||||||
{
|
{
|
||||||
|
@@ -20,8 +20,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
private readonly Texture[] _rtColors;
|
private readonly Texture[] _rtColors;
|
||||||
private readonly ITexture[] _rtHostColors;
|
private readonly ITexture[] _rtHostColors;
|
||||||
|
private readonly bool[] _rtColorsBound;
|
||||||
private Texture _rtDepthStencil;
|
private Texture _rtDepthStencil;
|
||||||
private ITexture _rtHostDs;
|
private ITexture _rtHostDs;
|
||||||
|
private bool _rtDsBound;
|
||||||
|
|
||||||
public int ClipRegionWidth { get; private set; }
|
public int ClipRegionWidth { get; private set; }
|
||||||
public int ClipRegionHeight { get; private set; }
|
public int ClipRegionHeight { get; private set; }
|
||||||
@@ -51,6 +53,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
_rtColors = new Texture[Constants.TotalRenderTargets];
|
_rtColors = new Texture[Constants.TotalRenderTargets];
|
||||||
_rtHostColors = new ITexture[Constants.TotalRenderTargets];
|
_rtHostColors = new ITexture[Constants.TotalRenderTargets];
|
||||||
|
_rtColorsBound = new bool[Constants.TotalRenderTargets];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -153,8 +156,15 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
bool changesScale = (hasValue != (_rtColors[index] != null)) || (hasValue && RenderTargetScale != color.ScaleFactor);
|
bool changesScale = (hasValue != (_rtColors[index] != null)) || (hasValue && RenderTargetScale != color.ScaleFactor);
|
||||||
|
|
||||||
if (_rtColors[index] != color)
|
if (_rtColors[index] != color)
|
||||||
|
{
|
||||||
|
if (_rtColorsBound[index])
|
||||||
{
|
{
|
||||||
_rtColors[index]?.SignalModifying(false);
|
_rtColors[index]?.SignalModifying(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_rtColorsBound[index] = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (color != null)
|
if (color != null)
|
||||||
{
|
{
|
||||||
@@ -179,8 +189,15 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
bool changesScale = (hasValue != (_rtDepthStencil != null)) || (hasValue && RenderTargetScale != depthStencil.ScaleFactor);
|
bool changesScale = (hasValue != (_rtDepthStencil != null)) || (hasValue && RenderTargetScale != depthStencil.ScaleFactor);
|
||||||
|
|
||||||
if (_rtDepthStencil != depthStencil)
|
if (_rtDepthStencil != depthStencil)
|
||||||
|
{
|
||||||
|
if (_rtDsBound)
|
||||||
{
|
{
|
||||||
_rtDepthStencil?.SignalModifying(false);
|
_rtDepthStencil?.SignalModifying(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_rtDsBound = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (depthStencil != null)
|
if (depthStencil != null)
|
||||||
{
|
{
|
||||||
@@ -419,7 +436,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
if (dsTexture != null)
|
if (dsTexture != null)
|
||||||
{
|
{
|
||||||
hostDsTexture = dsTexture.HostTexture;
|
hostDsTexture = dsTexture.HostTexture;
|
||||||
dsTexture.ModifiedSinceLastFlush = true;
|
|
||||||
|
if (!_rtDsBound)
|
||||||
|
{
|
||||||
|
dsTexture.SignalModifying(true);
|
||||||
|
_rtDsBound = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_rtHostDs != hostDsTexture)
|
if (_rtHostDs != hostDsTexture)
|
||||||
@@ -436,7 +458,12 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
if (texture != null)
|
if (texture != null)
|
||||||
{
|
{
|
||||||
hostTexture = texture.HostTexture;
|
hostTexture = texture.HostTexture;
|
||||||
texture.ModifiedSinceLastFlush = true;
|
|
||||||
|
if (!_rtColorsBound[index])
|
||||||
|
{
|
||||||
|
texture.SignalModifying(true);
|
||||||
|
_rtColorsBound[index] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_rtHostColors[index] != hostTexture)
|
if (_rtHostColors[index] != hostTexture)
|
||||||
@@ -466,6 +493,31 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
_context.Renderer.Pipeline.SetRenderTargets(_rtHostColors, _rtHostDs);
|
_context.Renderer.Pipeline.SetRenderTargets(_rtHostColors, _rtHostDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks all currently bound render target textures as modified, and also makes them be set as modified again on next use.
|
||||||
|
/// </summary>
|
||||||
|
public void RefreshModifiedTextures()
|
||||||
|
{
|
||||||
|
Texture dsTexture = _rtDepthStencil;
|
||||||
|
|
||||||
|
if (dsTexture != null && _rtDsBound)
|
||||||
|
{
|
||||||
|
dsTexture.SignalModifying(false);
|
||||||
|
_rtDsBound = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int index = 0; index < _rtColors.Length; index++)
|
||||||
|
{
|
||||||
|
Texture texture = _rtColors[index];
|
||||||
|
|
||||||
|
if (texture != null && _rtColorsBound[index])
|
||||||
|
{
|
||||||
|
texture.SignalModifying(false);
|
||||||
|
_rtColorsBound[index] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Forces the texture and sampler pools to be re-loaded from the cache on next use.
|
/// Forces the texture and sampler pools to be re-loaded from the cache on next use.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -501,12 +553,20 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
_samplerPoolCache.Dispose();
|
_samplerPoolCache.Dispose();
|
||||||
|
|
||||||
for (int i = 0; i < _rtColors.Length; i++)
|
for (int i = 0; i < _rtColors.Length; i++)
|
||||||
|
{
|
||||||
|
if (_rtColorsBound[i])
|
||||||
{
|
{
|
||||||
_rtColors[i]?.DecrementReferenceCount();
|
_rtColors[i]?.DecrementReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
_rtColors[i] = null;
|
_rtColors[i] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_rtDsBound)
|
||||||
|
{
|
||||||
_rtDepthStencil?.DecrementReferenceCount();
|
_rtDepthStencil?.DecrementReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
_rtDepthStencil = null;
|
_rtDepthStencil = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -430,7 +430,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
if (!FormatTable.TryGetTextureFormat(format, srgb, out FormatInfo formatInfo))
|
if (!FormatTable.TryGetTextureFormat(format, srgb, out FormatInfo formatInfo))
|
||||||
{
|
{
|
||||||
if (gpuVa != 0 && (int)format > 0)
|
if (gpuVa != 0 && format != 0)
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Gpu, $"Invalid texture format 0x{format:X} (sRGB: {srgb}).");
|
Logger.Error?.Print(LogClass.Gpu, $"Invalid texture format 0x{format:X} (sRGB: {srgb}).");
|
||||||
}
|
}
|
||||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||||
private const uint CodeGenVersion = 5791;
|
private const uint CodeGenVersion = 5957;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
@@ -55,7 +55,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bindlessHandle.AsgOp is not Operation handleCombineOp)
|
if (!TryGetOperation(bindlessHandle.AsgOp, out Operation handleCombineOp))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -199,9 +199,64 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool TryGetOperation(INode asgOp, out Operation outOperation)
|
||||||
|
{
|
||||||
|
if (asgOp is PhiNode phi)
|
||||||
|
{
|
||||||
|
// If we have a phi, let's check if all inputs are effectively the same value.
|
||||||
|
// If so, we can "see through" the phi and pick any of the inputs (since they are all the same).
|
||||||
|
|
||||||
|
Operand firstSrc = phi.GetSource(0);
|
||||||
|
|
||||||
|
for (int index = 1; index < phi.SourcesCount; index++)
|
||||||
|
{
|
||||||
|
if (!IsSameOperand(firstSrc, phi.GetSource(index)))
|
||||||
|
{
|
||||||
|
outOperation = null;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
asgOp = firstSrc.AsgOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asgOp is Operation operation)
|
||||||
|
{
|
||||||
|
outOperation = operation;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
outOperation = null;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsSameOperand(Operand x, Operand y)
|
||||||
|
{
|
||||||
|
if (x.Type == y.Type && x.Type == OperandType.LocalVariable)
|
||||||
|
{
|
||||||
|
return x.AsgOp is Operation xOp &&
|
||||||
|
y.AsgOp is Operation yOp &&
|
||||||
|
xOp.Inst == Instruction.BitwiseOr &&
|
||||||
|
yOp.Inst == Instruction.BitwiseOr &&
|
||||||
|
AreBothEqualConstantBuffers(xOp.GetSource(0), yOp.GetSource(0)) &&
|
||||||
|
AreBothEqualConstantBuffers(xOp.GetSource(1), yOp.GetSource(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool AreBothEqualConstantBuffers(Operand x, Operand y)
|
||||||
|
{
|
||||||
|
return x.Type == y.Type && x.Value == y.Value && x.Type == OperandType.ConstantBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
private static Operand GetSourceForMaskedHandle(Operation asgOp, uint mask)
|
private static Operand GetSourceForMaskedHandle(Operation asgOp, uint mask)
|
||||||
{
|
{
|
||||||
// Assume it was already checked that the operation is bitwise AND.
|
// Assume it was already checked that the operation is bitwise AND.
|
||||||
|
|
||||||
Operand src0 = asgOp.GetSource(0);
|
Operand src0 = asgOp.GetSource(0);
|
||||||
Operand src1 = asgOp.GetSource(1);
|
Operand src1 = asgOp.GetSource(1);
|
||||||
|
|
||||||
@@ -210,6 +265,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
// We can't check if the mask matches here as both operands are from a constant buffer.
|
// We can't check if the mask matches here as both operands are from a constant buffer.
|
||||||
// Be optimistic and assume it matches. Avoid constant buffer 1 as official drivers
|
// Be optimistic and assume it matches. Avoid constant buffer 1 as official drivers
|
||||||
// uses this one to store compiler constants.
|
// uses this one to store compiler constants.
|
||||||
|
|
||||||
return src0.GetCbufSlot() == 1 ? src1 : src0;
|
return src0.GetCbufSlot() == 1 ? src1 : src0;
|
||||||
}
|
}
|
||||||
else if (src0.Type == OperandType.ConstantBuffer && src1.Type == OperandType.Constant)
|
else if (src0.Type == OperandType.ConstantBuffer && src1.Type == OperandType.Constant)
|
||||||
|
@@ -1,9 +0,0 @@
|
|||||||
namespace Ryujinx.Ui.Common.Configuration
|
|
||||||
{
|
|
||||||
public enum ConfigurationLoadResult
|
|
||||||
{
|
|
||||||
Success = 0,
|
|
||||||
NotLoaded = 1,
|
|
||||||
MigratedFromPreVulkan = 1 << 8,
|
|
||||||
}
|
|
||||||
}
|
|
@@ -5,6 +5,7 @@ using Ryujinx.Common.Configuration.Hid.Controller;
|
|||||||
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||||
using Ryujinx.Common.Configuration.Multiplayer;
|
using Ryujinx.Common.Configuration.Multiplayer;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Graphics.Vulkan;
|
||||||
using Ryujinx.Ui.Common.Configuration.System;
|
using Ryujinx.Ui.Common.Configuration.System;
|
||||||
using Ryujinx.Ui.Common.Configuration.Ui;
|
using Ryujinx.Ui.Common.Configuration.Ui;
|
||||||
using Ryujinx.Ui.Common.Helper;
|
using Ryujinx.Ui.Common.Helper;
|
||||||
@@ -763,7 +764,7 @@ namespace Ryujinx.Ui.Common.Configuration
|
|||||||
Graphics.ResScaleCustom.Value = 1.0f;
|
Graphics.ResScaleCustom.Value = 1.0f;
|
||||||
Graphics.MaxAnisotropy.Value = -1.0f;
|
Graphics.MaxAnisotropy.Value = -1.0f;
|
||||||
Graphics.AspectRatio.Value = AspectRatio.Fixed16x9;
|
Graphics.AspectRatio.Value = AspectRatio.Fixed16x9;
|
||||||
Graphics.GraphicsBackend.Value = OperatingSystem.IsMacOS() ? GraphicsBackend.Vulkan : GraphicsBackend.OpenGl;
|
Graphics.GraphicsBackend.Value = DefaultGraphicsBackend();
|
||||||
Graphics.PreferredGpu.Value = "";
|
Graphics.PreferredGpu.Value = "";
|
||||||
Graphics.ShadersDumpPath.Value = "";
|
Graphics.ShadersDumpPath.Value = "";
|
||||||
Logger.EnableDebug.Value = false;
|
Logger.EnableDebug.Value = false;
|
||||||
@@ -907,7 +908,7 @@ namespace Ryujinx.Ui.Common.Configuration
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigurationLoadResult Load(ConfigurationFileFormat configurationFileFormat, string configurationFilePath)
|
public void Load(ConfigurationFileFormat configurationFileFormat, string configurationFilePath)
|
||||||
{
|
{
|
||||||
bool configurationFileUpdated = false;
|
bool configurationFileUpdated = false;
|
||||||
|
|
||||||
@@ -916,12 +917,8 @@ namespace Ryujinx.Ui.Common.Configuration
|
|||||||
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Unsupported configuration version {configurationFileFormat.Version}, loading default.");
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Unsupported configuration version {configurationFileFormat.Version}, loading default.");
|
||||||
|
|
||||||
LoadDefault();
|
LoadDefault();
|
||||||
|
|
||||||
return ConfigurationLoadResult.NotLoaded;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationLoadResult result = ConfigurationLoadResult.Success;
|
|
||||||
|
|
||||||
if (configurationFileFormat.Version < 2)
|
if (configurationFileFormat.Version < 2)
|
||||||
{
|
{
|
||||||
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 2.");
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 2.");
|
||||||
@@ -1336,8 +1333,6 @@ namespace Ryujinx.Ui.Common.Configuration
|
|||||||
|
|
||||||
configurationFileFormat.GraphicsBackend = GraphicsBackend.OpenGl;
|
configurationFileFormat.GraphicsBackend = GraphicsBackend.OpenGl;
|
||||||
|
|
||||||
result |= ConfigurationLoadResult.MigratedFromPreVulkan;
|
|
||||||
|
|
||||||
configurationFileUpdated = true;
|
configurationFileUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1535,8 +1530,18 @@ namespace Ryujinx.Ui.Common.Configuration
|
|||||||
|
|
||||||
Ryujinx.Common.Logging.Logger.Notice.Print(LogClass.Application, $"Configuration file updated to version {ConfigurationFileFormat.CurrentVersion}");
|
Ryujinx.Common.Logging.Logger.Notice.Print(LogClass.Application, $"Configuration file updated to version {ConfigurationFileFormat.CurrentVersion}");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
private static GraphicsBackend DefaultGraphicsBackend()
|
||||||
|
{
|
||||||
|
// Any system running macOS or returning any amount of valid Vulkan devices should default to Vulkan.
|
||||||
|
// Checks for if the Vulkan version and featureset is compatible should be performed within VulkanRenderer.
|
||||||
|
if (OperatingSystem.IsMacOS() || VulkanRenderer.GetPhysicalDevices().Length > 0)
|
||||||
|
{
|
||||||
|
return GraphicsBackend.Vulkan;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GraphicsBackend.OpenGl;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void LogValueChange<T>(ReactiveEventArgs<T> eventArgs, string valueName)
|
private static void LogValueChange<T>(ReactiveEventArgs<T> eventArgs, string valueName)
|
||||||
|
@@ -62,6 +62,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
|
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -177,8 +177,6 @@ namespace Ryujinx
|
|||||||
? appDataConfigurationPath
|
? appDataConfigurationPath
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
bool showVulkanPrompt = false;
|
|
||||||
|
|
||||||
if (ConfigurationPath == null)
|
if (ConfigurationPath == null)
|
||||||
{
|
{
|
||||||
// No configuration, we load the default values and save it to disk
|
// No configuration, we load the default values and save it to disk
|
||||||
@@ -186,26 +184,17 @@ namespace Ryujinx
|
|||||||
|
|
||||||
ConfigurationState.Instance.LoadDefault();
|
ConfigurationState.Instance.LoadDefault();
|
||||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(ConfigurationPath);
|
ConfigurationState.Instance.ToFileFormat().SaveConfig(ConfigurationPath);
|
||||||
|
|
||||||
showVulkanPrompt = true;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ConfigurationFileFormat.TryLoad(ConfigurationPath, out ConfigurationFileFormat configurationFileFormat))
|
if (ConfigurationFileFormat.TryLoad(ConfigurationPath, out ConfigurationFileFormat configurationFileFormat))
|
||||||
{
|
{
|
||||||
ConfigurationLoadResult result = ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath);
|
ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath);
|
||||||
|
|
||||||
if ((result & ConfigurationLoadResult.MigratedFromPreVulkan) != 0)
|
|
||||||
{
|
|
||||||
showVulkanPrompt = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.LoadDefault();
|
ConfigurationState.Instance.LoadDefault();
|
||||||
|
|
||||||
showVulkanPrompt = true;
|
|
||||||
|
|
||||||
Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location {ConfigurationPath}");
|
Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location {ConfigurationPath}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,12 +205,10 @@ namespace Ryujinx
|
|||||||
if (CommandLineState.OverrideGraphicsBackend.ToLower() == "opengl")
|
if (CommandLineState.OverrideGraphicsBackend.ToLower() == "opengl")
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.OpenGl;
|
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.OpenGl;
|
||||||
showVulkanPrompt = false;
|
|
||||||
}
|
}
|
||||||
else if (CommandLineState.OverrideGraphicsBackend.ToLower() == "vulkan")
|
else if (CommandLineState.OverrideGraphicsBackend.ToLower() == "vulkan")
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.Vulkan;
|
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.Vulkan;
|
||||||
showVulkanPrompt = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,35 +330,6 @@ namespace Ryujinx
|
|||||||
}, TaskContinuationOptions.OnlyOnFaulted);
|
}, TaskContinuationOptions.OnlyOnFaulted);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showVulkanPrompt)
|
|
||||||
{
|
|
||||||
var buttonTexts = new Dictionary<int, string>()
|
|
||||||
{
|
|
||||||
{ 0, "Yes (Vulkan)" },
|
|
||||||
{ 1, "No (OpenGL)" },
|
|
||||||
};
|
|
||||||
|
|
||||||
ResponseType response = GtkDialog.CreateCustomDialog(
|
|
||||||
"Ryujinx - Default graphics backend",
|
|
||||||
"Use Vulkan as default graphics backend?",
|
|
||||||
"Ryujinx now supports the Vulkan API. " +
|
|
||||||
"Vulkan greatly improves shader compilation performance, " +
|
|
||||||
"and fixes some graphical glitches; however, since it is a new feature, " +
|
|
||||||
"you may experience some issues that did not occur with OpenGL.\n\n" +
|
|
||||||
"Note that you will also lose any existing shader cache the first time you start a game " +
|
|
||||||
"on version 1.1.200 onwards, because Vulkan required changes to the shader cache that makes it incompatible with previous versions.\n\n" +
|
|
||||||
"Would you like to set Vulkan as the default graphics backend? " +
|
|
||||||
"You can change this at any time on the settings window.",
|
|
||||||
buttonTexts,
|
|
||||||
MessageType.Question);
|
|
||||||
|
|
||||||
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = response == 0
|
|
||||||
? GraphicsBackend.Vulkan
|
|
||||||
: GraphicsBackend.OpenGl;
|
|
||||||
|
|
||||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(ConfigurationPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
Application.Run();
|
Application.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user