Compare commits

...

19 Commits

Author SHA1 Message Date
dependabot[bot]
d2686e0a5b nuget: bump DiscordRichPresence from 1.0.175 to 1.1.3.18 (#3965)
Bumps [DiscordRichPresence](https://github.com/Lachee/discord-rpc-csharp) from 1.0.175 to 1.1.3.18.
- [Release notes](https://github.com/Lachee/discord-rpc-csharp/releases)
- [Commits](https://github.com/Lachee/discord-rpc-csharp/commits)

---
updated-dependencies:
- dependency-name: DiscordRichPresence
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-30 21:58:45 +00:00
gdkchan
4905101df1 Remove shader dependency on SPV_KHR_shader_ballot and SPV_KHR_subgroup_vote extensions (#3943)
* Remove shader dependency on SPV_KHR_shader_ballot and SPV_KHR_subgroup_vote extensions

* Shader cache version bump
2022-11-30 18:24:15 -03:00
gdkchan
8750b90a7f Ensure that vertex attribute buffer index is valid on GPU (#3942)
* Ensure that vertex attribute buffer index is valid on GPU

* Remove vertex buffer validation code from OpenGL

* Remove some fields that are no longer necessary
2022-11-30 18:06:40 -03:00
dependabot[bot]
af01100050 nuget: bump System.Management from 6.0.0 to 7.0.0 (#3949)
Bumps [System.Management](https://github.com/dotnet/runtime) from 6.0.0 to 7.0.0.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v6.0.0...v7.0.0)

---
updated-dependencies:
- dependency-name: System.Management
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-29 23:30:33 +01:00
EmulationFanatic
c0821fee1f Update README.MD (#3946)
Updates the readme to include usage of Metal via MoltenVK, updated game compatibility statistics.
2022-11-29 17:20:26 +01:00
merry
a5c2aead67 ConcurrentBitmap: Use Interlocked Or/And (#3937) 2022-11-29 13:47:57 +00:00
Mary-nyan
d41c95dcff chore: Update OpenTK to 4.7.5 (#3944) 2022-11-29 13:32:40 +00:00
TSRBerry
fbf2b09706 ava: Make dialogs using an overlay window work on Linux (#3938) 2022-11-29 06:33:46 +01:00
riperiperi
1fc0f569de GPU: Always draw polygon topology as triangle fan (#3932)
Polygon topology wasn't really supported and would only work on OpenGL on drivers that haven't removed it. As an alternative, this PR makes all cases of polygon topology use triangle fan. The topology type and transform feedback type have not been changed, as I don't think geo shader/tfb should be used with polygons.

The OpenGL spec states:
Only convex polygons are guaranteed to be drawn correctly by the GL.

For convex polygons, triangle fan is equivalent to polygon. I imagine this is probably how it works on device, as this get-out-of-jail-free card is too enticing to pass up.

This fixes the stat display in Pokemon S/V.
2022-11-28 19:18:22 -03:00
Mary-nyan
dff138229c amadeus: Fixes and initial 15.0.0 support (#3908)
* amadeus: Allow OOB read of GC-ADPCM coefficients

Fixes "Ninja Gaiden Sigma 2" and possibly "NINJA GAIDEN 3: Razor's Edge"

* amadeus: Fix wrong variable usage in delay effect

We should transform the delay line values, not the input.

* amadeus: Update GroupedBiquadFilterCommand documentation

* amadeus: Simplify PoolMapper alignment checks

* amadeus: Update Surround delay effect matrix to REV11

* amadeus: Add drop parameter support and use 32 bits integers for estimate time

Also implement accurate ExecuteAudioRendererRendering stub.

* Address gdkchan's comments

* Address gdkchan's other comments

* Address gdkchan's comment
2022-11-28 08:28:45 +01:00
Ac_K
472119c8da sfdnsres; Fix deserializer of AddrInfoSerialized when addresses are empty (#3924) 2022-11-28 02:53:57 +01:00
Mary-nyan
1865ea87e5 bsd: Fix eventfd broken logic (#3647)
* bsd: Fix eventfd broken logic

This commit fix eventfd logic being broken.

The following changes were made:
- EventFd IPC definition had argument inverted
- EventFd events weren't fired correctly
- Poll logic was wrong and unfinished for eventfd
- Reintroduce workaround from #3385 but in a safer way, and spawn 4
  threads.

* ipc: Rework a bit for multithreads

* Clean up debug logs

* Make server thread yield when managed lock isn't availaible

* Fix replyTargetHandle not being added in the proper locking scope

* Simplify some scopes

* Address gdkchan's comments

* Revert IPC workaround for now

* Reintroduce the EventFileDescriptor workaround
2022-11-27 20:18:05 +00:00
&Olga
18b61aff59 Unbreak bug_report.md (#3915)
* Unbreak bug_report.md

* Update bug_report.md
2022-11-27 20:11:51 +00:00
Luminoso-256
cb22629ac1 HLE: fix small issue in IPsmSession (#3909) 2022-11-27 01:10:42 +00:00
TSRBerry
6f0f99ee2b Avalonia: Fix OpenGL crashing on Linux (#3902)
* ava: Fix OpenGL crashing on Linux

Fixes a regression from #3901

* Fix formatting
2022-11-26 12:06:53 +01:00
TSRBerry
70f2da8fdf ava: Fix invisible vulkan window on Linux (#3901)
Co-authored-by: emmauss <emmausssss@gmail.com>

Co-authored-by: emmauss <emmausssss@gmail.com>
2022-11-25 17:40:44 +00:00
Ac_K
5d3ef7761b ava: Refactor Title Update Manager window (#3898)
* ava: Refactor TitleUpdate Manager window

* Update locale
2022-11-25 17:55:08 +01:00
riperiperi
476b4683cf Fix CB0 alignment with addresses used for 8/16-bit LDG/STG (#3897)
This replacement is meant to be done with the original identified byteOffset, not the one assigned later on by the below conditionals (that already has the constant offset added, for instance).

This fixes videos being pixelated in Xenoblade 3, and other regressions that might have happened since #3847.
2022-11-25 14:39:03 +00:00
Mary-nyan
5fb5079730 chore: Update Avalonia related dependencies (#3891) 2022-11-25 13:27:41 +00:00
74 changed files with 437 additions and 291 deletions

View File

@@ -1,6 +1,6 @@
---
name: Bug Report
about: Something doesn't work correctly in Ryujinx. Note that game-specific issues should be instead posted on the Game Compatibility List at https://github.com/Ryujinx/Ryujinx-Games-List, unless it is a provable regression.
about: Something doesn't work correctly in Ryujinx. Game-specific issues should be posted at https://github.com/Ryujinx/Ryujinx-Games-List instead, unless it is a provable regression.
#assignees:
---

View File

@@ -36,7 +36,7 @@
## Compatibility
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.
As of November 2022, Ryujinx has been tested on approximately 3,800 titles; over 3,600 boot past menus and into gameplay, with roughly 3,200 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 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.
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) 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**

View File

@@ -5,7 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTK.OpenAL" Version="4.7.2" />
<PackageReference Include="OpenTK.OpenAL" Version="4.7.5" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,4 +1,5 @@
using Ryujinx.Audio.Renderer.Dsp.State;
using Ryujinx.Common.Logging;
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
@@ -71,6 +72,19 @@ namespace Ryujinx.Audio.Renderer.Dsp
return (short)value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static short GetCoefficientAtIndex(ReadOnlySpan<short> coefficients, int index)
{
if ((uint)index > (uint)coefficients.Length)
{
Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}");
return 0;
}
return coefficients[index];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Decode(Span<short> output, ReadOnlySpan<byte> input, int startSampleOffset, int endSampleOffset, int offset, int count, ReadOnlySpan<short> coefficients, ref AdpcmLoopContext loopContext)
{
@@ -84,8 +98,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
byte coefficientIndex = (byte)((predScale >> 4) & 0xF);
short history0 = loopContext.History0;
short history1 = loopContext.History1;
short coefficient0 = coefficients[coefficientIndex * 2 + 0];
short coefficient1 = coefficients[coefficientIndex * 2 + 1];
short coefficient0 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 0);
short coefficient1 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 1);
int decodedCount = Math.Min(count, endSampleOffset - startSampleOffset - offset);
int nibbles = GetNibblesFromSampleCount(offset + startSampleOffset);
@@ -109,8 +123,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
coefficientIndex = (byte)((predScale >> 4) & 0xF);
coefficient0 = coefficients[coefficientIndex * 2 + 0];
coefficient1 = coefficients[coefficientIndex * 2 + 1];
coefficient0 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2);
coefficient1 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 1);
nibbles += 2;

View File

@@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.AdpcmDataSourceVersion1;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort OutputBufferIndex { get; }
public uint SampleRate { get; }

View File

@@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.AuxiliaryBuffer;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public uint InputBufferIndex { get; }
public uint OutputBufferIndex { get; }

View File

@@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.BiquadFilter;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public Memory<BiquadFilterState> BiquadFilterState { get; }
public int InputBufferIndex { get; }

View File

@@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.CaptureBuffer;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public uint InputBufferIndex { get; }

View File

@@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.CircularBufferSink;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort[] Input { get; }
public uint InputCount { get; }

View File

@@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.ClearMixBuffer;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ClearMixBufferCommand(int nodeId)
{

View File

@@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.CopyMixBuffer;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }

View File

@@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType { get; }
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort OutputBufferIndex { get; }
public uint SampleRate { get; }

View File

@@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.Delay;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public DelayParameter Parameter => _parameter;
public Memory<DelayState> State { get; }
@@ -49,15 +49,15 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
}
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
// TODO: Update delay processing and remove this to use RemapLegacyChannelEffectMappingToChannelResourceMapping.
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, InputBufferIndices);
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, OutputBufferIndices);
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices);
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, OutputBufferIndices);
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private unsafe void ProcessDelayMono(ref DelayState state, float* outputBuffer, float* inputBuffer, uint sampleCount)
{
const ushort channelCount = 1;
float feedbackGain = FixedPointHelper.ToFloat(Parameter.FeedbackGain, FixedPointPrecision);
float inGain = FixedPointHelper.ToFloat(Parameter.InGain, FixedPointPrecision);
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
@@ -70,7 +70,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
float temp = input * inGain + delayLineValue * feedbackGain;
state.UpdateLowPassFilter(ref temp, 1);
state.UpdateLowPassFilter(ref temp, channelCount);
outputBuffer[i] = (input * dryGain + delayLineValue * outGain) / 64;
}
@@ -104,7 +104,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
Y = state.DelayLines[1].Read(),
};
Vector2 temp = MatrixHelper.Transform(ref channelInput, ref delayFeedback) + channelInput * inGain;
Vector2 temp = MatrixHelper.Transform(ref delayLineValues, ref delayFeedback) + channelInput * inGain;
state.UpdateLowPassFilter(ref Unsafe.As<Vector2, float>(ref temp), channelCount);
@@ -148,7 +148,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
W = state.DelayLines[3].Read()
};
Vector4 temp = MatrixHelper.Transform(ref channelInput, ref delayFeedback) + channelInput * inGain;
Vector4 temp = MatrixHelper.Transform(ref delayLineValues, ref delayFeedback) + channelInput * inGain;
state.UpdateLowPassFilter(ref Unsafe.As<Vector4, float>(ref temp), channelCount);
@@ -171,12 +171,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision);
Matrix6x6 delayFeedback = new Matrix6x6(delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain,
0.0f, delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f,
delayFeedbackCrossGain, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f,
0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f,
delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackBaseGain, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, feedbackGain);
Matrix6x6 delayFeedback = new Matrix6x6(delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, 0.0f, delayFeedbackCrossGain, 0.0f,
0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain,
delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, feedbackGain, 0.0f, 0.0f,
delayFeedbackCrossGain, 0.0f, 0.0f, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain,
0.0f, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackBaseGain);
for (int i = 0; i < sampleCount; i++)
{
@@ -200,7 +200,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
U = state.DelayLines[5].Read()
};
Vector6 temp = MatrixHelper.Transform(ref channelInput, ref delayFeedback) + channelInput * inGain;
Vector6 temp = MatrixHelper.Transform(ref delayLineValues, ref delayFeedback) + channelInput * inGain;
state.UpdateLowPassFilter(ref Unsafe.As<Vector6, float>(ref temp), channelCount);

View File

@@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.DepopForMixBuffers;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public uint MixBufferOffset { get; }

View File

@@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.DepopPrepare;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public uint MixBufferCount { get; }

View File

@@ -14,7 +14,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.DeviceSink;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public string DeviceName { get; }

View File

@@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.DownMixSurroundToStereo;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort[] InputBufferIndices { get; }
public ushort[] OutputBufferIndices { get; }

View File

@@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.GroupedBiquadFilter;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
private BiquadFilterParameter[] _parameters;
private Memory<BiquadFilterState> _biquadFilterStates;
@@ -47,9 +47,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
}
// NOTE: Nintendo also implements a hot path for double biquad filters, but no generic path when the command definition suggests it could be done.
// As such we currently only implement a generic path for simplicity.
// TODO: Implement double biquad filters fast path.
// NOTE: Nintendo only implement single and double biquad filters but no generic path when the command definition suggests it could be done.
// As such we currently only implement a generic path for simplicity for double biquad.
if (_parameters.Length == 1)
{
BiquadFilterHelper.ProcessBiquadFilter(ref _parameters[0], ref states[0], outputBuffer, inputBuffer, context.SampleCount);

View File

@@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType { get; }
public ulong EstimatedProcessingTime { get; }
public uint EstimatedProcessingTime { get; }
public void Process(CommandList context);

View File

@@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.LimiterVersion1;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public LimiterParameter Parameter => _parameter;
public Memory<LimiterState> State { get; }

View File

@@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.LimiterVersion2;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public LimiterParameter Parameter => _parameter;
public Memory<LimiterState> State { get; }

View File

@@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.Mix;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }

View File

@@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.MixRamp;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }

View File

@@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.MixRampGrouped;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public uint MixBufferCount { get; }

View File

@@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.PcmFloatDataSourceVersion1;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort OutputBufferIndex { get; }
public uint SampleRate { get; }

View File

@@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.PcmInt16DataSourceVersion1;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort OutputBufferIndex { get; }
public uint SampleRate { get; }

View File

@@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.Performance;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public PerformanceEntryAddresses PerformanceEntryAddresses { get; }

View File

@@ -31,7 +31,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.Reverb3d;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }

View File

@@ -34,7 +34,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.Reverb;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ReverbParameter Parameter => _parameter;
public Memory<ReverbState> State { get; }

View File

@@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.Upsample;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public uint BufferCount { get; }
public uint InputBufferIndex { get; }

View File

@@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.Volume;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }

View File

@@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CommandType CommandType => CommandType.VolumeRamp;
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
public ushort InputBufferIndex { get; }
public ushort OutputBufferIndex { get; }

View File

@@ -28,6 +28,7 @@ namespace Ryujinx.Audio.Renderer.Server
{
private object _lock = new object();
private AudioRendererRenderingDevice _renderingDevice;
private AudioRendererExecutionMode _executionMode;
private IWritableEvent _systemEvent;
private ManualResetEvent _terminationEvent;
@@ -63,6 +64,7 @@ namespace Ryujinx.Audio.Renderer.Server
private uint _renderingTimeLimitPercent;
private bool _voiceDropEnabled;
private uint _voiceDropCount;
private float _voiceDropParameter;
private bool _isDspRunningBehind;
private ICommandProcessingTimeEstimator _commandProcessingTimeEstimator;
@@ -95,6 +97,7 @@ namespace Ryujinx.Audio.Renderer.Server
_totalElapsedTicksUpdating = 0;
_sessionId = 0;
_voiceDropParameter = 1.0f;
}
public ResultCode Initialize(
@@ -130,6 +133,7 @@ namespace Ryujinx.Audio.Renderer.Server
_upsamplerCount = parameter.SinkCount + parameter.SubMixBufferCount;
_appletResourceId = appletResourceId;
_memoryPoolCount = parameter.EffectCount + parameter.VoiceCount * Constants.VoiceWaveBufferCount;
_renderingDevice = parameter.RenderingDevice;
_executionMode = parameter.ExecutionMode;
_sessionId = sessionId;
MemoryManager = memoryManager;
@@ -337,6 +341,7 @@ namespace Ryujinx.Audio.Renderer.Server
_processHandle = processHandle;
_elapsedFrameCount = 0;
_voiceDropParameter = 1.0f;
switch (_behaviourContext.GetCommandProcessingTimeEstimatorVersion())
{
@@ -515,7 +520,7 @@ namespace Ryujinx.Audio.Renderer.Server
return (ulong)(_manager.TickSource.ElapsedSeconds * Constants.TargetTimerFrequency);
}
private uint ComputeVoiceDrop(CommandBuffer commandBuffer, long voicesEstimatedTime, long deltaTimeDsp)
private uint ComputeVoiceDrop(CommandBuffer commandBuffer, uint voicesEstimatedTime, long deltaTimeDsp)
{
int i;
@@ -584,7 +589,7 @@ namespace Ryujinx.Audio.Renderer.Server
{
command.Enabled = false;
voicesEstimatedTime -= (long)command.EstimatedProcessingTime;
voicesEstimatedTime -= (uint)(_voiceDropParameter * command.EstimatedProcessingTime);
}
}
}
@@ -618,13 +623,13 @@ namespace Ryujinx.Audio.Renderer.Server
_voiceContext.Sort();
commandGenerator.GenerateVoices();
long voicesEstimatedTime = (long)commandBuffer.EstimatedProcessingTime;
uint voicesEstimatedTime = (uint)(_voiceDropParameter * commandBuffer.EstimatedProcessingTime);
commandGenerator.GenerateSubMixes();
commandGenerator.GenerateFinalMixes();
commandGenerator.GenerateSinks();
long totalEstimatedTime = (long)commandBuffer.EstimatedProcessingTime;
uint totalEstimatedTime = (uint)(_voiceDropParameter * commandBuffer.EstimatedProcessingTime);
if (_voiceDropEnabled)
{
@@ -856,5 +861,26 @@ namespace Ryujinx.Audio.Renderer.Server
}
}
}
public void SetVoiceDropParameter(float voiceDropParameter)
{
_voiceDropParameter = Math.Clamp(voiceDropParameter, 0.0f, 2.0f);
}
public float GetVoiceDropParameter()
{
return _voiceDropParameter;
}
public ResultCode ExecuteAudioRendererRendering()
{
if (_executionMode == AudioRendererExecutionMode.Manual && _renderingDevice == AudioRendererRenderingDevice.Cpu)
{
// NOTE: Here Nintendo aborts with this error code, we don't want that.
return ResultCode.InvalidExecutionContextOperation;
}
return ResultCode.UnsupportedOperation;
}
}
}

View File

@@ -94,8 +94,9 @@ namespace Ryujinx.Audio.Renderer.Server
/// REV11:
/// The "legacy" effects (Delay, Reverb and Reverb 3D) were updated to match the standard channel mapping used by the audio renderer.
/// A new version of the command estimator was added to address timing changes caused by the legacy effects changes.
/// A voice drop parameter was added in 15.0.0: This allows an application to amplify or attenuate the estimated time of DSP commands.
/// </summary>
/// <remarks>This was added in system update 14.0.0</remarks>
/// <remarks>This was added in system update 14.0.0 but some changes were made in 15.0.0</remarks>
public const int Revision11 = 11 << 24;
/// <summary>

View File

@@ -25,7 +25,7 @@ namespace Ryujinx.Audio.Renderer.Server
/// <summary>
/// The estimated total processing time.
/// </summary>
public ulong EstimatedProcessingTime { get; set; }
public uint EstimatedProcessingTime { get; set; }
/// <summary>
/// The command list that is populated by the <see cref="CommandBuffer"/>.

View File

@@ -263,12 +263,12 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
return UpdateResult.Success;
}
if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress & (pageSize - 1)) != 0)
if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress % pageSize) != 0)
{
return UpdateResult.InvalidParameter;
}
if (inParameter.Size == 0 || (inParameter.Size & (pageSize - 1)) != 0)
if (inParameter.Size == 0 || (inParameter.Size % pageSize) != 0)
{
return UpdateResult.InvalidParameter;
}

