Compare commits

...

4 Commits

Author SHA1 Message Date
gdkchan
619ac86bd0 Do not output ViewportIndex on SPIR-V if GPU does not support it (#3644)
* Do not output ViewportIndex on SPIR-V if GPU does not support it

* Bump shader cache version
2022-09-10 13:20:23 +00:00
EmulationFanatic
7a1ab71c73 Update README.MD verbiage and compatibility 2022-09-10 15:07:37 +02:00
riperiperi
dc4ba3993b Rebind textures if format changes or they're buffer textures 2022-09-10 14:12:50 +02:00
gdkchan
81f1a4dc31 Allocate work buffer for audio renderer instead of using guest supplied memory (#3276)
* Allocate work buffer for audio renderer instead of using guest supplied memory

* Typo

* Use GC.AllocateArray to allocate pinned array
2022-09-10 01:16:24 +00:00
13 changed files with 119 additions and 27 deletions

View File

@@ -36,8 +36,8 @@
## Compatibility
As of January 2022, Ryujinx has been tested on approximately 3,500 titles; over 3,200 boot past menus and into gameplay, with roughly 2,500 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 an updated test on an existing game 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 September 2022, Ryujinx has been tested on approximately 3,600 titles; over 3,400 boot past menus and into gameplay, with roughly 2,700 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
@@ -118,11 +118,11 @@ If you'd like to support the project financially, Ryujinx has an active Patreon
<img src="https://images.squarespace-cdn.com/content/v1/560c1d39e4b0b4fae0c9cf2a/1567548955044-WVD994WZP76EWF15T0L3/Patreon+Button.png?format=500w" width="150">
</a>
All the developers working on the project do so on their free time, but the project has several expenses:
All developers working on the project do so in their free time, but the project has several expenses:
* Hackable Nintendo Switch consoles to reverse-engineer the hardware
* Additional computer hardware for testing purposes (e.g. GPUs to diagnose graphical bugs, etc.)
* Licenses for various software development tools (e.g. Jetbrains, LDN servers, IDA)
* Web hosting and infrastructure maintenance
* Licenses for various software development tools (e.g. Jetbrains, IDA)
* Web hosting and infrastructure maintenance (e.g. LDN servers)
All funds received through Patreon are considered a donation to support the project. Patrons receive early access to progress reports and exclusive access to developer interviews.

View File

@@ -55,7 +55,6 @@ namespace Ryujinx.Audio.Renderer.Server
private uint _processHandle;
private ulong _appletResourceId;
private WritableRegion _workBufferRegion;
private MemoryHandle _workBufferMemoryPin;
private Memory<float> _mixBuffer;
@@ -98,7 +97,15 @@ namespace Ryujinx.Audio.Renderer.Server
_sessionId = 0;
}
public ResultCode Initialize(ref AudioRendererConfiguration parameter, uint processHandle, CpuAddress workBuffer, ulong workBufferSize, int sessionId, ulong appletResourceId, IVirtualMemoryManager memoryManager)
public ResultCode Initialize(
ref AudioRendererConfiguration parameter,
uint processHandle,
Memory<byte> workBufferMemory,
CpuAddress workBuffer,
ulong workBufferSize,
int sessionId,
ulong appletResourceId,
IVirtualMemoryManager memoryManager)
{
if (!BehaviourContext.CheckValidRevision(parameter.Revision))
{
@@ -134,11 +141,10 @@ namespace Ryujinx.Audio.Renderer.Server
WorkBufferAllocator workBufferAllocator;
_workBufferRegion = MemoryManager.GetWritableRegion(workBuffer, (int)workBufferSize);
_workBufferRegion.Memory.Span.Fill(0);
_workBufferMemoryPin = _workBufferRegion.Memory.Pin();
workBufferMemory.Span.Fill(0);
_workBufferMemoryPin = workBufferMemory.Pin();
workBufferAllocator = new WorkBufferAllocator(_workBufferRegion.Memory);
workBufferAllocator = new WorkBufferAllocator(workBufferMemory);
PoolMapper poolMapper = new PoolMapper(processHandle, false);
poolMapper.InitializeSystemPool(ref _dspMemoryPoolState, workBuffer, workBufferSize);
@@ -841,7 +847,6 @@ namespace Ryujinx.Audio.Renderer.Server
_manager.Unregister(this);
_terminationEvent.Dispose();
_workBufferMemoryPin.Dispose();
_workBufferRegion.Dispose();
if (MemoryManager is IRefCounted rc)
{

View File

@@ -305,13 +305,34 @@ namespace Ryujinx.Audio.Renderer.Server
/// <param name="workBufferSize">The guest work buffer size.</param>
/// <param name="processHandle">The process handle of the application.</param>
/// <returns>A <see cref="ResultCode"/> reporting an error or a success.</returns>
public ResultCode OpenAudioRenderer(out AudioRenderSystem renderer, IVirtualMemoryManager memoryManager, ref AudioRendererConfiguration parameter, ulong appletResourceUserId, ulong workBufferAddress, ulong workBufferSize, uint processHandle, float volume)
public ResultCode OpenAudioRenderer(
out AudioRenderSystem renderer,
IVirtualMemoryManager memoryManager,
ref AudioRendererConfiguration parameter,
ulong appletResourceUserId,
ulong workBufferAddress,
ulong workBufferSize,
uint processHandle,
float volume)
{
int sessionId = AcquireSessionId();
AudioRenderSystem audioRenderer = new AudioRenderSystem(this, _sessionsSystemEvent[sessionId]);
ResultCode result = audioRenderer.Initialize(ref parameter, processHandle, workBufferAddress, workBufferSize, sessionId, appletResourceUserId, memoryManager);
// TODO: Eventually, we should try to use the guest supplied work buffer instead of allocating
// our own. However, it was causing problems on some applications that would unmap the memory
// before the audio renderer was fully disposed.
Memory<byte> workBufferMemory = GC.AllocateArray<byte>((int)workBufferSize, pinned: true);
ResultCode result = audioRenderer.Initialize(
ref parameter,
processHandle,
workBufferMemory,
workBufferAddress,
workBufferSize,
sessionId,
appletResourceUserId,
memoryManager);
if (result == ResultCode.Success)
{

View File

@@ -26,6 +26,7 @@ namespace Ryujinx.Graphics.GAL
public readonly bool SupportsNonConstantTextureOffset;
public readonly bool SupportsShaderBallot;
public readonly bool SupportsTextureShadowLod;
public readonly bool SupportsViewportIndex;
public readonly bool SupportsViewportSwizzle;
public readonly bool SupportsIndirectParameters;
@@ -59,6 +60,7 @@ namespace Ryujinx.Graphics.GAL
bool supportsNonConstantTextureOffset,
bool supportsShaderBallot,
bool supportsTextureShadowLod,
bool supportsViewportIndex,
bool supportsViewportSwizzle,
bool supportsIndirectParameters,
uint maximumUniformBuffersPerStage,
@@ -89,6 +91,7 @@ namespace Ryujinx.Graphics.GAL
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
SupportsShaderBallot = supportsShaderBallot;
SupportsTextureShadowLod = supportsTextureShadowLod;
SupportsViewportIndex = supportsViewportIndex;
SupportsViewportSwizzle = supportsViewportSwizzle;
SupportsIndirectParameters = supportsIndirectParameters;
MaximumUniformBuffersPerStage = maximumUniformBuffersPerStage;

View File

@@ -47,6 +47,7 @@ namespace Ryujinx.Graphics.Gpu.Image
public int TextureHandle;
public int SamplerHandle;
public Format ImageFormat;
public int InvalidatedSequence;
public Texture CachedTexture;
public Sampler CachedSampler;
@@ -564,6 +565,9 @@ namespace Ryujinx.Graphics.Gpu.Image
// Buffers are frequently re-created to accomodate larger data, so we need to re-bind
// to ensure we're not using a old buffer that was already deleted.
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, bindingInfo.Format, false);
// Cache is not used for buffer texture, it must always rebind.
state.CachedTexture = null;
}
else
{
@@ -659,14 +663,16 @@ namespace Ryujinx.Graphics.Gpu.Image
cachedTexture?.SignalModified();
}
if ((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 &&
UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage))
Format format = bindingInfo.Format == 0 ? cachedTexture.Format : bindingInfo.Format;
if (state.ImageFormat != format ||
((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 &&
UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage)))
{
ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target);
Format format = bindingInfo.Format == 0 ? cachedTexture.Format : bindingInfo.Format;
state.Texture = hostTextureRebind;
state.ImageFormat = format;
_context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTextureRebind, format);
}
@@ -696,6 +702,9 @@ namespace Ryujinx.Graphics.Gpu.Image
}
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, format, true);
// Cache is not used for buffer texture, it must always rebind.
state.CachedTexture = null;
}
else
{
@@ -721,6 +730,8 @@ namespace Ryujinx.Graphics.Gpu.Image
format = texture.Format;
}
state.ImageFormat = format;
_context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTexture, format);
}

