Compare commits

...

8 Commits

Author SHA1 Message Date
Isaac Marovitz
f07ae7d53f Fix Title Update Manager not selecting right update (#4452) 2023-02-22 17:58:32 -03:00
dependabot[bot]
c308f09722 nuget: bump Microsoft.NET.Test.Sdk from 17.4.1 to 17.5.0 (#4458)
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.4.1 to 17.5.0.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.4.1...v17.5.0)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-22 16:08:25 +01:00
dependabot[bot]
f1eef29409 nuget: bump UnicornEngine.Unicorn (#4459)
Bumps [UnicornEngine.Unicorn](https://github.com/unicorn-engine/unicorn) from 2.0.2-rc1-9c9356d to 2.0.2-rc1-a913199.
- [Release notes](https://github.com/unicorn-engine/unicorn/releases)
- [Changelog](https://github.com/unicorn-engine/unicorn/blob/master/ChangeLog)
- [Commits](https://github.com/unicorn-engine/unicorn/commits)

---
updated-dependencies:
- dependency-name: UnicornEngine.Unicorn
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-22 13:30:53 +01:00
TSRBerry
1f8d66db7c Ava: Fix Updater crashing on Linux (#4457) 2023-02-22 09:13:50 +01:00
gdkchan
c3a5716a95 Add copy dependency for some incompatible texture formats (#4380)
* Add copy dependency for some incompatible texture formats

* Simplify compatibility check
2023-02-21 19:21:57 -03:00
Mary
1f1e2a7f03 misc: changes base application directory behaviour (#4460)
This allows changing base application directory behavior at build time via FORCE_EXTERNAL_BASE_DIR.

This is intended to be used by nixpkgs and flathub builds.

I also added the missing patch for macOS that we have on macos1 to avoid invalidating code signature.
2023-02-21 22:38:34 +01:00
Andrew Glaze
e54f9dc4b4 Move Ryujinx Folder from ~/.config to ~/Library/Application Support on macOS (#4296)
* Move Ryujinx folder to Application Support on macOS

* Create a symlink to preserve back compat

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Remove extra whitespace

* Don’t create a symlink

* Update Ryujinx.Common/Configuration/AppDataManager.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Revert "Don’t create a symlink"

This reverts commit 31752fe8ab.

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-02-21 12:14:31 +01:00
Logan Stromberg
edfd4d70c0 Use SIMD acceleration for audio upsampler (#4410)
* Use SIMD acceleration for audio upsampler filter kernel for a moderate speedup

* Address formatting. Implement AVX2 fast path for high quality resampling in ResamplerHelper

* now really, are we really getting the benefit of inlining 50+ line methods?

* adding unit tests for resampler + upsampler. The upsampler ones fail for some reason

* Fixing upsampler test. Apparently this algo only works at specific ratios

---------

Co-authored-by: Logan Stromberg <lostromb@microsoft.com>
2023-02-21 11:44:57 +01:00
18 changed files with 1163 additions and 138 deletions

View File

@@ -22,7 +22,7 @@
<PackageVersion Include="LibHac" Version="0.17.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
<PackageVersion Include="NUnit" Version="3.13.3" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
@@ -49,7 +49,7 @@
<PackageVersion Include="System.Management" Version="7.0.0" />
<PackageVersion Include="System.Net.NameResolution" Version="4.3.0" />
<PackageVersion Include="System.Threading.ThreadPool" Version="4.3.0" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-9c9356d" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-a913199" />
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.5.1" />
</ItemGroup>
</Project>

View File

@@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
@@ -380,7 +381,6 @@ namespace Ryujinx.Audio.Renderer.Dsp
return _normalCurveLut2F;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static void ResampleDefaultQuality(Span<float> outputBuffer, ReadOnlySpan<short> inputBuffer, float ratio, ref float fraction, int sampleCount, bool needPitch)
{
ReadOnlySpan<float> parameters = GetDefaultParameter(ratio);
@@ -394,35 +394,33 @@ namespace Ryujinx.Audio.Renderer.Dsp
if (ratio == 1f)
{
fixed (short* pInput = inputBuffer)
fixed (float* pOutput = outputBuffer, pParameters = parameters)
{
fixed (float* pOutput = outputBuffer, pParameters = parameters)
Vector128<float> parameter = Sse.LoadVector128(pParameters);
for (; i < (sampleCount & ~3); i += 4)
{
Vector128<float> parameter = Sse.LoadVector128(pParameters);
Vector128<int> intInput0 = Sse41.ConvertToVector128Int32(pInput + (uint)i);
Vector128<int> intInput1 = Sse41.ConvertToVector128Int32(pInput + (uint)i + 1);
Vector128<int> intInput2 = Sse41.ConvertToVector128Int32(pInput + (uint)i + 2);
Vector128<int> intInput3 = Sse41.ConvertToVector128Int32(pInput + (uint)i + 3);
for (; i < (sampleCount & ~3); i += 4)
{
Vector128<int> intInput0 = Sse41.ConvertToVector128Int32(pInput + (uint)i);
Vector128<int> intInput1 = Sse41.ConvertToVector128Int32(pInput + (uint)i + 1);
Vector128<int> intInput2 = Sse41.ConvertToVector128Int32(pInput + (uint)i + 2);
Vector128<int> intInput3 = Sse41.ConvertToVector128Int32(pInput + (uint)i + 3);
Vector128<float> input0 = Sse2.ConvertToVector128Single(intInput0);
Vector128<float> input1 = Sse2.ConvertToVector128Single(intInput1);
Vector128<float> input2 = Sse2.ConvertToVector128Single(intInput2);
Vector128<float> input3 = Sse2.ConvertToVector128Single(intInput3);
Vector128<float> input0 = Sse2.ConvertToVector128Single(intInput0);
Vector128<float> input1 = Sse2.ConvertToVector128Single(intInput1);
Vector128<float> input2 = Sse2.ConvertToVector128Single(intInput2);
Vector128<float> input3 = Sse2.ConvertToVector128Single(intInput3);
Vector128<float> mix0 = Sse.Multiply(input0, parameter);
Vector128<float> mix1 = Sse.Multiply(input1, parameter);
Vector128<float> mix2 = Sse.Multiply(input2, parameter);
Vector128<float> mix3 = Sse.Multiply(input3, parameter);
Vector128<float> mix0 = Sse.Multiply(input0, parameter);
Vector128<float> mix1 = Sse.Multiply(input1, parameter);
Vector128<float> mix2 = Sse.Multiply(input2, parameter);
Vector128<float> mix3 = Sse.Multiply(input3, parameter);
Vector128<float> mix01 = Sse3.HorizontalAdd(mix0, mix1);
Vector128<float> mix23 = Sse3.HorizontalAdd(mix2, mix3);
Vector128<float> mix01 = Sse3.HorizontalAdd(mix0, mix1);
Vector128<float> mix23 = Sse3.HorizontalAdd(mix2, mix3);
Vector128<float> mix0123 = Sse3.HorizontalAdd(mix01, mix23);
Vector128<float> mix0123 = Sse3.HorizontalAdd(mix01, mix23);
Sse.Store(pOutput + (uint)i, Sse41.RoundToNearestInteger(mix0123));
}
Sse.Store(pOutput + (uint)i, Sse41.RoundToNearestInteger(mix0123));
}
}
@@ -431,62 +429,60 @@ namespace Ryujinx.Audio.Renderer.Dsp
else
{
fixed (short* pInput = inputBuffer)
fixed (float* pOutput = outputBuffer, pParameters = parameters)
{
fixed (float* pOutput = outputBuffer, pParameters = parameters)
for (; i < (sampleCount & ~3); i += 4)
{
for (; i < (sampleCount & ~3); i += 4)
{
uint baseIndex0 = (uint)(fraction * 128) * 4;
uint inputIndex0 = (uint)inputBufferIndex;
uint baseIndex0 = (uint)(fraction * 128) * 4;
uint inputIndex0 = (uint)inputBufferIndex;
fraction += ratio;
fraction += ratio;
uint baseIndex1 = ((uint)(fraction * 128) & 127) * 4;
uint inputIndex1 = (uint)inputBufferIndex + (uint)fraction;
uint baseIndex1 = ((uint)(fraction * 128) & 127) * 4;
uint inputIndex1 = (uint)inputBufferIndex + (uint)fraction;
fraction += ratio;
fraction += ratio;
uint baseIndex2 = ((uint)(fraction * 128) & 127) * 4;
uint inputIndex2 = (uint)inputBufferIndex + (uint)fraction;
uint baseIndex2 = ((uint)(fraction * 128) & 127) * 4;
uint inputIndex2 = (uint)inputBufferIndex + (uint)fraction;
fraction += ratio;
fraction += ratio;
uint baseIndex3 = ((uint)(fraction * 128) & 127) * 4;
uint inputIndex3 = (uint)inputBufferIndex + (uint)fraction;
uint baseIndex3 = ((uint)(fraction * 128) & 127) * 4;
uint inputIndex3 = (uint)inputBufferIndex + (uint)fraction;
fraction += ratio;
inputBufferIndex += (int)fraction;
fraction += ratio;
inputBufferIndex += (int)fraction;
// Only keep lower part (safe as fraction isn't supposed to be negative)
fraction -= (int)fraction;
// Only keep lower part (safe as fraction isn't supposed to be negative)
fraction -= (int)fraction;
Vector128<float> parameter0 = Sse.LoadVector128(pParameters + baseIndex0);
Vector128<float> parameter1 = Sse.LoadVector128(pParameters + baseIndex1);
Vector128<float> parameter2 = Sse.LoadVector128(pParameters + baseIndex2);
Vector128<float> parameter3 = Sse.LoadVector128(pParameters + baseIndex3);
Vector128<float> parameter0 = Sse.LoadVector128(pParameters + baseIndex0);
Vector128<float> parameter1 = Sse.LoadVector128(pParameters + baseIndex1);
Vector128<float> parameter2 = Sse.LoadVector128(pParameters + baseIndex2);
Vector128<float> parameter3 = Sse.LoadVector128(pParameters + baseIndex3);
Vector128<int> intInput0 = Sse41.ConvertToVector128Int32(pInput + inputIndex0);
Vector128<int> intInput1 = Sse41.ConvertToVector128Int32(pInput + inputIndex1);
Vector128<int> intInput2 = Sse41.ConvertToVector128Int32(pInput + inputIndex2);
Vector128<int> intInput3 = Sse41.ConvertToVector128Int32(pInput + inputIndex3);
Vector128<int> intInput0 = Sse41.ConvertToVector128Int32(pInput + inputIndex0);
Vector128<int> intInput1 = Sse41.ConvertToVector128Int32(pInput + inputIndex1);
Vector128<int> intInput2 = Sse41.ConvertToVector128Int32(pInput + inputIndex2);
Vector128<int> intInput3 = Sse41.ConvertToVector128Int32(pInput + inputIndex3);
Vector128<float> input0 = Sse2.ConvertToVector128Single(intInput0);
Vector128<float> input1 = Sse2.ConvertToVector128Single(intInput1);
Vector128<float> input2 = Sse2.ConvertToVector128Single(intInput2);
Vector128<float> input3 = Sse2.ConvertToVector128Single(intInput3);
Vector128<float> input0 = Sse2.ConvertToVector128Single(intInput0);
Vector128<float> input1 = Sse2.ConvertToVector128Single(intInput1);
Vector128<float> input2 = Sse2.ConvertToVector128Single(intInput2);
Vector128<float> input3 = Sse2.ConvertToVector128Single(intInput3);
Vector128<float> mix0 = Sse.Multiply(input0, parameter0);
Vector128<float> mix1 = Sse.Multiply(input1, parameter1);
Vector128<float> mix2 = Sse.Multiply(input2, parameter2);
Vector128<float> mix3 = Sse.Multiply(input3, parameter3);
Vector128<float> mix0 = Sse.Multiply(input0, parameter0);
Vector128<float> mix1 = Sse.Multiply(input1, parameter1);
Vector128<float> mix2 = Sse.Multiply(input2, parameter2);
Vector128<float> mix3 = Sse.Multiply(input3, parameter3);
Vector128<float> mix01 = Sse3.HorizontalAdd(mix0, mix1);
Vector128<float> mix23 = Sse3.HorizontalAdd(mix2, mix3);
Vector128<float> mix01 = Sse3.HorizontalAdd(mix0, mix1);
Vector128<float> mix23 = Sse3.HorizontalAdd(mix2, mix3);
Vector128<float> mix0123 = Sse3.HorizontalAdd(mix01, mix23);
Vector128<float> mix0123 = Sse3.HorizontalAdd(mix01, mix23);
Sse.Store(pOutput + (uint)i, Sse41.RoundToNearestInteger(mix0123));
}
Sse.Store(pOutput + (uint)i, Sse41.RoundToNearestInteger(mix0123));
}
}
}
@@ -526,34 +522,59 @@ namespace Ryujinx.Audio.Renderer.Dsp
return _highCurveLut2F;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void ResampleHighQuality(Span<float> outputBuffer, ReadOnlySpan<short> inputBuffer, float ratio, ref float fraction, int sampleCount)
private static unsafe void ResampleHighQuality(Span<float> outputBuffer, ReadOnlySpan<short> inputBuffer, float ratio, ref float fraction, int sampleCount)
{
ReadOnlySpan<float> parameters = GetHighParameter(ratio);
int inputBufferIndex = 0;
// TODO: fast path
for (int i = 0; i < sampleCount; i++)
if (Avx2.IsSupported)
{
int baseIndex = (int)(fraction * 128) * 8;
ReadOnlySpan<float> parameter = parameters.Slice(baseIndex, 8);
ReadOnlySpan<short> currentInput = inputBuffer.Slice(inputBufferIndex, 8);
// Fast path; assumes 256-bit vectors for simplicity because the filter is 8 taps
fixed (short* pInput = inputBuffer)
fixed (float* pParameters = parameters)
{
for (int i = 0; i < sampleCount; i++)
{
int baseIndex = (int)(fraction * 128) * 8;
outputBuffer[i] = (float)Math.Round(currentInput[0] * parameter[0] +
currentInput[1] * parameter[1] +
currentInput[2] * parameter[2] +
currentInput[3] * parameter[3] +
currentInput[4] * parameter[4] +
currentInput[5] * parameter[5] +
currentInput[6] * parameter[6] +
currentInput[7] * parameter[7]);
Vector256<int> intInput = Avx2.ConvertToVector256Int32(pInput + inputBufferIndex);
Vector256<float> floatInput = Avx.ConvertToVector256Single(intInput);
Vector256<float> parameter = Avx.LoadVector256(pParameters + baseIndex);
Vector256<float> dp = Avx.DotProduct(floatInput, parameter, control: 0xFF);
fraction += ratio;
inputBufferIndex += (int)MathF.Truncate(fraction);
// avx2 does an 8-element dot product piecewise so we have to sum up 2 intermediate results
outputBuffer[i] = (float)Math.Round(dp[0] + dp[4]);
fraction -= (int)fraction;
fraction += ratio;
inputBufferIndex += (int)MathF.Truncate(fraction);
fraction -= (int)fraction;
}
}
}
else
{
for (int i = 0; i < sampleCount; i++)
{
int baseIndex = (int)(fraction * 128) * 8;
ReadOnlySpan<float> parameter = parameters.Slice(baseIndex, 8);
ReadOnlySpan<short> currentInput = inputBuffer.Slice(inputBufferIndex, 8);
outputBuffer[i] = (float)Math.Round(currentInput[0] * parameter[0] +
currentInput[1] * parameter[1] +
currentInput[2] * parameter[2] +
currentInput[3] * parameter[3] +
currentInput[4] * parameter[4] +
currentInput[5] * parameter[5] +
currentInput[6] * parameter[6] +
currentInput[7] * parameter[7]);
fraction += ratio;
inputBufferIndex += (int)MathF.Truncate(fraction);
fraction -= (int)fraction;
}
}
}

View File

@@ -2,6 +2,7 @@ using Ryujinx.Audio.Renderer.Server.Upsampler;
using Ryujinx.Common.Memory;
using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace Ryujinx.Audio.Renderer.Dsp
@@ -70,16 +71,32 @@ namespace Ryujinx.Audio.Renderer.Dsp
return;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
float DoFilterBank(ref UpsamplerBufferState state, in Array20<float> bank)
{
float result = 0.0f;
Debug.Assert(state.History.Length == HistoryLength);
Debug.Assert(bank.Length == FilterBankLength);
for (int j = 0; j < FilterBankLength; j++)
int curIdx = 0;
if (Vector.IsHardwareAccelerated)
{
result += bank[j] * state.History[j];
// Do SIMD-accelerated block operations where possible.
// Only about a 2x speedup since filter bank length is short
int stopIdx = FilterBankLength - (FilterBankLength % Vector<float>.Count);
while (curIdx < stopIdx)
{
result += Vector.Dot(
new Vector<float>(bank.AsSpan().Slice(curIdx, Vector<float>.Count)),
new Vector<float>(state.History.AsSpan().Slice(curIdx, Vector<float>.Count)));
curIdx += Vector<float>.Count;
}
}
while (curIdx < FilterBankLength)
{
result += bank[curIdx] * state.History[curIdx];
curIdx++;
}
return result;

View File

@@ -506,6 +506,11 @@ namespace Ryujinx.Modules
Dispatcher.UIThread.Post(() =>
{
if (tarEntry is null)
{
return;
}
taskDialog.SetProgressBarState(GetPercentage(tarEntry.Size, inStream.Length), TaskDialogProgressState.Normal);
});
}

View File

@@ -105,13 +105,13 @@ public class TitleUpdateViewModel : BaseModel
AddUpdate(path);
}
// NOTE: Save the list again to remove leftovers.
Save();
TitleUpdateModel selected = TitleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected, null);
SelectedUpdate = selected;
// NOTE: Save the list again to remove leftovers.
Save();
SortUpdates();
}

View File

@@ -45,7 +45,15 @@ namespace Ryujinx.Common.Configuration
public static void Initialize(string baseDirPath)
{
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string appDataPath;
if (OperatingSystem.IsMacOS())
{
appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Library", "Application Support");
}
else
{
appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
}
if (appDataPath.Length == 0)
{
@@ -81,6 +89,21 @@ namespace Ryujinx.Common.Configuration
BaseDirPath = Path.GetFullPath(BaseDirPath); // convert relative paths
// NOTE: Moves the Ryujinx folder in `~/.config` to `~/Library/Application Support` if one is found
// and a Ryujinx folder does not already exist in Application Support.
// Also creates a symlink from `~/.config/Ryujinx` to `~/Library/Application Support/Ryujinx` to preserve backwards compatibility.
// This should be removed in the future.
if (OperatingSystem.IsMacOS() && Mode == LaunchMode.UserProfile)
{
string oldConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), DefaultBaseDir);
if (Path.Exists(oldConfigPath) && !Path.Exists(BaseDirPath))
{
CopyDirectory(oldConfigPath, BaseDirPath);
Directory.Delete(oldConfigPath, true);
Directory.CreateSymbolicLink(oldConfigPath, BaseDirPath);
}
}
SetupBasePaths();
}
@@ -92,6 +115,34 @@ namespace Ryujinx.Common.Configuration
Directory.CreateDirectory(KeysDirPath = Path.Combine(BaseDirPath, KeysDir));
}
private static void CopyDirectory(string sourceDir, string destinationDir)
{
var dir = new DirectoryInfo(sourceDir);
if (!dir.Exists)
{
throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}");
}
DirectoryInfo[] subDirs = dir.GetDirectories();
Directory.CreateDirectory(destinationDir);
foreach (FileInfo file in dir.GetFiles())
{
if (file.Name == ".DS_Store")
{
continue;
}
file.CopyTo(Path.Combine(destinationDir, file.Name));
}
foreach (DirectoryInfo subDir in subDirs)
{
CopyDirectory(subDir.FullName, Path.Combine(destinationDir, subDir.Name));
}
}
public static string GetModsPath() => CustomModsPath ?? Directory.CreateDirectory(Path.Combine(BaseDirPath, DefaultModsDir)).FullName;
public static string GetSdModsPath() => CustomSdModsPath ?? Directory.CreateDirectory(Path.Combine(BaseDirPath, DefaultSdcardDir, "atmosphere")).FullName;
}

View File

@@ -40,14 +40,21 @@ namespace Ryujinx.Common
}
}
#if FORCE_EXTERNAL_BASE_DIR
public static string GetBaseApplicationDirectory()
{
if (IsFlatHubBuild())
return AppDataManager.BaseDirPath;
}
#else
public static string GetBaseApplicationDirectory()
{
if (IsFlatHubBuild() || OperatingSystem.IsMacOS())
{
return AppDataManager.BaseDirPath;
}
return AppDomain.CurrentDomain.BaseDirectory;
}
#endif
}
}

View File

@@ -214,41 +214,6 @@ namespace Ryujinx.Graphics.Gpu.Image
return true;
}
/// <summary>
/// Checks if two formats are compatible, according to the host API copy format compatibility rules.
/// </summary>
/// <param name="lhsFormat">First comparand</param>
/// <param name="rhsFormat">Second comparand</param>
/// <param name="caps">Host GPU capabilities</param>
/// <returns>True if the formats are compatible, false otherwise</returns>
public static bool FormatCompatible(TextureInfo lhs, TextureInfo rhs, Capabilities caps)
{
FormatInfo lhsFormat = lhs.FormatInfo;
FormatInfo rhsFormat = rhs.FormatInfo;
if (lhsFormat.Format.IsDepthOrStencil() || rhsFormat.Format.IsDepthOrStencil())
{
return lhsFormat.Format == rhsFormat.Format;
}
if (IsFormatHostIncompatible(lhs, caps) || IsFormatHostIncompatible(rhs, caps))
{
return lhsFormat.Format == rhsFormat.Format;
}
if (lhsFormat.IsCompressed && rhsFormat.IsCompressed)
{
FormatClass lhsClass = GetFormatClass(lhsFormat.Format);
FormatClass rhsClass = GetFormatClass(rhsFormat.Format);
return lhsClass == rhsClass;
}
else
{
return lhsFormat.BytesPerPixel == rhsFormat.BytesPerPixel;
}
}
/// <summary>
/// Checks if the texture format matches with the specified texture information.
/// </summary>
@@ -391,6 +356,13 @@ namespace Ryujinx.Graphics.Gpu.Image
Size lhsSize = GetSizeInBlocks(lhs, level);
Size rhsSize = GetSizeInBlocks(rhs);
bool alignedWidthMatches = lhsAlignedSize.Width == rhsAlignedSize.Width;
if (lhs.FormatInfo.BytesPerPixel != rhs.FormatInfo.BytesPerPixel && IsIncompatibleFormatAliasingAllowed(lhs.FormatInfo, rhs.FormatInfo))
{
alignedWidthMatches = lhsSize.Width * lhs.FormatInfo.BytesPerPixel == rhsSize.Width * rhs.FormatInfo.BytesPerPixel;
}
TextureViewCompatibility result = TextureViewCompatibility.Full;
// For copies, we can copy a subset of the 3D texture slices,
@@ -404,7 +376,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// so the width may not match in this case for different uses of the same texture.
// To account for this, we compare the aligned width here.
// We expect height to always match exactly, if the texture is the same.
if (lhsAlignedSize.Width == rhsAlignedSize.Width && lhsSize.Height == rhsSize.Height)
if (alignedWidthMatches && lhsSize.Height == rhsSize.Height)
{
return (exact && lhsSize.Width != rhsSize.Width) || lhsSize.Width < rhsSize.Width
? TextureViewCompatibility.CopyOnly
@@ -659,21 +631,62 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <returns>The view compatibility level of the texture formats</returns>
public static TextureViewCompatibility ViewFormatCompatible(TextureInfo lhs, TextureInfo rhs, Capabilities caps)
{
if (FormatCompatible(lhs, rhs, caps))
FormatInfo lhsFormat = lhs.FormatInfo;
FormatInfo rhsFormat = rhs.FormatInfo;
if (lhsFormat.Format.IsDepthOrStencil() || rhsFormat.Format.IsDepthOrStencil())
{
if (lhs.FormatInfo.IsCompressed != rhs.FormatInfo.IsCompressed)
{
return TextureViewCompatibility.CopyOnly;
}
else
{
return TextureViewCompatibility.Full;
}
return lhsFormat.Format == rhsFormat.Format ? TextureViewCompatibility.Full : TextureViewCompatibility.Incompatible;
}
if (IsFormatHostIncompatible(lhs, caps) || IsFormatHostIncompatible(rhs, caps))
{
return lhsFormat.Format == rhsFormat.Format ? TextureViewCompatibility.Full : TextureViewCompatibility.Incompatible;
}
if (lhsFormat.IsCompressed && rhsFormat.IsCompressed)
{
FormatClass lhsClass = GetFormatClass(lhsFormat.Format);
FormatClass rhsClass = GetFormatClass(rhsFormat.Format);
return lhsClass == rhsClass ? TextureViewCompatibility.Full : TextureViewCompatibility.Incompatible;
}
else if (lhsFormat.BytesPerPixel == rhsFormat.BytesPerPixel)
{
return lhs.FormatInfo.IsCompressed == rhs.FormatInfo.IsCompressed
? TextureViewCompatibility.Full
: TextureViewCompatibility.CopyOnly;
}
else if (IsIncompatibleFormatAliasingAllowed(lhsFormat, rhsFormat))
{
return TextureViewCompatibility.CopyOnly;
}
return TextureViewCompatibility.Incompatible;
}
/// <summary>
/// Checks if aliasing of two formats that would normally be considered incompatible be allowed,
/// using copy dependencies.
/// </summary>
/// <param name="lhsFormat">Format information of the first texture</param
/// <param name="rhsFormat">Format information of the second texture</param>
/// <returns>True if aliasing should be allowed, false otherwise</returns>
private static bool IsIncompatibleFormatAliasingAllowed(FormatInfo lhsFormat, FormatInfo rhsFormat)
{
// Some games will try to alias textures with incompatible foramts, with different BPP (bytes per pixel).
// We allow that in some cases as long Width * BPP is equal on both textures.
// This is very conservative right now as we want to avoid copies as much as possible,
// so we only consider the formats we have seen being aliased.
if (rhsFormat.BytesPerPixel < lhsFormat.BytesPerPixel)
{
(lhsFormat, rhsFormat) = (rhsFormat, lhsFormat);
}
return lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm;
}
/// <summary>
/// Check if the target of the first texture view information is compatible with the target of the second texture view information.
/// This follows the host API target compatibility rules.

View File

@@ -0,0 +1,252 @@
using OpenTK.Graphics.OpenGL;
using Ryujinx.Graphics.GAL;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Numerics;
namespace Ryujinx.Graphics.OpenGL.Image
{
class TextureCopyIncompatible
{
private const string ComputeShaderShortening = @"#version 450 core
layout (binding = 0, $SRC_FORMAT$) uniform uimage2D src;
layout (binding = 1, $DST_FORMAT$) uniform uimage2D dst;
layout (local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
void main()
{
uvec2 coords = gl_GlobalInvocationID.xy;
ivec2 imageSz = imageSize(src);
if (int(coords.x) >= imageSz.x || int(coords.y) >= imageSz.y)
{
return;
}
uint coordsShifted = coords.x << $RATIO_LOG2$;
uvec2 dstCoords0 = uvec2(coordsShifted, coords.y);
uvec2 dstCoords1 = uvec2(coordsShifted + 1, coords.y);
uvec2 dstCoords2 = uvec2(coordsShifted + 2, coords.y);
uvec2 dstCoords3 = uvec2(coordsShifted + 3, coords.y);
uvec4 rgba = imageLoad(src, ivec2(coords));
imageStore(dst, ivec2(dstCoords0), rgba.rrrr);
imageStore(dst, ivec2(dstCoords1), rgba.gggg);
imageStore(dst, ivec2(dstCoords2), rgba.bbbb);
imageStore(dst, ivec2(dstCoords3), rgba.aaaa);
}";
private const string ComputeShaderWidening = @"#version 450 core
layout (binding = 0, $SRC_FORMAT$) uniform uimage2D src;
layout (binding = 1, $DST_FORMAT$) uniform uimage2D dst;
layout (local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
void main()
{
uvec2 coords = gl_GlobalInvocationID.xy;
ivec2 imageSz = imageSize(dst);
if (int(coords.x) >= imageSz.x || int(coords.y) >= imageSz.y)
{
return;
}
uvec2 srcCoords = uvec2(coords.x << $RATIO_LOG2$, coords.y);
uint r = imageLoad(src, ivec2(srcCoords) + ivec2(0, 0)).r;
uint g = imageLoad(src, ivec2(srcCoords) + ivec2(1, 0)).r;
uint b = imageLoad(src, ivec2(srcCoords) + ivec2(2, 0)).r;
uint a = imageLoad(src, ivec2(srcCoords) + ivec2(3, 0)).r;
imageStore(dst, ivec2(coords), uvec4(r, g, b, a));
}";
private readonly OpenGLRenderer _renderer;
private readonly Dictionary<int, int> _shorteningProgramHandles;
private readonly Dictionary<int, int> _wideningProgramHandles;
public TextureCopyIncompatible(OpenGLRenderer renderer)
{
_renderer = renderer;
_shorteningProgramHandles = new Dictionary<int, int>();
_wideningProgramHandles = new Dictionary<int, int>();
}
public void CopyIncompatibleFormats(ITextureInfo src, ITextureInfo dst, int srcLayer, int dstLayer, int srcLevel, int dstLevel, int depth, int levels)
{
TextureCreateInfo srcInfo = src.Info;
TextureCreateInfo dstInfo = dst.Info;
int srcBpp = src.Info.BytesPerPixel;
int dstBpp = dst.Info.BytesPerPixel;
// Calculate ideal component size, given our constraints:
// - Component size must not exceed bytes per pixel of source and destination image formats.
// - Maximum component size is 4 (R32).
int componentSize = Math.Min(Math.Min(srcBpp, dstBpp), 4);
int srcComponentsCount = srcBpp / componentSize;
int dstComponentsCount = dstBpp / componentSize;
var srcFormat = GetFormat(componentSize, srcComponentsCount);
var dstFormat = GetFormat(componentSize, dstComponentsCount);
GL.UseProgram(srcBpp < dstBpp
? GetWideningShader(componentSize, srcComponentsCount, dstComponentsCount)
: GetShorteningShader(componentSize, srcComponentsCount, dstComponentsCount));
for (int l = 0; l < levels; l++)
{
int srcWidth = Math.Max(1, src.Info.Width >> l);
int srcHeight = Math.Max(1, src.Info.Height >> l);
int dstWidth = Math.Max(1, dst.Info.Width >> l);
int dstHeight = Math.Max(1, dst.Info.Height >> l);
int width = Math.Min(srcWidth, dstWidth);
int height = Math.Min(srcHeight, dstHeight);
for (int z = 0; z < depth; z++)
{
GL.BindImageTexture(0, src.Handle, srcLevel + l, false, srcLayer + z, TextureAccess.ReadOnly, srcFormat);
GL.BindImageTexture(1, dst.Handle, dstLevel + l, false, dstLayer + z, TextureAccess.WriteOnly, dstFormat);
GL.DispatchCompute((width + 31) / 32, (height + 31) / 32, 1);
}
}
Pipeline pipeline = (Pipeline)_renderer.Pipeline;
pipeline.RestoreProgram();
pipeline.RestoreImages1And2();
}
private static SizedInternalFormat GetFormat(int componentSize, int componentsCount)
{
if (componentSize == 1)
{
return componentsCount switch
{
1 => SizedInternalFormat.R8ui,
2 => SizedInternalFormat.Rg8ui,
4 => SizedInternalFormat.Rgba8ui,
_ => throw new ArgumentException($"Invalid components count {componentsCount}.")
};
}
else if (componentSize == 2)
{
return componentsCount switch
{
1 => SizedInternalFormat.R16ui,
2 => SizedInternalFormat.Rg16ui,
4 => SizedInternalFormat.Rgba16ui,
_ => throw new ArgumentException($"Invalid components count {componentsCount}.")
};
}
else if (componentSize == 4)
{
return componentsCount switch
{
1 => SizedInternalFormat.R32ui,
2 => SizedInternalFormat.Rg32ui,
4 => SizedInternalFormat.Rgba32ui,
_ => throw new ArgumentException($"Invalid components count {componentsCount}.")
};
}
else
{
throw new ArgumentException($"Invalid component size {componentSize}.");
}
}
private int GetShorteningShader(int componentSize, int srcComponentsCount, int dstComponentsCount)
{
return GetShader(ComputeShaderShortening, _shorteningProgramHandles, componentSize, srcComponentsCount, dstComponentsCount);
}
private int GetWideningShader(int componentSize, int srcComponentsCount, int dstComponentsCount)
{
return GetShader(ComputeShaderWidening, _wideningProgramHandles, componentSize, srcComponentsCount, dstComponentsCount);
}
private int GetShader(
string code,
Dictionary<int, int> programHandles,
int componentSize,
int srcComponentsCount,
int dstComponentsCount)
{
int componentSizeLog2 = BitOperations.Log2((uint)componentSize);
int srcIndex = componentSizeLog2 + BitOperations.Log2((uint)srcComponentsCount) * 3;
int dstIndex = componentSizeLog2 + BitOperations.Log2((uint)dstComponentsCount) * 3;
int key = srcIndex | (dstIndex << 8);
if (!programHandles.TryGetValue(key, out int programHandle))
{
int csHandle = GL.CreateShader(ShaderType.ComputeShader);
string[] formatTable = new[] { "r8ui", "r16ui", "r32ui", "rg8ui", "rg16ui", "rg32ui", "rgba8ui", "rgba16ui", "rgba32ui" };
string srcFormat = formatTable[srcIndex];
string dstFormat = formatTable[dstIndex];
int srcBpp = srcComponentsCount * componentSize;
int dstBpp = dstComponentsCount * componentSize;
int ratio = srcBpp < dstBpp ? dstBpp / srcBpp : srcBpp / dstBpp;
int ratioLog2 = BitOperations.Log2((uint)ratio);
GL.ShaderSource(csHandle, code
.Replace("$SRC_FORMAT$", srcFormat)
.Replace("$DST_FORMAT$", dstFormat)
.Replace("$RATIO_LOG2$", ratioLog2.ToString(CultureInfo.InvariantCulture)));
GL.CompileShader(csHandle);
programHandle = GL.CreateProgram();
GL.AttachShader(programHandle, csHandle);
GL.LinkProgram(programHandle);
GL.DetachShader(programHandle, csHandle);
GL.DeleteShader(csHandle);
GL.GetProgram(programHandle, GetProgramParameterName.LinkStatus, out int status);
if (status == 0)
{
throw new Exception(GL.GetProgramInfoLog(programHandle));
}
programHandles.Add(key, programHandle);
}
return programHandle;
}
public void Dispose()
{
foreach (int handle in _shorteningProgramHandles.Values)
{
GL.DeleteProgram(handle);
}
_shorteningProgramHandles.Clear();
foreach (int handle in _wideningProgramHandles.Values)
{
GL.DeleteProgram(handle);
}
_wideningProgramHandles.Clear();
}
}
}

View File

@@ -127,6 +127,12 @@ namespace Ryujinx.Graphics.OpenGL.Image
int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
_renderer.TextureCopyMS.CopyNonMSToMS(this, destinationView, 0, firstLayer, layers);
}
else if (destinationView.Info.BytesPerPixel != Info.BytesPerPixel)
{
int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
int levels = Math.Min(Info.Levels, destinationView.Info.Levels - firstLevel);
_renderer.TextureCopyIncompatible.CopyIncompatibleFormats(this, destinationView, 0, firstLayer, 0, firstLevel, layers, levels);
}
else
{
_renderer.TextureCopy.CopyUnscaled(this, destinationView, 0, firstLayer, 0, firstLevel);
@@ -145,6 +151,10 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
_renderer.TextureCopyMS.CopyNonMSToMS(this, destinationView, srcLayer, dstLayer, 1);
}
else if (destinationView.Info.BytesPerPixel != Info.BytesPerPixel)
{
_renderer.TextureCopyIncompatible.CopyIncompatibleFormats(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
}
else
{
_renderer.TextureCopy.CopyUnscaled(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);

View File

@@ -24,6 +24,7 @@ namespace Ryujinx.Graphics.OpenGL
private TextureCopy _textureCopy;
private TextureCopy _backgroundTextureCopy;
internal TextureCopy TextureCopy => BackgroundContextWorker.InBackground ? _backgroundTextureCopy : _textureCopy;
internal TextureCopyIncompatible TextureCopyIncompatible { get; }
internal TextureCopyMS TextureCopyMS { get; }
private Sync _sync;
@@ -49,6 +50,7 @@ namespace Ryujinx.Graphics.OpenGL
_window = new Window(this);
_textureCopy = new TextureCopy(this);
_backgroundTextureCopy = new TextureCopy(this);
TextureCopyIncompatible = new TextureCopyIncompatible(this);
TextureCopyMS = new TextureCopyMS(this);
_sync = new Sync();
PersistentBuffers = new PersistentBuffers();

View File

@@ -5,6 +5,7 @@ using Ryujinx.Graphics.Vulkan.Shaders;
using Silk.NET.Vulkan;
using System;
using System.Collections.Generic;
using System.Numerics;
using VkFormat = Silk.NET.Vulkan.Format;
namespace Ryujinx.Graphics.Vulkan
@@ -32,7 +33,9 @@ namespace Ryujinx.Graphics.Vulkan
private readonly IProgram _programStrideChange;
private readonly IProgram _programConvertIndexBuffer;
private readonly IProgram _programConvertIndirectData;
private readonly IProgram _programColorCopyShortening;
private readonly IProgram _programColorCopyToNonMs;
private readonly IProgram _programColorCopyWidening;
private readonly IProgram _programColorDrawToMs;
private readonly IProgram _programDepthBlit;
private readonly IProgram _programDepthBlitMs;
@@ -112,15 +115,25 @@ namespace Ryujinx.Graphics.Vulkan
new ShaderSource(ShaderBinaries.ChangeBufferStrideShaderSource, strideChangeBindings, ShaderStage.Compute, TargetLanguage.Spirv),
});
var colorCopyToNonMsBindings = new ShaderBindings(
var colorCopyBindings = new ShaderBindings(
new[] { 0 },
Array.Empty<int>(),
new[] { 0 },
new[] { 0 });
_programColorCopyShortening = gd.CreateProgramWithMinimalLayout(new[]
{
new ShaderSource(ShaderBinaries.ColorCopyShorteningComputeShaderSource, colorCopyBindings, ShaderStage.Compute, TargetLanguage.Spirv),
});
_programColorCopyToNonMs = gd.CreateProgramWithMinimalLayout(new[]
{
new ShaderSource(ShaderBinaries.ColorCopyToNonMsComputeShaderSource, colorCopyToNonMsBindings, ShaderStage.Compute, TargetLanguage.Spirv),
new ShaderSource(ShaderBinaries.ColorCopyToNonMsComputeShaderSource, colorCopyBindings, ShaderStage.Compute, TargetLanguage.Spirv),
});
_programColorCopyWidening = gd.CreateProgramWithMinimalLayout(new[]
{
new ShaderSource(ShaderBinaries.ColorCopyWideningComputeShaderSource, colorCopyBindings, ShaderStage.Compute, TargetLanguage.Spirv),
});
var colorDrawToMsVertexBindings = new ShaderBindings(
@@ -922,6 +935,107 @@ namespace Ryujinx.Graphics.Vulkan
convertedCount * outputIndexSize);
}
public void CopyIncompatibleFormats(
VulkanRenderer gd,
CommandBufferScoped cbs,
TextureView src,
TextureView dst,
int srcLayer,
int dstLayer,
int srcLevel,
int dstLevel,
int depth,
int levels)
{
const int ParamsBufferSize = 4;
Span<int> shaderParams = stackalloc int[sizeof(int)];
int srcBpp = src.Info.BytesPerPixel;
int dstBpp = dst.Info.BytesPerPixel;
int ratio = srcBpp < dstBpp ? dstBpp / srcBpp : srcBpp / dstBpp;
shaderParams[0] = BitOperations.Log2((uint)ratio);
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize, false);
gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams);
TextureView.InsertImageBarrier(
gd.Api,
cbs.CommandBuffer,
src.GetImage().Get(cbs).Value,
TextureStorage.DefaultAccessMask,
AccessFlags.ShaderReadBit,
PipelineStageFlags.AllCommandsBit,
PipelineStageFlags.ComputeShaderBit,
ImageAspectFlags.ColorBit,
src.FirstLayer + srcLayer,
src.FirstLevel + srcLevel,
depth,
levels);
_pipeline.SetCommandBuffer(cbs);
_pipeline.SetProgram(srcBpp < dstBpp ? _programColorCopyWidening : _programColorCopyShortening);
// Calculate ideal component size, given our constraints:
// - Component size must not exceed bytes per pixel of source and destination image formats.
// - Maximum component size is 4 (R32).
int componentSize = Math.Min(Math.Min(srcBpp, dstBpp), 4);
var srcFormat = GetFormat(componentSize, srcBpp / componentSize);
var dstFormat = GetFormat(componentSize, dstBpp / componentSize);
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
for (int l = 0; l < levels; l++)
{
for (int z = 0; z < depth; z++)
{
var srcView = Create2DLayerView(src, srcLayer + z, srcLevel + l, srcFormat);
var dstView = Create2DLayerView(dst, dstLayer + z, dstLevel + l);
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 0, srcView, null);
_pipeline.SetImage(0, dstView, dstFormat);
int dispatchX = (Math.Min(srcView.Info.Width, dstView.Info.Width) + 31) / 32;
int dispatchY = (Math.Min(srcView.Info.Height, dstView.Info.Height) + 31) / 32;
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
if (srcView != src)
{
srcView.Release();
}
if (dstView != dst)
{
dstView.Release();
}
}
}
gd.BufferManager.Delete(bufferHandle);
_pipeline.Finish(gd, cbs);
TextureView.InsertImageBarrier(
gd.Api,
cbs.CommandBuffer,
dst.GetImage().Get(cbs).Value,
AccessFlags.ShaderWriteBit,
TextureStorage.DefaultAccessMask,
PipelineStageFlags.ComputeShaderBit,
PipelineStageFlags.AllCommandsBit,
ImageAspectFlags.ColorBit,
dst.FirstLayer + dstLayer,
dst.FirstLevel + dstLevel,
depth,
levels);
}
public void CopyMSToNonMS(VulkanRenderer gd, CommandBufferScoped cbs, TextureView src, TextureView dst, int srcLayer, int dstLayer, int depth)
{
const int ParamsBufferSize = 16;
@@ -1196,6 +1310,44 @@ namespace Ryujinx.Graphics.Vulkan
};
}
private static GAL.Format GetFormat(int componentSize, int componentsCount)
{
if (componentSize == 1)
{
return componentsCount switch
{
1 => GAL.Format.R8Uint,
2 => GAL.Format.R8G8Uint,
4 => GAL.Format.R8G8B8A8Uint,
_ => throw new ArgumentException($"Invalid components count {componentsCount}.")
};
}
else if (componentSize == 2)
{
return componentsCount switch
{
1 => GAL.Format.R16Uint,
2 => GAL.Format.R16G16Uint,
4 => GAL.Format.R16G16B16A16Uint,
_ => throw new ArgumentException($"Invalid components count {componentsCount}.")
};
}
else if (componentSize == 4)
{
return componentsCount switch
{
1 => GAL.Format.R32Uint,
2 => GAL.Format.R32G32Uint,
4 => GAL.Format.R32G32B32A32Uint,
_ => throw new ArgumentException($"Invalid components count {componentsCount}.")
};
}
else
{
throw new ArgumentException($"Invalid component size {componentSize}.");
}
}
public void ConvertIndexBufferIndirect(
VulkanRenderer gd,
CommandBufferScoped cbs,
@@ -1336,7 +1488,9 @@ namespace Ryujinx.Graphics.Vulkan
_programStrideChange.Dispose();
_programConvertIndexBuffer.Dispose();
_programConvertIndirectData.Dispose();
_programColorCopyShortening.Dispose();
_programColorCopyToNonMs.Dispose();
_programColorCopyWidening.Dispose();
_programColorDrawToMs.Dispose();
_programDepthBlit.Dispose();
_programDepthBlitMs.Dispose();

View File

@@ -0,0 +1,36 @@
#version 450 core
layout (std140, binding = 0) uniform ratio_in
{
int ratio;
};
layout (set = 2, binding = 0) uniform usampler2D src;
layout (set = 3, binding = 0) writeonly uniform uimage2D dst;
layout (local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
void main()
{
uvec2 coords = gl_GlobalInvocationID.xy;
ivec2 textureSz = textureSize(src, 0);
if (int(coords.x) >= textureSz.x || int(coords.y) >= textureSz.y)
{
return;
}
uint coordsShifted = coords.x << ratio;
uvec2 dstCoords0 = uvec2(coordsShifted, coords.y);
uvec2 dstCoords1 = uvec2(coordsShifted + 1, coords.y);
uvec2 dstCoords2 = uvec2(coordsShifted + 2, coords.y);
uvec2 dstCoords3 = uvec2(coordsShifted + 3, coords.y);
uvec4 rgba = texelFetch(src, ivec2(coords), 0);
imageStore(dst, ivec2(dstCoords0), rgba.rrrr);
imageStore(dst, ivec2(dstCoords1), rgba.gggg);
imageStore(dst, ivec2(dstCoords2), rgba.bbbb);
imageStore(dst, ivec2(dstCoords3), rgba.aaaa);
}

View File

@@ -0,0 +1,31 @@
#version 450 core
layout (std140, binding = 0) uniform ratio_in
{
int ratio;
};
layout (set = 2, binding = 0) uniform usampler2D src;
layout (set = 3, binding = 0) writeonly uniform uimage2D dst;
layout (local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
void main()
{
uvec2 coords = gl_GlobalInvocationID.xy;
ivec2 imageSz = imageSize(dst);
if (int(coords.x) >= imageSz.x || int(coords.y) >= imageSz.y)
{
return;
}
uvec2 srcCoords = uvec2(coords.x << ratio, coords.y);
uint r = texelFetchOffset(src, ivec2(srcCoords), 0, ivec2(0, 0)).r;
uint g = texelFetchOffset(src, ivec2(srcCoords), 0, ivec2(1, 0)).r;
uint b = texelFetchOffset(src, ivec2(srcCoords), 0, ivec2(2, 0)).r;
uint a = texelFetchOffset(src, ivec2(srcCoords), 0, ivec2(3, 0)).r;
imageStore(dst, ivec2(coords), uvec4(r, g, b, a));
}

View File

@@ -669,6 +669,138 @@ namespace Ryujinx.Graphics.Vulkan.Shaders
0x35, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};
public static readonly byte[] ColorCopyShorteningComputeShaderSource = new byte[]
{
0x03, 0x02, 0x23, 0x07, 0x00, 0x05, 0x01, 0x00, 0x0B, 0x00, 0x08, 0x00, 0x79, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x32, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30,
0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x09, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x60, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,
0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00,
0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x47, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x49, 0x6E, 0x76, 0x6F, 0x63, 0x61, 0x74,
0x69, 0x6F, 0x6E, 0x49, 0x44, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x16, 0x00, 0x00, 0x00,
0x73, 0x72, 0x63, 0x00, 0x05, 0x00, 0x05, 0x00, 0x36, 0x00, 0x00, 0x00, 0x72, 0x61, 0x74, 0x69,
0x6F, 0x5F, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x36, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x60, 0x00, 0x00, 0x00,
0x64, 0x73, 0x74, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x1C, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x36, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x60, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x60, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x60, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x76, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00,
0x13, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x03, 0x00,
0x36, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x37, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x37, 0x00, 0x00, 0x00,
0x38, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x39, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
0x4A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
0x51, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x56, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x5E, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x5F, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x06, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
0xF7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0x00, 0x03, 0x00,
0x1C, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x78, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x4F, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x14, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00,
0x13, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x67, 0x00, 0x05, 0x00,
0x10, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x1F, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x00, 0x05, 0x00, 0x1B, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x04, 0x00,
0x1B, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00,
0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00,
0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x26, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00,
0x2A, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,
0x1A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAF, 0x00, 0x05, 0x00, 0x1B, 0x00, 0x00, 0x00,
0x2E, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
0x27, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x27, 0x00, 0x00, 0x00, 0xF5, 0x00, 0x07, 0x00,
0x1B, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
0x2E, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x31, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x30, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
0x77, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x31, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x39, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00,
0xC4, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,
0x41, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00,
0x06, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x50, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00,
0x3C, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,
0x4E, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00,
0x06, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00,
0x50, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00,
0x0E, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x07, 0x00, 0x56, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00,
0x5C, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
0x7C, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
0x4F, 0x00, 0x09, 0x00, 0x56, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00,
0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x05, 0x00, 0x61, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00,
0x65, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x5E, 0x00, 0x00, 0x00,
0x66, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
0x68, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x09, 0x00, 0x56, 0x00, 0x00, 0x00,
0x6A, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x63, 0x00, 0x05, 0x00,
0x66, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
0x7C, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00,
0x4F, 0x00, 0x09, 0x00, 0x56, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00,
0x5D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x63, 0x00, 0x05, 0x00, 0x6B, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x00, 0x00,
0x6F, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x5E, 0x00, 0x00, 0x00,
0x70, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
0x72, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x09, 0x00, 0x56, 0x00, 0x00, 0x00,
0x74, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x63, 0x00, 0x05, 0x00,
0x70, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
0xF9, 0x00, 0x02, 0x00, 0x77, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x77, 0x00, 0x00, 0x00,
0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};
public static readonly byte[] ColorCopyToNonMsComputeShaderSource = new byte[]
{
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x86, 0x00, 0x00, 0x00,
@@ -801,6 +933,133 @@ namespace Ryujinx.Graphics.Vulkan.Shaders
0x84, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};
public static readonly byte[] ColorCopyWideningComputeShaderSource = new byte[]
{
0x03, 0x02, 0x23, 0x07, 0x00, 0x05, 0x01, 0x00, 0x0B, 0x00, 0x08, 0x00, 0x72, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x32, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30,
0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x09, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00,
0x42, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,
0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00,
0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x47, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x49, 0x6E, 0x76, 0x6F, 0x63, 0x61, 0x74,
0x69, 0x6F, 0x6E, 0x49, 0x44, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x15, 0x00, 0x00, 0x00,
0x64, 0x73, 0x74, 0x00, 0x05, 0x00, 0x05, 0x00, 0x33, 0x00, 0x00, 0x00, 0x72, 0x61, 0x74, 0x69,
0x6F, 0x5F, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x33, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x42, 0x00, 0x00, 0x00,
0x73, 0x72, 0x63, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x1C, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x35, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x35, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x42, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x42, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,
0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x18, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x34, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x34, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x37, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00,
0x3F, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1B, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x05, 0x00,
0x10, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
0x17, 0x00, 0x04, 0x00, 0x48, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x2C, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00,
0x36, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00,
0x58, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x61, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00,
0x62, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x06, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00,
0x25, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
0xF7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0x00, 0x03, 0x00,
0x19, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x71, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x4F, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x13, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x68, 0x00, 0x04, 0x00,
0x10, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
0x06, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7C, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xAF, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x1D, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x24, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x23, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
0x06, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x7C, 0x00, 0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0xAF, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, 0xF5, 0x00, 0x07, 0x00, 0x18, 0x00, 0x00, 0x00,
0x2C, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFA, 0x00, 0x04, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x2D, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x70, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x37, 0x00, 0x00, 0x00,
0x38, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xC4, 0x00, 0x05, 0x00,
0x06, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00,
0x3A, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00,
0x43, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
0x45, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00,
0x47, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x08, 0x00, 0x48, 0x00, 0x00, 0x00,
0x49, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x0A, 0x20, 0x00, 0x00,
0x36, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
0x4A, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00,
0x3F, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x08, 0x00,
0x48, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00,
0x0A, 0x20, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
0x06, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x64, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00,
0x5F, 0x00, 0x08, 0x00, 0x48, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00,
0x45, 0x00, 0x00, 0x00, 0x0A, 0x20, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00,
0x43, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x08, 0x00, 0x48, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
0x63, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x0A, 0x20, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
0x62, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00,
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00,
0x66, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
0x68, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x48, 0x00, 0x00, 0x00,
0x6D, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00,
0x65, 0x00, 0x00, 0x00, 0x63, 0x00, 0x05, 0x00, 0x66, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00,
0x6D, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x70, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x70, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};
public static readonly byte[] ColorDrawToMsVertexShaderSource = new byte[]
{
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x2E, 0x00, 0x00, 0x00,

View File

@@ -199,6 +199,12 @@ namespace Ryujinx.Graphics.Vulkan
int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
_gd.HelperShader.CopyNonMSToMS(_gd, cbs, src, dst, 0, firstLayer, layers);
}
else if (dst.Info.BytesPerPixel != Info.BytesPerPixel)
{
int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
int levels = Math.Min(Info.Levels, dst.Info.Levels - firstLevel);
_gd.HelperShader.CopyIncompatibleFormats(_gd, cbs, src, dst, 0, firstLayer, 0, firstLevel, layers, levels);
}
else
{
TextureCopy.Copy(
@@ -244,6 +250,10 @@ namespace Ryujinx.Graphics.Vulkan
{
_gd.HelperShader.CopyNonMSToMS(_gd, cbs, src, dst, srcLayer, dstLayer, 1);
}
else if (dst.Info.BytesPerPixel != Info.BytesPerPixel)
{
_gd.HelperShader.CopyIncompatibleFormats(_gd, cbs, src, dst, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
}
else
{
TextureCopy.Copy(

View File

@@ -0,0 +1,93 @@
using NUnit.Framework;
using Ryujinx.Audio.Renderer.Dsp;
using Ryujinx.Audio.Renderer.Parameter;
using Ryujinx.Audio.Renderer.Server.Upsampler;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Ryujinx.Tests.Audio.Renderer.Dsp
{
class ResamplerTests
{
[Test]
[TestCase(VoiceInParameter.SampleRateConversionQuality.Low)]
[TestCase(VoiceInParameter.SampleRateConversionQuality.Default)]
[TestCase(VoiceInParameter.SampleRateConversionQuality.High)]
public void TestResamplerConsistencyUpsampling(VoiceInParameter.SampleRateConversionQuality quality)
{
DoResamplingTest(44100, 48000, quality);
}
[Test]
[TestCase(VoiceInParameter.SampleRateConversionQuality.Low)]
[TestCase(VoiceInParameter.SampleRateConversionQuality.Default)]
[TestCase(VoiceInParameter.SampleRateConversionQuality.High)]
public void TestResamplerConsistencyDownsampling(VoiceInParameter.SampleRateConversionQuality quality)
{
DoResamplingTest(48000, 44100, quality);
}
/// <summary>
/// Generates a 1-second sine wave sample at input rate, resamples it to output rate, and
/// ensures that it resampled at the expected rate with no discontinuities
/// </summary>
/// <param name="inputRate">The input sample rate to test</param>
/// <param name="outputRate">The output sample rate to test</param>
/// <param name="quality">The resampler quality to use</param>
private static void DoResamplingTest(int inputRate, int outputRate, VoiceInParameter.SampleRateConversionQuality quality)
{
float inputSampleRate = (float)inputRate;
float outputSampleRate = (float)outputRate;
int inputSampleCount = inputRate;
int outputSampleCount = outputRate;
short[] inputBuffer = new short[inputSampleCount + 100]; // add some safety buffer at the end
float[] outputBuffer = new float[outputSampleCount + 100];
for (int sample = 0; sample < inputBuffer.Length; sample++)
{
// 440 hz sine wave with amplitude = 0.5f at input sample rate
inputBuffer[sample] = (short)(32767 * MathF.Sin((440 / inputSampleRate) * (float)sample * MathF.PI * 2f) * 0.5f);
}
float fraction = 0;
ResamplerHelper.Resample(
outputBuffer.AsSpan(),
inputBuffer.AsSpan(),
inputSampleRate / outputSampleRate,
ref fraction,
outputSampleCount,
quality,
false);
float[] expectedOutput = new float[outputSampleCount];
float sumDifference = 0;
int delay = quality switch
{
VoiceInParameter.SampleRateConversionQuality.High => 3,
VoiceInParameter.SampleRateConversionQuality.Default => 1,
_ => 0
};
for (int sample = 0; sample < outputSampleCount; sample++)
{
outputBuffer[sample] /= 32767;
// 440 hz sine wave with amplitude = 0.5f at output sample rate
expectedOutput[sample] = MathF.Sin((440 / outputSampleRate) * (float)(sample + delay) * MathF.PI * 2f) * 0.5f;
float thisDelta = Math.Abs(expectedOutput[sample] - outputBuffer[sample]);
// Ensure no discontinuities
Assert.IsTrue(thisDelta < 0.1f);
sumDifference += thisDelta;
}
sumDifference = sumDifference / (float)outputSampleCount;
// Expect the output to be 99% similar to the expected resampled sine wave
Assert.IsTrue(sumDifference < 0.01f);
}
}
}

View File

@@ -0,0 +1,64 @@
using NUnit.Framework;
using Ryujinx.Audio.Renderer.Dsp;
using Ryujinx.Audio.Renderer.Parameter;
using Ryujinx.Audio.Renderer.Server.Upsampler;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Ryujinx.Tests.Audio.Renderer.Dsp
{
class UpsamplerTests
{
[Test]
public void TestUpsamplerConsistency()
{
UpsamplerBufferState bufferState = new UpsamplerBufferState();
int inputBlockSize = 160;
int numInputSamples = 32000;
int numOutputSamples = 48000;
float inputSampleRate = numInputSamples;
float outputSampleRate = numOutputSamples;
float[] inputBuffer = new float[numInputSamples + 100];
float[] outputBuffer = new float[numOutputSamples + 100];
for (int sample = 0; sample < inputBuffer.Length; sample++)
{
// 440 hz sine wave with amplitude = 0.5f at input sample rate
inputBuffer[sample] = MathF.Sin((440 / inputSampleRate) * (float)sample * MathF.PI * 2f) * 0.5f;
}
int inputIdx = 0;
int outputIdx = 0;
while (inputIdx + inputBlockSize < numInputSamples)
{
int outputBufLength = (int)Math.Round((float)(inputIdx + inputBlockSize) * outputSampleRate / inputSampleRate) - outputIdx;
UpsamplerHelper.Upsample(
outputBuffer.AsSpan(outputIdx),
inputBuffer.AsSpan(inputIdx),
outputBufLength,
inputBlockSize,
ref bufferState);
inputIdx += inputBlockSize;
outputIdx += outputBufLength;
}
float[] expectedOutput = new float[numOutputSamples];
float sumDifference = 0;
for (int sample = 0; sample < numOutputSamples; sample++)
{
// 440 hz sine wave with amplitude = 0.5f at output sample rate with an offset of 15
expectedOutput[sample] = MathF.Sin((440 / outputSampleRate) * (float)(sample - 15) * MathF.PI * 2f) * 0.5f;
sumDifference += Math.Abs(expectedOutput[sample] - outputBuffer[sample]);
}
sumDifference = sumDifference / (float)expectedOutput.Length;
// Expect the output to be 98% similar to the expected resampled sine wave
Assert.IsTrue(sumDifference < 0.02f);
}
}
}