View File

@@ -17,5 +17,6 @@ namespace Ryujinx.Audio
InvalidAddressInfo = (42 << ErrorCodeShift) | ModuleId,
InvalidMixSorting = (43 << ErrorCodeShift) | ModuleId,
UnsupportedOperation = (513 << ErrorCodeShift) | ModuleId,
InvalidExecutionContextOperation = (514 << ErrorCodeShift) | ModuleId,
}
}

View File

@@ -564,10 +564,10 @@
"Writable": "Writable",
"SelectDlcDialogTitle": "Select DLC files",
"SelectUpdateDialogTitle": "Select update files",
"UserProfileWindowTitle": "Manage User Profiles",
"CheatWindowTitle": "Manage Game Cheats",
"DlcWindowTitle": "Manage Game DLC",
"UpdateWindowTitle": "Manage Game Updates",
"UserProfileWindowTitle": "User Profiles Manager",
"CheatWindowTitle": "Cheats Manager",
"DlcWindowTitle": "Downloadable Content Manager",
"UpdateWindowTitle": "Title Update Manager",
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
"UserProfilesEditProfile": "Edit Selected",
@@ -577,7 +577,7 @@
"UserProfilesSetProfileImage": "Set Profile Image",
"UserProfileEmptyNameError": "Name is required",
"UserProfileNoImageError": "Profile image must be set",
"GameUpdateWindowHeading": "Updates Available for {0} [{1}]",
"GameUpdateWindowHeading": "{0} Update(s) available for {1} ({2})",
"SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
"SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
"UserProfilesName": "Name:",

