diff --git a/Directory.Packages.props b/Directory.Packages.props index e45ffccae..3fa3bfe2c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -17,12 +17,11 @@ - - + @@ -33,7 +32,7 @@ - + @@ -51,4 +50,4 @@ - \ No newline at end of file + diff --git a/src/Ryujinx.Ava/Ryujinx.Ava.csproj b/src/Ryujinx.Ava/Ryujinx.Ava.csproj index b6d37a2f1..7f5224cfb 100644 --- a/src/Ryujinx.Ava/Ryujinx.Ava.csproj +++ b/src/Ryujinx.Ava/Ryujinx.Ava.csproj @@ -43,7 +43,6 @@ - diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml b/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml index bbdb4c4a7..2dc95662a 100644 --- a/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml +++ b/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml @@ -4,7 +4,6 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" @@ -33,11 +32,10 @@ SelectionChanged="GameList_SelectionChanged"> - + VerticalAlignment="Top" + Orientation="Horizontal" /> diff --git a/src/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml b/src/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml index 818a21d69..3a9de3039 100644 --- a/src/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml +++ b/src/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml @@ -4,7 +4,6 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models" @@ -40,11 +39,10 @@ ItemsSource="{Binding Profiles}"> - + @@ -161,4 +159,4 @@ Content="{locale:Locale UserProfilesClose}" /> - \ No newline at end of file + diff --git a/src/Ryujinx.Ava/UI/Windows/AboutWindow.axaml b/src/Ryujinx.Ava/UI/Windows/AboutWindow.axaml index a0fd2a1ac..ace1094e4 100644 --- a/src/Ryujinx.Ava/UI/Windows/AboutWindow.axaml +++ b/src/Ryujinx.Ava/UI/Windows/AboutWindow.axaml @@ -3,7 +3,6 @@ xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" @@ -49,13 +48,11 @@ Grid.Column="0" Height="80" Source="resm:Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.Ui.Common" /> - + HorizontalAlignment="Right" + VerticalAlignment="Center" + Orientation="Vertical"> - + Instructions; public readonly bool EndsWithBranch; public readonly bool HasHostCall; + public readonly bool HasHostCallSkipContext; public readonly bool IsTruncated; public readonly bool IsLoopEnd; public readonly bool IsThumb; @@ -20,6 +21,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 List instructions, bool endsWithBranch, bool hasHostCall, + bool hasHostCallSkipContext, bool isTruncated, bool isLoopEnd, bool isThumb) @@ -31,6 +33,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 Instructions = instructions; EndsWithBranch = endsWithBranch; HasHostCall = hasHostCall; + HasHostCallSkipContext = hasHostCallSkipContext; IsTruncated = isTruncated; IsLoopEnd = isLoopEnd; IsThumb = isThumb; @@ -57,6 +60,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 Instructions.GetRange(0, splitIndex), false, HasHostCall, + HasHostCallSkipContext, false, false, IsThumb); @@ -67,6 +71,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 Instructions.GetRange(splitIndex, splitCount), EndsWithBranch, HasHostCall, + HasHostCallSkipContext, IsTruncated, IsLoopEnd, IsThumb); diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Decoder.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Decoder.cs index e0a18e666..8a2b389ad 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Decoder.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Decoder.cs @@ -208,6 +208,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 InstMeta meta; InstFlags extraFlags = InstFlags.None; bool hasHostCall = false; + bool hasHostCallSkipContext = false; bool isTruncated = false; do @@ -246,9 +247,17 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 meta = InstTableA32.GetMeta(encoding, cpuPreset.Version, cpuPreset.Features); } - if (meta.Name.IsSystemOrCall() && !hasHostCall) + if (meta.Name.IsSystemOrCall()) { - hasHostCall = meta.Name.IsCall() || InstEmitSystem.NeedsCall(meta.Name); + if (!hasHostCall) + { + hasHostCall = InstEmitSystem.NeedsCall(meta.Name); + } + + if (!hasHostCallSkipContext) + { + hasHostCallSkipContext = meta.Name.IsCall() || InstEmitSystem.NeedsCallSkipContext(meta.Name); + } } insts.Add(new(encoding, meta.Name, meta.EmitFunc, meta.Flags | extraFlags)); @@ -259,8 +268,8 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 if (!isTruncated && IsBackwardsBranch(meta.Name, encoding)) { - hasHostCall = true; isLoopEnd = true; + hasHostCallSkipContext = true; } return new( @@ -269,6 +278,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 insts, !isTruncated, hasHostCall, + hasHostCallSkipContext, isTruncated, isLoopEnd, isThumb); diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/MultiBlock.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/MultiBlock.cs index a213c222c..ca25057fe 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/MultiBlock.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/MultiBlock.cs @@ -6,6 +6,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 { public readonly List Blocks; public readonly bool HasHostCall; + public readonly bool HasHostCallSkipContext; public readonly bool IsTruncated; public MultiBlock(List blocks) @@ -15,12 +16,14 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 Block block = blocks[0]; HasHostCall = block.HasHostCall; + HasHostCallSkipContext = block.HasHostCallSkipContext; for (int index = 1; index < blocks.Count; index++) { block = blocks[index]; HasHostCall |= block.HasHostCall; + HasHostCallSkipContext |= block.HasHostCallSkipContext; } block = blocks[^1]; diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/RegisterAllocator.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/RegisterAllocator.cs index 6c7057229..4a3f03b8a 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/RegisterAllocator.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/RegisterAllocator.cs @@ -106,6 +106,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32 if ((regMask & AbiConstants.ReservedRegsMask) == 0) { _gprMask |= regMask; + UsedGprsMask |= regMask; return firstCalleeSaved; } diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs index 1e8a89157..a668b5777 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs @@ -305,12 +305,23 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 ForceConditionalEnd(cgContext, ref lastCondition, lastConditionIp); } + int reservedStackSize = 0; + + if (multiBlock.HasHostCall) + { + reservedStackSize = CalculateStackSizeForCallSpill(regAlloc.UsedGprsMask, regAlloc.UsedFpSimdMask, UsablePStateMask); + } + else if (multiBlock.HasHostCallSkipContext) + { + reservedStackSize = 2 * sizeof(ulong); // Context and page table pointers. + } + RegisterSaveRestore rsr = new( regAlloc.UsedGprsMask & AbiConstants.GprCalleeSavedRegsMask, regAlloc.UsedFpSimdMask & AbiConstants.FpSimdCalleeSavedRegsMask, OperandType.FP64, - multiBlock.HasHostCall, - multiBlock.HasHostCall ? CalculateStackSizeForCallSpill(regAlloc.UsedGprsMask, regAlloc.UsedFpSimdMask, UsablePStateMask) : 0); + multiBlock.HasHostCall || multiBlock.HasHostCallSkipContext, + reservedStackSize); TailMerger tailMerger = new(); @@ -596,7 +607,8 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 name == InstName.Ldm || name == InstName.Ldmda || name == InstName.Ldmdb || - name == InstName.Ldmib) + name == InstName.Ldmib || + name == InstName.Pop) { // Arm32 does not have a return instruction, instead returns are implemented // either using BX LR (for leaf functions), or POP { ... PC }. @@ -711,7 +723,14 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 switch (type) { case BranchType.SyncPoint: - InstEmitSystem.WriteSyncPoint(context.Writer, context.RegisterAllocator, context.TailMerger, context.GetReservedStackOffset()); + InstEmitSystem.WriteSyncPoint( + context.Writer, + ref asm, + context.RegisterAllocator, + context.TailMerger, + context.GetReservedStackOffset(), + context.StoreToContext, + context.LoadFromContext); break; case BranchType.SoftwareInterrupt: context.StoreToContext(); diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs index 81e44ba00..3b1ff5a2a 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs @@ -199,12 +199,12 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 } } - private static void WriteSpillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset) + public static void WriteSpillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset) { WriteSpillOrFillSkipContext(ref asm, regAlloc, spillOffset, spill: true); } - private static void WriteFillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset) + public static void WriteFillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset) { WriteSpillOrFillSkipContext(ref asm, regAlloc, spillOffset, spill: false); } diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSystem.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSystem.cs index be0976fd3..07f9f86a8 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSystem.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSystem.cs @@ -354,11 +354,18 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 // All instructions that might do a host call should be included here. // That is required to reserve space on the stack for caller saved registers. + return name == InstName.Mrrc; + } + + public static bool NeedsCallSkipContext(InstName name) + { + // All instructions that might do a host call should be included here. + // That is required to reserve space on the stack for caller saved registers. + switch (name) { case InstName.Mcr: case InstName.Mrc: - case InstName.Mrrc: case InstName.Svc: case InstName.Udf: return true; @@ -372,7 +379,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 Assembler asm = new(writer); WriteCall(ref asm, regAlloc, GetBkptHandlerPtr(), skipContext: true, spillBaseOffset, null, pc, imm); - WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, skipContext: true, spillBaseOffset); + WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, spillBaseOffset); } public static void WriteSvc(CodeWriter writer, RegisterAllocator regAlloc, TailMerger tailMerger, int spillBaseOffset, uint pc, uint svcId) @@ -380,7 +387,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 Assembler asm = new(writer); WriteCall(ref asm, regAlloc, GetSvcHandlerPtr(), skipContext: true, spillBaseOffset, null, pc, svcId); - WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, skipContext: true, spillBaseOffset); + WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, spillBaseOffset); } public static void WriteUdf(CodeWriter writer, RegisterAllocator regAlloc, TailMerger tailMerger, int spillBaseOffset, uint pc, uint imm) @@ -388,7 +395,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 Assembler asm = new(writer); WriteCall(ref asm, regAlloc, GetUdfHandlerPtr(), skipContext: true, spillBaseOffset, null, pc, imm); - WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, skipContext: true, spillBaseOffset); + WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, spillBaseOffset); } public static void WriteReadCntpct(CodeWriter writer, RegisterAllocator regAlloc, int spillBaseOffset, int rt, int rt2) @@ -422,14 +429,14 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 WriteFill(ref asm, regAlloc, resultMask, skipContext: false, spillBaseOffset, tempRegister); } - public static void WriteSyncPoint(CodeWriter writer, RegisterAllocator regAlloc, TailMerger tailMerger, int spillBaseOffset) - { - Assembler asm = new(writer); - - WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, skipContext: false, spillBaseOffset); - } - - private static void WriteSyncPoint(CodeWriter writer, ref Assembler asm, RegisterAllocator regAlloc, TailMerger tailMerger, bool skipContext, int spillBaseOffset) + public static void WriteSyncPoint( + CodeWriter writer, + ref Assembler asm, + RegisterAllocator regAlloc, + TailMerger tailMerger, + int spillBaseOffset, + Action storeToContext = null, + Action loadFromContext = null) { int tempRegister = regAlloc.AllocateTempGprRegister(); @@ -440,7 +447,8 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 int branchIndex = writer.InstructionPointer; asm.Cbnz(rt, 0); - WriteSpill(ref asm, regAlloc, 1u << tempRegister, skipContext, spillBaseOffset, tempRegister); + storeToContext?.Invoke(); + WriteSpill(ref asm, regAlloc, 1u << tempRegister, skipContext: true, spillBaseOffset, tempRegister); Operand rn = Register(tempRegister == 0 ? 1 : 0); @@ -449,7 +457,8 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 tailMerger.AddConditionalZeroReturn(writer, asm, Register(0, OperandType.I32)); - WriteFill(ref asm, regAlloc, 1u << tempRegister, skipContext, spillBaseOffset, tempRegister); + WriteFill(ref asm, regAlloc, 1u << tempRegister, skipContext: true, spillBaseOffset, tempRegister); + loadFromContext?.Invoke(); asm.LdrRiUn(rt, Register(regAlloc.FixedContextRegister), NativeContextOffsets.CounterOffset); @@ -514,18 +523,31 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 private static void WriteSpill(ref Assembler asm, RegisterAllocator regAlloc, uint exceptMask, bool skipContext, int spillOffset, int tempRegister) { - WriteSpillOrFill(ref asm, regAlloc, skipContext, exceptMask, spillOffset, tempRegister, spill: true); + if (skipContext) + { + InstEmitFlow.WriteSpillSkipContext(ref asm, regAlloc, spillOffset); + } + else + { + WriteSpillOrFill(ref asm, regAlloc, exceptMask, spillOffset, tempRegister, spill: true); + } } private static void WriteFill(ref Assembler asm, RegisterAllocator regAlloc, uint exceptMask, bool skipContext, int spillOffset, int tempRegister) { - WriteSpillOrFill(ref asm, regAlloc, skipContext, exceptMask, spillOffset, tempRegister, spill: false); + if (skipContext) + { + InstEmitFlow.WriteFillSkipContext(ref asm, regAlloc, spillOffset); + } + else + { + WriteSpillOrFill(ref asm, regAlloc, exceptMask, spillOffset, tempRegister, spill: false); + } } private static void WriteSpillOrFill( ref Assembler asm, RegisterAllocator regAlloc, - bool skipContext, uint exceptMask, int spillOffset, int tempRegister, @@ -533,11 +555,6 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 { uint gprMask = regAlloc.UsedGprsMask & ~(AbiConstants.GprCalleeSavedRegsMask | exceptMask); - if (skipContext) - { - gprMask &= ~Compiler.UsableGprsMask; - } - if (!spill) { // We must reload the status register before reloading the GPRs, @@ -600,11 +617,6 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 uint fpSimdMask = regAlloc.UsedFpSimdMask; - if (skipContext) - { - fpSimdMask &= ~Compiler.UsableFpSimdMask; - } - while (fpSimdMask != 0) { int reg = BitOperations.TrailingZeroCount(fpSimdMask); diff --git a/src/Ryujinx.Graphics.GAL/Format.cs b/src/Ryujinx.Graphics.GAL/Format.cs index 99c89dcec..035543560 100644 --- a/src/Ryujinx.Graphics.GAL/Format.cs +++ b/src/Ryujinx.Graphics.GAL/Format.cs @@ -147,6 +147,7 @@ namespace Ryujinx.Graphics.GAL A1B5G5R5Unorm, B8G8R8A8Unorm, B8G8R8A8Srgb, + B10G10R10A2Unorm, } public static class FormatExtensions @@ -260,6 +261,7 @@ namespace Ryujinx.Graphics.GAL case Format.R10G10B10A2Sint: case Format.R10G10B10A2Uscaled: case Format.R10G10B10A2Sscaled: + case Format.B10G10R10A2Unorm: return 4; case Format.S8Uint: @@ -451,6 +453,7 @@ namespace Ryujinx.Graphics.GAL case Format.R32G32Uint: case Format.B8G8R8A8Unorm: case Format.B8G8R8A8Srgb: + case Format.B10G10R10A2Unorm: case Format.R10G10B10A2Unorm: case Format.R10G10B10A2Uint: case Format.R8G8B8A8Unorm: @@ -611,6 +614,7 @@ namespace Ryujinx.Graphics.GAL case Format.B5G5R5A1Unorm: case Format.B8G8R8A8Unorm: case Format.B8G8R8A8Srgb: + case Format.B10G10R10A2Unorm: return true; } diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs index 2b65b4560..6b4ea89f3 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs @@ -26,6 +26,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed public const int PrimitiveRestartStateIndex = 12; public const int RenderTargetStateIndex = 27; + // Vertex buffers larger than this size will be clamped to the mapped size. + private const ulong VertexBufferSizeToMappedSizeThreshold = 256 * 1024 * 1024; // 256 MB + private readonly GpuContext _context; private readonly GpuChannel _channel; private readonly DeviceStateWithShadow _state; @@ -1144,6 +1147,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed size = Math.Min(size, maxVertexBufferSize); } + else if (size > VertexBufferSizeToMappedSizeThreshold) + { + // Make sure we have a sane vertex buffer size, since in some cases applications + // might set the "end address" of the vertex buffer to the end of the GPU address space, + // which would result in a several GBs large buffer. + + size = _channel.MemoryManager.GetMappedSize(address, size); + } } else { diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs b/src/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs index c798384f0..273438a67 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs @@ -37,6 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Types R16G16Sint = 0xdc, R16G16Uint = 0xdd, R16G16Float = 0xde, + B10G10R10A2Unorm = 0xdf, R11G11B10Float = 0xe0, R32Sint = 0xe3, R32Uint = 0xe4, @@ -104,6 +105,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Types ColorFormat.R16G16Sint => new FormatInfo(Format.R16G16Sint, 1, 1, 4, 2), ColorFormat.R16G16Uint => new FormatInfo(Format.R16G16Uint, 1, 1, 4, 2), ColorFormat.R16G16Float => new FormatInfo(Format.R16G16Float, 1, 1, 4, 2), + ColorFormat.B10G10R10A2Unorm => new FormatInfo(Format.B10G10R10A2Unorm, 1, 1, 4, 4), ColorFormat.R11G11B10Float => new FormatInfo(Format.R11G11B10Float, 1, 1, 4, 3), ColorFormat.R32Sint => new FormatInfo(Format.R32Sint, 1, 1, 4, 1), ColorFormat.R32Uint => new FormatInfo(Format.R32Uint, 1, 1, 4, 1), diff --git a/src/Ryujinx.Graphics.OpenGL/FormatTable.cs b/src/Ryujinx.Graphics.OpenGL/FormatTable.cs index 3dac33b94..c7e3e4e28 100644 --- a/src/Ryujinx.Graphics.OpenGL/FormatTable.cs +++ b/src/Ryujinx.Graphics.OpenGL/FormatTable.cs @@ -161,6 +161,7 @@ namespace Ryujinx.Graphics.OpenGL Add(Format.A1B5G5R5Unorm, new FormatInfo(4, true, false, All.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551)); Add(Format.B8G8R8A8Unorm, new FormatInfo(4, true, false, All.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte)); Add(Format.B8G8R8A8Srgb, new FormatInfo(4, false, false, All.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte)); + Add(Format.B10G10R10A2Unorm, new FormatInfo(4, false, false, All.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed)); Add(Format.R8Unorm, SizedInternalFormat.R8); Add(Format.R8Uint, SizedInternalFormat.R8ui); diff --git a/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj b/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj index b3f39f2ef..a6c4fb2bb 100644 --- a/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj +++ b/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj @@ -8,7 +8,6 @@ - diff --git a/src/Ryujinx.Graphics.Vulkan/FormatTable.cs b/src/Ryujinx.Graphics.Vulkan/FormatTable.cs index a12e3efd0..596a665fc 100644 --- a/src/Ryujinx.Graphics.Vulkan/FormatTable.cs +++ b/src/Ryujinx.Graphics.Vulkan/FormatTable.cs @@ -161,6 +161,7 @@ namespace Ryujinx.Graphics.Vulkan Add(Format.A1B5G5R5Unorm, VkFormat.R5G5B5A1UnormPack16); Add(Format.B8G8R8A8Unorm, VkFormat.B8G8R8A8Unorm); Add(Format.B8G8R8A8Srgb, VkFormat.B8G8R8A8Srgb); + Add(Format.B10G10R10A2Unorm, VkFormat.A2R10G10B10UnormPack32); #pragma warning restore IDE0055 } diff --git a/src/Ryujinx.Ui.Common/Helper/ShortcutHelper.cs b/src/Ryujinx.Ui.Common/Helper/ShortcutHelper.cs index 60b928985..3d27d3ffb 100644 --- a/src/Ryujinx.Ui.Common/Helper/ShortcutHelper.cs +++ b/src/Ryujinx.Ui.Common/Helper/ShortcutHelper.cs @@ -2,15 +2,13 @@ using Ryujinx.Common; using Ryujinx.Common.Configuration; using ShellLink; using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; using System; using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; using System.IO; using System.Runtime.Versioning; -using Image = System.Drawing.Image; namespace Ryujinx.Ui.Common.Helper { @@ -23,12 +21,9 @@ namespace Ryujinx.Ui.Common.Helper iconPath += ".ico"; MemoryStream iconDataStream = new(iconData); - using Image image = Image.FromStream(iconDataStream); - using Bitmap bitmap = new(128, 128); - using System.Drawing.Graphics graphic = System.Drawing.Graphics.FromImage(bitmap); - graphic.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphic.DrawImage(image, 0, 0, 128, 128); - SaveBitmapAsIcon(bitmap, iconPath); + var image = Image.Load(iconDataStream); + image.Mutate(x => x.Resize(128, 128)); + SaveBitmapAsIcon(image, iconPath); var shortcut = Shortcut.CreateShortcut(basePath, GetArgsString(applicationFilePath), iconPath, 0); shortcut.StringData.NameString = cleanedAppName; @@ -42,7 +37,7 @@ namespace Ryujinx.Ui.Common.Helper var desktopFile = EmbeddedResources.ReadAllText("Ryujinx.Ui.Common/shortcut-template.desktop"); iconPath += ".png"; - var image = SixLabors.ImageSharp.Image.Load(iconData); + var image = Image.Load(iconData); image.SaveAsPng(iconPath); using StreamWriter outputFile = new(Path.Combine(desktopPath, cleanedAppName + ".desktop")); @@ -83,7 +78,7 @@ namespace Ryujinx.Ui.Common.Helper } const string IconName = "icon.png"; - var image = SixLabors.ImageSharp.Image.Load(iconData); + var image = Image.Load(iconData); image.SaveAsPng(Path.Combine(resourceFolderPath, IconName)); // plist file @@ -147,7 +142,7 @@ namespace Ryujinx.Ui.Common.Helper /// The source bitmap image that will be saved as an .ico file /// The location that the new .ico file will be saved too (Make sure to include '.ico' in the path). [SupportedOSPlatform("windows")] - private static void SaveBitmapAsIcon(Bitmap source, string filePath) + private static void SaveBitmapAsIcon(Image source, string filePath) { // Code Modified From https://stackoverflow.com/a/11448060/368354 by Benlitz byte[] header = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 32, 0, 0, 0, 0, 0, 22, 0, 0, 0 }; @@ -155,7 +150,7 @@ namespace Ryujinx.Ui.Common.Helper fs.Write(header); // Writing actual data - source.Save(fs, ImageFormat.Png); + source.Save(fs, PngFormat.Instance); // Getting data length (file length minus header) long dataLength = fs.Length - header.Length; // Write it in the correct place diff --git a/src/Ryujinx.Ui.Common/Ryujinx.Ui.Common.csproj b/src/Ryujinx.Ui.Common/Ryujinx.Ui.Common.csproj index 1a8c216aa..24f26a3f5 100644 --- a/src/Ryujinx.Ui.Common/Ryujinx.Ui.Common.csproj +++ b/src/Ryujinx.Ui.Common/Ryujinx.Ui.Common.csproj @@ -57,7 +57,6 @@ -