Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f7c7b66fc0 | ||
|
28ba55598d | ||
|
9719b6a112 | ||
|
f70236f947 | ||
|
eafadf10c7 |
@@ -36,8 +36,8 @@
|
||||
|
||||
## Compatibility
|
||||
|
||||
As of October 2022, Ryujinx has been tested on approximately 3,600 titles; over 3,500 boot past menus and into gameplay, with roughly 3,000 of those being considered playable. You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues).
|
||||
Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
||||
As of October 2022, Ryujinx has been tested on approximately 3,700 titles; over 3,500 boot past menus and into gameplay, with roughly 3,000 of those being considered playable.
|
||||
You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -90,7 +90,7 @@ Ryujinx system files are stored in the `Ryujinx` folder. This folder is located
|
||||
|
||||
- **GPU**
|
||||
|
||||
The GPU emulator emulates the Switch's Maxwell GPU using the OpenGL API (version 4.5 minimum) through a custom build of OpenTK. There are currently four graphics enhancements available to the end user in Ryujinx: disk shader caching, resolution scaling, aspect ratio adjustment and anisotropic filtering. These enhancements can be adjusted or toggled as desired in the GUI.
|
||||
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum) or Vulkan APIs through a custom build of OpenTK or Silk.NET respectively. There are currently four graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Aspect Ratio Adjustment, and Anisotropic Filtering. These enhancements can be adjusted or toggled as desired in the GUI.
|
||||
|
||||
- **Input**
|
||||
|
||||
|
@@ -12,13 +12,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private const int MaxUpdateBufferSize = 0x10000;
|
||||
|
||||
public const AccessFlags DefaultAccessFlags =
|
||||
AccessFlags.AccessIndirectCommandReadBit |
|
||||
AccessFlags.AccessShaderReadBit |
|
||||
AccessFlags.AccessShaderWriteBit |
|
||||
AccessFlags.AccessTransferReadBit |
|
||||
AccessFlags.AccessTransferWriteBit |
|
||||
AccessFlags.AccessUniformReadBit |
|
||||
AccessFlags.AccessShaderReadBit |
|
||||
AccessFlags.AccessShaderWriteBit;
|
||||
AccessFlags.AccessUniformReadBit;
|
||||
|
||||
private readonly VulkanRenderer _gd;
|
||||
private readonly Device _device;
|
||||
|
@@ -228,10 +228,26 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
|
||||
}
|
||||
|
||||
public void CommandBufferBarrier()
|
||||
public unsafe void CommandBufferBarrier()
|
||||
{
|
||||
// TODO: More specific barrier?
|
||||
Barrier();
|
||||
MemoryBarrier memoryBarrier = new MemoryBarrier()
|
||||
{
|
||||
SType = StructureType.MemoryBarrier,
|
||||
SrcAccessMask = BufferHolder.DefaultAccessFlags,
|
||||
DstAccessMask = AccessFlags.AccessIndirectCommandReadBit
|
||||
};
|
||||
|
||||
Gd.Api.CmdPipelineBarrier(
|
||||
CommandBuffer,
|
||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
||||
PipelineStageFlags.PipelineStageDrawIndirectBit,
|
||||
0,
|
||||
1,
|
||||
memoryBarrier,
|
||||
0,
|
||||
null,
|
||||
0,
|
||||
null);
|
||||
}
|
||||
|
||||
public void CopyBuffer(BufferHandle source, BufferHandle destination, int srcOffset, int dstOffset, int size)
|
||||
@@ -535,10 +551,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
vkBlend = new PipelineColorBlendAttachmentState();
|
||||
}
|
||||
|
||||
_newState.BlendConstantR = blend.BlendConstant.Red;
|
||||
_newState.BlendConstantG = blend.BlendConstant.Green;
|
||||
_newState.BlendConstantB = blend.BlendConstant.Blue;
|
||||
_newState.BlendConstantA = blend.BlendConstant.Alpha;
|
||||
DynamicState.SetBlendConstants(
|
||||
blend.BlendConstant.Red,
|
||||
blend.BlendConstant.Green,
|
||||
blend.BlendConstant.Blue,
|
||||
blend.BlendConstant.Alpha);
|
||||
|
||||
SignalStateChange();
|
||||
}
|
||||
@@ -823,7 +840,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
if (range.Handle != BufferHandle.Null)
|
||||
{
|
||||
_transformFeedbackBuffers[i] =
|
||||
_transformFeedbackBuffers[i] =
|
||||
new BufferState(Gd.BufferManager.GetBuffer(CommandBuffer, range.Handle, range.Offset, range.Size, true), range.Offset, range.Size);
|
||||
_transformFeedbackBuffers[i].BindTransformFeedbackBuffer(Gd, Cbs, (uint)i);
|
||||
}
|
||||
|
@@ -135,11 +135,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
// It is assumed that Dynamic State is enabled when this conversion is used.
|
||||
|
||||
pipeline.BlendConstantA = state.BlendDescriptors[0].BlendConstant.Alpha;
|
||||
pipeline.BlendConstantB = state.BlendDescriptors[0].BlendConstant.Blue;
|
||||
pipeline.BlendConstantG = state.BlendDescriptors[0].BlendConstant.Green;
|
||||
pipeline.BlendConstantR = state.BlendDescriptors[0].BlendConstant.Red;
|
||||
|
||||
pipeline.CullMode = state.CullEnable ? state.CullMode.Convert() : CullModeFlags.CullModeNone;
|
||||
|
||||
pipeline.DepthBoundsTestEnable = false; // Not implemented.
|
||||
|
@@ -19,21 +19,34 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private uint _frontWriteMask;
|
||||
private uint _frontReference;
|
||||
|
||||
private Array4<float> _blendConstants;
|
||||
|
||||
public int ViewportsCount;
|
||||
public Array16<Viewport> Viewports;
|
||||
|
||||
private enum DirtyFlags
|
||||
{
|
||||
None = 0,
|
||||
DepthBias = 1 << 0,
|
||||
Scissor = 1 << 1,
|
||||
Stencil = 1 << 2,
|
||||
Viewport = 1 << 3,
|
||||
All = DepthBias | Scissor | Stencil | Viewport
|
||||
Blend = 1 << 0,
|
||||
DepthBias = 1 << 1,
|
||||
Scissor = 1 << 2,
|
||||
Stencil = 1 << 3,
|
||||
Viewport = 1 << 4,
|
||||
All = Blend | DepthBias | Scissor | Stencil | Viewport
|
||||
}
|
||||
|
||||
private DirtyFlags _dirty;
|
||||
|
||||
public void SetBlendConstants(float r, float g, float b, float a)
|
||||
{
|
||||
_blendConstants[0] = r;
|
||||
_blendConstants[1] = g;
|
||||
_blendConstants[2] = b;
|
||||
_blendConstants[3] = a;
|
||||
|
||||
_dirty |= DirtyFlags.Blend;
|
||||
}
|
||||
|
||||
public void SetDepthBias(float slopeFactor, float constantFactor, float clamp)
|
||||
{
|
||||
_depthBiasSlopeFactor = slopeFactor;
|
||||
@@ -87,6 +100,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public void ReplayIfDirty(Vk api, CommandBuffer commandBuffer)
|
||||
{
|
||||
if (_dirty.HasFlag(DirtyFlags.Blend))
|
||||
{
|
||||
RecordBlend(api, commandBuffer);
|
||||
}
|
||||
|
||||
if (_dirty.HasFlag(DirtyFlags.DepthBias))
|
||||
{
|
||||
RecordDepthBias(api, commandBuffer);
|
||||
@@ -110,6 +128,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_dirty = DirtyFlags.None;
|
||||
}
|
||||
|
||||
private void RecordBlend(Vk api, CommandBuffer commandBuffer)
|
||||
{
|
||||
api.CmdSetBlendConstants(commandBuffer, _blendConstants.AsSpan());
|
||||
}
|
||||
|
||||
private void RecordDepthBias(Vk api, CommandBuffer commandBuffer)
|
||||
{
|
||||
api.CmdSetDepthBias(commandBuffer, _depthBiasConstantFactor, _depthBiasClamp, _depthBiasSlopeFactor);
|
||||
|
@@ -499,7 +499,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
colorBlendState.BlendConstants[3] = BlendConstantA;
|
||||
|
||||
bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
|
||||
int dynamicStatesCount = supportsExtDynamicState ? 8 : 7;
|
||||
int dynamicStatesCount = supportsExtDynamicState ? 9 : 8;
|
||||
|
||||
DynamicState* dynamicStates = stackalloc DynamicState[dynamicStatesCount];
|
||||
|
||||
@@ -510,10 +510,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
dynamicStates[4] = DynamicState.StencilCompareMask;
|
||||
dynamicStates[5] = DynamicState.StencilWriteMask;
|
||||
dynamicStates[6] = DynamicState.StencilReference;
|
||||
dynamicStates[7] = DynamicState.BlendConstants;
|
||||
|
||||
if (supportsExtDynamicState)
|
||||
{
|
||||
dynamicStates[7] = DynamicState.VertexInputBindingStrideExt;
|
||||
dynamicStates[8] = DynamicState.VertexInputBindingStrideExt;
|
||||
}
|
||||
|
||||
var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo()
|
||||
|
@@ -203,6 +203,18 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(318)] // 4.0.0+
|
||||
// StopImageProcessorAsync(nn::irsensor::IrCameraHandle, nn::applet::AppletResourceUserId, pid)
|
||||
public ResultCode StopImageProcessorAsync(ServiceCtx context)
|
||||
{
|
||||
int irCameraHandle = context.RequestData.ReadInt32();
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceIrs, new { appletResourceUserId, irCameraHandle });
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(319)] // 4.0.0+
|
||||
// ActivateIrsensorWithFunctionLevel(nn::applet::AppletResourceUserId, nn::irsensor::PackedFunctionLevel, pid)
|
||||
public ResultCode ActivateIrsensorWithFunctionLevel(ServiceCtx context)
|
||||
@@ -225,4 +237,4 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,9 +3,10 @@ using System;
|
||||
|
||||
namespace Ryujinx.Tests.Unicorn
|
||||
{
|
||||
public class UnicornAArch32
|
||||
public class UnicornAArch32 : IDisposable
|
||||
{
|
||||
internal readonly IntPtr uc;
|
||||
private bool _isDisposed = false;
|
||||
|
||||
public IndexedProperty<int, uint> R
|
||||
{
|
||||
@@ -107,7 +108,22 @@ namespace Ryujinx.Tests.Unicorn
|
||||
|
||||
~UnicornAArch32()
|
||||
{
|
||||
Interface.Checked(Native.Interface.uc_close(uc));
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
Interface.Checked(Native.Interface.uc_close(uc));
|
||||
_isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void RunForCount(ulong count)
|
||||
|
@@ -3,9 +3,10 @@ using System;
|
||||
|
||||
namespace Ryujinx.Tests.Unicorn
|
||||
{
|
||||
public class UnicornAArch64
|
||||
public class UnicornAArch64 : IDisposable
|
||||
{
|
||||
internal readonly IntPtr uc;
|
||||
private bool _isDisposed = false;
|
||||
|
||||
public IndexedProperty<int, ulong> X
|
||||
{
|
||||
@@ -96,7 +97,22 @@ namespace Ryujinx.Tests.Unicorn
|
||||
|
||||
~UnicornAArch64()
|
||||
{
|
||||
Interface.Checked(Native.Interface.uc_close(uc));
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
Interface.Checked(Native.Interface.uc_close(uc));
|
||||
_isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void RunForCount(ulong count)
|
||||
|
@@ -80,6 +80,12 @@ namespace Ryujinx.Tests.Cpu
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu.Dispose();
|
||||
_unicornEmu = null;
|
||||
}
|
||||
|
||||
_memory.DecrementReferenceCount();
|
||||
_context.Dispose();
|
||||
_ram.Dispose();
|
||||
|
@@ -76,6 +76,12 @@ namespace Ryujinx.Tests.Cpu
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
if (_unicornAvailable)
|
||||
{
|
||||
_unicornEmu.Dispose();
|
||||
_unicornEmu = null;
|
||||
}
|
||||
|
||||
_memory.DecrementReferenceCount();
|
||||
_context.Dispose();
|
||||
_ram.Dispose();
|
||||
|
Reference in New Issue
Block a user