View File

@@ -19,18 +19,18 @@
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.18" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.15" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.15" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.15" />
<PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="0.10.15" />
<PackageReference Include="Avalonia.Svg" Version="0.10.14" />
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.14" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.18" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.18" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.18" />
<PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="0.10.18" />
<PackageReference Include="Avalonia.Svg" Version="0.10.18" />
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.18" />
<PackageReference Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
<PackageReference Include="DynamicData" Version="7.9.4" />
<PackageReference Include="FluentAvaloniaUI" Version="1.4.1" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />
<PackageReference Include="DynamicData" Version="7.12.8" />
<PackageReference Include="FluentAvaloniaUI" Version="1.4.5" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.4.2" />
<PackageReference Include="OpenTK.Core" Version="4.7.2" />
<PackageReference Include="OpenTK.Core" Version="4.7.5" />
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Silk.NET.Vulkan" Version="2.10.1" />

View File

@@ -127,9 +127,16 @@ namespace Ryujinx.Ava.Ui.Controls
contentDialog.PrimaryButtonClick += deferCloseAction;
}
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
if (useOverlay)
{
await contentDialog.ShowAsync(overlay, ContentDialogPlacement.Popup);
overlay?.Close();
overlay!.Close();
}
else
{
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
}
}
if (useOverlay)
@@ -391,4 +398,4 @@ namespace Ryujinx.Ava.Ui.Controls
return string.Empty;
}
}
}
}

View File