View File

@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 3672;
private const uint CodeGenVersion = 3644;
private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";
@@ -827,4 +827,4 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
}
}
}
}
}

View File

@@ -134,6 +134,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
public bool QueryHostSupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
public bool QueryHostSupportsViewportIndex() => _context.Capabilities.SupportsViewportIndex;
/// <summary>
/// Converts a packed Maxwell texture format to the shader translator texture format.
/// </summary>

View File

@@ -120,6 +120,7 @@ namespace Ryujinx.Graphics.OpenGL
supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset,
supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
supportsViewportIndex: true,
supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver?

View File

@@ -267,6 +267,15 @@ namespace Ryujinx.Graphics.Shader
return true;
}
/// <summary>
/// Queries host GPU shader viewport index output support.
/// </summary>
/// <returns>True if the GPU and driver supports shader viewport index output, false otherwise</returns>
bool QueryHostSupportsViewportIndex()
{
return true;
}
/// <summary>
/// Queries the point size from the GPU state, used when it is not explicitly set on the shader.
/// </summary>

View File

@@ -78,6 +78,11 @@ namespace Ryujinx.Graphics.Shader.Translation
public static bool Validate(ShaderConfig config, int value, bool isOutAttr)
{
if (value == AttributeConsts.ViewportIndex && !config.GpuAccessor.QueryHostSupportsViewportIndex())
{
return false;
}
return From(config, value, isOutAttr).IsValid;
}

