Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
d692a9b83e | ||
|
9677ddaa5d | ||
|
ce92e8cd04 | ||
|
456fc04007 | ||
|
458452279c | ||
|
817b89767a | ||
|
3fb583c98c | ||
|
d2686e0a5b | ||
|
4905101df1 | ||
|
8750b90a7f | ||
|
af01100050 | ||
|
c0821fee1f | ||
|
a5c2aead67 | ||
|
d41c95dcff | ||
|
fbf2b09706 | ||
|
1fc0f569de | ||
|
dff138229c | ||
|
472119c8da | ||
|
1865ea87e5 | ||
|
18b61aff59 | ||
|
cb22629ac1 | ||
|
6f0f99ee2b | ||
|
70f2da8fdf | ||
|
5d3ef7761b | ||
|
476b4683cf | ||
|
5fb5079730 |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: Bug Report
|
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:
|
#assignees:
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
## Compatibility
|
## 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!
|
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
|
## Usage
|
||||||
@@ -90,7 +90,7 @@ Ryujinx system files are stored in the `Ryujinx` folder. This folder is located
|
|||||||
|
|
||||||
- **GPU**
|
- **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**
|
- **Input**
|
||||||
|
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="OpenTK.OpenAL" Version="4.7.2" />
|
<PackageReference Include="OpenTK.OpenAL" Version="4.7.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Audio.Common;
|
using Ryujinx.Audio.Common;
|
||||||
using Ryujinx.Audio.Integration;
|
using Ryujinx.Audio.Integration;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using Ryujinx.SDL2.Common;
|
using Ryujinx.SDL2.Common;
|
||||||
using System;
|
using System;
|
||||||
@@ -112,6 +113,9 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
|
|
||||||
if (device == 0)
|
if (device == 0)
|
||||||
{
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application,
|
||||||
|
$"SDL2 open audio device initialization failed with error \"{SDL_GetError()}\"");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +123,7 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
|
|
||||||
if (!isValid)
|
if (!isValid)
|
||||||
{
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, "SDL2 open audio device is not valid");
|
||||||
SDL_CloseAudioDevice(device);
|
SDL_CloseAudioDevice(device);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Audio.Renderer.Dsp.State;
|
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@@ -71,6 +72,19 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
return (short)value;
|
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)]
|
[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)
|
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);
|
byte coefficientIndex = (byte)((predScale >> 4) & 0xF);
|
||||||
short history0 = loopContext.History0;
|
short history0 = loopContext.History0;
|
||||||
short history1 = loopContext.History1;
|
short history1 = loopContext.History1;
|
||||||
short coefficient0 = coefficients[coefficientIndex * 2 + 0];
|
short coefficient0 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 0);
|
||||||
short coefficient1 = coefficients[coefficientIndex * 2 + 1];
|
short coefficient1 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 1);
|
||||||
|
|
||||||
int decodedCount = Math.Min(count, endSampleOffset - startSampleOffset - offset);
|
int decodedCount = Math.Min(count, endSampleOffset - startSampleOffset - offset);
|
||||||
int nibbles = GetNibblesFromSampleCount(offset + startSampleOffset);
|
int nibbles = GetNibblesFromSampleCount(offset + startSampleOffset);
|
||||||
@@ -109,8 +123,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
|
|
||||||
coefficientIndex = (byte)((predScale >> 4) & 0xF);
|
coefficientIndex = (byte)((predScale >> 4) & 0xF);
|
||||||
|
|
||||||
coefficient0 = coefficients[coefficientIndex * 2 + 0];
|
coefficient0 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2);
|
||||||
coefficient1 = coefficients[coefficientIndex * 2 + 1];
|
coefficient1 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 1);
|
||||||
|
|
||||||
nibbles += 2;
|
nibbles += 2;
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.AdpcmDataSourceVersion1;
|
public CommandType CommandType => CommandType.AdpcmDataSourceVersion1;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
public uint SampleRate { get; }
|
public uint SampleRate { get; }
|
||||||
|
@@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.AuxiliaryBuffer;
|
public CommandType CommandType => CommandType.AuxiliaryBuffer;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint InputBufferIndex { get; }
|
public uint InputBufferIndex { get; }
|
||||||
public uint OutputBufferIndex { get; }
|
public uint OutputBufferIndex { get; }
|
||||||
|
@@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.BiquadFilter;
|
public CommandType CommandType => CommandType.BiquadFilter;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public Memory<BiquadFilterState> BiquadFilterState { get; }
|
public Memory<BiquadFilterState> BiquadFilterState { get; }
|
||||||
public int InputBufferIndex { get; }
|
public int InputBufferIndex { get; }
|
||||||
|
@@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.CaptureBuffer;
|
public CommandType CommandType => CommandType.CaptureBuffer;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint InputBufferIndex { get; }
|
public uint InputBufferIndex { get; }
|
||||||
|
|
||||||
|
@@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.CircularBufferSink;
|
public CommandType CommandType => CommandType.CircularBufferSink;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort[] Input { get; }
|
public ushort[] Input { get; }
|
||||||
public uint InputCount { get; }
|
public uint InputCount { get; }
|
||||||
|
@@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.ClearMixBuffer;
|
public CommandType CommandType => CommandType.ClearMixBuffer;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ClearMixBufferCommand(int nodeId)
|
public ClearMixBufferCommand(int nodeId)
|
||||||
{
|
{
|
||||||
|
@@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.CopyMixBuffer;
|
public CommandType CommandType => CommandType.CopyMixBuffer;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
@@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType { get; }
|
public CommandType CommandType { get; }
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
public uint SampleRate { get; }
|
public uint SampleRate { get; }
|
||||||
|
@@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.Delay;
|
public CommandType CommandType => CommandType.Delay;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public DelayParameter Parameter => _parameter;
|
public DelayParameter Parameter => _parameter;
|
||||||
public Memory<DelayState> State { get; }
|
public Memory<DelayState> State { get; }
|
||||||
@@ -49,15 +49,15 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
|
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices);
|
||||||
// TODO: Update delay processing and remove this to use RemapLegacyChannelEffectMappingToChannelResourceMapping.
|
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, OutputBufferIndices);
|
||||||
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, InputBufferIndices);
|
|
||||||
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, OutputBufferIndices);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
private unsafe void ProcessDelayMono(ref DelayState state, float* outputBuffer, float* inputBuffer, uint sampleCount)
|
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 feedbackGain = FixedPointHelper.ToFloat(Parameter.FeedbackGain, FixedPointPrecision);
|
||||||
float inGain = FixedPointHelper.ToFloat(Parameter.InGain, FixedPointPrecision);
|
float inGain = FixedPointHelper.ToFloat(Parameter.InGain, FixedPointPrecision);
|
||||||
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
|
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
|
||||||
@@ -70,7 +70,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
float temp = input * inGain + delayLineValue * feedbackGain;
|
float temp = input * inGain + delayLineValue * feedbackGain;
|
||||||
|
|
||||||
state.UpdateLowPassFilter(ref temp, 1);
|
state.UpdateLowPassFilter(ref temp, channelCount);
|
||||||
|
|
||||||
outputBuffer[i] = (input * dryGain + delayLineValue * outGain) / 64;
|
outputBuffer[i] = (input * dryGain + delayLineValue * outGain) / 64;
|
||||||
}
|
}
|
||||||
@@ -104,7 +104,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
Y = state.DelayLines[1].Read(),
|
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);
|
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()
|
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);
|
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 dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
|
||||||
float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision);
|
float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision);
|
||||||
|
|
||||||
Matrix6x6 delayFeedback = new Matrix6x6(delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain,
|
Matrix6x6 delayFeedback = new Matrix6x6(delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, 0.0f, delayFeedbackCrossGain, 0.0f,
|
||||||
0.0f, delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f,
|
0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain,
|
||||||
delayFeedbackCrossGain, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f,
|
delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f,
|
||||||
0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f,
|
0.0f, 0.0f, 0.0f, feedbackGain, 0.0f, 0.0f,
|
||||||
delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackBaseGain, 0.0f,
|
delayFeedbackCrossGain, 0.0f, 0.0f, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain,
|
||||||
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, feedbackGain);
|
0.0f, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackBaseGain);
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
@@ -200,7 +200,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
U = state.DelayLines[5].Read()
|
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);
|
state.UpdateLowPassFilter(ref Unsafe.As<Vector6, float>(ref temp), channelCount);
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.DepopForMixBuffers;
|
public CommandType CommandType => CommandType.DepopForMixBuffers;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint MixBufferOffset { get; }
|
public uint MixBufferOffset { get; }
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.DepopPrepare;
|
public CommandType CommandType => CommandType.DepopPrepare;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint MixBufferCount { get; }
|
public uint MixBufferCount { get; }
|
||||||
|
|
||||||
|
@@ -14,7 +14,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.DeviceSink;
|
public CommandType CommandType => CommandType.DeviceSink;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public string DeviceName { get; }
|
public string DeviceName { get; }
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.DownMixSurroundToStereo;
|
public CommandType CommandType => CommandType.DownMixSurroundToStereo;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort[] InputBufferIndices { get; }
|
public ushort[] InputBufferIndices { get; }
|
||||||
public ushort[] OutputBufferIndices { get; }
|
public ushort[] OutputBufferIndices { get; }
|
||||||
|
@@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.GroupedBiquadFilter;
|
public CommandType CommandType => CommandType.GroupedBiquadFilter;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
private BiquadFilterParameter[] _parameters;
|
private BiquadFilterParameter[] _parameters;
|
||||||
private Memory<BiquadFilterState> _biquadFilterStates;
|
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.
|
// 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.
|
// As such we currently only implement a generic path for simplicity for double biquad.
|
||||||
// TODO: Implement double biquad filters fast path.
|
|
||||||
if (_parameters.Length == 1)
|
if (_parameters.Length == 1)
|
||||||
{
|
{
|
||||||
BiquadFilterHelper.ProcessBiquadFilter(ref _parameters[0], ref states[0], outputBuffer, inputBuffer, context.SampleCount);
|
BiquadFilterHelper.ProcessBiquadFilter(ref _parameters[0], ref states[0], outputBuffer, inputBuffer, context.SampleCount);
|
||||||
|
@@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType { get; }
|
public CommandType CommandType { get; }
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; }
|
public uint EstimatedProcessingTime { get; }
|
||||||
|
|
||||||
public void Process(CommandList context);
|
public void Process(CommandList context);
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.LimiterVersion1;
|
public CommandType CommandType => CommandType.LimiterVersion1;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public LimiterParameter Parameter => _parameter;
|
public LimiterParameter Parameter => _parameter;
|
||||||
public Memory<LimiterState> State { get; }
|
public Memory<LimiterState> State { get; }
|
||||||
|
@@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.LimiterVersion2;
|
public CommandType CommandType => CommandType.LimiterVersion2;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public LimiterParameter Parameter => _parameter;
|
public LimiterParameter Parameter => _parameter;
|
||||||
public Memory<LimiterState> State { get; }
|
public Memory<LimiterState> State { get; }
|
||||||
|
@@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.Mix;
|
public CommandType CommandType => CommandType.Mix;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
@@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.MixRamp;
|
public CommandType CommandType => CommandType.MixRamp;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
@@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.MixRampGrouped;
|
public CommandType CommandType => CommandType.MixRampGrouped;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint MixBufferCount { get; }
|
public uint MixBufferCount { get; }
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.PcmFloatDataSourceVersion1;
|
public CommandType CommandType => CommandType.PcmFloatDataSourceVersion1;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
public uint SampleRate { get; }
|
public uint SampleRate { get; }
|
||||||
|
@@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.PcmInt16DataSourceVersion1;
|
public CommandType CommandType => CommandType.PcmInt16DataSourceVersion1;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
public uint SampleRate { get; }
|
public uint SampleRate { get; }
|
||||||
|
@@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.Performance;
|
public CommandType CommandType => CommandType.Performance;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public PerformanceEntryAddresses PerformanceEntryAddresses { get; }
|
public PerformanceEntryAddresses PerformanceEntryAddresses { get; }
|
||||||
|
|
||||||
|
@@ -31,7 +31,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.Reverb3d;
|
public CommandType CommandType => CommandType.Reverb3d;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
@@ -34,7 +34,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.Reverb;
|
public CommandType CommandType => CommandType.Reverb;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ReverbParameter Parameter => _parameter;
|
public ReverbParameter Parameter => _parameter;
|
||||||
public Memory<ReverbState> State { get; }
|
public Memory<ReverbState> State { get; }
|
||||||
|
@@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.Upsample;
|
public CommandType CommandType => CommandType.Upsample;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public uint BufferCount { get; }
|
public uint BufferCount { get; }
|
||||||
public uint InputBufferIndex { get; }
|
public uint InputBufferIndex { get; }
|
||||||
|
@@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.Volume;
|
public CommandType CommandType => CommandType.Volume;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
@@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public CommandType CommandType => CommandType.VolumeRamp;
|
public CommandType CommandType => CommandType.VolumeRamp;
|
||||||
|
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
public ushort InputBufferIndex { get; }
|
public ushort InputBufferIndex { get; }
|
||||||
public ushort OutputBufferIndex { get; }
|
public ushort OutputBufferIndex { get; }
|
||||||
|
@@ -28,6 +28,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
private object _lock = new object();
|
private object _lock = new object();
|
||||||
|
|
||||||
|
private AudioRendererRenderingDevice _renderingDevice;
|
||||||
private AudioRendererExecutionMode _executionMode;
|
private AudioRendererExecutionMode _executionMode;
|
||||||
private IWritableEvent _systemEvent;
|
private IWritableEvent _systemEvent;
|
||||||
private ManualResetEvent _terminationEvent;
|
private ManualResetEvent _terminationEvent;
|
||||||
@@ -63,6 +64,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
private uint _renderingTimeLimitPercent;
|
private uint _renderingTimeLimitPercent;
|
||||||
private bool _voiceDropEnabled;
|
private bool _voiceDropEnabled;
|
||||||
private uint _voiceDropCount;
|
private uint _voiceDropCount;
|
||||||
|
private float _voiceDropParameter;
|
||||||
private bool _isDspRunningBehind;
|
private bool _isDspRunningBehind;
|
||||||
|
|
||||||
private ICommandProcessingTimeEstimator _commandProcessingTimeEstimator;
|
private ICommandProcessingTimeEstimator _commandProcessingTimeEstimator;
|
||||||
@@ -95,6 +97,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
_totalElapsedTicksUpdating = 0;
|
_totalElapsedTicksUpdating = 0;
|
||||||
_sessionId = 0;
|
_sessionId = 0;
|
||||||
|
_voiceDropParameter = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode Initialize(
|
public ResultCode Initialize(
|
||||||
@@ -130,6 +133,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
_upsamplerCount = parameter.SinkCount + parameter.SubMixBufferCount;
|
_upsamplerCount = parameter.SinkCount + parameter.SubMixBufferCount;
|
||||||
_appletResourceId = appletResourceId;
|
_appletResourceId = appletResourceId;
|
||||||
_memoryPoolCount = parameter.EffectCount + parameter.VoiceCount * Constants.VoiceWaveBufferCount;
|
_memoryPoolCount = parameter.EffectCount + parameter.VoiceCount * Constants.VoiceWaveBufferCount;
|
||||||
|
_renderingDevice = parameter.RenderingDevice;
|
||||||
_executionMode = parameter.ExecutionMode;
|
_executionMode = parameter.ExecutionMode;
|
||||||
_sessionId = sessionId;
|
_sessionId = sessionId;
|
||||||
MemoryManager = memoryManager;
|
MemoryManager = memoryManager;
|
||||||
@@ -337,6 +341,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
_processHandle = processHandle;
|
_processHandle = processHandle;
|
||||||
_elapsedFrameCount = 0;
|
_elapsedFrameCount = 0;
|
||||||
|
_voiceDropParameter = 1.0f;
|
||||||
|
|
||||||
switch (_behaviourContext.GetCommandProcessingTimeEstimatorVersion())
|
switch (_behaviourContext.GetCommandProcessingTimeEstimatorVersion())
|
||||||
{
|
{
|
||||||
@@ -515,7 +520,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
return (ulong)(_manager.TickSource.ElapsedSeconds * Constants.TargetTimerFrequency);
|
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;
|
int i;
|
||||||
|
|
||||||
@@ -584,7 +589,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
command.Enabled = false;
|
command.Enabled = false;
|
||||||
|
|
||||||
voicesEstimatedTime -= (long)command.EstimatedProcessingTime;
|
voicesEstimatedTime -= (uint)(_voiceDropParameter * command.EstimatedProcessingTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -618,13 +623,13 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
_voiceContext.Sort();
|
_voiceContext.Sort();
|
||||||
commandGenerator.GenerateVoices();
|
commandGenerator.GenerateVoices();
|
||||||
|
|
||||||
long voicesEstimatedTime = (long)commandBuffer.EstimatedProcessingTime;
|
uint voicesEstimatedTime = (uint)(_voiceDropParameter * commandBuffer.EstimatedProcessingTime);
|
||||||
|
|
||||||
commandGenerator.GenerateSubMixes();
|
commandGenerator.GenerateSubMixes();
|
||||||
commandGenerator.GenerateFinalMixes();
|
commandGenerator.GenerateFinalMixes();
|
||||||
commandGenerator.GenerateSinks();
|
commandGenerator.GenerateSinks();
|
||||||
|
|
||||||
long totalEstimatedTime = (long)commandBuffer.EstimatedProcessingTime;
|
uint totalEstimatedTime = (uint)(_voiceDropParameter * commandBuffer.EstimatedProcessingTime);
|
||||||
|
|
||||||
if (_voiceDropEnabled)
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -94,8 +94,9 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
/// REV11:
|
/// REV11:
|
||||||
/// The "legacy" effects (Delay, Reverb and Reverb 3D) were updated to match the standard channel mapping used by the audio renderer.
|
/// 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 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>
|
/// </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;
|
public const int Revision11 = 11 << 24;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -25,7 +25,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The estimated total processing time.
|
/// The estimated total processing time.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ulong EstimatedProcessingTime { get; set; }
|
public uint EstimatedProcessingTime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The command list that is populated by the <see cref="CommandBuffer"/>.
|
/// The command list that is populated by the <see cref="CommandBuffer"/>.
|
||||||
|
@@ -263,12 +263,12 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
|
|||||||
return UpdateResult.Success;
|
return UpdateResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress & (pageSize - 1)) != 0)
|
if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress % pageSize) != 0)
|
||||||
{
|
{
|
||||||
return UpdateResult.InvalidParameter;
|
return UpdateResult.InvalidParameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inParameter.Size == 0 || (inParameter.Size & (pageSize - 1)) != 0)
|
if (inParameter.Size == 0 || (inParameter.Size % pageSize) != 0)
|
||||||
{
|
{
|
||||||
return UpdateResult.InvalidParameter;
|
return UpdateResult.InvalidParameter;
|
||||||
}
|
}
|
||||||
|
@@ -17,5 +17,6 @@ namespace Ryujinx.Audio
|
|||||||
InvalidAddressInfo = (42 << ErrorCodeShift) | ModuleId,
|
InvalidAddressInfo = (42 << ErrorCodeShift) | ModuleId,
|
||||||
InvalidMixSorting = (43 << ErrorCodeShift) | ModuleId,
|
InvalidMixSorting = (43 << ErrorCodeShift) | ModuleId,
|
||||||
UnsupportedOperation = (513 << ErrorCodeShift) | ModuleId,
|
UnsupportedOperation = (513 << ErrorCodeShift) | ModuleId,
|
||||||
|
InvalidExecutionContextOperation = (514 << ErrorCodeShift) | ModuleId,
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -564,10 +564,10 @@
|
|||||||
"Writable": "Writable",
|
"Writable": "Writable",
|
||||||
"SelectDlcDialogTitle": "Select DLC files",
|
"SelectDlcDialogTitle": "Select DLC files",
|
||||||
"SelectUpdateDialogTitle": "Select update files",
|
"SelectUpdateDialogTitle": "Select update files",
|
||||||
"UserProfileWindowTitle": "Manage User Profiles",
|
"UserProfileWindowTitle": "User Profiles Manager",
|
||||||
"CheatWindowTitle": "Manage Game Cheats",
|
"CheatWindowTitle": "Cheats Manager",
|
||||||
"DlcWindowTitle": "Manage Game DLC",
|
"DlcWindowTitle": "Downloadable Content Manager",
|
||||||
"UpdateWindowTitle": "Manage Game Updates",
|
"UpdateWindowTitle": "Title Update Manager",
|
||||||
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
|
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
|
||||||
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
|
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
|
||||||
"UserProfilesEditProfile": "Edit Selected",
|
"UserProfilesEditProfile": "Edit Selected",
|
||||||
@@ -577,7 +577,7 @@
|
|||||||
"UserProfilesSetProfileImage": "Set Profile Image",
|
"UserProfilesSetProfileImage": "Set Profile Image",
|
||||||
"UserProfileEmptyNameError": "Name is required",
|
"UserProfileEmptyNameError": "Name is required",
|
||||||
"UserProfileNoImageError": "Profile image must be set",
|
"UserProfileNoImageError": "Profile image must be set",
|
||||||
"GameUpdateWindowHeading": "Updates Available for {0} [{1}]",
|
"GameUpdateWindowHeading": "{0} Update(s) available for {1} ({2})",
|
||||||
"SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
|
"SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
|
||||||
"SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
|
"SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
|
||||||
"UserProfilesName": "Name:",
|
"UserProfilesName": "Name:",
|
||||||
|
@@ -1,8 +1,5 @@
|
|||||||
using ARMeilleure.Translation.PTC;
|
using ARMeilleure.Translation.PTC;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Rendering;
|
|
||||||
using Avalonia.Threading;
|
|
||||||
using Ryujinx.Ava.Ui.Controls;
|
|
||||||
using Ryujinx.Ava.Ui.Windows;
|
using Ryujinx.Ava.Ui.Windows;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
@@ -23,18 +20,15 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
public static double WindowScaleFactor { get; set; }
|
public static double WindowScaleFactor { get; set; }
|
||||||
public static double ActualScaleFactor { get; set; }
|
public static string Version { get; private set; }
|
||||||
public static string Version { get; private set; }
|
public static string ConfigurationPath { get; private set; }
|
||||||
public static string ConfigurationPath { get; private set; }
|
public static bool PreviewerDetached { get; private set; }
|
||||||
public static bool PreviewerDetached { get; private set; }
|
|
||||||
public static RenderTimer RenderTimer { get; private set; }
|
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern int MessageBoxA(IntPtr hWnd, string text, string caption, uint type);
|
public static extern int MessageBoxA(IntPtr hWnd, string text, string caption, uint type);
|
||||||
|
|
||||||
private const uint MB_ICONWARNING = 0x30;
|
private const uint MB_ICONWARNING = 0x30;
|
||||||
private const int BaseDpi = 96;
|
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
@@ -49,11 +43,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
Initialize(args);
|
Initialize(args);
|
||||||
|
|
||||||
RenderTimer = new RenderTimer();
|
|
||||||
|
|
||||||
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
||||||
|
|
||||||
RenderTimer.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AppBuilder BuildAvaloniaApp()
|
public static AppBuilder BuildAvaloniaApp()
|
||||||
@@ -65,7 +55,7 @@ namespace Ryujinx.Ava
|
|||||||
EnableMultiTouch = true,
|
EnableMultiTouch = true,
|
||||||
EnableIme = true,
|
EnableIme = true,
|
||||||
UseEGL = false,
|
UseEGL = false,
|
||||||
UseGpu = false
|
UseGpu = true
|
||||||
})
|
})
|
||||||
.With(new Win32PlatformOptions
|
.With(new Win32PlatformOptions
|
||||||
{
|
{
|
||||||
@@ -75,12 +65,6 @@ namespace Ryujinx.Ava
|
|||||||
CompositionBackdropCornerRadius = 8.0f,
|
CompositionBackdropCornerRadius = 8.0f,
|
||||||
})
|
})
|
||||||
.UseSkia()
|
.UseSkia()
|
||||||
.AfterSetup(_ =>
|
|
||||||
{
|
|
||||||
AvaloniaLocator.CurrentMutable
|
|
||||||
.Bind<IRenderTimer>().ToConstant(RenderTimer)
|
|
||||||
.Bind<IRenderLoop>().ToConstant(new RenderLoop(RenderTimer, Dispatcher.UIThread));
|
|
||||||
})
|
|
||||||
.LogToTrace();
|
.LogToTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +99,6 @@ namespace Ryujinx.Ava
|
|||||||
ForceDpiAware.Windows();
|
ForceDpiAware.Windows();
|
||||||
|
|
||||||
WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor();
|
WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor();
|
||||||
ActualScaleFactor = ForceDpiAware.GetActualScaleFactor() / BaseDpi;
|
|
||||||
|
|
||||||
// Logging system information.
|
// Logging system information.
|
||||||
PrintSystemInfo();
|
PrintSystemInfo();
|
||||||
|
@@ -19,23 +19,23 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia" Version="0.10.18" />
|
<PackageReference Include="Avalonia" Version="0.10.18" />
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="0.10.15" />
|
<PackageReference Include="Avalonia.Desktop" Version="0.10.18" />
|
||||||
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.15" />
|
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.18" />
|
||||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.15" />
|
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.18" />
|
||||||
<PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="0.10.15" />
|
<PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="0.10.18" />
|
||||||
<PackageReference Include="Avalonia.Svg" Version="0.10.14" />
|
<PackageReference Include="Avalonia.Svg" Version="0.10.18" />
|
||||||
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.14" />
|
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
||||||
<PackageReference Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
|
<PackageReference Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
|
||||||
<PackageReference Include="DynamicData" Version="7.9.4" />
|
<PackageReference Include="DynamicData" Version="7.12.8" />
|
||||||
<PackageReference Include="FluentAvaloniaUI" Version="1.4.1" />
|
<PackageReference Include="FluentAvaloniaUI" Version="1.4.5" />
|
||||||
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />
|
<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.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="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" />
|
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.10.1" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.10.1" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
|
||||||
<PackageReference Include="SPB" Version="0.0.4-build28" />
|
<PackageReference Include="SPB" Version="0.0.4-build28" />
|
||||||
<PackageReference Include="SharpZipLib" Version="1.4.1" />
|
<PackageReference Include="SharpZipLib" Version="1.4.1" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||||
|
@@ -127,9 +127,16 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
contentDialog.PrimaryButtonClick += deferCloseAction;
|
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)
|
if (useOverlay)
|
||||||
@@ -391,4 +398,4 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -6,8 +6,8 @@ using SPB.Graphics;
|
|||||||
using SPB.Platform;
|
using SPB.Platform;
|
||||||
using SPB.Platform.GLX;
|
using SPB.Platform.GLX;
|
||||||
using SPB.Platform.X11;
|
using SPB.Platform.X11;
|
||||||
|
using SPB.Windowing;
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -15,12 +15,12 @@ using static Ryujinx.Ava.Ui.Controls.Win32NativeInterop;
|
|||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Controls
|
namespace Ryujinx.Ava.Ui.Controls
|
||||||
{
|
{
|
||||||
public unsafe class EmbeddedWindow : NativeControlHost
|
public class EmbeddedWindow : NativeControlHost
|
||||||
{
|
{
|
||||||
private WindowProc _wndProcDelegate;
|
private WindowProc _wndProcDelegate;
|
||||||
private string _className;
|
private string _className;
|
||||||
|
|
||||||
protected GLXWindow X11Window { get; private set; }
|
protected GLXWindow X11Window { get; set; }
|
||||||
protected IntPtr WindowHandle { get; set; }
|
protected IntPtr WindowHandle { get; set; }
|
||||||
protected IntPtr X11Display { get; set; }
|
protected IntPtr X11Display { get; set; }
|
||||||
|
|
||||||
@@ -94,19 +94,17 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("linux")]
|
[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;
|
WindowHandle = X11Window.WindowHandle.RawHandle;
|
||||||
|
X11Display = X11Window.DisplayHandle.RawHandle;
|
||||||
X11Display = X11Window.DisplayHandle.RawHandle;
|
|
||||||
|
|
||||||
return new PlatformHandle(WindowHandle, "X11");
|
return new PlatformHandle(WindowHandle, "X11");
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
unsafe IPlatformHandle CreateWin32(IPlatformHandle parent)
|
IPlatformHandle CreateWin32(IPlatformHandle parent)
|
||||||
{
|
{
|
||||||
_className = "NativeWindow-" + Guid.NewGuid();
|
_className = "NativeWindow-" + Guid.NewGuid();
|
||||||
_wndProcDelegate = WndProc;
|
_wndProcDelegate = WndProc;
|
||||||
@@ -142,7 +140,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[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 point = new Point((long)lParam & 0xFFFF, ((long)lParam >> 16) & 0xFFFF);
|
||||||
var root = VisualRoot as Window;
|
var root = VisualRoot as Window;
|
||||||
|
@@ -1,100 +0,0 @@
|
|||||||
using Avalonia.Rendering;
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Timers;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Controls
|
|
||||||
{
|
|
||||||
internal class RenderTimer : IRenderTimer, IDisposable
|
|
||||||
{
|
|
||||||
public event Action<TimeSpan> Tick
|
|
||||||
{
|
|
||||||
add
|
|
||||||
{
|
|
||||||
_tick += value;
|
|
||||||
|
|
||||||
if (_subscriberCount++ == 0)
|
|
||||||
{
|
|
||||||
Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
remove
|
|
||||||
{
|
|
||||||
if (--_subscriberCount == 0)
|
|
||||||
{
|
|
||||||
Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
_tick -= value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Thread _tickThread;
|
|
||||||
private readonly System.Timers.Timer _timer;
|
|
||||||
|
|
||||||
private Action<TimeSpan> _tick;
|
|
||||||
private int _subscriberCount;
|
|
||||||
|
|
||||||
private bool _isRunning;
|
|
||||||
|
|
||||||
private AutoResetEvent _resetEvent;
|
|
||||||
|
|
||||||
public RenderTimer()
|
|
||||||
{
|
|
||||||
_timer = new System.Timers.Timer(15);
|
|
||||||
_resetEvent = new AutoResetEvent(true);
|
|
||||||
_timer.Elapsed += Timer_Elapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
|
|
||||||
{
|
|
||||||
TickNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Start()
|
|
||||||
{
|
|
||||||
_timer.Start();
|
|
||||||
if (_tickThread == null)
|
|
||||||
{
|
|
||||||
_tickThread = new Thread(RunTick);
|
|
||||||
_tickThread.Name = "RenderTimerTickThread";
|
|
||||||
_tickThread.IsBackground = true;
|
|
||||||
_isRunning = true;
|
|
||||||
_tickThread.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RunTick()
|
|
||||||
{
|
|
||||||
while (_isRunning)
|
|
||||||
{
|
|
||||||
_resetEvent.WaitOne();
|
|
||||||
_tick?.Invoke(TimeSpan.FromMilliseconds(Environment.TickCount));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void TickNow()
|
|
||||||
{
|
|
||||||
lock (_timer)
|
|
||||||
{
|
|
||||||
_resetEvent.Set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Stop()
|
|
||||||
{
|
|
||||||
_timer.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_timer.Elapsed -= Timer_Elapsed;
|
|
||||||
_timer.Stop();
|
|
||||||
_isRunning = false;
|
|
||||||
_resetEvent.Set();
|
|
||||||
_tickThread.Join();
|
|
||||||
_resetEvent.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -4,11 +4,4 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Ryujinx.Ava.Ui.Controls.RendererHost">
|
x:Class="Ryujinx.Ava.Ui.Controls.RendererHost">
|
||||||
<ContentControl
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
HorizontalContentAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
VerticalContentAlignment="Stretch"
|
|
||||||
Name="View"
|
|
||||||
/>
|
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
@@ -41,7 +41,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
|||||||
{
|
{
|
||||||
_currentWindow.WindowCreated += CurrentWindow_WindowCreated;
|
_currentWindow.WindowCreated += CurrentWindow_WindowCreated;
|
||||||
_currentWindow.SizeChanged += CurrentWindow_SizeChanged;
|
_currentWindow.SizeChanged += CurrentWindow_SizeChanged;
|
||||||
View.Content = _currentWindow;
|
Content = _currentWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateVulkan()
|
public void CreateVulkan()
|
||||||
|
@@ -1,10 +1,13 @@
|
|||||||
|
using Avalonia.Platform;
|
||||||
using Ryujinx.Ava.Ui.Controls;
|
using Ryujinx.Ava.Ui.Controls;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using SPB.Graphics.Vulkan;
|
using SPB.Graphics.Vulkan;
|
||||||
|
using SPB.Platform.GLX;
|
||||||
using SPB.Platform.Win32;
|
using SPB.Platform.Win32;
|
||||||
using SPB.Platform.X11;
|
using SPB.Platform.X11;
|
||||||
using SPB.Windowing;
|
using SPB.Windowing;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui
|
namespace Ryujinx.Ava.Ui
|
||||||
{
|
{
|
||||||
@@ -12,6 +15,18 @@ namespace Ryujinx.Ava.Ui
|
|||||||
{
|
{
|
||||||
private NativeWindowBase _window;
|
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)
|
public SurfaceKHR CreateSurface(Instance instance)
|
||||||
{
|
{
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
@@ -20,7 +35,7 @@ namespace Ryujinx.Ava.Ui
|
|||||||
}
|
}
|
||||||
else if (OperatingSystem.IsLinux())
|
else if (OperatingSystem.IsLinux())
|
||||||
{
|
{
|
||||||
_window = X11Window;
|
_window = new SimpleX11Window(new NativeHandle(X11Display), new NativeHandle(WindowHandle));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -1283,7 +1283,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||||||
ApplicationData selection = SelectedApplication;
|
ApplicationData selection = SelectedApplication;
|
||||||
if (selection != null)
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,8 +8,10 @@
|
|||||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||||
Width="800"
|
Width="800"
|
||||||
Height="500"
|
Height="500"
|
||||||
MinWidth="600"
|
MinWidth="800"
|
||||||
MinHeight="500"
|
MinHeight="500"
|
||||||
|
MaxWidth="800"
|
||||||
|
MaxHeight="500"
|
||||||
SizeToContent="Height"
|
SizeToContent="Height"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
@@ -8,7 +8,6 @@ using LibHac.FsSystem;
|
|||||||
using LibHac.Tools.Fs;
|
using LibHac.Tools.Fs;
|
||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using LibHac.Tools.FsSystem.Save;
|
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.Ui.Controls;
|
using Ryujinx.Ava.Ui.Controls;
|
||||||
using Ryujinx.Ava.Ui.Models;
|
using Ryujinx.Ava.Ui.Models;
|
||||||
@@ -17,8 +16,6 @@ using Ryujinx.Common.Utilities;
|
|||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
@@ -36,8 +33,8 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
private VirtualFileSystem _virtualFileSystem { get; }
|
private VirtualFileSystem _virtualFileSystem { get; }
|
||||||
private AvaloniaList<DownloadableContentModel> _downloadableContents { get; set; }
|
private AvaloniaList<DownloadableContentModel> _downloadableContents { get; set; }
|
||||||
|
|
||||||
private ulong TitleId { get; }
|
private ulong _titleId { get; }
|
||||||
private string TitleName { get; }
|
private string _titleName { get; }
|
||||||
|
|
||||||
public DownloadableContentManagerWindow()
|
public DownloadableContentManagerWindow()
|
||||||
{
|
{
|
||||||
@@ -45,15 +42,16 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
|
|
||||||
InitializeComponent();
|
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)
|
public DownloadableContentManagerWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
|
||||||
{
|
{
|
||||||
_virtualFileSystem = virtualFileSystem;
|
_virtualFileSystem = virtualFileSystem;
|
||||||
_downloadableContents = new AvaloniaList<DownloadableContentModel>();
|
_downloadableContents = new AvaloniaList<DownloadableContentModel>();
|
||||||
TitleId = titleId;
|
|
||||||
TitleName = titleName;
|
_titleId = titleId;
|
||||||
|
_titleName = titleName;
|
||||||
|
|
||||||
_downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "dlc.json");
|
_downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "dlc.json");
|
||||||
|
|
||||||
@@ -74,7 +72,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
|
|
||||||
DlcDataGrid.SelectionChanged += DlcDataGrid_SelectionChanged;
|
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();
|
LoadDownloadableContents();
|
||||||
PrintHeading();
|
PrintHeading();
|
||||||
@@ -87,7 +85,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
|
|
||||||
private void PrintHeading()
|
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()
|
private void LoadDownloadableContents()
|
||||||
@@ -98,15 +96,15 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
{
|
{
|
||||||
using FileStream containerFile = File.OpenRead(downloadableContentContainer.ContainerPath);
|
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)
|
foreach (DownloadableContentNca downloadableContentNca in downloadableContentContainer.DownloadableContentNcaList)
|
||||||
{
|
{
|
||||||
using UniqueRef<IFile> ncaFile = new();
|
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);
|
Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), downloadableContentContainer.ContainerPath);
|
||||||
if (nca != null)
|
if (nca != null)
|
||||||
@@ -169,7 +167,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
|
|
||||||
if (nca.Header.ContentType == NcaContentType.PublicData)
|
if (nca.Header.ContentType == NcaContentType.PublicData)
|
||||||
{
|
{
|
||||||
if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000) != TitleId)
|
if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000) != _titleId)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
Title="Ryujinx"
|
Title="Ryujinx"
|
||||||
Width="1280"
|
Width="1280"
|
||||||
Height="785"
|
Height="785"
|
||||||
MinWidth="1024"
|
MinWidth="1092"
|
||||||
MinHeight="680"
|
MinHeight="680"
|
||||||
d:DesignHeight="720"
|
d:DesignHeight="720"
|
||||||
d:DesignWidth="1280"
|
d:DesignWidth="1280"
|
||||||
@@ -57,6 +57,8 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
Name="MenuBar"
|
||||||
|
MinHeight="35"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Margin="0"
|
Margin="0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
@@ -549,6 +551,7 @@
|
|||||||
<Grid
|
<Grid
|
||||||
Name="StatusBar"
|
Name="StatusBar"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
|
MinHeight="30"
|
||||||
Height="30"
|
Height="30"
|
||||||
Margin="0,0"
|
Margin="0,0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
@@ -90,7 +90,9 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
|
|
||||||
Title = $"Ryujinx {Program.Version}";
|
Title = $"Ryujinx {Program.Version}";
|
||||||
|
|
||||||
Height /= Program.WindowScaleFactor;
|
// NOTE: Height of MenuBar and StatusBar is not usable here, since it would still be 0 at this point.
|
||||||
|
double barHeight = MenuBar.MinHeight + StatusBar.MinHeight;
|
||||||
|
Height = ((Height - barHeight) / Program.WindowScaleFactor) + barHeight;
|
||||||
Width /= Program.WindowScaleFactor;
|
Width /= Program.WindowScaleFactor;
|
||||||
|
|
||||||
if (Program.PreviewerDetached)
|
if (Program.PreviewerDetached)
|
||||||
|
@@ -3,13 +3,17 @@
|
|||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
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:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||||
SizeToContent="Height"
|
Width="600"
|
||||||
Width="600" MinHeight="500" Height="500"
|
Height="400"
|
||||||
WindowStartupLocation="CenterOwner"
|
|
||||||
MinWidth="600"
|
MinWidth="600"
|
||||||
|
MinHeight="400"
|
||||||
|
MaxWidth="600"
|
||||||
|
MaxHeight="400"
|
||||||
|
SizeToContent="Height"
|
||||||
|
WindowStartupLocation="CenterOwner"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Grid Margin="15">
|
<Grid Margin="15">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
@@ -19,15 +23,15 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
Name="Heading"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
MaxWidth="500"
|
||||||
Margin="20,15,20,20"
|
Margin="20,15,20,20"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
MaxWidth="500"
|
|
||||||
LineHeight="18"
|
LineHeight="18"
|
||||||
TextWrapping="Wrap"
|
TextAlignment="Center"
|
||||||
Text="{Binding Heading}"
|
TextWrapping="Wrap" />
|
||||||
TextAlignment="Center" />
|
|
||||||
<Border
|
<Border
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Margin="5"
|
Margin="5"
|
||||||
@@ -36,8 +40,6 @@
|
|||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1">
|
BorderThickness="1">
|
||||||
<ScrollViewer
|
<ScrollViewer
|
||||||
Width="550"
|
|
||||||
MinHeight="200"
|
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
HorizontalScrollBarVisibility="Auto"
|
HorizontalScrollBarVisibility="Auto"
|
||||||
VerticalScrollBarVisibility="Auto">
|
VerticalScrollBarVisibility="Auto">
|
||||||
@@ -45,11 +47,19 @@
|
|||||||
Margin="10"
|
Margin="10"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
Items="{Binding TitleUpdates}">
|
Items="{Binding _titleUpdates}">
|
||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<RadioButton Padding="8, 0" VerticalContentAlignment="Center" GroupName="Update" IsChecked="{Binding IsEnabled, Mode=TwoWay}">
|
<RadioButton
|
||||||
<Label Margin="0" VerticalAlignment="Center" Content="{Binding Label}" />
|
Padding="8,0"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
GroupName="Update"
|
||||||
|
IsChecked="{Binding IsEnabled, Mode=TwoWay}">
|
||||||
|
<Label
|
||||||
|
Margin="0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Content="{Binding Label}"
|
||||||
|
FontSize="12" />
|
||||||
</RadioButton>
|
</RadioButton>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
|
@@ -30,13 +30,11 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
private readonly string _titleUpdateJsonPath;
|
private readonly string _titleUpdateJsonPath;
|
||||||
private TitleUpdateMetadata _titleUpdateWindowData;
|
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>();
|
private ulong _titleId { get; }
|
||||||
public string TitleId { get; }
|
private string _titleName { get; }
|
||||||
public string TitleName { get; }
|
|
||||||
|
|
||||||
public string Heading => string.Format(LocaleManager.Instance["GameUpdateWindowHeading"], TitleName, TitleId.ToUpper());
|
|
||||||
|
|
||||||
public TitleUpdateWindow()
|
public TitleUpdateWindow()
|
||||||
{
|
{
|
||||||
@@ -44,16 +42,18 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
|
|
||||||
InitializeComponent();
|
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;
|
_virtualFileSystem = virtualFileSystem;
|
||||||
TitleId = titleId;
|
_titleUpdates = new AvaloniaList<TitleUpdateModel>();
|
||||||
TitleName = titleName;
|
|
||||||
|
|
||||||
_titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId, "updates.json");
|
_titleId = titleId;
|
||||||
|
_titleName = titleName;
|
||||||
|
|
||||||
|
_titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -64,7 +64,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
_titleUpdateWindowData = new TitleUpdateMetadata
|
_titleUpdateWindowData = new TitleUpdateMetadata
|
||||||
{
|
{
|
||||||
Selected = "",
|
Selected = "",
|
||||||
Paths = new List<string>()
|
Paths = new List<string>()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,14 +72,20 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["UpdateWindowTitle"];
|
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["UpdateWindowTitle"]} - {_titleName} ({_titleId:X16})";
|
||||||
|
|
||||||
LoadUpdates();
|
LoadUpdates();
|
||||||
|
PrintHeading();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintHeading()
|
||||||
|
{
|
||||||
|
Heading.Text = string.Format(LocaleManager.Instance["GameUpdateWindowHeading"], _titleUpdates.Count, _titleName, _titleId.ToString("X16"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadUpdates()
|
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)
|
foreach (string path in _titleUpdateWindowData.Paths)
|
||||||
{
|
{
|
||||||
@@ -88,12 +94,12 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
|
|
||||||
if (_titleUpdateWindowData.Selected == "")
|
if (_titleUpdateWindowData.Selected == "")
|
||||||
{
|
{
|
||||||
TitleUpdates[0].IsEnabled = true;
|
_titleUpdates[0].IsEnabled = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TitleUpdateModel selected = TitleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected);
|
TitleUpdateModel selected = _titleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected);
|
||||||
List<TitleUpdateModel> enabled = TitleUpdates.Where(x => x.IsEnabled).ToList();
|
List<TitleUpdateModel> enabled = _titleUpdates.Where(x => x.IsEnabled).ToList();
|
||||||
|
|
||||||
foreach (TitleUpdateModel update in enabled)
|
foreach (TitleUpdateModel update in enabled)
|
||||||
{
|
{
|
||||||
@@ -111,50 +117,47 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
|
|
||||||
private void AddUpdate(string path)
|
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();
|
update.IsEnabled = false;
|
||||||
|
|
||||||
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"]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_titleUpdates.Last().IsEnabled = true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
else
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(async () =>
|
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)
|
if (removeSelectedOnly)
|
||||||
{
|
{
|
||||||
TitleUpdates.RemoveAll(TitleUpdates.Where(x => x.IsEnabled && !x.IsNoUpdate).ToList());
|
_titleUpdates.RemoveAll(_titleUpdates.Where(x => x.IsEnabled && !x.IsNoUpdate).ToList());
|
||||||
}
|
}
|
||||||
else
|
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();
|
SortUpdates();
|
||||||
|
PrintHeading();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveSelected()
|
public void RemoveSelected()
|
||||||
@@ -186,7 +190,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
|
|
||||||
public async void Add()
|
public async void Add()
|
||||||
{
|
{
|
||||||
OpenFileDialog dialog = new OpenFileDialog()
|
OpenFileDialog dialog = new()
|
||||||
{
|
{
|
||||||
Title = LocaleManager.Instance["SelectUpdateDialogTitle"],
|
Title = LocaleManager.Instance["SelectUpdateDialogTitle"],
|
||||||
AllowMultiple = true
|
AllowMultiple = true
|
||||||
@@ -209,11 +213,12 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
}
|
}
|
||||||
|
|
||||||
SortUpdates();
|
SortUpdates();
|
||||||
|
PrintHeading();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SortUpdates()
|
private void SortUpdates()
|
||||||
{
|
{
|
||||||
var list = TitleUpdates.ToList();
|
var list = _titleUpdates.ToList();
|
||||||
|
|
||||||
list.Sort((first, second) =>
|
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;
|
return Version.Parse(first.Control.DisplayVersionString.ToString()).CompareTo(Version.Parse(second.Control.DisplayVersionString.ToString())) * -1;
|
||||||
});
|
});
|
||||||
|
|
||||||
TitleUpdates.Clear();
|
_titleUpdates.Clear();
|
||||||
TitleUpdates.AddRange(list);
|
_titleUpdates.AddRange(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save()
|
public void Save()
|
||||||
@@ -239,7 +244,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
|||||||
|
|
||||||
_titleUpdateWindowData.Selected = "";
|
_titleUpdateWindowData.Selected = "";
|
||||||
|
|
||||||
foreach (TitleUpdateModel update in TitleUpdates)
|
foreach (TitleUpdateModel update in _titleUpdates)
|
||||||
{
|
{
|
||||||
_titleUpdateWindowData.Paths.Add(update.Path);
|
_titleUpdateWindowData.Paths.Add(update.Path);
|
||||||
|
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MsgPack.Cli" Version="1.0.1" />
|
<PackageReference Include="MsgPack.Cli" Version="1.0.1" />
|
||||||
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
|
<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>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -29,6 +29,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
ReadOnlySpan<byte> GetBufferData(BufferHandle buffer, int offset, int size);
|
ReadOnlySpan<byte> GetBufferData(BufferHandle buffer, int offset, int size);
|
||||||
|
|
||||||
Capabilities GetCapabilities();
|
Capabilities GetCapabilities();
|
||||||
|
ulong GetCurrentSync();
|
||||||
HardwareInfo GetHardwareInfo();
|
HardwareInfo GetHardwareInfo();
|
||||||
|
|
||||||
IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info);
|
IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info);
|
||||||
|
@@ -338,6 +338,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
return box.Result;
|
return box.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ulong GetCurrentSync()
|
||||||
|
{
|
||||||
|
return _baseRenderer.GetCurrentSync();
|
||||||
|
}
|
||||||
|
|
||||||
public HardwareInfo GetHardwareInfo()
|
public HardwareInfo GetHardwareInfo()
|
||||||
{
|
{
|
||||||
return _baseRenderer.GetHardwareInfo();
|
return _baseRenderer.GetHardwareInfo();
|
||||||
|
@@ -37,6 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
private bool _vsUsesDrawParameters;
|
private bool _vsUsesDrawParameters;
|
||||||
private bool _vtgWritesRtLayer;
|
private bool _vtgWritesRtLayer;
|
||||||
private byte _vsClipDistancesWritten;
|
private byte _vsClipDistancesWritten;
|
||||||
|
private uint _vbEnableMask;
|
||||||
|
|
||||||
private bool _prevDrawIndexed;
|
private bool _prevDrawIndexed;
|
||||||
private bool _prevDrawIndirect;
|
private bool _prevDrawIndirect;
|
||||||
@@ -76,6 +77,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
nameof(ThreedClassState.VertexBufferState),
|
nameof(ThreedClassState.VertexBufferState),
|
||||||
nameof(ThreedClassState.VertexBufferEndAddress)),
|
nameof(ThreedClassState.VertexBufferEndAddress)),
|
||||||
|
|
||||||
|
// Must be done after vertex buffer updates.
|
||||||
new StateUpdateCallbackEntry(UpdateVertexAttribState, nameof(ThreedClassState.VertexAttribState)),
|
new StateUpdateCallbackEntry(UpdateVertexAttribState, nameof(ThreedClassState.VertexAttribState)),
|
||||||
|
|
||||||
new StateUpdateCallbackEntry(UpdateBlendState,
|
new StateUpdateCallbackEntry(UpdateBlendState,
|
||||||
@@ -852,12 +854,23 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateVertexAttribState()
|
private void UpdateVertexAttribState()
|
||||||
{
|
{
|
||||||
|
uint vbEnableMask = _vbEnableMask;
|
||||||
|
|
||||||
Span<VertexAttribDescriptor> vertexAttribs = stackalloc VertexAttribDescriptor[Constants.TotalVertexAttribs];
|
Span<VertexAttribDescriptor> vertexAttribs = stackalloc VertexAttribDescriptor[Constants.TotalVertexAttribs];
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalVertexAttribs; index++)
|
for (int index = 0; index < Constants.TotalVertexAttribs; index++)
|
||||||
{
|
{
|
||||||
var vertexAttrib = _state.State.VertexAttribState[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))
|
if (!FormatTable.TryGetAttribFormat(vertexAttrib.UnpackFormat(), out Format format))
|
||||||
{
|
{
|
||||||
Logger.Debug?.Print(LogClass.Gpu, $"Invalid attribute format 0x{vertexAttrib.UnpackFormat():X}.");
|
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(
|
vertexAttribs[index] = new VertexAttribDescriptor(
|
||||||
vertexAttrib.UnpackBufferIndex(),
|
bufferIndex,
|
||||||
vertexAttrib.UnpackOffset(),
|
vertexAttrib.UnpackOffset(),
|
||||||
vertexAttrib.UnpackIsConstant(),
|
vertexAttrib.UnpackIsConstant(),
|
||||||
format);
|
format);
|
||||||
@@ -954,6 +967,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
bool drawIndexed = _drawState.DrawIndexed;
|
bool drawIndexed = _drawState.DrawIndexed;
|
||||||
bool drawIndirect = _drawState.DrawIndirect;
|
bool drawIndirect = _drawState.DrawIndirect;
|
||||||
|
uint vbEnableMask = 0;
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalVertexBuffers; index++)
|
for (int index = 0; index < Constants.TotalVertexBuffers; index++)
|
||||||
{
|
{
|
||||||
@@ -971,6 +985,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
ulong address = vertexBuffer.Address.Pack();
|
ulong address = vertexBuffer.Address.Pack();
|
||||||
|
|
||||||
|
if (_channel.MemoryManager.IsMapped(address))
|
||||||
|
{
|
||||||
|
vbEnableMask |= 1u << index;
|
||||||
|
}
|
||||||
|
|
||||||
int stride = vertexBuffer.UnpackStride();
|
int stride = vertexBuffer.UnpackStride();
|
||||||
|
|
||||||
bool instanced = _state.State.VertexBufferInstanced[index];
|
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);
|
_pipeline.VertexBuffers[index] = new BufferPipelineDescriptor(_channel.MemoryManager.IsMapped(address), stride, divisor);
|
||||||
_channel.BufferManager.SetVertexBuffer(index, address, size, stride, divisor);
|
_channel.BufferManager.SetVertexBuffer(index, address, size, stride, divisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_vbEnableMask != vbEnableMask)
|
||||||
|
{
|
||||||
|
_vbEnableMask = vbEnableMask;
|
||||||
|
UpdateVertexAttribState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -69,6 +69,12 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal List<Action> SyncpointActions { get; }
|
internal List<Action> SyncpointActions { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Buffer migrations that are currently in-flight. These are checked whenever sync is created to determine if buffer migration
|
||||||
|
/// copies have completed on the GPU, and their data can be freed.
|
||||||
|
/// </summary>
|
||||||
|
internal List<BufferMigration> BufferMigrations { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queue with deferred actions that must run on the render thread.
|
/// Queue with deferred actions that must run on the render thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -90,6 +96,7 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
public event Action<ShaderCacheState, int, int> ShaderCacheStateChanged;
|
public event Action<ShaderCacheState, int, int> ShaderCacheStateChanged;
|
||||||
|
|
||||||
private Thread _gpuThread;
|
private Thread _gpuThread;
|
||||||
|
private bool _pendingSync;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the GPU emulation context.
|
/// Creates a new instance of the GPU emulation context.
|
||||||
@@ -109,6 +116,7 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
|
|
||||||
SyncActions = new List<Action>();
|
SyncActions = new List<Action>();
|
||||||
SyncpointActions = new List<Action>();
|
SyncpointActions = new List<Action>();
|
||||||
|
BufferMigrations = new List<BufferMigration>();
|
||||||
|
|
||||||
DeferredActions = new Queue<Action>();
|
DeferredActions = new Queue<Action>();
|
||||||
|
|
||||||
@@ -273,6 +281,17 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
SequenceNumber++;
|
SequenceNumber++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers a buffer migration. These are checked to see if they can be disposed when the sync number increases,
|
||||||
|
/// and the migration copy has completed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="migration">The buffer migration</param>
|
||||||
|
internal void RegisterBufferMigration(BufferMigration migration)
|
||||||
|
{
|
||||||
|
BufferMigrations.Add(migration);
|
||||||
|
_pendingSync = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers an action to be performed the next time a syncpoint is incremented.
|
/// Registers an action to be performed the next time a syncpoint is incremented.
|
||||||
/// This will also ensure a host sync object is created, and <see cref="SyncNumber"/> is incremented.
|
/// This will also ensure a host sync object is created, and <see cref="SyncNumber"/> is incremented.
|
||||||
@@ -288,6 +307,7 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
SyncActions.Add(action);
|
SyncActions.Add(action);
|
||||||
|
_pendingSync = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,7 +318,24 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
/// <param name="syncpoint">True if host sync is being created by a syncpoint</param>
|
/// <param name="syncpoint">True if host sync is being created by a syncpoint</param>
|
||||||
public void CreateHostSyncIfNeeded(bool syncpoint)
|
public void CreateHostSyncIfNeeded(bool syncpoint)
|
||||||
{
|
{
|
||||||
if (SyncActions.Count > 0 || (syncpoint && SyncpointActions.Count > 0))
|
if (BufferMigrations.Count > 0)
|
||||||
|
{
|
||||||
|
ulong currentSyncNumber = Renderer.GetCurrentSync();
|
||||||
|
|
||||||
|
for (int i = 0; i < BufferMigrations.Count; i++)
|
||||||
|
{
|
||||||
|
BufferMigration migration = BufferMigrations[i];
|
||||||
|
long diff = (long)(currentSyncNumber - migration.SyncNumber);
|
||||||
|
|
||||||
|
if (diff >= 0)
|
||||||
|
{
|
||||||
|
migration.Dispose();
|
||||||
|
BufferMigrations.RemoveAt(i--);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pendingSync || (syncpoint && SyncpointActions.Count > 0))
|
||||||
{
|
{
|
||||||
Renderer.CreateSync(SyncNumber);
|
Renderer.CreateSync(SyncNumber);
|
||||||
|
|
||||||
@@ -317,6 +354,8 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
SyncActions.Clear();
|
SyncActions.Clear();
|
||||||
SyncpointActions.Clear();
|
SyncpointActions.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_pendingSync = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -65,6 +65,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
private bool _useGranular;
|
private bool _useGranular;
|
||||||
private bool _syncActionRegistered;
|
private bool _syncActionRegistered;
|
||||||
|
|
||||||
|
private int _referenceCount = 1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the buffer.
|
/// Creates a new instance of the buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -229,7 +231,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
if (_modifiedRanges == null)
|
if (_modifiedRanges == null)
|
||||||
{
|
{
|
||||||
_modifiedRanges = new BufferModifiedRangeList(_context);
|
_modifiedRanges = new BufferModifiedRangeList(_context, this, Flush);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,7 +292,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <param name="from">The buffer to inherit from</param>
|
/// <param name="from">The buffer to inherit from</param>
|
||||||
public void InheritModifiedRanges(Buffer from)
|
public void InheritModifiedRanges(Buffer from)
|
||||||
{
|
{
|
||||||
if (from._modifiedRanges != null)
|
if (from._modifiedRanges != null && from._modifiedRanges.HasRanges)
|
||||||
{
|
{
|
||||||
if (from._syncActionRegistered && !_syncActionRegistered)
|
if (from._syncActionRegistered && !_syncActionRegistered)
|
||||||
{
|
{
|
||||||
@@ -310,17 +312,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_modifiedRanges == null)
|
EnsureRangeList();
|
||||||
{
|
|
||||||
_modifiedRanges = from._modifiedRanges;
|
|
||||||
_modifiedRanges.ReregisterRanges(registerRangeAction);
|
|
||||||
|
|
||||||
from._modifiedRanges = null;
|
_modifiedRanges.InheritRanges(from._modifiedRanges, registerRangeAction);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_modifiedRanges.InheritRanges(from._modifiedRanges, registerRangeAction);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,7 +450,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
if (ranges != null)
|
if (ranges != null)
|
||||||
{
|
{
|
||||||
(address, size) = PageAlign(address, size);
|
(address, size) = PageAlign(address, size);
|
||||||
ranges.WaitForAndGetRanges(address, size, Flush);
|
ranges.WaitForAndFlushRanges(address, size);
|
||||||
}
|
}
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
@@ -508,6 +502,25 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
UnmappedSequence++;
|
UnmappedSequence++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Increments the buffer reference count.
|
||||||
|
/// </summary>
|
||||||
|
public void IncrementReferenceCount()
|
||||||
|
{
|
||||||
|
_referenceCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decrements the buffer reference count.
|
||||||
|
/// </summary>
|
||||||
|
public void DecrementReferenceCount()
|
||||||
|
{
|
||||||
|
if (--_referenceCount == 0)
|
||||||
|
{
|
||||||
|
DisposeData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disposes the host buffer's data, not its tracking handles.
|
/// Disposes the host buffer's data, not its tracking handles.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -528,7 +541,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
_memoryTrackingGranular?.Dispose();
|
_memoryTrackingGranular?.Dispose();
|
||||||
_memoryTracking?.Dispose();
|
_memoryTracking?.Dispose();
|
||||||
|
|
||||||
DisposeData();
|
DecrementReferenceCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -273,7 +273,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
buffer.CopyTo(newBuffer, dstOffset);
|
buffer.CopyTo(newBuffer, dstOffset);
|
||||||
newBuffer.InheritModifiedRanges(buffer);
|
newBuffer.InheritModifiedRanges(buffer);
|
||||||
|
|
||||||
buffer.DisposeData();
|
buffer.DecrementReferenceCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
newBuffer.SynchronizeMemory(address, newSize);
|
newBuffer.SynchronizeMemory(address, newSize);
|
||||||
|
125
Ryujinx.Graphics.Gpu/Memory/BufferMigration.cs
Normal file
125
Ryujinx.Graphics.Gpu/Memory/BufferMigration.cs
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A record of when buffer data was copied from one buffer to another, along with the SyncNumber when the migration will be complete.
|
||||||
|
/// Keeps the source buffer alive for data flushes until the migration is complete.
|
||||||
|
/// </summary>
|
||||||
|
internal class BufferMigration : IDisposable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The offset for the migrated region.
|
||||||
|
/// </summary>
|
||||||
|
private readonly ulong _offset;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The size for the migrated region.
|
||||||
|
/// </summary>
|
||||||
|
private readonly ulong _size;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The buffer that was migrated from.
|
||||||
|
/// </summary>
|
||||||
|
private readonly Buffer _buffer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The source range action, to be called on overlap with an unreached sync number.
|
||||||
|
/// </summary>
|
||||||
|
private readonly Action<ulong, ulong> _sourceRangeAction;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The source range list.
|
||||||
|
/// </summary>
|
||||||
|
private readonly BufferModifiedRangeList _source;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The destination range list. This range list must be updated when flushing the source.
|
||||||
|
/// </summary>
|
||||||
|
public readonly BufferModifiedRangeList Destination;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The sync number that needs to be reached for this migration to be removed. This is set to the pending sync number on creation.
|
||||||
|
/// </summary>
|
||||||
|
public readonly ulong SyncNumber;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a record for a buffer migration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">The source buffer for this migration</param>
|
||||||
|
/// <param name="sourceRangeAction">The flush action for the source buffer</param>
|
||||||
|
/// <param name="source">The modified range list for the source buffer</param>
|
||||||
|
/// <param name="dest">The modified range list for the destination buffer</param>
|
||||||
|
/// <param name="syncNumber">The sync number for when the migration is complete</param>
|
||||||
|
public BufferMigration(
|
||||||
|
Buffer buffer,
|
||||||
|
Action<ulong, ulong> sourceRangeAction,
|
||||||
|
BufferModifiedRangeList source,
|
||||||
|
BufferModifiedRangeList dest,
|
||||||
|
ulong syncNumber)
|
||||||
|
{
|
||||||
|
_offset = buffer.Address;
|
||||||
|
_size = buffer.Size;
|
||||||
|
_buffer = buffer;
|
||||||
|
_sourceRangeAction = sourceRangeAction;
|
||||||
|
_source = source;
|
||||||
|
Destination = dest;
|
||||||
|
SyncNumber = syncNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determine if the given range overlaps this migration, and has not been completed yet.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">Start offset</param>
|
||||||
|
/// <param name="size">Range size</param>
|
||||||
|
/// <param name="syncNumber">The sync number that was waited on</param>
|
||||||
|
/// <returns>True if overlapping and in progress, false otherwise</returns>
|
||||||
|
public bool Overlaps(ulong offset, ulong size, ulong syncNumber)
|
||||||
|
{
|
||||||
|
ulong end = offset + size;
|
||||||
|
ulong destEnd = _offset + _size;
|
||||||
|
long syncDiff = (long)(syncNumber - SyncNumber); // syncNumber is less if the copy has not completed.
|
||||||
|
|
||||||
|
return !(end <= _offset || offset >= destEnd) && syncDiff < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determine if the given range matches this migration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">Start offset</param>
|
||||||
|
/// <param name="size">Range size</param>
|
||||||
|
/// <returns>True if the range exactly matches, false otherwise</returns>
|
||||||
|
public bool FullyMatches(ulong offset, ulong size)
|
||||||
|
{
|
||||||
|
return _offset == offset && _size == size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Perform the migration source's range action on the range provided, clamped to the bounds of the source buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">Start offset</param>
|
||||||
|
/// <param name="size">Range size</param>
|
||||||
|
/// <param name="syncNumber">Current sync number</param>
|
||||||
|
/// <param name="parent">The modified range list that originally owned this range</param>
|
||||||
|
public void RangeActionWithMigration(ulong offset, ulong size, ulong syncNumber, BufferModifiedRangeList parent)
|
||||||
|
{
|
||||||
|
ulong end = offset + size;
|
||||||
|
end = Math.Min(_offset + _size, end);
|
||||||
|
offset = Math.Max(_offset, offset);
|
||||||
|
|
||||||
|
size = end - offset;
|
||||||
|
|
||||||
|
_source.RangeActionWithMigration(offset, size, syncNumber, parent, _sourceRangeAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes this reference to the range list, potentially allowing for the source buffer to be disposed.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Destination.RemoveMigration(this);
|
||||||
|
|
||||||
|
_buffer.DecrementReferenceCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,6 +1,8 @@
|
|||||||
using Ryujinx.Common.Pools;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Common.Pools;
|
||||||
using Ryujinx.Memory.Range;
|
using Ryujinx.Memory.Range;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Memory
|
namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
@@ -30,17 +32,24 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ulong SyncNumber { get; internal set; }
|
public ulong SyncNumber { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The range list that originally owned this range.
|
||||||
|
/// </summary>
|
||||||
|
public BufferModifiedRangeList Parent { get; internal set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of a modified range.
|
/// Creates a new instance of a modified range.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="address">Start address of the range</param>
|
/// <param name="address">Start address of the range</param>
|
||||||
/// <param name="size">Size of the range in bytes</param>
|
/// <param name="size">Size of the range in bytes</param>
|
||||||
/// <param name="syncNumber">The GPU sync number at the time of creation</param>
|
/// <param name="syncNumber">The GPU sync number at the time of creation</param>
|
||||||
public BufferModifiedRange(ulong address, ulong size, ulong syncNumber)
|
/// <param name="parent">The range list that owns this range</param>
|
||||||
|
public BufferModifiedRange(ulong address, ulong size, ulong syncNumber, BufferModifiedRangeList parent)
|
||||||
{
|
{
|
||||||
Address = address;
|
Address = address;
|
||||||
Size = size;
|
Size = size;
|
||||||
SyncNumber = syncNumber;
|
SyncNumber = syncNumber;
|
||||||
|
Parent = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -63,16 +72,39 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
private const int BackingInitialSize = 8;
|
private const int BackingInitialSize = 8;
|
||||||
|
|
||||||
private GpuContext _context;
|
private GpuContext _context;
|
||||||
|
private Buffer _parent;
|
||||||
|
private Action<ulong, ulong> _flushAction;
|
||||||
|
|
||||||
|
private List<BufferMigration> _sources;
|
||||||
|
private BufferMigration _migrationTarget;
|
||||||
|
|
||||||
private object _lock = new object();
|
private object _lock = new object();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the modified range list has any entries or not.
|
||||||
|
/// </summary>
|
||||||
|
public bool HasRanges
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
return Count > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of a modified range list.
|
/// Creates a new instance of a modified range list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">GPU context that the buffer range list belongs to</param>
|
/// <param name="context">GPU context that the buffer range list belongs to</param>
|
||||||
public BufferModifiedRangeList(GpuContext context) : base(BackingInitialSize)
|
/// <param name="parent">The parent buffer that owns this range list</param>
|
||||||
|
/// <param name="flushAction">The flush action for the parent buffer</param>
|
||||||
|
public BufferModifiedRangeList(GpuContext context, Buffer parent, Action<ulong, ulong> flushAction) : base(BackingInitialSize)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
|
_parent = parent;
|
||||||
|
_flushAction = flushAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -142,6 +174,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
// Region already exists. Just update the existing sync number.
|
// Region already exists. Just update the existing sync number.
|
||||||
overlap.SyncNumber = syncNumber;
|
overlap.SyncNumber = syncNumber;
|
||||||
|
overlap.Parent = this;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -152,18 +185,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
// A split item must be created behind this overlap.
|
// A split item must be created behind this overlap.
|
||||||
|
|
||||||
Add(new BufferModifiedRange(overlap.Address, address - overlap.Address, overlap.SyncNumber));
|
Add(new BufferModifiedRange(overlap.Address, address - overlap.Address, overlap.SyncNumber, overlap.Parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overlap.Address < endAddress && overlap.EndAddress > endAddress)
|
if (overlap.Address < endAddress && overlap.EndAddress > endAddress)
|
||||||
{
|
{
|
||||||
// A split item must be created after this overlap.
|
// A split item must be created after this overlap.
|
||||||
|
|
||||||
Add(new BufferModifiedRange(endAddress, overlap.EndAddress - endAddress, overlap.SyncNumber));
|
Add(new BufferModifiedRange(endAddress, overlap.EndAddress - endAddress, overlap.SyncNumber, overlap.Parent));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Add(new BufferModifiedRange(address, size, syncNumber));
|
Add(new BufferModifiedRange(address, size, syncNumber, this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,9 +240,102 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs the given range action, or one from a migration that overlaps and has not synced yet.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">The offset to pass to the action</param>
|
||||||
|
/// <param name="size">The size to pass to the action</param>
|
||||||
|
/// <param name="syncNumber">The sync number that has been reached</param>
|
||||||
|
/// <param name="parent">The modified range list that originally owned this range</param>
|
||||||
|
/// <param name="rangeAction">The action to perform</param>
|
||||||
|
public void RangeActionWithMigration(ulong offset, ulong size, ulong syncNumber, BufferModifiedRangeList parent, Action<ulong, ulong> rangeAction)
|
||||||
|
{
|
||||||
|
bool firstSource = true;
|
||||||
|
|
||||||
|
if (parent != this)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
if (_sources != null)
|
||||||
|
{
|
||||||
|
foreach (BufferMigration source in _sources)
|
||||||
|
{
|
||||||
|
if (source.Overlaps(offset, size, syncNumber))
|
||||||
|
{
|
||||||
|
if (firstSource && !source.FullyMatches(offset, size))
|
||||||
|
{
|
||||||
|
// Perform this buffer's action first. The migrations will run after.
|
||||||
|
rangeAction(offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
source.RangeActionWithMigration(offset, size, syncNumber, parent);
|
||||||
|
|
||||||
|
firstSource = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstSource)
|
||||||
|
{
|
||||||
|
// No overlapping migrations, or they are not meant for this range, flush the data using the given action.
|
||||||
|
rangeAction(offset, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes modified ranges ready by the sync number from the list, and flushes their buffer data within a given address range.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="overlaps">Overlapping ranges to check</param>
|
||||||
|
/// <param name="rangeCount">Number of overlapping ranges</param>
|
||||||
|
/// <param name="highestDiff">The highest difference between an overlapping range's sync number and the current one</param>
|
||||||
|
/// <param name="currentSync">The current sync number</param>
|
||||||
|
/// <param name="address">The start address of the flush range</param>
|
||||||
|
/// <param name="endAddress">The end address of the flush range</param>
|
||||||
|
private void RemoveRangesAndFlush(
|
||||||
|
BufferModifiedRange[] overlaps,
|
||||||
|
int rangeCount,
|
||||||
|
long highestDiff,
|
||||||
|
ulong currentSync,
|
||||||
|
ulong address,
|
||||||
|
ulong endAddress)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
if (_migrationTarget == null)
|
||||||
|
{
|
||||||
|
ulong waitSync = currentSync + (ulong)highestDiff;
|
||||||
|
|
||||||
|
for (int i = 0; i < rangeCount; i++)
|
||||||
|
{
|
||||||
|
BufferModifiedRange overlap = overlaps[i];
|
||||||
|
|
||||||
|
long diff = (long)(overlap.SyncNumber - currentSync);
|
||||||
|
|
||||||
|
if (diff <= highestDiff)
|
||||||
|
{
|
||||||
|
ulong clampAddress = Math.Max(address, overlap.Address);
|
||||||
|
ulong clampEnd = Math.Min(endAddress, overlap.EndAddress);
|
||||||
|
|
||||||
|
ClearPart(overlap, clampAddress, clampEnd);
|
||||||
|
|
||||||
|
RangeActionWithMigration(clampAddress, clampEnd - clampAddress, waitSync, overlap.Parent, _flushAction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// There is a migration target to call instead. This can't be changed after set so accessing it outside the lock is fine.
|
||||||
|
|
||||||
|
_migrationTarget.Destination.RemoveRangesAndFlush(overlaps, rangeCount, highestDiff, currentSync, address, endAddress);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets modified ranges within the specified region, waits on ones from a previous sync number,
|
/// Gets modified ranges within the specified region, waits on ones from a previous sync number,
|
||||||
/// and then fires the given action for each range individually.
|
/// and then fires the flush action for each range individually.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This function assumes it is called from the background thread.
|
/// This function assumes it is called from the background thread.
|
||||||
@@ -218,8 +344,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="address">Start address to query</param>
|
/// <param name="address">Start address to query</param>
|
||||||
/// <param name="size">Size to query</param>
|
/// <param name="size">Size to query</param>
|
||||||
/// <param name="rangeAction">The action to call for each modified range</param>
|
public void WaitForAndFlushRanges(ulong address, ulong size)
|
||||||
public void WaitForAndGetRanges(ulong address, ulong size, Action<ulong, ulong> rangeAction)
|
|
||||||
{
|
{
|
||||||
ulong endAddress = address + size;
|
ulong endAddress = address + size;
|
||||||
ulong currentSync = _context.SyncNumber;
|
ulong currentSync = _context.SyncNumber;
|
||||||
@@ -231,10 +356,23 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
// Range list must be consistent for this operation
|
// Range list must be consistent for this operation
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
rangeCount = FindOverlapsNonOverlapping(address, size, ref overlaps);
|
if (_migrationTarget != null)
|
||||||
|
{
|
||||||
|
rangeCount = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rangeCount = FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rangeCount == 0)
|
if (rangeCount == -1)
|
||||||
|
{
|
||||||
|
_migrationTarget.Destination.WaitForAndFlushRanges(address, size);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (rangeCount == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -264,47 +402,37 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
// Wait for the syncpoint.
|
// Wait for the syncpoint.
|
||||||
_context.Renderer.WaitSync(currentSync + (ulong)highestDiff);
|
_context.Renderer.WaitSync(currentSync + (ulong)highestDiff);
|
||||||
|
|
||||||
// Flush and remove all regions with the older syncpoint.
|
RemoveRangesAndFlush(overlaps, rangeCount, highestDiff, currentSync, address, endAddress);
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < rangeCount; i++)
|
|
||||||
{
|
|
||||||
BufferModifiedRange overlap = overlaps[i];
|
|
||||||
|
|
||||||
long diff = (long)(overlap.SyncNumber - currentSync);
|
|
||||||
|
|
||||||
if (diff <= highestDiff)
|
|
||||||
{
|
|
||||||
ulong clampAddress = Math.Max(address, overlap.Address);
|
|
||||||
ulong clampEnd = Math.Min(endAddress, overlap.EndAddress);
|
|
||||||
|
|
||||||
ClearPart(overlap, clampAddress, clampEnd);
|
|
||||||
|
|
||||||
rangeAction(clampAddress, clampEnd - clampAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Inherit ranges from another modified range list.
|
/// Inherit ranges from another modified range list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ranges">The range list to inherit from</param>
|
/// <param name="ranges">The range list to inherit from</param>
|
||||||
/// <param name="rangeAction">The action to call for each modified range</param>
|
/// <param name="registerRangeAction">The action to call for each modified range</param>
|
||||||
public void InheritRanges(BufferModifiedRangeList ranges, Action<ulong, ulong> rangeAction)
|
public void InheritRanges(BufferModifiedRangeList ranges, Action<ulong, ulong> registerRangeAction)
|
||||||
{
|
{
|
||||||
BufferModifiedRange[] inheritRanges;
|
BufferModifiedRange[] inheritRanges;
|
||||||
|
|
||||||
lock (ranges._lock)
|
lock (ranges._lock)
|
||||||
{
|
{
|
||||||
inheritRanges = ranges.ToArray();
|
BufferMigration migration = new(ranges._parent, ranges._flushAction, ranges, this, _context.SyncNumber);
|
||||||
}
|
|
||||||
|
|
||||||
lock (_lock)
|
ranges._parent.IncrementReferenceCount();
|
||||||
{
|
ranges._migrationTarget = migration;
|
||||||
foreach (BufferModifiedRange range in inheritRanges)
|
|
||||||
|
_context.RegisterBufferMigration(migration);
|
||||||
|
|
||||||
|
inheritRanges = ranges.ToArray();
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
{
|
{
|
||||||
Add(range);
|
(_sources ??= new List<BufferMigration>()).Add(migration);
|
||||||
|
|
||||||
|
foreach (BufferModifiedRange range in inheritRanges)
|
||||||
|
{
|
||||||
|
Add(range);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,44 +441,20 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
if (range.SyncNumber != currentSync)
|
if (range.SyncNumber != currentSync)
|
||||||
{
|
{
|
||||||
rangeAction(range.Address, range.Size);
|
registerRangeAction(range.Address, range.Size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calls the given action for modified ranges that aren't from the current sync number.
|
/// Removes a source buffer migration, indicating its copy has completed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="rangeAction">The action to call for each modified range</param>
|
/// <param name="migration">The migration to remove</param>
|
||||||
public void ReregisterRanges(Action<ulong, ulong> rangeAction)
|
public void RemoveMigration(BufferMigration migration)
|
||||||
{
|
{
|
||||||
ref var ranges = ref ThreadStaticArray<BufferModifiedRange>.Get();
|
|
||||||
int count;
|
|
||||||
|
|
||||||
// Range list must be consistent for this operation.
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
count = Count;
|
_sources.Remove(migration);
|
||||||
if (ranges.Length < count)
|
|
||||||
{
|
|
||||||
Array.Resize(ref ranges, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (BufferModifiedRange range in this)
|
|
||||||
{
|
|
||||||
ranges[i++] = range;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong currentSync = _context.SyncNumber;
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
BufferModifiedRange range = ranges[i];
|
|
||||||
if (range.SyncNumber != currentSync)
|
|
||||||
{
|
|
||||||
rangeAction(range.Address, range.Size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,12 +466,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
if (overlap.Address < address)
|
if (overlap.Address < address)
|
||||||
{
|
{
|
||||||
Add(new BufferModifiedRange(overlap.Address, address - overlap.Address, overlap.SyncNumber));
|
Add(new BufferModifiedRange(overlap.Address, address - overlap.Address, overlap.SyncNumber, overlap.Parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overlap.EndAddress > endAddress)
|
if (overlap.EndAddress > endAddress)
|
||||||
{
|
{
|
||||||
Add(new BufferModifiedRange(endAddress, overlap.EndAddress - endAddress, overlap.SyncNumber));
|
Add(new BufferModifiedRange(endAddress, overlap.EndAddress - endAddress, overlap.SyncNumber, overlap.Parent));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||||
private const uint CodeGenVersion = 3868;
|
private const uint CodeGenVersion = 3943;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
@@ -331,7 +331,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
case PrimitiveTopology.QuadStrip:
|
case PrimitiveTopology.QuadStrip:
|
||||||
return PrimitiveType.QuadStrip;
|
return PrimitiveType.QuadStrip;
|
||||||
case PrimitiveTopology.Polygon:
|
case PrimitiveTopology.Polygon:
|
||||||
return PrimitiveType.Polygon;
|
return PrimitiveType.TriangleFan;
|
||||||
case PrimitiveTopology.LinesAdjacency:
|
case PrimitiveTopology.LinesAdjacency:
|
||||||
return PrimitiveType.LinesAdjacency;
|
return PrimitiveType.LinesAdjacency;
|
||||||
case PrimitiveTopology.LineStripAdjacency:
|
case PrimitiveTopology.LineStripAdjacency:
|
||||||
|
@@ -238,6 +238,11 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
_sync.Wait(id);
|
_sync.Wait(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ulong GetCurrentSync()
|
||||||
|
{
|
||||||
|
return _sync.GetCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
public void Screenshot()
|
public void Screenshot()
|
||||||
{
|
{
|
||||||
_window.ScreenCaptureRequested = true;
|
_window.ScreenCaptureRequested = true;
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="OpenTK.Graphics" Version="4.7.2" />
|
<PackageReference Include="OpenTK.Graphics" Version="4.7.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -40,6 +40,37 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ulong GetCurrent()
|
||||||
|
{
|
||||||
|
lock (_handles)
|
||||||
|
{
|
||||||
|
ulong lastHandle = _firstHandle;
|
||||||
|
|
||||||
|
foreach (SyncHandle handle in _handles)
|
||||||
|
{
|
||||||
|
lock (handle)
|
||||||
|
{
|
||||||
|
if (handle.Handle == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle.ID > lastHandle)
|
||||||
|
{
|
||||||
|
WaitSyncStatus syncResult = GL.ClientWaitSync(handle.Handle, _syncFlags, 0);
|
||||||
|
|
||||||
|
if (syncResult == WaitSyncStatus.AlreadySignaled)
|
||||||
|
{
|
||||||
|
lastHandle = handle.ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastHandle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Wait(ulong id)
|
public void Wait(ulong id)
|
||||||
{
|
{
|
||||||
SyncHandle result = null;
|
SyncHandle result = null;
|
||||||
|
@@ -10,13 +10,9 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
{
|
{
|
||||||
public int Handle { get; private set; }
|
public int Handle { get; private set; }
|
||||||
|
|
||||||
private bool _needsAttribsUpdate;
|
|
||||||
|
|
||||||
private readonly VertexAttribDescriptor[] _vertexAttribs;
|
private readonly VertexAttribDescriptor[] _vertexAttribs;
|
||||||
private readonly VertexBufferDescriptor[] _vertexBuffers;
|
private readonly VertexBufferDescriptor[] _vertexBuffers;
|
||||||
|
|
||||||
private int _vertexAttribsCount;
|
|
||||||
private int _vertexBuffersCount;
|
|
||||||
private int _minVertexCount;
|
private int _minVertexCount;
|
||||||
|
|
||||||
private uint _vertexAttribsInUse;
|
private uint _vertexAttribsInUse;
|
||||||
@@ -76,9 +72,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
_vertexBuffers[bindingIndex] = vb;
|
_vertexBuffers[bindingIndex] = vb;
|
||||||
}
|
}
|
||||||
|
|
||||||
_vertexBuffersCount = bindingIndex;
|
|
||||||
_minVertexCount = minVertexCount;
|
_minVertexCount = minVertexCount;
|
||||||
_needsAttribsUpdate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetVertexAttributes(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
|
public void SetVertexAttributes(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
|
||||||
@@ -131,8 +125,6 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
_vertexAttribs[index] = attrib;
|
_vertexAttribs[index] = attrib;
|
||||||
}
|
}
|
||||||
|
|
||||||
_vertexAttribsCount = index;
|
|
||||||
|
|
||||||
for (; index < Constants.MaxVertexAttribs; index++)
|
for (; index < Constants.MaxVertexAttribs; index++)
|
||||||
{
|
{
|
||||||
DisableVertexAttrib(index);
|
DisableVertexAttrib(index);
|
||||||
@@ -160,13 +152,11 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
public void PreDraw(int vertexCount)
|
public void PreDraw(int vertexCount)
|
||||||
{
|
{
|
||||||
LimitVertexBuffers(vertexCount);
|
LimitVertexBuffers(vertexCount);
|
||||||
Validate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PreDrawVbUnbounded()
|
public void PreDrawVbUnbounded()
|
||||||
{
|
{
|
||||||
UnlimitVertexBuffers();
|
UnlimitVertexBuffers();
|
||||||
Validate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LimitVertexBuffers(int vertexCount)
|
public void LimitVertexBuffers(int vertexCount)
|
||||||
@@ -252,36 +242,6 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
_vertexBuffersLimited = 0;
|
_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)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void EnableVertexAttrib(int index)
|
private void EnableVertexAttrib(int index)
|
||||||
{
|
{
|
||||||
|
@@ -234,7 +234,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
var source = operation.GetSource(0);
|
var source = operation.GetSource(0);
|
||||||
|
|
||||||
var uvec4Type = context.TypeVector(context.TypeU32(), 4);
|
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 maskVector = context.GroupNonUniformBallot(uvec4Type, execution, context.Get(AggregateType.Bool, source));
|
||||||
var mask = context.CompositeExtract(context.TypeU32(), maskVector, (SpvLiteralInteger)0);
|
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 maxThreadId = context.BitwiseOr(context.TypeU32(), minThreadId, clampNotSegMask);
|
||||||
var srcThreadId = context.BitwiseOr(context.TypeU32(), indexNotSegMask, minThreadId);
|
var srcThreadId = context.BitwiseOr(context.TypeU32(), indexNotSegMask, minThreadId);
|
||||||
var valid = context.ULessThanEqual(context.TypeBool(), srcThreadId, maxThreadId);
|
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 result = context.Select(context.TypeFP32(), valid, value, x);
|
||||||
|
|
||||||
var validLocal = (AstOperand)operation.GetSource(3);
|
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 maxThreadId = context.BitwiseOr(context.TypeU32(), minThreadId, clampNotSegMask);
|
||||||
var srcThreadId = context.IAdd(context.TypeU32(), threadId, index);
|
var srcThreadId = context.IAdd(context.TypeU32(), threadId, index);
|
||||||
var valid = context.ULessThanEqual(context.TypeBool(), srcThreadId, maxThreadId);
|
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 result = context.Select(context.TypeFP32(), valid, value, x);
|
||||||
|
|
||||||
var validLocal = (AstOperand)operation.GetSource(3);
|
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 minThreadId = context.BitwiseAnd(context.TypeU32(), threadId, segMask);
|
||||||
var srcThreadId = context.ISub(context.TypeU32(), threadId, index);
|
var srcThreadId = context.ISub(context.TypeU32(), threadId, index);
|
||||||
var valid = context.SGreaterThanEqual(context.TypeBool(), srcThreadId, minThreadId);
|
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 result = context.Select(context.TypeFP32(), valid, value, x);
|
||||||
|
|
||||||
var validLocal = (AstOperand)operation.GetSource(3);
|
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 maxThreadId = context.BitwiseOr(context.TypeU32(), minThreadId, clampNotSegMask);
|
||||||
var srcThreadId = context.BitwiseXor(context.TypeU32(), threadId, index);
|
var srcThreadId = context.BitwiseXor(context.TypeU32(), threadId, index);
|
||||||
var valid = context.ULessThanEqual(context.TypeBool(), srcThreadId, maxThreadId);
|
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 result = context.Select(context.TypeFP32(), valid, value, x);
|
||||||
|
|
||||||
var validLocal = (AstOperand)operation.GetSource(3);
|
var validLocal = (AstOperand)operation.GetSource(3);
|
||||||
@@ -1861,19 +1861,22 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
|
|
||||||
private static OperationResult GenerateVoteAll(CodeGenContext context, AstOperation operation)
|
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);
|
return new OperationResult(AggregateType.Bool, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static OperationResult GenerateVoteAllEqual(CodeGenContext context, AstOperation operation)
|
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);
|
return new OperationResult(AggregateType.Bool, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static OperationResult GenerateVoteAny(CodeGenContext context, AstOperation operation)
|
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);
|
return new OperationResult(AggregateType.Bool, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -50,12 +50,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
CodeGenContext context = new CodeGenContext(info, config, instPool, integerPool);
|
CodeGenContext context = new CodeGenContext(info, config, instPool, integerPool);
|
||||||
|
|
||||||
context.AddCapability(Capability.GroupNonUniformBallot);
|
context.AddCapability(Capability.GroupNonUniformBallot);
|
||||||
|
context.AddCapability(Capability.GroupNonUniformShuffle);
|
||||||
|
context.AddCapability(Capability.GroupNonUniformVote);
|
||||||
context.AddCapability(Capability.ImageBuffer);
|
context.AddCapability(Capability.ImageBuffer);
|
||||||
context.AddCapability(Capability.ImageGatherExtended);
|
context.AddCapability(Capability.ImageGatherExtended);
|
||||||
context.AddCapability(Capability.ImageQuery);
|
context.AddCapability(Capability.ImageQuery);
|
||||||
context.AddCapability(Capability.SampledBuffer);
|
context.AddCapability(Capability.SampledBuffer);
|
||||||
context.AddCapability(Capability.SubgroupBallotKHR);
|
|
||||||
context.AddCapability(Capability.SubgroupVoteKHR);
|
|
||||||
|
|
||||||
if (config.TransformFeedbackEnabled && config.LastInVertexPipeline)
|
if (config.TransformFeedbackEnabled && config.LastInVertexPipeline)
|
||||||
{
|
{
|
||||||
@@ -94,9 +94,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
context.AddCapability(Capability.DrawParameters);
|
context.AddCapability(Capability.DrawParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.AddExtension("SPV_KHR_shader_ballot");
|
|
||||||
context.AddExtension("SPV_KHR_subgroup_vote");
|
|
||||||
|
|
||||||
Declarations.DeclareAll(context, info);
|
Declarations.DeclareAll(context, info);
|
||||||
|
|
||||||
if ((info.HelperFunctionsMask & NeedsInvocationIdMask) != 0)
|
if ((info.HelperFunctionsMask & NeedsInvocationIdMask) != 0)
|
||||||
|
@@ -128,6 +128,11 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
GetStorageOffset(block, Utils.FindLastOperation(addrLow, block), baseAddressCbOffset) :
|
GetStorageOffset(block, Utils.FindLastOperation(addrLow, block), baseAddressCbOffset) :
|
||||||
(null, 0);
|
(null, 0);
|
||||||
|
|
||||||
|
if (byteOffset != null)
|
||||||
|
{
|
||||||
|
ReplaceAddressAlignment(node.List, addrLow, byteOffset, constantOffset);
|
||||||
|
}
|
||||||
|
|
||||||
if (byteOffset == null)
|
if (byteOffset == null)
|
||||||
{
|
{
|
||||||
Operand baseAddrLow = Cbuf(0, baseAddressCbOffset);
|
Operand baseAddrLow = Cbuf(0, baseAddressCbOffset);
|
||||||
@@ -156,11 +161,6 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
byteOffset = offset;
|
byteOffset = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (byteOffset != null)
|
|
||||||
{
|
|
||||||
ReplaceAddressAlignment(node.List, addrLow, byteOffset, constantOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isStg16Or8)
|
if (isStg16Or8)
|
||||||
{
|
{
|
||||||
return byteOffset;
|
return byteOffset;
|
||||||
|
@@ -12,12 +12,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private const int MaxUpdateBufferSize = 0x10000;
|
private const int MaxUpdateBufferSize = 0x10000;
|
||||||
|
|
||||||
public const AccessFlags DefaultAccessFlags =
|
public const AccessFlags DefaultAccessFlags =
|
||||||
AccessFlags.AccessIndirectCommandReadBit |
|
AccessFlags.IndirectCommandReadBit |
|
||||||
AccessFlags.AccessShaderReadBit |
|
AccessFlags.ShaderReadBit |
|
||||||
AccessFlags.AccessShaderWriteBit |
|
AccessFlags.ShaderWriteBit |
|
||||||
AccessFlags.AccessTransferReadBit |
|
AccessFlags.TransferReadBit |
|
||||||
AccessFlags.AccessTransferWriteBit |
|
AccessFlags.TransferWriteBit |
|
||||||
AccessFlags.AccessUniformReadBit;
|
AccessFlags.UniformReadBit;
|
||||||
|
|
||||||
private readonly VulkanRenderer _gd;
|
private readonly VulkanRenderer _gd;
|
||||||
private readonly Device _device;
|
private readonly Device _device;
|
||||||
@@ -87,9 +87,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_gd.Api.CmdPipelineBarrier(
|
_gd.Api.CmdPipelineBarrier(
|
||||||
commandBuffer,
|
commandBuffer,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
DependencyFlags.DependencyDeviceGroupBit,
|
DependencyFlags.DeviceGroupBit,
|
||||||
1,
|
1,
|
||||||
memoryBarrier,
|
memoryBarrier,
|
||||||
0,
|
0,
|
||||||
@@ -273,9 +273,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
BufferHolder.DefaultAccessFlags,
|
BufferHolder.DefaultAccessFlags,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
dstOffset,
|
dstOffset,
|
||||||
data.Length);
|
data.Length);
|
||||||
|
|
||||||
@@ -293,10 +293,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_gd,
|
_gd,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
BufferHolder.DefaultAccessFlags,
|
BufferHolder.DefaultAccessFlags,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
dstOffset,
|
dstOffset,
|
||||||
data.Length);
|
data.Length);
|
||||||
|
|
||||||
@@ -320,9 +320,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
BufferHolder.DefaultAccessFlags,
|
BufferHolder.DefaultAccessFlags,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
dstOffset,
|
dstOffset,
|
||||||
size);
|
size);
|
||||||
|
|
||||||
@@ -334,10 +334,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
gd,
|
gd,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
BufferHolder.DefaultAccessFlags,
|
BufferHolder.DefaultAccessFlags,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
dstOffset,
|
dstOffset,
|
||||||
size);
|
size);
|
||||||
}
|
}
|
||||||
|
@@ -10,28 +10,28 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
class BufferManager : IDisposable
|
class BufferManager : IDisposable
|
||||||
{
|
{
|
||||||
private const MemoryPropertyFlags DefaultBufferMemoryFlags =
|
private const MemoryPropertyFlags DefaultBufferMemoryFlags =
|
||||||
MemoryPropertyFlags.MemoryPropertyHostVisibleBit |
|
MemoryPropertyFlags.HostVisibleBit |
|
||||||
MemoryPropertyFlags.MemoryPropertyHostCoherentBit |
|
MemoryPropertyFlags.HostCoherentBit |
|
||||||
MemoryPropertyFlags.MemoryPropertyHostCachedBit;
|
MemoryPropertyFlags.HostCachedBit;
|
||||||
|
|
||||||
private const MemoryPropertyFlags DeviceLocalBufferMemoryFlags =
|
private const MemoryPropertyFlags DeviceLocalBufferMemoryFlags =
|
||||||
MemoryPropertyFlags.MemoryPropertyDeviceLocalBit;
|
MemoryPropertyFlags.DeviceLocalBit;
|
||||||
|
|
||||||
private const MemoryPropertyFlags FlushableDeviceLocalBufferMemoryFlags =
|
private const MemoryPropertyFlags FlushableDeviceLocalBufferMemoryFlags =
|
||||||
MemoryPropertyFlags.MemoryPropertyHostVisibleBit |
|
MemoryPropertyFlags.HostVisibleBit |
|
||||||
MemoryPropertyFlags.MemoryPropertyHostCoherentBit |
|
MemoryPropertyFlags.HostCoherentBit |
|
||||||
MemoryPropertyFlags.MemoryPropertyDeviceLocalBit;
|
MemoryPropertyFlags.DeviceLocalBit;
|
||||||
|
|
||||||
private const BufferUsageFlags DefaultBufferUsageFlags =
|
private const BufferUsageFlags DefaultBufferUsageFlags =
|
||||||
BufferUsageFlags.BufferUsageTransferSrcBit |
|
BufferUsageFlags.TransferSrcBit |
|
||||||
BufferUsageFlags.BufferUsageTransferDstBit |
|
BufferUsageFlags.TransferDstBit |
|
||||||
BufferUsageFlags.BufferUsageUniformTexelBufferBit |
|
BufferUsageFlags.UniformTexelBufferBit |
|
||||||
BufferUsageFlags.BufferUsageStorageTexelBufferBit |
|
BufferUsageFlags.StorageTexelBufferBit |
|
||||||
BufferUsageFlags.BufferUsageUniformBufferBit |
|
BufferUsageFlags.UniformBufferBit |
|
||||||
BufferUsageFlags.BufferUsageStorageBufferBit |
|
BufferUsageFlags.StorageBufferBit |
|
||||||
BufferUsageFlags.BufferUsageIndexBufferBit |
|
BufferUsageFlags.IndexBufferBit |
|
||||||
BufferUsageFlags.BufferUsageVertexBufferBit |
|
BufferUsageFlags.VertexBufferBit |
|
||||||
BufferUsageFlags.BufferUsageTransformFeedbackBufferBitExt;
|
BufferUsageFlags.TransformFeedbackBufferBitExt;
|
||||||
|
|
||||||
private readonly PhysicalDevice _physicalDevice;
|
private readonly PhysicalDevice _physicalDevice;
|
||||||
private readonly Device _device;
|
private readonly Device _device;
|
||||||
@@ -76,11 +76,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
if (forConditionalRendering && gd.Capabilities.SupportsConditionalRendering)
|
if (forConditionalRendering && gd.Capabilities.SupportsConditionalRendering)
|
||||||
{
|
{
|
||||||
usage |= BufferUsageFlags.BufferUsageConditionalRenderingBitExt;
|
usage |= BufferUsageFlags.ConditionalRenderingBitExt;
|
||||||
}
|
}
|
||||||
else if (gd.Capabilities.SupportsIndirectParameters)
|
else if (gd.Capabilities.SupportsIndirectParameters)
|
||||||
{
|
{
|
||||||
usage |= BufferUsageFlags.BufferUsageIndirectBufferBit;
|
usage |= BufferUsageFlags.IndirectBufferBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bufferCreateInfo = new BufferCreateInfo()
|
var bufferCreateInfo = new BufferCreateInfo()
|
||||||
|
@@ -71,8 +71,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
SType = StructureType.CommandPoolCreateInfo,
|
SType = StructureType.CommandPoolCreateInfo,
|
||||||
QueueFamilyIndex = queueFamilyIndex,
|
QueueFamilyIndex = queueFamilyIndex,
|
||||||
Flags = CommandPoolCreateFlags.CommandPoolCreateTransientBit |
|
Flags = CommandPoolCreateFlags.TransientBit |
|
||||||
CommandPoolCreateFlags.CommandPoolCreateResetCommandBufferBit
|
CommandPoolCreateFlags.ResetCommandBufferBit
|
||||||
};
|
};
|
||||||
|
|
||||||
api.CreateCommandPool(device, commandPoolCreateInfo, null, out _pool).ThrowOnError();
|
api.CreateCommandPool(device, commandPoolCreateInfo, null, out _pool).ThrowOnError();
|
||||||
|
@@ -229,7 +229,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
else if (texture is TextureView view)
|
else if (texture is TextureView view)
|
||||||
{
|
{
|
||||||
view.Storage.InsertBarrier(cbs, AccessFlags.AccessShaderReadBit, stage.ConvertToPipelineStageFlags());
|
view.Storage.InsertBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
||||||
|
|
||||||
_textureRefs[binding] = view.GetImageView();
|
_textureRefs[binding] = view.GetImageView();
|
||||||
_samplerRefs[binding] = ((SamplerHolder)sampler)?.GetSampler();
|
_samplerRefs[binding] = ((SamplerHolder)sampler)?.GetSampler();
|
||||||
|
@@ -12,12 +12,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
return stage switch
|
return stage switch
|
||||||
{
|
{
|
||||||
ShaderStage.Vertex => ShaderStageFlags.ShaderStageVertexBit,
|
ShaderStage.Vertex => ShaderStageFlags.VertexBit,
|
||||||
ShaderStage.Geometry => ShaderStageFlags.ShaderStageGeometryBit,
|
ShaderStage.Geometry => ShaderStageFlags.GeometryBit,
|
||||||
ShaderStage.TessellationControl => ShaderStageFlags.ShaderStageTessellationControlBit,
|
ShaderStage.TessellationControl => ShaderStageFlags.TessellationControlBit,
|
||||||
ShaderStage.TessellationEvaluation => ShaderStageFlags.ShaderStageTessellationEvaluationBit,
|
ShaderStage.TessellationEvaluation => ShaderStageFlags.TessellationEvaluationBit,
|
||||||
ShaderStage.Fragment => ShaderStageFlags.ShaderStageFragmentBit,
|
ShaderStage.Fragment => ShaderStageFlags.FragmentBit,
|
||||||
ShaderStage.Compute => ShaderStageFlags.ShaderStageComputeBit,
|
ShaderStage.Compute => ShaderStageFlags.ComputeBit,
|
||||||
_ => LogInvalidAndReturn(stage, nameof(ShaderStage), (ShaderStageFlags)0)
|
_ => LogInvalidAndReturn(stage, nameof(ShaderStage), (ShaderStageFlags)0)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -26,12 +26,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
return stage switch
|
return stage switch
|
||||||
{
|
{
|
||||||
ShaderStage.Vertex => PipelineStageFlags.PipelineStageVertexShaderBit,
|
ShaderStage.Vertex => PipelineStageFlags.VertexShaderBit,
|
||||||
ShaderStage.Geometry => PipelineStageFlags.PipelineStageGeometryShaderBit,
|
ShaderStage.Geometry => PipelineStageFlags.GeometryShaderBit,
|
||||||
ShaderStage.TessellationControl => PipelineStageFlags.PipelineStageTessellationControlShaderBit,
|
ShaderStage.TessellationControl => PipelineStageFlags.TessellationControlShaderBit,
|
||||||
ShaderStage.TessellationEvaluation => PipelineStageFlags.PipelineStageTessellationEvaluationShaderBit,
|
ShaderStage.TessellationEvaluation => PipelineStageFlags.TessellationEvaluationShaderBit,
|
||||||
ShaderStage.Fragment => PipelineStageFlags.PipelineStageFragmentShaderBit,
|
ShaderStage.Fragment => PipelineStageFlags.FragmentShaderBit,
|
||||||
ShaderStage.Compute => PipelineStageFlags.PipelineStageComputeShaderBit,
|
ShaderStage.Compute => PipelineStageFlags.ComputeShaderBit,
|
||||||
_ => LogInvalidAndReturn(stage, nameof(ShaderStage), (PipelineStageFlags)0)
|
_ => LogInvalidAndReturn(stage, nameof(ShaderStage), (PipelineStageFlags)0)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -112,10 +112,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
return face switch
|
return face switch
|
||||||
{
|
{
|
||||||
Face.Back => CullModeFlags.CullModeBackBit,
|
Face.Back => CullModeFlags.BackBit,
|
||||||
Face.Front => CullModeFlags.CullModeFrontBit,
|
Face.Front => CullModeFlags.FrontBit,
|
||||||
Face.FrontAndBack => CullModeFlags.CullModeFrontAndBack,
|
Face.FrontAndBack => CullModeFlags.FrontAndBack,
|
||||||
_ => LogInvalidAndReturn(face, nameof(Face), CullModeFlags.CullModeBackBit)
|
_ => LogInvalidAndReturn(face, nameof(Face), CullModeFlags.BackBit)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,6 +180,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
GAL.PrimitiveTopology.TrianglesAdjacency => Silk.NET.Vulkan.PrimitiveTopology.TriangleListWithAdjacency,
|
GAL.PrimitiveTopology.TrianglesAdjacency => Silk.NET.Vulkan.PrimitiveTopology.TriangleListWithAdjacency,
|
||||||
GAL.PrimitiveTopology.TriangleStripAdjacency => Silk.NET.Vulkan.PrimitiveTopology.TriangleStripWithAdjacency,
|
GAL.PrimitiveTopology.TriangleStripAdjacency => Silk.NET.Vulkan.PrimitiveTopology.TriangleStripWithAdjacency,
|
||||||
GAL.PrimitiveTopology.Patches => Silk.NET.Vulkan.PrimitiveTopology.PatchList,
|
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.Quads => throw new NotSupportedException("Quad topology is not available in Vulkan."),
|
||||||
GAL.PrimitiveTopology.QuadStrip => throw new NotSupportedException("QuadStrip 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)
|
_ => LogInvalidAndReturn(topology, nameof(GAL.PrimitiveTopology), Silk.NET.Vulkan.PrimitiveTopology.TriangleList)
|
||||||
@@ -222,14 +223,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
Target.Texture1D or
|
Target.Texture1D or
|
||||||
Target.Texture1DArray or
|
Target.Texture1DArray or
|
||||||
Target.TextureBuffer => ImageType.ImageType1D,
|
Target.TextureBuffer => ImageType.Type1D,
|
||||||
Target.Texture2D or
|
Target.Texture2D or
|
||||||
Target.Texture2DArray or
|
Target.Texture2DArray or
|
||||||
Target.Texture2DMultisample or
|
Target.Texture2DMultisample or
|
||||||
Target.Cubemap or
|
Target.Cubemap or
|
||||||
Target.CubemapArray => ImageType.ImageType2D,
|
Target.CubemapArray => ImageType.Type2D,
|
||||||
Target.Texture3D => ImageType.ImageType3D,
|
Target.Texture3D => ImageType.Type3D,
|
||||||
_ => LogInvalidAndReturn(target, nameof(Target), ImageType.ImageType2D)
|
_ => LogInvalidAndReturn(target, nameof(Target), ImageType.Type2D)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,14 +238,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
return target switch
|
return target switch
|
||||||
{
|
{
|
||||||
Target.Texture1D => ImageViewType.ImageViewType1D,
|
Target.Texture1D => ImageViewType.Type1D,
|
||||||
Target.Texture2D or Target.Texture2DMultisample => ImageViewType.ImageViewType2D,
|
Target.Texture2D or Target.Texture2DMultisample => ImageViewType.Type2D,
|
||||||
Target.Texture3D => ImageViewType.ImageViewType3D,
|
Target.Texture3D => ImageViewType.Type3D,
|
||||||
Target.Texture1DArray => ImageViewType.ImageViewType1DArray,
|
Target.Texture1DArray => ImageViewType.Type1DArray,
|
||||||
Target.Texture2DArray => ImageViewType.ImageViewType2DArray,
|
Target.Texture2DArray => ImageViewType.Type2DArray,
|
||||||
Target.Cubemap => ImageViewType.Cube,
|
Target.Cubemap => ImageViewType.TypeCube,
|
||||||
Target.CubemapArray => ImageViewType.CubeArray,
|
Target.CubemapArray => ImageViewType.TypeCubeArray,
|
||||||
_ => LogInvalidAndReturn(target, nameof(Target), ImageViewType.ImageViewType2D)
|
_ => LogInvalidAndReturn(target, nameof(Target), ImageViewType.Type2D)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,12 +253,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
return format switch
|
return format switch
|
||||||
{
|
{
|
||||||
GAL.Format.D16Unorm or GAL.Format.D32Float => ImageAspectFlags.ImageAspectDepthBit,
|
GAL.Format.D16Unorm or GAL.Format.D32Float => ImageAspectFlags.DepthBit,
|
||||||
GAL.Format.S8Uint => ImageAspectFlags.ImageAspectStencilBit,
|
GAL.Format.S8Uint => ImageAspectFlags.StencilBit,
|
||||||
GAL.Format.D24UnormS8Uint or
|
GAL.Format.D24UnormS8Uint or
|
||||||
GAL.Format.D32FloatS8Uint or
|
GAL.Format.D32FloatS8Uint or
|
||||||
GAL.Format.S8UintD24Unorm => ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit,
|
GAL.Format.S8UintD24Unorm => ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit,
|
||||||
_ => ImageAspectFlags.ImageAspectColorBit
|
_ => ImageAspectFlags.ColorBit
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,12 +266,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
return format switch
|
return format switch
|
||||||
{
|
{
|
||||||
GAL.Format.D16Unorm or GAL.Format.D32Float => ImageAspectFlags.ImageAspectDepthBit,
|
GAL.Format.D16Unorm or GAL.Format.D32Float => ImageAspectFlags.DepthBit,
|
||||||
GAL.Format.S8Uint => ImageAspectFlags.ImageAspectStencilBit,
|
GAL.Format.S8Uint => ImageAspectFlags.StencilBit,
|
||||||
GAL.Format.D24UnormS8Uint or
|
GAL.Format.D24UnormS8Uint or
|
||||||
GAL.Format.D32FloatS8Uint or
|
GAL.Format.D32FloatS8Uint or
|
||||||
GAL.Format.S8UintD24Unorm => depthStencilMode == DepthStencilMode.Stencil ? ImageAspectFlags.ImageAspectStencilBit : ImageAspectFlags.ImageAspectDepthBit,
|
GAL.Format.S8UintD24Unorm => depthStencilMode == DepthStencilMode.Stencil ? ImageAspectFlags.StencilBit : ImageAspectFlags.DepthBit,
|
||||||
_ => ImageAspectFlags.ImageAspectColorBit
|
_ => ImageAspectFlags.ColorBit
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -83,22 +83,22 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
var format = FormatTable.GetFormat(srcFormat);
|
var format = FormatTable.GetFormat(srcFormat);
|
||||||
|
|
||||||
var requiredFeatures = FormatFeatureFlags.FormatFeatureSampledImageBit |
|
var requiredFeatures = FormatFeatureFlags.SampledImageBit |
|
||||||
FormatFeatureFlags.FormatFeatureTransferSrcBit |
|
FormatFeatureFlags.TransferSrcBit |
|
||||||
FormatFeatureFlags.FormatFeatureTransferDstBit;
|
FormatFeatureFlags.TransferDstBit;
|
||||||
|
|
||||||
if (srcFormat.IsDepthOrStencil())
|
if (srcFormat.IsDepthOrStencil())
|
||||||
{
|
{
|
||||||
requiredFeatures |= FormatFeatureFlags.FormatFeatureDepthStencilAttachmentBit;
|
requiredFeatures |= FormatFeatureFlags.DepthStencilAttachmentBit;
|
||||||
}
|
}
|
||||||
else if (srcFormat.IsRtColorCompatible())
|
else if (srcFormat.IsRtColorCompatible())
|
||||||
{
|
{
|
||||||
requiredFeatures |= FormatFeatureFlags.FormatFeatureColorAttachmentBit;
|
requiredFeatures |= FormatFeatureFlags.ColorAttachmentBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (srcFormat.IsImageCompatible())
|
if (srcFormat.IsImageCompatible())
|
||||||
{
|
{
|
||||||
requiredFeatures |= FormatFeatureFlags.FormatFeatureStorageImageBit;
|
requiredFeatures |= FormatFeatureFlags.StorageImageBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!OptimalFormatSupports(requiredFeatures, srcFormat) || (IsD24S8(srcFormat) && VulkanConfiguration.ForceD24S8Unsupported))
|
if (!OptimalFormatSupports(requiredFeatures, srcFormat) || (IsD24S8(srcFormat) && VulkanConfiguration.ForceD24S8Unsupported))
|
||||||
@@ -125,7 +125,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
var format = FormatTable.GetFormat(srcFormat);
|
var format = FormatTable.GetFormat(srcFormat);
|
||||||
|
|
||||||
if (!BufferFormatSupports(FormatFeatureFlags.FormatFeatureVertexBufferBit, srcFormat) ||
|
if (!BufferFormatSupports(FormatFeatureFlags.VertexBufferBit, srcFormat) ||
|
||||||
(IsRGB16IntFloat(srcFormat) && VulkanConfiguration.ForceRGB16IntFloatUnsupported))
|
(IsRGB16IntFloat(srcFormat) && VulkanConfiguration.ForceRGB16IntFloatUnsupported))
|
||||||
{
|
{
|
||||||
// The format is not supported. Can we convert it to an alternative format?
|
// The format is not supported. Can we convert it to an alternative format?
|
||||||
|
@@ -190,14 +190,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
for (int index = 0; index < _colors.Length; index++)
|
for (int index = 0; index < _colors.Length; index++)
|
||||||
{
|
{
|
||||||
_colors[index].Storage.SetModification(
|
_colors[index].Storage.SetModification(
|
||||||
AccessFlags.AccessColorAttachmentWriteBit,
|
AccessFlags.ColorAttachmentWriteBit,
|
||||||
PipelineStageFlags.PipelineStageColorAttachmentOutputBit);
|
PipelineStageFlags.ColorAttachmentOutputBit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_depthStencil?.Storage.SetModification(
|
_depthStencil?.Storage.SetModification(
|
||||||
AccessFlags.AccessDepthStencilAttachmentWriteBit,
|
AccessFlags.DepthStencilAttachmentWriteBit,
|
||||||
PipelineStageFlags.PipelineStageColorAttachmentOutputBit);
|
PipelineStageFlags.ColorAttachmentOutputBit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -349,8 +349,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
var srcBuffer = srcBufferAuto.Get(cbs, srcOffset, size).Value;
|
var srcBuffer = srcBufferAuto.Get(cbs, srcOffset, size).Value;
|
||||||
var dstBuffer = dstBufferAuto.Get(cbs, 0, newSize).Value;
|
var dstBuffer = dstBufferAuto.Get(cbs, 0, newSize).Value;
|
||||||
|
|
||||||
var access = supportsUint8 ? AccessFlags.AccessShaderWriteBit : AccessFlags.AccessTransferWriteBit;
|
var access = supportsUint8 ? AccessFlags.ShaderWriteBit : AccessFlags.TransferWriteBit;
|
||||||
var stage = supportsUint8 ? PipelineStageFlags.PipelineStageComputeShaderBit : PipelineStageFlags.PipelineStageTransferBit;
|
var stage = supportsUint8 ? PipelineStageFlags.ComputeShaderBit : PipelineStageFlags.TransferBit;
|
||||||
|
|
||||||
BufferHolder.InsertBufferBarrier(
|
BufferHolder.InsertBufferBarrier(
|
||||||
gd,
|
gd,
|
||||||
@@ -358,7 +358,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
dstBuffer,
|
dstBuffer,
|
||||||
BufferHolder.DefaultAccessFlags,
|
BufferHolder.DefaultAccessFlags,
|
||||||
access,
|
access,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
stage,
|
stage,
|
||||||
0,
|
0,
|
||||||
newSize);
|
newSize);
|
||||||
@@ -420,7 +420,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
access,
|
access,
|
||||||
BufferHolder.DefaultAccessFlags,
|
BufferHolder.DefaultAccessFlags,
|
||||||
stage,
|
stage,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
0,
|
0,
|
||||||
newSize);
|
newSize);
|
||||||
}
|
}
|
||||||
@@ -484,9 +484,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
BufferHolder.DefaultAccessFlags,
|
BufferHolder.DefaultAccessFlags,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
0,
|
0,
|
||||||
convertedCount * outputIndexSize);
|
convertedCount * outputIndexSize);
|
||||||
|
|
||||||
@@ -499,10 +499,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
gd,
|
gd,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
BufferHolder.DefaultAccessFlags,
|
BufferHolder.DefaultAccessFlags,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
0,
|
0,
|
||||||
convertedCount * outputIndexSize);
|
convertedCount * outputIndexSize);
|
||||||
}
|
}
|
||||||
@@ -548,10 +548,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
src.GetImage().Get(cbs).Value,
|
src.GetImage().Get(cbs).Value,
|
||||||
TextureStorage.DefaultAccessMask,
|
TextureStorage.DefaultAccessMask,
|
||||||
AccessFlags.AccessShaderReadBit,
|
AccessFlags.ShaderReadBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
PipelineStageFlags.PipelineStageComputeShaderBit,
|
PipelineStageFlags.ComputeShaderBit,
|
||||||
ImageAspectFlags.ImageAspectColorBit,
|
ImageAspectFlags.ColorBit,
|
||||||
src.FirstLayer + srcLayer,
|
src.FirstLayer + srcLayer,
|
||||||
src.FirstLevel,
|
src.FirstLevel,
|
||||||
depth,
|
depth,
|
||||||
@@ -610,11 +610,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
gd.Api,
|
gd.Api,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dst.GetImage().Get(cbs).Value,
|
dst.GetImage().Get(cbs).Value,
|
||||||
AccessFlags.AccessShaderWriteBit,
|
AccessFlags.ShaderWriteBit,
|
||||||
TextureStorage.DefaultAccessMask,
|
TextureStorage.DefaultAccessMask,
|
||||||
PipelineStageFlags.PipelineStageComputeShaderBit,
|
PipelineStageFlags.ComputeShaderBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
ImageAspectFlags.ImageAspectColorBit,
|
ImageAspectFlags.ColorBit,
|
||||||
dst.FirstLayer + dstLayer,
|
dst.FirstLayer + dstLayer,
|
||||||
dst.FirstLevel,
|
dst.FirstLevel,
|
||||||
depth,
|
depth,
|
||||||
@@ -770,9 +770,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
srcIndirectBuffer.GetBuffer().Get(cbs, srcIndirectBufferOffset, indirectDataSize).Value,
|
srcIndirectBuffer.GetBuffer().Get(cbs, srcIndirectBufferOffset, indirectDataSize).Value,
|
||||||
BufferHolder.DefaultAccessFlags,
|
BufferHolder.DefaultAccessFlags,
|
||||||
AccessFlags.AccessShaderReadBit,
|
AccessFlags.ShaderReadBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
PipelineStageFlags.PipelineStageComputeShaderBit,
|
PipelineStageFlags.ComputeShaderBit,
|
||||||
srcIndirectBufferOffset,
|
srcIndirectBufferOffset,
|
||||||
indirectDataSize);
|
indirectDataSize);
|
||||||
|
|
||||||
@@ -786,10 +786,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
gd,
|
gd,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
patternBufferAuto.Get(cbs, ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize).Value,
|
patternBufferAuto.Get(cbs, ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize).Value,
|
||||||
AccessFlags.AccessShaderWriteBit,
|
AccessFlags.ShaderWriteBit,
|
||||||
AccessFlags.AccessIndirectCommandReadBit,
|
AccessFlags.IndirectCommandReadBit,
|
||||||
PipelineStageFlags.PipelineStageComputeShaderBit,
|
PipelineStageFlags.ComputeShaderBit,
|
||||||
PipelineStageFlags.PipelineStageDrawIndirectBit,
|
PipelineStageFlags.DrawIndirectBit,
|
||||||
ParamsIndirectDispatchOffset,
|
ParamsIndirectDispatchOffset,
|
||||||
ParamsIndirectDispatchSize);
|
ParamsIndirectDispatchSize);
|
||||||
|
|
||||||
@@ -798,9 +798,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
BufferHolder.DefaultAccessFlags,
|
BufferHolder.DefaultAccessFlags,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
0,
|
0,
|
||||||
convertedCount * outputIndexSize);
|
convertedCount * outputIndexSize);
|
||||||
|
|
||||||
@@ -814,10 +814,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
gd,
|
gd,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
BufferHolder.DefaultAccessFlags,
|
BufferHolder.DefaultAccessFlags,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
0,
|
0,
|
||||||
convertedCount * outputIndexSize);
|
convertedCount * outputIndexSize);
|
||||||
|
|
||||||
|
@@ -33,7 +33,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool map = flags.HasFlag(MemoryPropertyFlags.MemoryPropertyHostVisibleBit);
|
bool map = flags.HasFlag(MemoryPropertyFlags.HostVisibleBit);
|
||||||
return Allocate(memoryTypeIndex, requirements.Size, requirements.Alignment, map);
|
return Allocate(memoryTypeIndex, requirements.Size, requirements.Alignment, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -128,14 +128,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
MemoryBarrier memoryBarrier = new MemoryBarrier()
|
MemoryBarrier memoryBarrier = new MemoryBarrier()
|
||||||
{
|
{
|
||||||
SType = StructureType.MemoryBarrier,
|
SType = StructureType.MemoryBarrier,
|
||||||
SrcAccessMask = AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit,
|
SrcAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit,
|
||||||
DstAccessMask = AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit
|
DstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit
|
||||||
};
|
};
|
||||||
|
|
||||||
Gd.Api.CmdPipelineBarrier(
|
Gd.Api.CmdPipelineBarrier(
|
||||||
CommandBuffer,
|
CommandBuffer,
|
||||||
PipelineStageFlags.PipelineStageFragmentShaderBit,
|
PipelineStageFlags.FragmentShaderBit,
|
||||||
PipelineStageFlags.PipelineStageFragmentShaderBit,
|
PipelineStageFlags.FragmentShaderBit,
|
||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
memoryBarrier,
|
memoryBarrier,
|
||||||
@@ -161,9 +161,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Cbs.CommandBuffer,
|
Cbs.CommandBuffer,
|
||||||
dst,
|
dst,
|
||||||
BufferHolder.DefaultAccessFlags,
|
BufferHolder.DefaultAccessFlags,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
offset,
|
offset,
|
||||||
size);
|
size);
|
||||||
|
|
||||||
@@ -173,10 +173,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Gd,
|
Gd,
|
||||||
Cbs.CommandBuffer,
|
Cbs.CommandBuffer,
|
||||||
dst,
|
dst,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
BufferHolder.DefaultAccessFlags,
|
BufferHolder.DefaultAccessFlags,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
offset,
|
offset,
|
||||||
size);
|
size);
|
||||||
}
|
}
|
||||||
@@ -196,7 +196,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
BeginRenderPass();
|
BeginRenderPass();
|
||||||
|
|
||||||
var clearValue = new ClearValue(new ClearColorValue(color.Red, color.Green, color.Blue, color.Alpha));
|
var clearValue = new ClearValue(new ClearColorValue(color.Red, color.Green, color.Blue, color.Alpha));
|
||||||
var attachment = new ClearAttachment(ImageAspectFlags.ImageAspectColorBit, (uint)index, clearValue);
|
var attachment = new ClearAttachment(ImageAspectFlags.ColorBit, (uint)index, clearValue);
|
||||||
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
|
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
|
||||||
|
|
||||||
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
|
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
|
||||||
@@ -219,11 +219,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
BeginRenderPass();
|
BeginRenderPass();
|
||||||
|
|
||||||
var clearValue = new ClearValue(null, new ClearDepthStencilValue(depthValue, (uint)stencilValue));
|
var clearValue = new ClearValue(null, new ClearDepthStencilValue(depthValue, (uint)stencilValue));
|
||||||
var flags = depthMask ? ImageAspectFlags.ImageAspectDepthBit : 0;
|
var flags = depthMask ? ImageAspectFlags.DepthBit : 0;
|
||||||
|
|
||||||
if (stencilMask != 0)
|
if (stencilMask != 0)
|
||||||
{
|
{
|
||||||
flags |= ImageAspectFlags.ImageAspectStencilBit;
|
flags |= ImageAspectFlags.StencilBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
var attachment = new ClearAttachment(flags, 0, clearValue);
|
var attachment = new ClearAttachment(flags, 0, clearValue);
|
||||||
@@ -238,13 +238,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
SType = StructureType.MemoryBarrier,
|
SType = StructureType.MemoryBarrier,
|
||||||
SrcAccessMask = BufferHolder.DefaultAccessFlags,
|
SrcAccessMask = BufferHolder.DefaultAccessFlags,
|
||||||
DstAccessMask = AccessFlags.AccessIndirectCommandReadBit
|
DstAccessMask = AccessFlags.IndirectCommandReadBit
|
||||||
};
|
};
|
||||||
|
|
||||||
Gd.Api.CmdPipelineBarrier(
|
Gd.Api.CmdPipelineBarrier(
|
||||||
CommandBuffer,
|
CommandBuffer,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
PipelineStageFlags.PipelineStageDrawIndirectBit,
|
PipelineStageFlags.DrawIndirectBit,
|
||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
memoryBarrier,
|
memoryBarrier,
|
||||||
@@ -328,7 +328,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
IndexBufferPattern pattern = _topology switch
|
IndexBufferPattern pattern = _topology switch
|
||||||
{
|
{
|
||||||
GAL.PrimitiveTopology.Quads => QuadsToTrisPattern,
|
GAL.PrimitiveTopology.Quads => QuadsToTrisPattern,
|
||||||
GAL.PrimitiveTopology.TriangleFan => TriFanToTrisPattern,
|
GAL.PrimitiveTopology.TriangleFan or
|
||||||
|
GAL.PrimitiveTopology.Polygon => TriFanToTrisPattern,
|
||||||
_ => throw new NotSupportedException($"Unsupported topology: {_topology}")
|
_ => throw new NotSupportedException($"Unsupported topology: {_topology}")
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -359,7 +360,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
pattern = _topology switch
|
pattern = _topology switch
|
||||||
{
|
{
|
||||||
GAL.PrimitiveTopology.Quads => QuadsToTrisPattern,
|
GAL.PrimitiveTopology.Quads => QuadsToTrisPattern,
|
||||||
GAL.PrimitiveTopology.TriangleFan => TriFanToTrisPattern,
|
GAL.PrimitiveTopology.TriangleFan or
|
||||||
|
GAL.PrimitiveTopology.Polygon => TriFanToTrisPattern,
|
||||||
_ => throw new NotSupportedException($"Unsupported topology: {_topology}")
|
_ => throw new NotSupportedException($"Unsupported topology: {_topology}")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -622,7 +624,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
var oldViewports = DynamicState.Viewports;
|
var oldViewports = DynamicState.Viewports;
|
||||||
var oldViewportsCount = _newState.ViewportsCount;
|
var oldViewportsCount = _newState.ViewportsCount;
|
||||||
|
|
||||||
_newState.CullMode = CullModeFlags.CullModeNone;
|
_newState.CullMode = CullModeFlags.None;
|
||||||
_newState.StencilTestEnable = false;
|
_newState.StencilTestEnable = false;
|
||||||
_newState.DepthTestEnable = false;
|
_newState.DepthTestEnable = false;
|
||||||
_newState.DepthWriteEnable = false;
|
_newState.DepthWriteEnable = false;
|
||||||
@@ -735,7 +737,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public void SetFaceCulling(bool enable, Face face)
|
public void SetFaceCulling(bool enable, Face face)
|
||||||
{
|
{
|
||||||
_newState.CullMode = enable ? face.Convert() : CullModeFlags.CullModeNone;
|
_newState.CullMode = enable ? face.Convert() : CullModeFlags.None;
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1198,14 +1200,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
MemoryBarrier memoryBarrier = new MemoryBarrier()
|
MemoryBarrier memoryBarrier = new MemoryBarrier()
|
||||||
{
|
{
|
||||||
SType = StructureType.MemoryBarrier,
|
SType = StructureType.MemoryBarrier,
|
||||||
SrcAccessMask = AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit,
|
SrcAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit,
|
||||||
DstAccessMask = AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit
|
DstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit
|
||||||
};
|
};
|
||||||
|
|
||||||
Gd.Api.CmdPipelineBarrier(
|
Gd.Api.CmdPipelineBarrier(
|
||||||
CommandBuffer,
|
CommandBuffer,
|
||||||
PipelineStageFlags.PipelineStageFragmentShaderBit,
|
PipelineStageFlags.FragmentShaderBit,
|
||||||
PipelineStageFlags.PipelineStageFragmentShaderBit,
|
PipelineStageFlags.FragmentShaderBit,
|
||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
memoryBarrier,
|
memoryBarrier,
|
||||||
|
@@ -6,8 +6,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
static class PipelineConverter
|
static class PipelineConverter
|
||||||
{
|
{
|
||||||
private const AccessFlags SubpassSrcAccessMask = AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit | AccessFlags.AccessColorAttachmentWriteBit;
|
private const AccessFlags SubpassSrcAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit | AccessFlags.ColorAttachmentWriteBit;
|
||||||
private const AccessFlags SubpassDstAccessMask = AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit | AccessFlags.AccessShaderReadBit;
|
private const AccessFlags SubpassDstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit | AccessFlags.ShaderReadBit;
|
||||||
|
|
||||||
public static unsafe DisposableRenderPass ToRenderPass(this ProgramPipelineState state, VulkanRenderer gd, Device device)
|
public static unsafe DisposableRenderPass ToRenderPass(this ProgramPipelineState state, VulkanRenderer gd, Device device)
|
||||||
{
|
{
|
||||||
@@ -129,8 +129,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return new SubpassDependency(
|
return new SubpassDependency(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
PipelineStageFlags.PipelineStageAllGraphicsBit,
|
PipelineStageFlags.AllGraphicsBit,
|
||||||
PipelineStageFlags.PipelineStageAllGraphicsBit,
|
PipelineStageFlags.AllGraphicsBit,
|
||||||
SubpassSrcAccessMask,
|
SubpassSrcAccessMask,
|
||||||
SubpassDstAccessMask,
|
SubpassDstAccessMask,
|
||||||
0);
|
0);
|
||||||
@@ -143,8 +143,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
null,
|
null,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
PipelineStageFlags.PipelineStageAllGraphicsBit,
|
PipelineStageFlags.AllGraphicsBit,
|
||||||
PipelineStageFlags.PipelineStageAllGraphicsBit,
|
PipelineStageFlags.AllGraphicsBit,
|
||||||
SubpassSrcAccessMask,
|
SubpassSrcAccessMask,
|
||||||
SubpassDstAccessMask,
|
SubpassDstAccessMask,
|
||||||
0);
|
0);
|
||||||
@@ -157,7 +157,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
// It is assumed that Dynamic State is enabled when this conversion is used.
|
// It is assumed that Dynamic State is enabled when this conversion is used.
|
||||||
|
|
||||||
pipeline.CullMode = state.CullEnable ? state.CullMode.Convert() : CullModeFlags.CullModeNone;
|
pipeline.CullMode = state.CullEnable ? state.CullMode.Convert() : CullModeFlags.None;
|
||||||
|
|
||||||
pipeline.DepthBoundsTestEnable = false; // Not implemented.
|
pipeline.DepthBoundsTestEnable = false; // Not implemented.
|
||||||
|
|
||||||
|
@@ -145,12 +145,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private void RecordStencilMasks(Vk api, CommandBuffer commandBuffer)
|
private void RecordStencilMasks(Vk api, CommandBuffer commandBuffer)
|
||||||
{
|
{
|
||||||
api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.StencilFaceBackBit, _backCompareMask);
|
api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backCompareMask);
|
||||||
api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.StencilFaceBackBit, _backWriteMask);
|
api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backWriteMask);
|
||||||
api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.StencilFaceBackBit, _backReference);
|
api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.FaceBackBit, _backReference);
|
||||||
api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.StencilFaceFrontBit, _frontCompareMask);
|
api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontCompareMask);
|
||||||
api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.StencilFaceFrontBit, _frontWriteMask);
|
api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontWriteMask);
|
||||||
api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.StencilFaceFrontBit, _frontReference);
|
api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RecordViewport(Vk api, CommandBuffer commandBuffer)
|
private void RecordViewport(Vk api, CommandBuffer commandBuffer)
|
||||||
|
@@ -125,7 +125,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
if (Gd.Capabilities.SupportsConditionalRendering)
|
if (Gd.Capabilities.SupportsConditionalRendering)
|
||||||
{
|
{
|
||||||
var buffer = evt.GetBuffer().Get(Cbs, 0, sizeof(long)).Value;
|
var buffer = evt.GetBuffer().Get(Cbs, 0, sizeof(long)).Value;
|
||||||
var flags = isEqual ? ConditionalRenderingFlagsEXT.ConditionalRenderingInvertedBitExt : 0;
|
var flags = isEqual ? ConditionalRenderingFlagsEXT.InvertedBitExt : 0;
|
||||||
|
|
||||||
var conditionalRenderingBeginInfo = new ConditionalRenderingBeginInfoEXT()
|
var conditionalRenderingBeginInfo = new ConditionalRenderingBeginInfoEXT()
|
||||||
{
|
{
|
||||||
|
@@ -8,9 +8,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
static class PipelineLayoutFactory
|
static class PipelineLayoutFactory
|
||||||
{
|
{
|
||||||
private const ShaderStageFlags SupportBufferStages =
|
private const ShaderStageFlags SupportBufferStages =
|
||||||
ShaderStageFlags.ShaderStageVertexBit |
|
ShaderStageFlags.VertexBit |
|
||||||
ShaderStageFlags.ShaderStageFragmentBit |
|
ShaderStageFlags.FragmentBit |
|
||||||
ShaderStageFlags.ShaderStageComputeBit;
|
ShaderStageFlags.ComputeBit;
|
||||||
|
|
||||||
public static unsafe DescriptorSetLayout[] Create(VulkanRenderer gd, Device device, uint stages, bool usePd, out PipelineLayout layout)
|
public static unsafe DescriptorSetLayout[] Create(VulkanRenderer gd, Device device, uint stages, bool usePd, out PipelineLayout layout)
|
||||||
{
|
{
|
||||||
@@ -42,11 +42,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
var stageFlags = stage switch
|
var stageFlags = stage switch
|
||||||
{
|
{
|
||||||
1 => ShaderStageFlags.ShaderStageFragmentBit,
|
1 => ShaderStageFlags.FragmentBit,
|
||||||
2 => ShaderStageFlags.ShaderStageGeometryBit,
|
2 => ShaderStageFlags.GeometryBit,
|
||||||
3 => ShaderStageFlags.ShaderStageTessellationControlBit,
|
3 => ShaderStageFlags.TessellationControlBit,
|
||||||
4 => ShaderStageFlags.ShaderStageTessellationEvaluationBit,
|
4 => ShaderStageFlags.TessellationEvaluationBit,
|
||||||
_ => ShaderStageFlags.ShaderStageVertexBit | ShaderStageFlags.ShaderStageComputeBit
|
_ => ShaderStageFlags.VertexBit | ShaderStageFlags.ComputeBit
|
||||||
};
|
};
|
||||||
|
|
||||||
void Set(DescriptorSetLayoutBinding* bindings, int maxPerStage, DescriptorType type, int start, int skip)
|
void Set(DescriptorSetLayoutBinding* bindings, int maxPerStage, DescriptorType type, int start, int skip)
|
||||||
@@ -93,7 +93,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
SType = StructureType.DescriptorSetLayoutCreateInfo,
|
SType = StructureType.DescriptorSetLayoutCreateInfo,
|
||||||
PBindings = uLayoutBindings,
|
PBindings = uLayoutBindings,
|
||||||
BindingCount = (uint)uCount,
|
BindingCount = (uint)uCount,
|
||||||
Flags = usePd ? DescriptorSetLayoutCreateFlags.DescriptorSetLayoutCreatePushDescriptorBitKhr : 0
|
Flags = usePd ? DescriptorSetLayoutCreateFlags.PushDescriptorBitKhr : 0
|
||||||
};
|
};
|
||||||
|
|
||||||
var sDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
|
var sDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
|
||||||
|
@@ -41,7 +41,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
|||||||
if (_isSupported)
|
if (_isSupported)
|
||||||
{
|
{
|
||||||
QueryPipelineStatisticFlags flags = type == CounterType.PrimitivesGenerated ?
|
QueryPipelineStatisticFlags flags = type == CounterType.PrimitivesGenerated ?
|
||||||
QueryPipelineStatisticFlags.QueryPipelineStatisticGeometryShaderPrimitivesBit : 0;
|
QueryPipelineStatisticFlags.GeometryShaderPrimitivesBit : 0;
|
||||||
|
|
||||||
var queryPoolCreateInfo = new QueryPoolCreateInfo()
|
var queryPoolCreateInfo = new QueryPoolCreateInfo()
|
||||||
{
|
{
|
||||||
@@ -175,11 +175,11 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
|||||||
{
|
{
|
||||||
var buffer = _buffer.GetBuffer(cbs.CommandBuffer, true).Get(cbs, 0, sizeof(long)).Value;
|
var buffer = _buffer.GetBuffer(cbs.CommandBuffer, true).Get(cbs, 0, sizeof(long)).Value;
|
||||||
|
|
||||||
QueryResultFlags flags = QueryResultFlags.QueryResultWaitBit;
|
QueryResultFlags flags = QueryResultFlags.ResultWaitBit;
|
||||||
|
|
||||||
if (!_result32Bit)
|
if (!_result32Bit)
|
||||||
{
|
{
|
||||||
flags |= QueryResultFlags.QueryResult64Bit;
|
flags |= QueryResultFlags.Result64Bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
_api.CmdCopyQueryPoolResults(
|
_api.CmdCopyQueryPoolResults(
|
||||||
|
@@ -13,11 +13,11 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<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="shaderc.net" Version="0.1.0" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan" Version="2.10.1" />
|
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.10.1" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
|
||||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.10.1" />
|
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
|
||||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
|
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Threading.ThreadPool" Version="4.3.0" />
|
<PackageReference Include="System.Threading.ThreadPool" Version="4.3.0" />
|
||||||
|
@@ -82,14 +82,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
stages |= 1u << shader.StageFlags switch
|
stages |= 1u << shader.StageFlags switch
|
||||||
{
|
{
|
||||||
ShaderStageFlags.ShaderStageFragmentBit => 1,
|
ShaderStageFlags.FragmentBit => 1,
|
||||||
ShaderStageFlags.ShaderStageGeometryBit => 2,
|
ShaderStageFlags.GeometryBit => 2,
|
||||||
ShaderStageFlags.ShaderStageTessellationControlBit => 3,
|
ShaderStageFlags.TessellationControlBit => 3,
|
||||||
ShaderStageFlags.ShaderStageTessellationEvaluationBit => 4,
|
ShaderStageFlags.TessellationEvaluationBit => 4,
|
||||||
_ => 0
|
_ => 0
|
||||||
};
|
};
|
||||||
|
|
||||||
if (shader.StageFlags == ShaderStageFlags.ShaderStageComputeBit)
|
if (shader.StageFlags == ShaderStageFlags.ComputeBit)
|
||||||
{
|
{
|
||||||
IsCompute = true;
|
IsCompute = true;
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
public ulong ID;
|
public ulong ID;
|
||||||
public MultiFenceHolder Waitable;
|
public MultiFenceHolder Waitable;
|
||||||
|
public bool Signalled;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ulong _firstHandle = 0;
|
private ulong _firstHandle = 0;
|
||||||
@@ -45,6 +46,37 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ulong GetCurrent()
|
||||||
|
{
|
||||||
|
lock (_handles)
|
||||||
|
{
|
||||||
|
ulong lastHandle = _firstHandle;
|
||||||
|
|
||||||
|
foreach (SyncHandle handle in _handles)
|
||||||
|
{
|
||||||
|
lock (handle)
|
||||||
|
{
|
||||||
|
if (handle.Waitable == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle.ID > lastHandle)
|
||||||
|
{
|
||||||
|
bool signaled = handle.Signalled || handle.Waitable.WaitForFences(_gd.Api, _device, 0);
|
||||||
|
if (signaled)
|
||||||
|
{
|
||||||
|
lastHandle = handle.ID;
|
||||||
|
handle.Signalled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastHandle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Wait(ulong id)
|
public void Wait(ulong id)
|
||||||
{
|
{
|
||||||
SyncHandle result = null;
|
SyncHandle result = null;
|
||||||
@@ -75,11 +107,15 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool signaled = result.Waitable.WaitForFences(_gd.Api, _device, 1000000000);
|
bool signaled = result.Signalled || result.Waitable.WaitForFences(_gd.Api, _device, 1000000000);
|
||||||
if (!signaled)
|
if (!signaled)
|
||||||
{
|
{
|
||||||
Logger.Error?.PrintMsg(LogClass.Gpu, $"VK Sync Object {result.ID} failed to signal within 1000ms. Continuing...");
|
Logger.Error?.PrintMsg(LogClass.Gpu, $"VK Sync Object {result.ID} failed to signal within 1000ms. Continuing...");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Signalled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -60,9 +60,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
commandBuffer,
|
commandBuffer,
|
||||||
srcImage,
|
srcImage,
|
||||||
TextureStorage.DefaultAccessMask,
|
TextureStorage.DefaultAccessMask,
|
||||||
AccessFlags.AccessTransferReadBit,
|
AccessFlags.TransferReadBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
srcAspectFlags,
|
srcAspectFlags,
|
||||||
srcLayer,
|
srcLayer,
|
||||||
srcLevel,
|
srcLevel,
|
||||||
@@ -103,10 +103,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
api,
|
api,
|
||||||
commandBuffer,
|
commandBuffer,
|
||||||
dstImage,
|
dstImage,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
TextureStorage.DefaultAccessMask,
|
TextureStorage.DefaultAccessMask,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
dstAspectFlags,
|
dstAspectFlags,
|
||||||
dstLayer,
|
dstLayer,
|
||||||
dstLevel,
|
dstLevel,
|
||||||
@@ -285,9 +285,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
commandBuffer,
|
commandBuffer,
|
||||||
srcImage,
|
srcImage,
|
||||||
TextureStorage.DefaultAccessMask,
|
TextureStorage.DefaultAccessMask,
|
||||||
AccessFlags.AccessTransferReadBit,
|
AccessFlags.TransferReadBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
srcAspect,
|
srcAspect,
|
||||||
srcViewLayer + srcLayer,
|
srcViewLayer + srcLayer,
|
||||||
srcViewLevel + srcLevel,
|
srcViewLevel + srcLevel,
|
||||||
@@ -345,10 +345,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
api,
|
api,
|
||||||
commandBuffer,
|
commandBuffer,
|
||||||
dstImage,
|
dstImage,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
TextureStorage.DefaultAccessMask,
|
TextureStorage.DefaultAccessMask,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
dstAspect,
|
dstAspect,
|
||||||
dstViewLayer + dstLayer,
|
dstViewLayer + dstLayer,
|
||||||
dstViewLevel + dstLevel,
|
dstViewLevel + dstLevel,
|
||||||
@@ -370,8 +370,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
SType = StructureType.SubpassDescriptionDepthStencilResolve,
|
SType = StructureType.SubpassDescriptionDepthStencilResolve,
|
||||||
PDepthStencilResolveAttachment = &dsResolveAttachmentReference,
|
PDepthStencilResolveAttachment = &dsResolveAttachmentReference,
|
||||||
DepthResolveMode = ResolveModeFlags.ResolveModeSampleZeroBit,
|
DepthResolveMode = ResolveModeFlags.SampleZeroBit,
|
||||||
StencilResolveMode = ResolveModeFlags.ResolveModeSampleZeroBit
|
StencilResolveMode = ResolveModeFlags.SampleZeroBit
|
||||||
};
|
};
|
||||||
|
|
||||||
var subpass = new SubpassDescription2()
|
var subpass = new SubpassDescription2()
|
||||||
|
@@ -12,22 +12,22 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
class TextureStorage : IDisposable
|
class TextureStorage : IDisposable
|
||||||
{
|
{
|
||||||
private const MemoryPropertyFlags DefaultImageMemoryFlags =
|
private const MemoryPropertyFlags DefaultImageMemoryFlags =
|
||||||
MemoryPropertyFlags.MemoryPropertyDeviceLocalBit;
|
MemoryPropertyFlags.DeviceLocalBit;
|
||||||
|
|
||||||
private const ImageUsageFlags DefaultUsageFlags =
|
private const ImageUsageFlags DefaultUsageFlags =
|
||||||
ImageUsageFlags.ImageUsageSampledBit |
|
ImageUsageFlags.SampledBit |
|
||||||
ImageUsageFlags.ImageUsageTransferSrcBit |
|
ImageUsageFlags.TransferSrcBit |
|
||||||
ImageUsageFlags.ImageUsageTransferDstBit;
|
ImageUsageFlags.TransferDstBit;
|
||||||
|
|
||||||
public const AccessFlags DefaultAccessMask =
|
public const AccessFlags DefaultAccessMask =
|
||||||
AccessFlags.AccessShaderReadBit |
|
AccessFlags.ShaderReadBit |
|
||||||
AccessFlags.AccessShaderWriteBit |
|
AccessFlags.ShaderWriteBit |
|
||||||
AccessFlags.AccessColorAttachmentReadBit |
|
AccessFlags.ColorAttachmentReadBit |
|
||||||
AccessFlags.AccessColorAttachmentWriteBit |
|
AccessFlags.ColorAttachmentWriteBit |
|
||||||
AccessFlags.AccessDepthStencilAttachmentReadBit |
|
AccessFlags.DepthStencilAttachmentReadBit |
|
||||||
AccessFlags.AccessDepthStencilAttachmentWriteBit |
|
AccessFlags.DepthStencilAttachmentWriteBit |
|
||||||
AccessFlags.AccessTransferReadBit |
|
AccessFlags.TransferReadBit |
|
||||||
AccessFlags.AccessTransferWriteBit;
|
AccessFlags.TransferWriteBit;
|
||||||
|
|
||||||
private readonly VulkanRenderer _gd;
|
private readonly VulkanRenderer _gd;
|
||||||
|
|
||||||
@@ -83,32 +83,32 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
if (info.Format.IsDepthOrStencil())
|
if (info.Format.IsDepthOrStencil())
|
||||||
{
|
{
|
||||||
usage |= ImageUsageFlags.ImageUsageDepthStencilAttachmentBit;
|
usage |= ImageUsageFlags.DepthStencilAttachmentBit;
|
||||||
}
|
}
|
||||||
else if (info.Format.IsRtColorCompatible())
|
else if (info.Format.IsRtColorCompatible())
|
||||||
{
|
{
|
||||||
usage |= ImageUsageFlags.ImageUsageColorAttachmentBit;
|
usage |= ImageUsageFlags.ColorAttachmentBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.Format.IsImageCompatible())
|
if (info.Format.IsImageCompatible())
|
||||||
{
|
{
|
||||||
usage |= ImageUsageFlags.ImageUsageStorageBit;
|
usage |= ImageUsageFlags.StorageBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
var flags = ImageCreateFlags.ImageCreateMutableFormatBit;
|
var flags = ImageCreateFlags.CreateMutableFormatBit;
|
||||||
|
|
||||||
// This flag causes mipmapped texture arrays to break on AMD GCN, so for that copy dependencies are forced for aliasing as cube.
|
// This flag causes mipmapped texture arrays to break on AMD GCN, so for that copy dependencies are forced for aliasing as cube.
|
||||||
bool isCube = info.Target == Target.Cubemap || info.Target == Target.CubemapArray;
|
bool isCube = info.Target == Target.Cubemap || info.Target == Target.CubemapArray;
|
||||||
bool cubeCompatible = gd.IsAmdGcn ? isCube : (info.Width == info.Height && layers >= 6);
|
bool cubeCompatible = gd.IsAmdGcn ? isCube : (info.Width == info.Height && layers >= 6);
|
||||||
|
|
||||||
if (type == ImageType.ImageType2D && cubeCompatible)
|
if (type == ImageType.Type2D && cubeCompatible)
|
||||||
{
|
{
|
||||||
flags |= ImageCreateFlags.ImageCreateCubeCompatibleBit;
|
flags |= ImageCreateFlags.CreateCubeCompatibleBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == ImageType.ImageType3D)
|
if (type == ImageType.Type3D)
|
||||||
{
|
{
|
||||||
flags |= ImageCreateFlags.ImageCreate2DArrayCompatibleBit;
|
flags |= ImageCreateFlags.Create2DArrayCompatibleBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
var imageCreateInfo = new ImageCreateInfo()
|
var imageCreateInfo = new ImageCreateInfo()
|
||||||
@@ -290,8 +290,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_gd.Api.CmdPipelineBarrier(
|
_gd.Api.CmdPipelineBarrier(
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
PipelineStageFlags.PipelineStageTopOfPipeBit,
|
PipelineStageFlags.TopOfPipeBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
null,
|
null,
|
||||||
@@ -308,9 +308,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public static SampleCountFlags ConvertToSampleCountFlags(uint samples)
|
public static SampleCountFlags ConvertToSampleCountFlags(uint samples)
|
||||||
{
|
{
|
||||||
if (samples == 0 || samples > (uint)SampleCountFlags.SampleCount64Bit)
|
if (samples == 0 || samples > (uint)SampleCountFlags.Count64Bit)
|
||||||
{
|
{
|
||||||
return SampleCountFlags.SampleCount1Bit;
|
return SampleCountFlags.Count1Bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Round up to the nearest power of two.
|
// Round up to the nearest power of two.
|
||||||
@@ -428,7 +428,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public void InsertBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags)
|
public void InsertBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags)
|
||||||
{
|
{
|
||||||
if (_lastModificationAccess != AccessFlags.AccessNoneKhr)
|
if (_lastModificationAccess != AccessFlags.NoneKhr)
|
||||||
{
|
{
|
||||||
ImageAspectFlags aspectFlags;
|
ImageAspectFlags aspectFlags;
|
||||||
|
|
||||||
@@ -436,20 +436,20 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
if (_info.Format == GAL.Format.S8Uint)
|
if (_info.Format == GAL.Format.S8Uint)
|
||||||
{
|
{
|
||||||
aspectFlags = ImageAspectFlags.ImageAspectStencilBit;
|
aspectFlags = ImageAspectFlags.StencilBit;
|
||||||
}
|
}
|
||||||
else if (_info.Format == GAL.Format.D16Unorm || _info.Format == GAL.Format.D32Float)
|
else if (_info.Format == GAL.Format.D16Unorm || _info.Format == GAL.Format.D32Float)
|
||||||
{
|
{
|
||||||
aspectFlags = ImageAspectFlags.ImageAspectDepthBit;
|
aspectFlags = ImageAspectFlags.DepthBit;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
aspectFlags = ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit;
|
aspectFlags = ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
aspectFlags = ImageAspectFlags.ImageAspectColorBit;
|
aspectFlags = ImageAspectFlags.ColorBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureView.InsertImageBarrier(
|
TextureView.InsertImageBarrier(
|
||||||
@@ -466,7 +466,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_info.GetLayers(),
|
_info.GetLayers(),
|
||||||
_info.Levels);
|
_info.Levels);
|
||||||
|
|
||||||
_lastModificationAccess = AccessFlags.AccessNoneKhr;
|
_lastModificationAccess = AccessFlags.NoneKhr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -126,7 +126,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, (uint)info.Depth);
|
subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, (uint)info.Depth);
|
||||||
|
|
||||||
_imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.ImageViewType2DArray);
|
_imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.Type2DArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
Valid = true;
|
Valid = true;
|
||||||
@@ -322,8 +322,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (_gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.FormatFeatureBlitSrcBit, srcFormat) &&
|
else if (_gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.BlitSrcBit, srcFormat) &&
|
||||||
_gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.FormatFeatureBlitDstBit, dstFormat))
|
_gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.BlitDstBit, dstFormat))
|
||||||
{
|
{
|
||||||
TextureCopy.Blit(
|
TextureCopy.Blit(
|
||||||
_gd.Api,
|
_gd.Api,
|
||||||
@@ -402,8 +402,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
layers,
|
layers,
|
||||||
levels,
|
levels,
|
||||||
linearFilter,
|
linearFilter,
|
||||||
ImageAspectFlags.ImageAspectColorBit,
|
ImageAspectFlags.ColorBit,
|
||||||
ImageAspectFlags.ImageAspectColorBit);
|
ImageAspectFlags.ColorBit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void BlitDepthStencilWithBuffer(
|
private static void BlitDepthStencilWithBuffer(
|
||||||
@@ -471,10 +471,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
gd,
|
gd,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value,
|
srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
AccessFlags.AccessTransferReadBit,
|
AccessFlags.TransferReadBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
0,
|
0,
|
||||||
srcSize);
|
srcSize);
|
||||||
|
|
||||||
@@ -498,10 +498,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
gd.Api,
|
gd.Api,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
srcTemp.GetImage().Get(cbs).Value,
|
srcTemp.GetImage().Get(cbs).Value,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
AccessFlags.AccessTransferReadBit,
|
AccessFlags.TransferReadBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
aspectFlags,
|
aspectFlags,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -531,10 +531,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
gd.Api,
|
gd.Api,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstTemp.GetImage().Get(cbs).Value,
|
dstTemp.GetImage().Get(cbs).Value,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
AccessFlags.AccessTransferReadBit,
|
AccessFlags.TransferReadBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
aspectFlags,
|
aspectFlags,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -561,10 +561,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
gd,
|
gd,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value,
|
dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
AccessFlags.AccessTransferReadBit,
|
AccessFlags.TransferReadBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
PipelineStageFlags.TransferBit,
|
||||||
0,
|
0,
|
||||||
dstSize);
|
dstSize);
|
||||||
|
|
||||||
@@ -585,8 +585,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SlowBlit(d32SrcStorage, d32DstStorage, ImageAspectFlags.ImageAspectDepthBit);
|
SlowBlit(d32SrcStorage, d32DstStorage, ImageAspectFlags.DepthBit);
|
||||||
SlowBlit(s8SrcStorage, s8DstStorage, ImageAspectFlags.ImageAspectStencilBit);
|
SlowBlit(s8SrcStorage, s8DstStorage, ImageAspectFlags.StencilBit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe void InsertImageBarrier(
|
public static unsafe void InsertImageBarrier(
|
||||||
@@ -631,7 +631,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private bool SupportsBlitFromD32FS8ToD32FAndS8()
|
private bool SupportsBlitFromD32FS8ToD32FAndS8()
|
||||||
{
|
{
|
||||||
var formatFeatureFlags = FormatFeatureFlags.FormatFeatureBlitSrcBit | FormatFeatureFlags.FormatFeatureBlitDstBit;
|
var formatFeatureFlags = FormatFeatureFlags.BlitSrcBit | FormatFeatureFlags.BlitDstBit;
|
||||||
return _gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.D32Float) &&
|
return _gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.D32Float) &&
|
||||||
_gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.S8Uint);
|
_gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.S8Uint);
|
||||||
}
|
}
|
||||||
@@ -903,9 +903,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
var aspectFlags = Info.Format.ConvertAspectFlags();
|
var aspectFlags = Info.Format.ConvertAspectFlags();
|
||||||
|
|
||||||
if (aspectFlags == (ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit))
|
if (aspectFlags == (ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit))
|
||||||
{
|
{
|
||||||
aspectFlags = ImageAspectFlags.ImageAspectDepthBit;
|
aspectFlags = ImageAspectFlags.DepthBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sl = new ImageSubresourceLayers(
|
var sl = new ImageSubresourceLayers(
|
||||||
@@ -962,9 +962,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
var aspectFlags = Info.Format.ConvertAspectFlags();
|
var aspectFlags = Info.Format.ConvertAspectFlags();
|
||||||
|
|
||||||
if (aspectFlags == (ImageAspectFlags.ImageAspectDepthBit | ImageAspectFlags.ImageAspectStencilBit))
|
if (aspectFlags == (ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit))
|
||||||
{
|
{
|
||||||
aspectFlags = ImageAspectFlags.ImageAspectDepthBit;
|
aspectFlags = ImageAspectFlags.DepthBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sl = new ImageSubresourceLayers(aspectFlags, (uint)(FirstLevel + dstLevel), (uint)(FirstLayer + dstLayer), 1);
|
var sl = new ImageSubresourceLayers(aspectFlags, (uint)(FirstLevel + dstLevel), (uint)(FirstLayer + dstLayer), 1);
|
||||||
|
@@ -37,7 +37,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
public static string[] RequiredExtensions { get; } = new string[]
|
public static string[] RequiredExtensions { get; } = new string[]
|
||||||
{
|
{
|
||||||
KhrSwapchain.ExtensionName,
|
KhrSwapchain.ExtensionName,
|
||||||
"VK_EXT_shader_subgroup_vote",
|
|
||||||
ExtTransformFeedback.ExtensionName
|
ExtTransformFeedback.ExtensionName
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -160,20 +159,20 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityErrorBitExt))
|
if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt))
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Gpu, msg);
|
Logger.Error?.Print(LogClass.Gpu, msg);
|
||||||
//throw new Exception(msg);
|
//throw new Exception(msg);
|
||||||
}
|
}
|
||||||
else if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityWarningBitExt))
|
else if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.WarningBitExt))
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Gpu, msg);
|
Logger.Warning?.Print(LogClass.Gpu, msg);
|
||||||
}
|
}
|
||||||
else if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityInfoBitExt))
|
else if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.InfoBitExt))
|
||||||
{
|
{
|
||||||
Logger.Info?.Print(LogClass.Gpu, msg);
|
Logger.Info?.Print(LogClass.Gpu, msg);
|
||||||
}
|
}
|
||||||
else // if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityVerboseBitExt))
|
else // if (messageSeverity.HasFlag(DebugUtilsMessageSeverityFlagsEXT.VerboseBitExt))
|
||||||
{
|
{
|
||||||
Logger.Debug?.Print(LogClass.Gpu, msg);
|
Logger.Debug?.Print(LogClass.Gpu, msg);
|
||||||
}
|
}
|
||||||
@@ -318,7 +317,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
internal static uint FindSuitableQueueFamily(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface, out uint queueCount)
|
internal static uint FindSuitableQueueFamily(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface, out uint queueCount)
|
||||||
{
|
{
|
||||||
const QueueFlags RequiredFlags = QueueFlags.QueueGraphicsBit | QueueFlags.QueueComputeBit;
|
const QueueFlags RequiredFlags = QueueFlags.GraphicsBit | QueueFlags.ComputeBit;
|
||||||
|
|
||||||
var khrSurface = new KhrSurface(api.Context);
|
var khrSurface = new KhrSurface(api.Context);
|
||||||
|
|
||||||
@@ -562,24 +561,24 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
var filterLogType = logLevel switch
|
var filterLogType = logLevel switch
|
||||||
{
|
{
|
||||||
GraphicsDebugLevel.Error => DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypeValidationBitExt,
|
GraphicsDebugLevel.Error => DebugUtilsMessageTypeFlagsEXT.ValidationBitExt,
|
||||||
GraphicsDebugLevel.Slowdowns => DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypeValidationBitExt |
|
GraphicsDebugLevel.Slowdowns => DebugUtilsMessageTypeFlagsEXT.ValidationBitExt |
|
||||||
DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypePerformanceBitExt,
|
DebugUtilsMessageTypeFlagsEXT.PerformanceBitExt,
|
||||||
GraphicsDebugLevel.All => DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypeGeneralBitExt |
|
GraphicsDebugLevel.All => DebugUtilsMessageTypeFlagsEXT.GeneralBitExt |
|
||||||
DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypeValidationBitExt |
|
DebugUtilsMessageTypeFlagsEXT.ValidationBitExt |
|
||||||
DebugUtilsMessageTypeFlagsEXT.DebugUtilsMessageTypePerformanceBitExt,
|
DebugUtilsMessageTypeFlagsEXT.PerformanceBitExt,
|
||||||
_ => throw new ArgumentException($"Invalid log level \"{logLevel}\".")
|
_ => throw new ArgumentException($"Invalid log level \"{logLevel}\".")
|
||||||
};
|
};
|
||||||
|
|
||||||
var filterLogSeverity = logLevel switch
|
var filterLogSeverity = logLevel switch
|
||||||
{
|
{
|
||||||
GraphicsDebugLevel.Error => DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityErrorBitExt,
|
GraphicsDebugLevel.Error => DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt,
|
||||||
GraphicsDebugLevel.Slowdowns => DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityErrorBitExt |
|
GraphicsDebugLevel.Slowdowns => DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt |
|
||||||
DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityWarningBitExt,
|
DebugUtilsMessageSeverityFlagsEXT.WarningBitExt,
|
||||||
GraphicsDebugLevel.All => DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityInfoBitExt |
|
GraphicsDebugLevel.All => DebugUtilsMessageSeverityFlagsEXT.InfoBitExt |
|
||||||
DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityWarningBitExt |
|
DebugUtilsMessageSeverityFlagsEXT.WarningBitExt |
|
||||||
DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityVerboseBitExt |
|
DebugUtilsMessageSeverityFlagsEXT.VerboseBitExt |
|
||||||
DebugUtilsMessageSeverityFlagsEXT.DebugUtilsMessageSeverityErrorBitExt,
|
DebugUtilsMessageSeverityFlagsEXT.ErrorBitExt,
|
||||||
_ => throw new ArgumentException($"Invalid log level \"{logLevel}\".")
|
_ => throw new ArgumentException($"Invalid log level \"{logLevel}\".")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -341,11 +341,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
public unsafe Capabilities GetCapabilities()
|
public unsafe Capabilities GetCapabilities()
|
||||||
{
|
{
|
||||||
FormatFeatureFlags compressedFormatFeatureFlags =
|
FormatFeatureFlags compressedFormatFeatureFlags =
|
||||||
FormatFeatureFlags.FormatFeatureSampledImageBit |
|
FormatFeatureFlags.SampledImageBit |
|
||||||
FormatFeatureFlags.FormatFeatureSampledImageFilterLinearBit |
|
FormatFeatureFlags.SampledImageFilterLinearBit |
|
||||||
FormatFeatureFlags.FormatFeatureBlitSrcBit |
|
FormatFeatureFlags.BlitSrcBit |
|
||||||
FormatFeatureFlags.FormatFeatureTransferSrcBit |
|
FormatFeatureFlags.TransferSrcBit |
|
||||||
FormatFeatureFlags.FormatFeatureTransferDstBit;
|
FormatFeatureFlags.TransferDstBit;
|
||||||
|
|
||||||
bool supportsBc123CompressionFormat = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
|
bool supportsBc123CompressionFormat = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
|
||||||
GAL.Format.Bc1RgbaSrgb,
|
GAL.Format.Bc1RgbaSrgb,
|
||||||
@@ -565,6 +565,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_syncManager.Wait(id);
|
_syncManager.Wait(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ulong GetCurrentSync()
|
||||||
|
{
|
||||||
|
return _syncManager.GetCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
public void Screenshot()
|
public void Screenshot()
|
||||||
{
|
{
|
||||||
_window.ScreenCaptureRequested = true;
|
_window.ScreenCaptureRequested = true;
|
||||||
|
@@ -109,11 +109,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
ImageFormat = surfaceFormat.Format,
|
ImageFormat = surfaceFormat.Format,
|
||||||
ImageColorSpace = surfaceFormat.ColorSpace,
|
ImageColorSpace = surfaceFormat.ColorSpace,
|
||||||
ImageExtent = extent,
|
ImageExtent = extent,
|
||||||
ImageUsage = ImageUsageFlags.ImageUsageColorAttachmentBit | ImageUsageFlags.ImageUsageTransferDstBit,
|
ImageUsage = ImageUsageFlags.ColorAttachmentBit | ImageUsageFlags.TransferDstBit,
|
||||||
ImageSharingMode = SharingMode.Exclusive,
|
ImageSharingMode = SharingMode.Exclusive,
|
||||||
ImageArrayLayers = 1,
|
ImageArrayLayers = 1,
|
||||||
PreTransform = capabilities.CurrentTransform,
|
PreTransform = capabilities.CurrentTransform,
|
||||||
CompositeAlpha = CompositeAlphaFlagsKHR.CompositeAlphaOpaqueBitKhr,
|
CompositeAlpha = CompositeAlphaFlagsKHR.OpaqueBitKhr,
|
||||||
PresentMode = ChooseSwapPresentMode(presentModes, _vsyncEnabled),
|
PresentMode = ChooseSwapPresentMode(presentModes, _vsyncEnabled),
|
||||||
Clipped = true,
|
Clipped = true,
|
||||||
OldSwapchain = oldSwapchain
|
OldSwapchain = oldSwapchain
|
||||||
@@ -146,7 +146,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
ComponentSwizzle.B,
|
ComponentSwizzle.B,
|
||||||
ComponentSwizzle.A);
|
ComponentSwizzle.A);
|
||||||
|
|
||||||
var aspectFlags = ImageAspectFlags.ImageAspectColorBit;
|
var aspectFlags = ImageAspectFlags.ColorBit;
|
||||||
|
|
||||||
var subresourceRange = new ImageSubresourceRange(aspectFlags, 0, 1, 0, 1);
|
var subresourceRange = new ImageSubresourceRange(aspectFlags, 0, 1, 0, 1);
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
SType = StructureType.ImageViewCreateInfo,
|
SType = StructureType.ImageViewCreateInfo,
|
||||||
Image = swapchainImage,
|
Image = swapchainImage,
|
||||||
ViewType = ImageViewType.ImageViewType2D,
|
ViewType = ImageViewType.Type2D,
|
||||||
Format = format,
|
Format = format,
|
||||||
Components = componentMapping,
|
Components = componentMapping,
|
||||||
SubresourceRange = subresourceRange
|
SubresourceRange = subresourceRange
|
||||||
@@ -168,12 +168,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
if (availableFormats.Length == 1 && availableFormats[0].Format == VkFormat.Undefined)
|
if (availableFormats.Length == 1 && availableFormats[0].Format == VkFormat.Undefined)
|
||||||
{
|
{
|
||||||
return new SurfaceFormatKHR(VkFormat.B8G8R8A8Unorm, ColorSpaceKHR.ColorspaceSrgbNonlinearKhr);
|
return new SurfaceFormatKHR(VkFormat.B8G8R8A8Unorm, ColorSpaceKHR.PaceSrgbNonlinearKhr);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var format in availableFormats)
|
foreach (var format in availableFormats)
|
||||||
{
|
{
|
||||||
if (format.Format == VkFormat.B8G8R8A8Unorm && format.ColorSpace == ColorSpaceKHR.ColorspaceSrgbNonlinearKhr)
|
if (format.Format == VkFormat.B8G8R8A8Unorm && format.ColorSpace == ColorSpaceKHR.PaceSrgbNonlinearKhr)
|
||||||
{
|
{
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
@@ -184,21 +184,21 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private static PresentModeKHR ChooseSwapPresentMode(PresentModeKHR[] availablePresentModes, bool vsyncEnabled)
|
private static PresentModeKHR ChooseSwapPresentMode(PresentModeKHR[] availablePresentModes, bool vsyncEnabled)
|
||||||
{
|
{
|
||||||
if (!vsyncEnabled && availablePresentModes.Contains(PresentModeKHR.PresentModeImmediateKhr))
|
if (!vsyncEnabled && availablePresentModes.Contains(PresentModeKHR.ImmediateKhr))
|
||||||
{
|
{
|
||||||
return PresentModeKHR.PresentModeImmediateKhr;
|
return PresentModeKHR.ImmediateKhr;
|
||||||
}
|
}
|
||||||
else if (availablePresentModes.Contains(PresentModeKHR.PresentModeMailboxKhr))
|
else if (availablePresentModes.Contains(PresentModeKHR.MailboxKhr))
|
||||||
{
|
{
|
||||||
return PresentModeKHR.PresentModeMailboxKhr;
|
return PresentModeKHR.MailboxKhr;
|
||||||
}
|
}
|
||||||
else if (availablePresentModes.Contains(PresentModeKHR.PresentModeFifoKhr))
|
else if (availablePresentModes.Contains(PresentModeKHR.FifoKhr))
|
||||||
{
|
{
|
||||||
return PresentModeKHR.PresentModeFifoKhr;
|
return PresentModeKHR.FifoKhr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return PresentModeKHR.PresentModeFifoKhr;
|
return PresentModeKHR.FifoKhr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +254,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
swapchainImage,
|
swapchainImage,
|
||||||
0,
|
0,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
AccessFlags.TransferWriteBit,
|
||||||
ImageLayout.Undefined,
|
ImageLayout.Undefined,
|
||||||
ImageLayout.General);
|
ImageLayout.General);
|
||||||
|
|
||||||
@@ -339,7 +339,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_gd.CommandBufferPool.Return(
|
_gd.CommandBufferPool.Return(
|
||||||
cbs,
|
cbs,
|
||||||
stackalloc[] { _imageAvailableSemaphore },
|
stackalloc[] { _imageAvailableSemaphore },
|
||||||
stackalloc[] { PipelineStageFlags.PipelineStageColorAttachmentOutputBit },
|
stackalloc[] { PipelineStageFlags.ColorAttachmentOutputBit },
|
||||||
stackalloc[] { _renderFinishedSemaphore });
|
stackalloc[] { _renderFinishedSemaphore });
|
||||||
|
|
||||||
// TODO: Present queue.
|
// TODO: Present queue.
|
||||||
@@ -373,7 +373,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
ImageLayout srcLayout,
|
ImageLayout srcLayout,
|
||||||
ImageLayout dstLayout)
|
ImageLayout dstLayout)
|
||||||
{
|
{
|
||||||
var subresourceRange = new ImageSubresourceRange(ImageAspectFlags.ImageAspectColorBit, 0, 1, 0, 1);
|
var subresourceRange = new ImageSubresourceRange(ImageAspectFlags.ColorBit, 0, 1, 0, 1);
|
||||||
|
|
||||||
var barrier = new ImageMemoryBarrier()
|
var barrier = new ImageMemoryBarrier()
|
||||||
{
|
{
|
||||||
@@ -390,8 +390,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_gd.Api.CmdPipelineBarrier(
|
_gd.Api.CmdPipelineBarrier(
|
||||||
commandBuffer,
|
commandBuffer,
|
||||||
PipelineStageFlags.PipelineStageTopOfPipeBit,
|
PipelineStageFlags.TopOfPipeBit,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.AllCommandsBit,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
null,
|
null,
|
||||||
|
@@ -16,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
|
|||||||
|
|
||||||
public ResultCode ExecuteAudioRendererRendering()
|
public ResultCode ExecuteAudioRendererRendering()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return (ResultCode)_impl.ExecuteAudioRendererRendering();
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint GetMixBufferCount()
|
public uint GetMixBufferCount()
|
||||||
@@ -108,5 +108,15 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
|
|||||||
_impl.Dispose();
|
_impl.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetVoiceDropParameter(float voiceDropParameter)
|
||||||
|
{
|
||||||
|
_impl.SetVoiceDropParameter(voiceDropParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetVoiceDropParameter()
|
||||||
|
{
|
||||||
|
return _impl.GetVoiceDropParameter();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -172,6 +172,35 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
|
|||||||
return result;
|
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)
|
protected override void Dispose(bool isDisposing)
|
||||||
{
|
{
|
||||||
if (isDisposing)
|
if (isDisposing)
|
||||||
|
@@ -16,5 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
|
|||||||
void SetRenderingTimeLimit(uint percent);
|
void SetRenderingTimeLimit(uint percent);
|
||||||
uint GetRenderingTimeLimit();
|
uint GetRenderingTimeLimit();
|
||||||
ResultCode ExecuteAudioRendererRendering();
|
ResultCode ExecuteAudioRendererRendering();
|
||||||
|
void SetVoiceDropParameter(float voiceDropParameter);
|
||||||
|
float GetVoiceDropParameter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.HLE.HOS.Services.Ptm.Psm
|
|||||||
{
|
{
|
||||||
if (_stateChangeEventHandle == -1)
|
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)
|
if (resultCode != KernelResult.Success)
|
||||||
{
|
{
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user