@@ -6,8 +6,8 @@ using SPB.Graphics;
using SPB.Platform;
using SPB.Platform.GLX;
using SPB.Platform.X11;
using SPB.Windowing;
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
@@ -15,12 +15,12 @@ using static Ryujinx.Ava.Ui.Controls.Win32NativeInterop;
namespace Ryujinx.Ava.Ui.Controls
{
public unsafe class EmbeddedWindow : NativeControlHost
public class EmbeddedWindow : NativeControlHost
{
private WindowProc _wndProcDelegate;
private string _className;
protected GLXWindow X11Window { get; private set; }
protected GLXWindow X11Window { get; set; }
protected IntPtr WindowHandle { get; set; }
protected IntPtr X11Display { get; set; }
@@ -94,19 +94,17 @@ namespace Ryujinx.Ava.Ui.Controls
}
[SupportedOSPlatform("linux")]
IPlatformHandle CreateLinux(IPlatformHandle parent)
protected virtual IPlatformHandle CreateLinux(IPlatformHandle parent)
{
X11Window = PlatformHelper.CreateOpenGLWindow(FramebufferFormat.Default, 0, 0, 100, 100) as GLXWindow;
X11Window = PlatformHelper.CreateOpenGLWindow(FramebufferFormat.Default, 0, 0, 100, 100) as GLXWindow;
WindowHandle = X11Window.WindowHandle.RawHandle;
X11Display = X11Window.DisplayHandle.RawHandle;
X11Display = X11Window.DisplayHandle.RawHandle;
return new PlatformHandle(WindowHandle, "X11");
}
[SupportedOSPlatform("windows")]
unsafe IPlatformHandle CreateWin32(IPlatformHandle parent)
IPlatformHandle CreateWin32(IPlatformHandle parent)
{
_className = "NativeWindow-" + Guid.NewGuid();
_wndProcDelegate = WndProc;
@@ -142,7 +140,7 @@ namespace Ryujinx.Ava.Ui.Controls
}
[SupportedOSPlatform("windows")]
internal IntPtr WndProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam)
IntPtr WndProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam)
{
var point = new Point((long)lParam & 0xFFFF, ((long)lParam >> 16) & 0xFFFF);
var root = VisualRoot as Window;

View File

@@ -1,10 +1,13 @@
using Avalonia.Platform;
using Ryujinx.Ava.Ui.Controls;
using Silk.NET.Vulkan;
using SPB.Graphics.Vulkan;
using SPB.Platform.GLX;
using SPB.Platform.Win32;
using SPB.Platform.X11;
using SPB.Windowing;
using System;
using System.Runtime.Versioning;
namespace Ryujinx.Ava.Ui
{
@@ -12,6 +15,18 @@ namespace Ryujinx.Ava.Ui
{
private NativeWindowBase _window;
[SupportedOSPlatform("linux")]
protected override IPlatformHandle CreateLinux(IPlatformHandle parent)
{
X11Window = new GLXWindow(new NativeHandle(X11.DefaultDisplay), new NativeHandle(parent.Handle));
WindowHandle = X11Window.WindowHandle.RawHandle;
X11Display = X11Window.DisplayHandle.RawHandle;
X11Window.Hide();
return new PlatformHandle(WindowHandle, "X11");
}
public SurfaceKHR CreateSurface(Instance instance)
{
if (OperatingSystem.IsWindows())
@@ -20,7 +35,7 @@ namespace Ryujinx.Ava.Ui
}
else if (OperatingSystem.IsLinux())
{
_window = X11Window;
_window = new SimpleX11Window(new NativeHandle(X11Display), new NativeHandle(WindowHandle));
}
else
{

View File

@@ -1283,7 +1283,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
ApplicationData selection = SelectedApplication;
if (selection != null)
{
await new TitleUpdateWindow(_owner.VirtualFileSystem, selection.TitleId, selection.TitleName).ShowDialog(_owner);
await new TitleUpdateWindow(_owner.VirtualFileSystem, ulong.Parse(selection.TitleId, NumberStyles.HexNumber), selection.TitleName).ShowDialog(_owner);
}
}

View File

@@ -8,8 +8,10 @@
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
Width="800"
Height="500"
MinWidth="600"
MinWidth="800"
MinHeight="500"
MaxWidth="800"
MaxHeight="500"
SizeToContent="Height"
WindowStartupLocation="CenterOwner"
mc:Ignorable="d">

View File

@@ -8,7 +8,6 @@ using LibHac.FsSystem;
using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils;
using LibHac.Tools.FsSystem.Save;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Ui.Controls;
using Ryujinx.Ava.Ui.Models;
@@ -17,8 +16,6 @@ using Ryujinx.Common.Utilities;
using Ryujinx.HLE.FileSystem;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
@@ -36,8 +33,8 @@ namespace Ryujinx.Ava.Ui.Windows
private VirtualFileSystem _virtualFileSystem { get; }
private AvaloniaList<DownloadableContentModel> _downloadableContents { get; set; }
private ulong TitleId { get; }
private string TitleName { get; }
private ulong _titleId { get; }
private string _titleName { get; }
public DownloadableContentManagerWindow()
{
@@ -45,15 +42,16 @@ namespace Ryujinx.Ava.Ui.Windows
InitializeComponent();
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["DlcWindowTitle"]} - {TitleName} ({TitleId:X16})";
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["DlcWindowTitle"]} - {_titleName} ({_titleId:X16})";
}
public DownloadableContentManagerWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
{
_virtualFileSystem = virtualFileSystem;
_downloadableContents = new AvaloniaList<DownloadableContentModel>();
TitleId = titleId;
TitleName = titleName;
_titleId = titleId;
_titleName = titleName;
_downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "dlc.json");
@@ -74,7 +72,7 @@ namespace Ryujinx.Ava.Ui.Windows
DlcDataGrid.SelectionChanged += DlcDataGrid_SelectionChanged;
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["DlcWindowTitle"]} - {TitleName} ({TitleId:X16})";
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["DlcWindowTitle"]} - {_titleName} ({_titleId:X16})";
LoadDownloadableContents();
PrintHeading();
@@ -87,7 +85,7 @@ namespace Ryujinx.Ava.Ui.Windows
private void PrintHeading()
{
Heading.Text = string.Format(LocaleManager.Instance["DlcWindowHeading"], _downloadableContents.Count, TitleName, TitleId.ToString("X16"));
Heading.Text = string.Format(LocaleManager.Instance["DlcWindowHeading"], _downloadableContents.Count, _titleName, _titleId.ToString("X16"));
}
private void LoadDownloadableContents()
@@ -98,15 +96,15 @@ namespace Ryujinx.Ava.Ui.Windows
{
using FileStream containerFile = File.OpenRead(downloadableContentContainer.ContainerPath);
PartitionFileSystem pfs = new(containerFile.AsStorage());
PartitionFileSystem partitionFileSystem = new(containerFile.AsStorage());
_virtualFileSystem.ImportTickets(pfs);
_virtualFileSystem.ImportTickets(partitionFileSystem);
foreach (DownloadableContentNca downloadableContentNca in downloadableContentContainer.DownloadableContentNcaList)
{
using UniqueRef<IFile> ncaFile = new();
pfs.OpenFile(ref ncaFile.Ref(), downloadableContentNca.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
partitionFileSystem.OpenFile(ref ncaFile.Ref(), downloadableContentNca.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), downloadableContentContainer.ContainerPath);
if (nca != null)
@@ -169,7 +167,7 @@ namespace Ryujinx.Ava.Ui.Windows
if (nca.Header.ContentType == NcaContentType.PublicData)
{
if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000) != TitleId)
if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000) != _titleId)
{
break;
}

View File

@@ -3,13 +3,17 @@
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
SizeToContent="Height"
Width="600" MinHeight="500" Height="500"
WindowStartupLocation="CenterOwner"
Width="600"
Height="400"
MinWidth="600"
MinHeight="400"
MaxWidth="600"
MaxHeight="400"
SizeToContent="Height"
WindowStartupLocation="CenterOwner"
mc:Ignorable="d">
<Grid Margin="15">
<Grid.RowDefinitions>
@@ -19,15 +23,15 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Name="Heading"
Grid.Row="1"
MaxWidth="500"
Margin="20,15,20,20"
HorizontalAlignment="Center"
VerticalAlignment="Center"
MaxWidth="500"
LineHeight="18"
TextWrapping="Wrap"
Text="{Binding Heading}"
TextAlignment="Center" />
TextAlignment="Center"
TextWrapping="Wrap" />
<Border
Grid.Row="2"
Margin="5"
@@ -36,8 +40,6 @@
BorderBrush="Gray"
BorderThickness="1">
<ScrollViewer
Width="550"
MinHeight="200"
VerticalAlignment="Stretch"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
@@ -45,11 +47,19 @@
Margin="10"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Items="{Binding TitleUpdates}">
Items="{Binding _titleUpdates}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<RadioButton Padding="8, 0" VerticalContentAlignment="Center" GroupName="Update" IsChecked="{Binding IsEnabled, Mode=TwoWay}">
<Label Margin="0" VerticalAlignment="Center" Content="{Binding Label}" />
<RadioButton
Padding="8,0"
VerticalContentAlignment="Center"
GroupName="Update"
IsChecked="{Binding IsEnabled, Mode=TwoWay}">
<Label
Margin="0"
VerticalAlignment="Center"
Content="{Binding Label}"
FontSize="12" />
</RadioButton>
</DataTemplate>
</ItemsControl.ItemTemplate>

View File