View File

@@ -380,7 +380,7 @@ namespace Ryujinx.Graphics.Vulkan
return BufferManager.GetData(buffer, offset, size);
}
public Capabilities GetCapabilities()
public unsafe Capabilities GetCapabilities()
{
FormatFeatureFlags compressedFormatFeatureFlags =
FormatFeatureFlags.FormatFeatureSampledImageBit |
@@ -409,7 +409,19 @@ namespace Ryujinx.Graphics.Vulkan
GAL.Format.Bc7Srgb,
GAL.Format.Bc7Unorm);
Api.GetPhysicalDeviceFeatures(_physicalDevice, out var features);
PhysicalDeviceVulkan12Features featuresVk12 = new PhysicalDeviceVulkan12Features()
{
SType = StructureType.PhysicalDeviceVulkan12Features
};
PhysicalDeviceFeatures2 features2 = new PhysicalDeviceFeatures2()
{
SType = StructureType.PhysicalDeviceFeatures2,
PNext = &featuresVk12
};
Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2);
Api.GetPhysicalDeviceProperties(_physicalDevice, out var properties);
var limits = properties.Limits;
@@ -419,7 +431,7 @@ namespace Ryujinx.Graphics.Vulkan
GpuVendor,
hasFrontFacingBug: IsIntelWindows,
hasVectorIndexingBug: Vendor == Vendor.Qualcomm,
supportsAstcCompression: features.TextureCompressionAstcLdr,
supportsAstcCompression: features2.Features.TextureCompressionAstcLdr,
supportsBc123Compression: supportsBc123CompressionFormat,
supportsBc45Compression: supportsBc45CompressionFormat,
supportsBc67Compression: supportsBc67CompressionFormat,
@@ -429,12 +441,13 @@ namespace Ryujinx.Graphics.Vulkan
supportsFragmentShaderInterlock: Capabilities.SupportsFragmentShaderInterlock,
supportsFragmentShaderOrderingIntel: false,
supportsGeometryShaderPassthrough: Capabilities.SupportsGeometryShaderPassthrough,
supportsImageLoadFormatted: features.ShaderStorageImageReadWithoutFormat,
supportsImageLoadFormatted: features2.Features.ShaderStorageImageReadWithoutFormat,
supportsMismatchingViewFormat: true,
supportsCubemapView: !IsAmdGcn,
supportsNonConstantTextureOffset: false,
supportsShaderBallot: false,
supportsTextureShadowLod: false,
supportsViewportIndex: featuresVk12.ShaderOutputViewportIndex,
supportsViewportSwizzle: false,
supportsIndirectParameters: Capabilities.SupportsIndirectParameters,
maximumUniformBuffersPerStage: Constants.MaxUniformBuffersPerStage,