@@ -30,13 +30,11 @@ namespace Ryujinx.Ava.Ui.Windows
private readonly string _titleUpdateJsonPath;
private TitleUpdateMetadata _titleUpdateWindowData;
public VirtualFileSystem VirtualFileSystem { get; }
private VirtualFileSystem _virtualFileSystem { get; }
private AvaloniaList<TitleUpdateModel> _titleUpdates { get; set; }
internal AvaloniaList<TitleUpdateModel> TitleUpdates { get; set; } = new AvaloniaList<TitleUpdateModel>();
public string TitleId { get; }
public string TitleName { get; }
public string Heading => string.Format(LocaleManager.Instance["GameUpdateWindowHeading"], TitleName, TitleId.ToUpper());
private ulong _titleId { get; }
private string _titleName { get; }
public TitleUpdateWindow()
{
@@ -44,16 +42,18 @@ namespace Ryujinx.Ava.Ui.Windows
InitializeComponent();
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["UpdateWindowTitle"];
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["UpdateWindowTitle"]} - {_titleName} ({_titleId:X16})";
}
public TitleUpdateWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName)
public TitleUpdateWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
{
VirtualFileSystem = virtualFileSystem;
TitleId = titleId;
TitleName = titleName;
_virtualFileSystem = virtualFileSystem;
_titleUpdates = new AvaloniaList<TitleUpdateModel>();
_titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId, "updates.json");
_titleId = titleId;
_titleName = titleName;
_titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json");
try
{
@@ -64,7 +64,7 @@ namespace Ryujinx.Ava.Ui.Windows
_titleUpdateWindowData = new TitleUpdateMetadata
{
Selected = "",
Paths = new List<string>()
Paths = new List<string>()
};
}
@@ -72,14 +72,20 @@ namespace Ryujinx.Ava.Ui.Windows
InitializeComponent();
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["UpdateWindowTitle"];
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["UpdateWindowTitle"]} - {_titleName} ({_titleId:X16})";
LoadUpdates();
PrintHeading();
}
private void PrintHeading()
{
Heading.Text = string.Format(LocaleManager.Instance["GameUpdateWindowHeading"], _titleUpdates.Count, _titleName, _titleId.ToString("X16"));
}
private void LoadUpdates()
{
TitleUpdates.Add(new TitleUpdateModel(default, string.Empty, true));
_titleUpdates.Add(new TitleUpdateModel(default, string.Empty, true));
foreach (string path in _titleUpdateWindowData.Paths)
{
@@ -88,12 +94,12 @@ namespace Ryujinx.Ava.Ui.Windows
if (_titleUpdateWindowData.Selected == "")
{
TitleUpdates[0].IsEnabled = true;
_titleUpdates[0].IsEnabled = true;
}
else
{
TitleUpdateModel selected = TitleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected);
List<TitleUpdateModel> enabled = TitleUpdates.Where(x => x.IsEnabled).ToList();
TitleUpdateModel selected = _titleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected);
List<TitleUpdateModel> enabled = _titleUpdates.Where(x => x.IsEnabled).ToList();
foreach (TitleUpdateModel update in enabled)
{
@@ -111,50 +117,47 @@ namespace Ryujinx.Ava.Ui.Windows
private void AddUpdate(string path)
{
if (File.Exists(path) && !TitleUpdates.Any(x => x.Path == path))
if (File.Exists(path) && !_titleUpdates.Any(x => x.Path == path))
{
using (FileStream file = new(path, FileMode.Open, FileAccess.Read))
using FileStream file = new(path, FileMode.Open, FileAccess.Read);
try
{
PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage());
(Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateDataFromPartition(_virtualFileSystem, new PartitionFileSystem(file.AsStorage()), _titleId.ToString("x16"), 0);
try
if (controlNca != null && patchNca != null)
{
(Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateDataFromPartition(VirtualFileSystem, nsp, TitleId, 0);
ApplicationControlProperty controlData = new();
if (controlNca != null && patchNca != null)
using UniqueRef<IFile> nacpFile = new();
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref(), "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
_titleUpdates.Add(new TitleUpdateModel(controlData, path));
foreach (var update in _titleUpdates)
{
ApplicationControlProperty controlData = new ApplicationControlProperty();
using var nacpFile = new UniqueRef<IFile>();
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref(), "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
TitleUpdates.Add(new TitleUpdateModel(controlData, path));
foreach (var update in TitleUpdates)
{
update.IsEnabled = false;
}
TitleUpdates.Last().IsEnabled = true;
}
else
{
Dispatcher.UIThread.Post(async () =>
{
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUpdateAddUpdateErrorMessage"]);
});
update.IsEnabled = false;
}
_titleUpdates.Last().IsEnabled = true;
}
catch (Exception ex)
else
{
Dispatcher.UIThread.Post(async () =>
{
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogDlcLoadNcaErrorMessage"], ex.Message, path));
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUpdateAddUpdateErrorMessage"]);
});
}
}
catch (Exception ex)
{
Dispatcher.UIThread.Post(async () =>
{
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogDlcLoadNcaErrorMessage"], ex.Message, path));
});
}
}
}
@@ -162,16 +165,17 @@ namespace Ryujinx.Ava.Ui.Windows
{
if (removeSelectedOnly)
{
TitleUpdates.RemoveAll(TitleUpdates.Where(x => x.IsEnabled && !x.IsNoUpdate).ToList());
_titleUpdates.RemoveAll(_titleUpdates.Where(x => x.IsEnabled && !x.IsNoUpdate).ToList());
}
else
{
TitleUpdates.RemoveAll(TitleUpdates.Where(x => !x.IsNoUpdate).ToList());
_titleUpdates.RemoveAll(_titleUpdates.Where(x => !x.IsNoUpdate).ToList());
}
TitleUpdates.FirstOrDefault(x => x.IsNoUpdate).IsEnabled = true;
_titleUpdates.FirstOrDefault(x => x.IsNoUpdate).IsEnabled = true;
SortUpdates();
PrintHeading();
}
public void RemoveSelected()
@@ -186,7 +190,7 @@ namespace Ryujinx.Ava.Ui.Windows
public async void Add()
{
OpenFileDialog dialog = new OpenFileDialog()
OpenFileDialog dialog = new()
{
Title = LocaleManager.Instance["SelectUpdateDialogTitle"],
AllowMultiple = true
@@ -209,11 +213,12 @@ namespace Ryujinx.Ava.Ui.Windows
}
SortUpdates();
PrintHeading();
}
private void SortUpdates()
{
var list = TitleUpdates.ToList();
var list = _titleUpdates.ToList();
list.Sort((first, second) =>
{
@@ -229,8 +234,8 @@ namespace Ryujinx.Ava.Ui.Windows
return Version.Parse(first.Control.DisplayVersionString.ToString()).CompareTo(Version.Parse(second.Control.DisplayVersionString.ToString())) * -1;
});
TitleUpdates.Clear();
TitleUpdates.AddRange(list);
_titleUpdates.Clear();
_titleUpdates.AddRange(list);
}
public void Save()
@@ -239,7 +244,7 @@ namespace Ryujinx.Ava.Ui.Windows
_titleUpdateWindowData.Selected = "";
foreach (TitleUpdateModel update in TitleUpdates)
foreach (TitleUpdateModel update in _titleUpdates)
{
_titleUpdateWindowData.Paths.Add(update.Path);

View File

@@ -8,7 +8,7 @@
<ItemGroup>
<PackageReference Include="MsgPack.Cli" Version="1.0.1" />
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
<PackageReference Include="System.Management" Version="6.0.0" />
<PackageReference Include="System.Management" Version="7.0.0" />
</ItemGroup>
</Project>

View File

@@ -37,6 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
private bool _vsUsesDrawParameters;
private bool _vtgWritesRtLayer;
private byte _vsClipDistancesWritten;
private uint _vbEnableMask;
private bool _prevDrawIndexed;
private bool _prevDrawIndirect;
@@ -76,6 +77,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
nameof(ThreedClassState.VertexBufferState),
nameof(ThreedClassState.VertexBufferEndAddress)),
// Must be done after vertex buffer updates.
new StateUpdateCallbackEntry(UpdateVertexAttribState, nameof(ThreedClassState.VertexAttribState)),
new StateUpdateCallbackEntry(UpdateBlendState,
@@ -852,12 +854,23 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// </summary>
private void UpdateVertexAttribState()
{
uint vbEnableMask = _vbEnableMask;
Span<VertexAttribDescriptor> vertexAttribs = stackalloc VertexAttribDescriptor[Constants.TotalVertexAttribs];
for (int index = 0; index < Constants.TotalVertexAttribs; index++)
{
var vertexAttrib = _state.State.VertexAttribState[index];
int bufferIndex = vertexAttrib.UnpackBufferIndex();
if ((vbEnableMask & (1u << bufferIndex)) == 0)
{
// Using a vertex buffer that doesn't exist is invalid, so let's use a dummy attribute for those cases.
vertexAttribs[index] = new VertexAttribDescriptor(0, 0, true, Format.R32G32B32A32Float);
continue;
}
if (!FormatTable.TryGetAttribFormat(vertexAttrib.UnpackFormat(), out Format format))
{
Logger.Debug?.Print(LogClass.Gpu, $"Invalid attribute format 0x{vertexAttrib.UnpackFormat():X}.");
@@ -866,7 +879,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
}
vertexAttribs[index] = new VertexAttribDescriptor(
vertexAttrib.UnpackBufferIndex(),
bufferIndex,
vertexAttrib.UnpackOffset(),
vertexAttrib.UnpackIsConstant(),
format);
@@ -954,6 +967,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
bool drawIndexed = _drawState.DrawIndexed;
bool drawIndirect = _drawState.DrawIndirect;
uint vbEnableMask = 0;
for (int index = 0; index < Constants.TotalVertexBuffers; index++)
{
@@ -971,6 +985,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
ulong address = vertexBuffer.Address.Pack();
if (_channel.MemoryManager.IsMapped(address))
{
vbEnableMask |= 1u << index;
}
int stride = vertexBuffer.UnpackStride();
bool instanced = _state.State.VertexBufferInstanced[index];
@@ -1017,6 +1036,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_pipeline.VertexBuffers[index] = new BufferPipelineDescriptor(_channel.MemoryManager.IsMapped(address), stride, divisor);
_channel.BufferManager.SetVertexBuffer(index, address, size, stride, divisor);
}
if (_vbEnableMask != vbEnableMask)
{
_vbEnableMask = vbEnableMask;
UpdateVertexAttribState();
}
}
/// <summary>

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 = 3868;
private const uint CodeGenVersion = 3943;
private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";

View File

@@ -331,7 +331,7 @@ namespace Ryujinx.Graphics.OpenGL
case PrimitiveTopology.QuadStrip:
return PrimitiveType.QuadStrip;
case PrimitiveTopology.Polygon:
return PrimitiveType.Polygon;
return PrimitiveType.TriangleFan;
case PrimitiveTopology.LinesAdjacency:
return PrimitiveType.LinesAdjacency;
case PrimitiveTopology.LineStripAdjacency:

View File

@@ -6,7 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTK.Graphics" Version="4.7.2" />
<PackageReference Include="OpenTK.Graphics" Version="4.7.5" />
</ItemGroup>
<ItemGroup>

View File

@@ -10,13 +10,9 @@ namespace Ryujinx.Graphics.OpenGL
{
public int Handle { get; private set; }
private bool _needsAttribsUpdate;
private readonly VertexAttribDescriptor[] _vertexAttribs;
private readonly VertexBufferDescriptor[] _vertexBuffers;
private int _vertexAttribsCount;
private int _vertexBuffersCount;
private int _minVertexCount;
private uint _vertexAttribsInUse;
@@ -76,9 +72,7 @@ namespace Ryujinx.Graphics.OpenGL
_vertexBuffers[bindingIndex] = vb;
}
_vertexBuffersCount = bindingIndex;
_minVertexCount = minVertexCount;
_needsAttribsUpdate = true;
}
public void SetVertexAttributes(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
@@ -131,8 +125,6 @@ namespace Ryujinx.Graphics.OpenGL
_vertexAttribs[index] = attrib;
}
_vertexAttribsCount = index;
for (; index < Constants.MaxVertexAttribs; index++)
{
DisableVertexAttrib(index);
@@ -160,13 +152,11 @@ namespace Ryujinx.Graphics.OpenGL
public void PreDraw(int vertexCount)
{
LimitVertexBuffers(vertexCount);
Validate();
}
public void PreDrawVbUnbounded()
{
UnlimitVertexBuffers();
Validate();
}
public void LimitVertexBuffers(int vertexCount)
@@ -252,36 +242,6 @@ namespace Ryujinx.Graphics.OpenGL
_vertexBuffersLimited = 0;
}
public void Validate()
{
for (int attribIndex = 0; attribIndex < _vertexAttribsCount; attribIndex++)
{
VertexAttribDescriptor attrib = _vertexAttribs[attribIndex];
if (!attrib.IsZero)
{
if ((uint)attrib.BufferIndex >= _vertexBuffersCount)
{
DisableVertexAttrib(attribIndex);
continue;
}
if (_vertexBuffers[attrib.BufferIndex].Buffer.Handle == BufferHandle.Null)
{
DisableVertexAttrib(attribIndex);
continue;
}
if (_needsAttribsUpdate)
{
EnableVertexAttrib(attribIndex);
}
}
}
_needsAttribsUpdate = false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EnableVertexAttrib(int index)
{

View File

@@ -234,7 +234,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
var source = operation.GetSource(0);
var uvec4Type = context.TypeVector(context.TypeU32(), 4);
var execution = context.Constant(context.TypeU32(), 3); // Subgroup
var execution = context.Constant(context.TypeU32(), Scope.Subgroup);
var maskVector = context.GroupNonUniformBallot(uvec4Type, execution, context.Get(AggregateType.Bool, source));
var mask = context.CompositeExtract(context.TypeU32(), maskVector, (SpvLiteralInteger)0);
@@ -1233,7 +1233,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
var maxThreadId = context.BitwiseOr(context.TypeU32(), minThreadId, clampNotSegMask);
var srcThreadId = context.BitwiseOr(context.TypeU32(), indexNotSegMask, minThreadId);
var valid = context.ULessThanEqual(context.TypeBool(), srcThreadId, maxThreadId);
var value = context.SubgroupReadInvocationKHR(context.TypeFP32(), x, srcThreadId);
var value = context.GroupNonUniformShuffle(context.TypeFP32(), context.Constant(context.TypeU32(), (int)Scope.Subgroup), x, srcThreadId);
var result = context.Select(context.TypeFP32(), valid, value, x);
var validLocal = (AstOperand)operation.GetSource(3);
@@ -1263,7 +1263,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
var maxThreadId = context.BitwiseOr(context.TypeU32(), minThreadId, clampNotSegMask);
var srcThreadId = context.IAdd(context.TypeU32(), threadId, index);
var valid = context.ULessThanEqual(context.TypeBool(), srcThreadId, maxThreadId);
var value = context.SubgroupReadInvocationKHR(context.TypeFP32(), x, srcThreadId);
var value = context.GroupNonUniformShuffle(context.TypeFP32(), context.Constant(context.TypeU32(), (int)Scope.Subgroup), x, srcThreadId);
var result = context.Select(context.TypeFP32(), valid, value, x);
var validLocal = (AstOperand)operation.GetSource(3);
@@ -1289,7 +1289,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
var minThreadId = context.BitwiseAnd(context.TypeU32(), threadId, segMask);
var srcThreadId = context.ISub(context.TypeU32(), threadId, index);
var valid = context.SGreaterThanEqual(context.TypeBool(), srcThreadId, minThreadId);
var value = context.SubgroupReadInvocationKHR(context.TypeFP32(), x, srcThreadId);
var value = context.GroupNonUniformShuffle(context.TypeFP32(), context.Constant(context.TypeU32(), (int)Scope.Subgroup), x, srcThreadId);
var result = context.Select(context.TypeFP32(), valid, value, x);
var validLocal = (AstOperand)operation.GetSource(3);
@@ -1319,7 +1319,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
var maxThreadId = context.BitwiseOr(context.TypeU32(), minThreadId, clampNotSegMask);
var srcThreadId = context.BitwiseXor(context.TypeU32(), threadId, index);
var valid = context.ULessThanEqual(context.TypeBool(), srcThreadId, maxThreadId);
var value = context.SubgroupReadInvocationKHR(context.TypeFP32(), x, srcThreadId);
var value = context.GroupNonUniformShuffle(context.TypeFP32(), context.Constant(context.TypeU32(), (int)Scope.Subgroup), x, srcThreadId);
var result = context.Select(context.TypeFP32(), valid, value, x);
var validLocal = (AstOperand)operation.GetSource(3);
@@ -1861,19 +1861,22 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
private static OperationResult GenerateVoteAll(CodeGenContext context, AstOperation operation)
{
var result = context.SubgroupAllKHR(context.TypeBool(), context.Get(AggregateType.Bool, operation.GetSource(0)));
var execution = context.Constant(context.TypeU32(), Scope.Subgroup);
var result = context.GroupNonUniformAll(context.TypeBool(), execution, context.Get(AggregateType.Bool, operation.GetSource(0)));
return new OperationResult(AggregateType.Bool, result);
}
private static OperationResult GenerateVoteAllEqual(CodeGenContext context, AstOperation operation)
{
var result = context.SubgroupAllEqualKHR(context.TypeBool(), context.Get(AggregateType.Bool, operation.GetSource(0)));
var execution = context.Constant(context.TypeU32(), Scope.Subgroup);
var result = context.GroupNonUniformAllEqual(context.TypeBool(), execution, context.Get(AggregateType.Bool, operation.GetSource(0)));
return new OperationResult(AggregateType.Bool, result);
}
private static OperationResult GenerateVoteAny(CodeGenContext context, AstOperation operation)
{
var result = context.SubgroupAnyKHR(context.TypeBool(), context.Get(AggregateType.Bool, operation.GetSource(0)));
var execution = context.Constant(context.TypeU32(), Scope.Subgroup);
var result = context.GroupNonUniformAny(context.TypeBool(), execution, context.Get(AggregateType.Bool, operation.GetSource(0)));
return new OperationResult(AggregateType.Bool, result);
}

View File

@@ -50,12 +50,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
CodeGenContext context = new CodeGenContext(info, config, instPool, integerPool);
context.AddCapability(Capability.GroupNonUniformBallot);
context.AddCapability(Capability.GroupNonUniformShuffle);
context.AddCapability(Capability.GroupNonUniformVote);
context.AddCapability(Capability.ImageBuffer);
context.AddCapability(Capability.ImageGatherExtended);
context.AddCapability(Capability.ImageQuery);
context.AddCapability(Capability.SampledBuffer);
context.AddCapability(Capability.SubgroupBallotKHR);
context.AddCapability(Capability.SubgroupVoteKHR);
if (config.TransformFeedbackEnabled && config.LastInVertexPipeline)
{
@@ -94,9 +94,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
context.AddCapability(Capability.DrawParameters);
}
context.AddExtension("SPV_KHR_shader_ballot");
context.AddExtension("SPV_KHR_subgroup_vote");
Declarations.DeclareAll(context, info);
if ((info.HelperFunctionsMask & NeedsInvocationIdMask) != 0)

View File

@@ -128,6 +128,11 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
GetStorageOffset(block, Utils.FindLastOperation(addrLow, block), baseAddressCbOffset) :
(null, 0);
if (byteOffset != null)
{
ReplaceAddressAlignment(node.List, addrLow, byteOffset, constantOffset);
}
if (byteOffset == null)
{
Operand baseAddrLow = Cbuf(0, baseAddressCbOffset);
@@ -156,11 +161,6 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
byteOffset = offset;
}
if (byteOffset != null)
{
ReplaceAddressAlignment(node.List, addrLow, byteOffset, constantOffset);
}
if (isStg16Or8)
{
return byteOffset;

View File

@@ -180,6 +180,7 @@ namespace Ryujinx.Graphics.Vulkan
GAL.PrimitiveTopology.TrianglesAdjacency => Silk.NET.Vulkan.PrimitiveTopology.TriangleListWithAdjacency,
GAL.PrimitiveTopology.TriangleStripAdjacency => Silk.NET.Vulkan.PrimitiveTopology.TriangleStripWithAdjacency,
GAL.PrimitiveTopology.Patches => Silk.NET.Vulkan.PrimitiveTopology.PatchList,
GAL.PrimitiveTopology.Polygon => Silk.NET.Vulkan.PrimitiveTopology.TriangleFan,
GAL.PrimitiveTopology.Quads => throw new NotSupportedException("Quad topology is not available in Vulkan."),
GAL.PrimitiveTopology.QuadStrip => throw new NotSupportedException("QuadStrip topology is not available in Vulkan."),
_ => LogInvalidAndReturn(topology, nameof(GAL.PrimitiveTopology), Silk.NET.Vulkan.PrimitiveTopology.TriangleList)

View File

@@ -328,7 +328,8 @@ namespace Ryujinx.Graphics.Vulkan
IndexBufferPattern pattern = _topology switch
{
GAL.PrimitiveTopology.Quads => QuadsToTrisPattern,
GAL.PrimitiveTopology.TriangleFan => TriFanToTrisPattern,
GAL.PrimitiveTopology.TriangleFan or
GAL.PrimitiveTopology.Polygon => TriFanToTrisPattern,
_ => throw new NotSupportedException($"Unsupported topology: {_topology}")
};
@@ -359,7 +360,8 @@ namespace Ryujinx.Graphics.Vulkan
pattern = _topology switch
{
GAL.PrimitiveTopology.Quads => QuadsToTrisPattern,
GAL.PrimitiveTopology.TriangleFan => TriFanToTrisPattern,
GAL.PrimitiveTopology.TriangleFan or
GAL.PrimitiveTopology.Polygon => TriFanToTrisPattern,
_ => throw new NotSupportedException($"Unsupported topology: {_topology}")
};
}

View File

@@ -13,7 +13,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.7.2" />
<PackageReference Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.7.5" />
<PackageReference Include="shaderc.net" Version="0.1.0" />
<PackageReference Include="Silk.NET.Vulkan" Version="2.10.1" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.10.1" />

View File

@@ -37,7 +37,6 @@ namespace Ryujinx.Graphics.Vulkan
public static string[] RequiredExtensions { get; } = new string[]
{
KhrSwapchain.ExtensionName,
"VK_EXT_shader_subgroup_vote",
ExtTransformFeedback.ExtensionName
};

View File

@@ -16,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
public ResultCode ExecuteAudioRendererRendering()
{
throw new NotImplementedException();
return (ResultCode)_impl.ExecuteAudioRendererRendering();
}
public uint GetMixBufferCount()
@@ -108,5 +108,15 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
_impl.Dispose();
}
}
public void SetVoiceDropParameter(float voiceDropParameter)
{
_impl.SetVoiceDropParameter(voiceDropParameter);
}
public float GetVoiceDropParameter()
{
return _impl.GetVoiceDropParameter();
}
}
}

View File

@@ -172,6 +172,35 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
return result;
}
[CommandHipc(11)] // 3.0.0+
// ExecuteAudioRendererRendering()
public ResultCode ExecuteAudioRendererRendering(ServiceCtx context)
{
return _impl.ExecuteAudioRendererRendering();
}
[CommandHipc(12)] // 15.0.0+
// SetVoiceDropParameter(f32 voiceDropParameter)
public ResultCode SetVoiceDropParameter(ServiceCtx context)
{
float voiceDropParameter = context.RequestData.ReadSingle();
_impl.SetVoiceDropParameter(voiceDropParameter);
return ResultCode.Success;
}
[CommandHipc(13)] // 15.0.0+
// GetVoiceDropParameter() -> f32 voiceDropParameter
public ResultCode GetVoiceDropParameter(ServiceCtx context)
{
float voiceDropParameter = _impl.GetVoiceDropParameter();
context.ResponseData.Write(voiceDropParameter);
return ResultCode.Success;
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)

View File

@@ -16,5 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
void SetRenderingTimeLimit(uint percent);
uint GetRenderingTimeLimit();
ResultCode ExecuteAudioRendererRendering();
void SetVoiceDropParameter(float voiceDropParameter);
float GetVoiceDropParameter();
}
}

View File

@@ -22,7 +22,7 @@ namespace Ryujinx.HLE.HOS.Services.Ptm.Psm
{
if (_stateChangeEventHandle == -1)
{
KernelResult resultCode = context.Process.HandleTable.GenerateHandle(_stateChangeEvent.ReadableEvent, out int stateChangeEventHandle);
KernelResult resultCode = context.Process.HandleTable.GenerateHandle(_stateChangeEvent.ReadableEvent, out _stateChangeEventHandle);
if (resultCode != KernelResult.Success)
{

View File

@@ -315,6 +315,11 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
}
}
if (updateCount > 0)
{
break;
}
// If we are here, that mean nothing was availaible, sleep for 50ms
context.Device.System.KernelContext.Syscall.SleepThread(50 * 1000000);
}
@@ -972,11 +977,12 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
}
[CommandHipc(31)] // 7.0.0+
// EventFd(u64 initval, nn::socket::EventFdFlags flags) -> (i32 ret, u32 bsd_errno)
// EventFd(nn::socket::EventFdFlags flags, u64 initval) -> (i32 ret, u32 bsd_errno)
public ResultCode EventFd(ServiceCtx context)
{
ulong initialValue = context.RequestData.ReadUInt64();
EventFdFlags flags = (EventFdFlags)context.RequestData.ReadUInt32();
context.RequestData.BaseStream.Position += 4; // Padding
ulong initialValue = context.RequestData.ReadUInt64();
EventFileDescriptor newEventFile = new EventFileDescriptor(initialValue, flags);

View File

@@ -26,8 +26,9 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
_value = value;
_flags = flags;
WriteEvent = new ManualResetEvent(true);
ReadEvent = new ManualResetEvent(true);
WriteEvent = new ManualResetEvent(false);
ReadEvent = new ManualResetEvent(false);
UpdateEventStates();
}
public int Refcount { get; set; }
@@ -38,6 +39,25 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
ReadEvent.Dispose();
}
private void ResetEventStates()
{
WriteEvent.Reset();
ReadEvent.Reset();
}
private void UpdateEventStates()
{
if (_value > 0)
{
ReadEvent.Set();
}
if (_value != uint.MaxValue - 1)
{
WriteEvent.Set();
}
}
public LinuxError Read(out int readSize, Span<byte> buffer)
{
if (buffer.Length < sizeof(ulong))
@@ -47,10 +67,10 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
return LinuxError.EINVAL;
}
ReadEvent.Reset();
lock (_lock)
{
ResetEventStates();
ref ulong count = ref MemoryMarshal.Cast<byte, ulong>(buffer)[0];
if (_value == 0)
@@ -66,6 +86,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
{
readSize = 0;
UpdateEventStates();
return LinuxError.EAGAIN;
}
}
@@ -85,8 +106,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
_value = 0;
}
ReadEvent.Set();
UpdateEventStates();
return LinuxError.SUCCESS;
}
}
@@ -100,10 +120,10 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
return LinuxError.EINVAL;
}
WriteEvent.Reset();
lock (_lock)
{
ResetEventStates();
if (_value > _value + count)
{
if (Blocking)
@@ -114,6 +134,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
{
writeSize = 0;
UpdateEventStates();
return LinuxError.EAGAIN;
}
}
@@ -123,8 +144,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
_value += count;
Monitor.Pulse(_lock);
WriteEvent.Set();
UpdateEventStates();
return LinuxError.SUCCESS;
}
}