View File

@@ -31,11 +31,26 @@ namespace Ryujinx.HLE.HOS.Services.Audio
return AudioRendererManagerImpl.GetWorkBufferSize(ref parameter);
}
public ResultCode OpenAudioRenderer(ServiceCtx context, out IAudioRenderer obj, ref AudioRendererConfiguration parameter, ulong workBufferSize, ulong appletResourceUserId, KTransferMemory workBufferTransferMemory, uint processHandle)
public ResultCode OpenAudioRenderer(
ServiceCtx context,
out IAudioRenderer obj,
ref AudioRendererConfiguration parameter,
ulong workBufferSize,
ulong appletResourceUserId,
KTransferMemory workBufferTransferMemory,
uint processHandle)
{
var memoryManager = context.Process.HandleTable.GetKProcess((int)processHandle).CpuMemory;
ResultCode result = (ResultCode)_impl.OpenAudioRenderer(out AudioRenderSystem renderer, memoryManager, ref parameter, appletResourceUserId, workBufferTransferMemory.Address, workBufferTransferMemory.Size, processHandle, context.Device.Configuration.AudioVolume);
ResultCode result = (ResultCode)_impl.OpenAudioRenderer(
out AudioRenderSystem renderer,
memoryManager,
ref parameter,
appletResourceUserId,
workBufferTransferMemory.Address,
workBufferTransferMemory.Size,
processHandle,
context.Device.Configuration.AudioVolume);
if (result == ResultCode.Success)
{

View File

@@ -34,7 +34,14 @@ namespace Ryujinx.HLE.HOS.Services.Audio
KTransferMemory workBufferTransferMemory = context.Process.HandleTable.GetObject<KTransferMemory>(transferMemoryHandle);
uint processHandle = (uint)context.Request.HandleDesc.ToCopy[1];
ResultCode result = _impl.OpenAudioRenderer(context, out IAudioRenderer renderer, ref parameter, workBufferSize, appletResourceUserId, workBufferTransferMemory, processHandle);
ResultCode result = _impl.OpenAudioRenderer(
context,
out IAudioRenderer renderer,
ref parameter,
workBufferSize,
appletResourceUserId,
workBufferTransferMemory,
processHandle);
if (result == ResultCode.Success)
{