View File

@@ -68,20 +68,37 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
{
for (int i = 0; i < events.Count; i++)
{
PollEventTypeMask outputEvents = 0;
PollEvent evnt = events[i];
EventFileDescriptor socket = (EventFileDescriptor)evnt.FileDescriptor;
if ((evnt.Data.InputEvents.HasFlag(PollEventTypeMask.Input) ||
evnt.Data.InputEvents.HasFlag(PollEventTypeMask.UrgentInput))
&& socket.ReadEvent.WaitOne(0))
if (socket.ReadEvent.WaitOne(0))
{
waiters.Add(socket.ReadEvent);
if (evnt.Data.InputEvents.HasFlag(PollEventTypeMask.Input))
{
outputEvents |= PollEventTypeMask.Input;
}
if (evnt.Data.InputEvents.HasFlag(PollEventTypeMask.UrgentInput))
{
outputEvents |= PollEventTypeMask.UrgentInput;
}
}
if ((evnt.Data.InputEvents.HasFlag(PollEventTypeMask.Output))
&& socket.WriteEvent.WaitOne(0))
{
waiters.Add(socket.WriteEvent);
outputEvents |= PollEventTypeMask.Output;
}
if (outputEvents != 0)
{
evnt.Data.OutputEvents = outputEvents;
updatedCount++;
}
}
}

View File

@@ -566,7 +566,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres
private static List<AddrInfoSerialized> DeserializeAddrInfos(IVirtualMemoryManager memory, ulong address, ulong size)
{
List<AddrInfoSerialized> result = new List<AddrInfoSerialized>();
List<AddrInfoSerialized> result = new();
ReadOnlySpan<byte> data = memory.GetSpan(address, (int)size);
@@ -606,9 +606,9 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres
}
// NOTE: 0 = Any
AddrInfoSerializedHeader header = new AddrInfoSerializedHeader(ip, 0);
AddrInfo4 addr = new AddrInfo4(ip, (short)port);
AddrInfoSerialized info = new AddrInfoSerialized(header, addr, null, hostEntry.HostName);
AddrInfoSerializedHeader header = new(ip, 0);
AddrInfo4 addr = new(ip, (short)port);
AddrInfoSerialized info = new(header, addr, null, hostEntry.HostName);
data = info.Write(data);
}

View File

@@ -14,6 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres.Types
public byte Family;
public short Port;
public Array4<byte> Address;
public Array8<byte> Padding;
public AddrInfo4(IPAddress address, short port)
{

View File

@@ -35,7 +35,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres.Types
AddrInfo4? socketAddress = null;
Array4<byte>? rawIPv4Address = null;
string canonicalName = null;
string canonicalName;
buffer = buffer[Unsafe.SizeOf<AddrInfoSerializedHeader>()..];
@@ -50,6 +50,13 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres.Types
Debug.Assert(header.Magic == SfdnsresContants.AddrInfoMagic);
if (header.AddressLength == 0)
{
rest = buffer;
return null;
}
if (header.Family == (int)AddressFamily.InterNetwork)
{
socketAddress = MemoryMarshal.Read<AddrInfo4>(buffer);

View File

@@ -11,7 +11,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTK.Core" Version="4.7.2" />
<PackageReference Include="OpenTK.Core" Version="4.7.5" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
</ItemGroup>

View File

@@ -41,7 +41,7 @@ namespace Ryujinx.Memory.Tracking
{
for (int i = 0; i < Masks.Length; i++)
{
if (Volatile.Read(ref Masks[i]) != 0)
if (Interlocked.Read(ref Masks[i]) != 0)
{
return true;
}
@@ -62,7 +62,7 @@ namespace Ryujinx.Memory.Tracking
long wordMask = 1L << wordBit;
return (Volatile.Read(ref Masks[wordIndex]) & wordMask) != 0;
return (Interlocked.Read(ref Masks[wordIndex]) & wordMask) != 0;
}
/// <summary>
@@ -86,7 +86,7 @@ namespace Ryujinx.Memory.Tracking
int endBit = end & IntMask;
long endMask = (long)(ulong.MaxValue >> (IntMask - endBit));
long startValue = Volatile.Read(ref Masks[startIndex]);
long startValue = Interlocked.Read(ref Masks[startIndex]);
if (startIndex == endIndex)
{
@@ -100,13 +100,13 @@ namespace Ryujinx.Memory.Tracking
for (int i = startIndex + 1; i < endIndex; i++)
{
if (Volatile.Read(ref Masks[i]) != 0)
if (Interlocked.Read(ref Masks[i]) != 0)
{
return true;
}
}
long endValue = Volatile.Read(ref Masks[endIndex]);
long endValue = Interlocked.Read(ref Masks[endIndex]);
if ((endValue & endMask) != 0)
{
@@ -128,23 +128,14 @@ namespace Ryujinx.Memory.Tracking
long wordMask = 1L << wordBit;
long existing;
long newValue;
do
if (value)
{
existing = Volatile.Read(ref Masks[wordIndex]);
if (value)
{
newValue = existing | wordMask;
}
else
{
newValue = existing & ~wordMask;
}
Interlocked.Or(ref Masks[wordIndex], wordMask);
}
else
{
Interlocked.And(ref Masks[wordIndex], ~wordMask);
}
while (Interlocked.CompareExchange(ref Masks[wordIndex], newValue, existing) != existing);
}
/// <summary>
@@ -154,7 +145,7 @@ namespace Ryujinx.Memory.Tracking
{
for (int i = 0; i < Masks.Length; i++)
{
Volatile.Write(ref Masks[i], 0);
Interlocked.Exchange(ref Masks[i], 0);
}
}
}

View File

@@ -41,7 +41,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="DiscordRichPresence" Version="1.0.175" />
<PackageReference Include="DiscordRichPresence" Version="1.1.3.18" />
</ItemGroup>
<ItemGroup>

View File

@@ -21,10 +21,10 @@
<ItemGroup>
<PackageReference Include="GtkSharp" Version="3.22.25.128" />
<PackageReference Include="GtkSharp.Dependencies" Version="1.1.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="OpenTK.Core" Version="4.7.2" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="OpenTK.Graphics" Version="4.7.2" />
<PackageReference Include="OpenTK.Core" Version="4.7.5" />
<PackageReference Include="OpenTK.Graphics" Version="4.7.5" />
<PackageReference Include="SPB" Version="0.0.4-build28" />
<PackageReference Include="SharpZipLib" Version="1.4.1" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />