From 298b6c3959fce51d55d25f6b9f9fdfd82b5b30db Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 15 May 2026 15:13:23 +0000 Subject: [PATCH 1/7] [HLE] Stub ILibrarySelfAccessor:ExitAndReturn (10) (#96) Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/96 --- .../ILibraryAppletSelfAccessor.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs b/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs index 44c4d133a..fa986de93 100644 --- a/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs +++ b/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs @@ -1,4 +1,5 @@ using Ryujinx.Common; +using Ryujinx.Common.Logging; using System; namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy @@ -60,6 +61,19 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib return ResultCode.Success; } + + [CommandCmif(10)] + // ExitProcessAndReturn -> nn::am::service::LibraryAppletInfo + public ResultCode ExitProcessAndReturn(ServiceCtx context) + { + // Exits the LibraryApplet and returns to running the title which launched this LibraryApplet (qlaunch for example). + // On success, official sw will enter an infinite loop with sleep-thread value 86400000000000. + // Since we don't currently support qlaunch, it's fine to stub it. + + Logger.Stub?.PrintStub(LogClass.Service); + return ResultCode.Success; + } + [CommandCmif(11)] // GetLibraryAppletInfo() -> nn::am::service::LibraryAppletInfo @@ -83,7 +97,8 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib AppletIdentifyInfo appletIdentifyInfo = new() { AppletId = AppletId.QLaunch, - TitleId = 0x0100000000001000, + // 0x4 padding + TitleId = 0x0100000000001000, // qlaunch systemAppletMenu title ID }; context.ResponseData.WriteStruct(appletIdentifyInfo); From 134453e62bb42765626559d4cde22816fb35043b Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 15 May 2026 15:13:49 +0000 Subject: [PATCH 2/7] Update dependency SharpCompress to 0.48.1 (#97) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [SharpCompress](https://github.com/adamhathcock/sharpcompress) | `0.48.0` → `0.48.1` | ![age](https://developer.mend.io/api/mc/badges/age/nuget/SharpCompress/0.48.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/SharpCompress/0.48.0/0.48.1?slim=true) | --- ### Release Notes
adamhathcock/sharpcompress (SharpCompress) ### [`v0.48.1`](https://github.com/adamhathcock/sharpcompress/releases/tag/0.48.1): - GZip writing fix [Compare Source](https://github.com/adamhathcock/sharpcompress/compare/0.48.0...0.48.1) #### What's Changed - release test cleanup by [@​adamhathcock](https://github.com/adamhathcock) in [#​1322](https://github.com/adamhathcock/sharpcompress/pull/1322) - Fix GZip write async by [@​adamhathcock](https://github.com/adamhathcock) in [#​1320](https://github.com/adamhathcock/sharpcompress/pull/1320) **Full Changelog**:
--- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/97 --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 3d39156b5..73cb36c51 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -8,7 +8,7 @@ - + From d307afc454e0b0b774c569c4d05f8e69ebbb24c9 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 15 May 2026 15:14:23 +0000 Subject: [PATCH 3/7] Update dependency Sep to 0.14.1 (#98) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [Sep](https://github.com/nietras/Sep) | `0.13.0` → `0.14.1` | ![age](https://developer.mend.io/api/mc/badges/age/nuget/Sep/0.14.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/Sep/0.13.0/0.14.1?slim=true) | --- ### Release Notes
nietras/Sep (Sep) ### [`v0.14.1`](https://github.com/nietras/Sep/releases/tag/v0.14.1): 0.14.1 #### What's Changed - Improve SepReaderOptions.Unescape/.Trim comments by [@​nietras](https://github.com/nietras) in [#​542](https://github.com/nietras/Sep/pull/542) - Improve SepReader/WriterExtensions.Strict() comments by [@​nietras](https://github.com/nietras) in [#​543](https://github.com/nietras/Sep/pull/543) **Full Changelog**: ### [`v0.14.0`](https://github.com/nietras/Sep/releases/tag/v0.14.0): 0.14.0 #### What's Changed - Add `leaveOpen` overloads for SepReaderOptions.From\* via SepTextReaderDisposers by [@​Copilot](https://github.com/Copilot) in [#​530](https://github.com/nietras/Sep/pull/530) - Bump MSTest from 4.2.1 to 4.2.2 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​533](https://github.com/nietras/Sep/pull/533) - Bump github/codeql-action from 4.35.2 to 4.35.3 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​532](https://github.com/nietras/Sep/pull/532) - Bump step-security/harden-runner from 2.19.0 to 2.19.1 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​531](https://github.com/nietras/Sep/pull/531) - Confirm statuses:write is the correct minimum permission for super-linter (not checks:write) by [@​Copilot](https://github.com/Copilot) in [#​540](https://github.com/nietras/Sep/pull/540) **Full Changelog**:
--- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/98 --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 73cb36c51..7c4da891f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -51,7 +51,7 @@ - + From 48888bd0144162b28a127d89c8dd131b7a2abdd3 Mon Sep 17 00:00:00 2001 From: AsperTheDog Date: Fri, 15 May 2026 15:19:12 +0000 Subject: [PATCH 4/7] Change non-unform shader extension to be more conservative (#99) The previous fix for Tomodachi Life (#91) included the extension to all shaders, independently on if it was needed or not. This PR fixes that by lazily adding the extension only when it is actually needed. This change should not be noticed by anyone, but it avoids having to modify shaders that do not perform any type of dynamic indexing, which apparently is something some modders care about. Co-authored-by: AsperTheDog Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/99 --- .../CodeGen/Spirv/CodeGenContext.cs | 3 +++ .../CodeGen/Spirv/Instructions.cs | 9 +++++++++ .../CodeGen/Spirv/SpirvGenerator.cs | 8 -------- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs index 4fe214778..3f80c2ae0 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs @@ -82,6 +82,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv public bool IsMainFunction { get; private set; } public bool MayHaveReturned { get; set; } + public bool WasNonUniformAccessDeclared { get; set; } public CodeGenContext( StructuredProgramInfo info, @@ -89,6 +90,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv GeneratorPool instPool, GeneratorPool integerPool) : base(SpirvVersionPacked, instPool, integerPool) { + WasNonUniformAccessDeclared = false; + Info = info; AttributeUsage = parameters.AttributeUsage; Definitions = parameters.Definitions; diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs index 9de806d89..77a23d1f2 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs @@ -591,7 +591,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv { if (context.HostCapabilities.SupportsShaderNonUniformIndexing) { + if (!context.WasNonUniformAccessDeclared) + { + context.AddExtension("SPV_EXT_descriptor_indexing"); + context.AddCapability(Capability.ShaderNonUniform); + context.AddCapability(Capability.SampledImageArrayNonUniformIndexing); + context.AddCapability(Capability.StorageImageArrayNonUniformIndexing); + } + context.Decorate(inst, Decoration.NonUniform); + context.WasNonUniformAccessDeclared = true; } } diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs index 2dd7186ba..e1561446b 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs @@ -60,14 +60,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv context.AddCapability(Capability.Float64); } - if (parameters.HostCapabilities.SupportsShaderNonUniformIndexing) - { - context.AddExtension("SPV_EXT_descriptor_indexing"); - context.AddCapability(Capability.ShaderNonUniform); - context.AddCapability(Capability.SampledImageArrayNonUniformIndexing); - context.AddCapability(Capability.StorageImageArrayNonUniformIndexing); - } - if (parameters.Definitions.TransformFeedbackEnabled && parameters.Definitions.LastInVertexPipeline) { context.AddCapability(Capability.TransformFeedback); From 58bd19a2f31a1f9e7d5e67d3a78661255d305229 Mon Sep 17 00:00:00 2001 From: AsperTheDog Date: Fri, 15 May 2026 15:36:14 +0000 Subject: [PATCH 5/7] Fix Vulkan validation errors (#92) This PR fixes several validation errors caused by invalid Vulkan usage. These validation errors often end up invoking Undefined Behavior on the driver side, which can lead to artifacts or crashes which are driver specific and otherwise incredibly hard to track. I don't think it should have any impact on performance, but it would be good to test it with as many games as possible (maybe a bug in a game was fixed?). Each commit fixes an error. I added to each a description with the validation error that was fixed and a small explanation on what was causing it and how I fixed it. Co-authored-by: AsperTheDog Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/92 --- src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs | 9 +++++- src/Ryujinx.Graphics.Vulkan/TextureCopy.cs | 31 +++++++++++++++++++ src/Ryujinx.Graphics.Vulkan/TextureStorage.cs | 11 ++++--- src/Ryujinx.Graphics.Vulkan/TextureView.cs | 14 ++++++++- .../VertexBufferState.cs | 10 ++---- .../VertexBufferUpdater.cs | 24 +++++++++++--- src/Ryujinx.Graphics.Vulkan/Window.cs | 4 ++- 7 files changed, 84 insertions(+), 19 deletions(-) diff --git a/src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs b/src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs index 251f74319..927845fa0 100644 --- a/src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs +++ b/src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs @@ -46,7 +46,14 @@ namespace Ryujinx.Graphics.Vulkan public static (AccessFlags Access, PipelineStageFlags Stages) GetSubpassAccessSuperset(VulkanRenderer gd) { - AccessFlags access = BufferAccess; + AccessFlags access = BufferAccess | + AccessFlags.ShaderReadBit | + AccessFlags.ShaderWriteBit | + AccessFlags.ColorAttachmentReadBit | + AccessFlags.ColorAttachmentWriteBit | + AccessFlags.DepthStencilAttachmentReadBit | + AccessFlags.DepthStencilAttachmentWriteBit; + PipelineStageFlags stages = PipelineStageFlags.AllGraphicsBit; if (gd.TransformFeedbackApi != null) diff --git a/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs b/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs index aae3b0afb..0efb4dbb0 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs @@ -15,6 +15,8 @@ namespace Ryujinx.Graphics.Vulkan Image dstImage, TextureCreateInfo srcInfo, TextureCreateInfo dstInfo, + TextureCreateInfo srcStorageInfo, + TextureCreateInfo dstStorageInfo, Extents2D srcRegion, Extents2D dstRegion, int srcLayer, @@ -40,6 +42,13 @@ namespace Ryujinx.Graphics.Vulkan return (xy1, xy2); } + static (Offset3D, Offset3D) ClampOffsetsToMip(Offset3D xy1, Offset3D xy2, int mipW, int mipH) + { + return ( + new Offset3D(Math.Min(xy1.X, mipW), Math.Min(xy1.Y, mipH), xy1.Z), + new Offset3D(Math.Min(xy2.X, mipW), Math.Min(xy2.Y, mipH), xy2.Z)); + } + if (srcAspectFlags == 0) { srcAspectFlags = srcInfo.Format.ConvertAspectFlags(); @@ -80,6 +89,14 @@ namespace Ryujinx.Graphics.Vulkan (srcOffsets.Element0, srcOffsets.Element1) = ExtentsToOffset3D(srcRegion, srcInfo.Width, srcInfo.Height, level); (dstOffsets.Element0, dstOffsets.Element1) = ExtentsToOffset3D(dstRegion, dstInfo.Width, dstInfo.Height, level); + int srcMipW = Math.Max(1, srcStorageInfo.Width >> (int)copySrcLevel); + int srcMipH = Math.Max(1, srcStorageInfo.Height >> (int)copySrcLevel); + int dstMipW = Math.Max(1, dstStorageInfo.Width >> (int)copyDstLevel); + int dstMipH = Math.Max(1, dstStorageInfo.Height >> (int)copyDstLevel); + + (srcOffsets.Element0, srcOffsets.Element1) = ClampOffsetsToMip(srcOffsets.Element0, srcOffsets.Element1, srcMipW, srcMipH); + (dstOffsets.Element0, dstOffsets.Element1) = ClampOffsetsToMip(dstOffsets.Element0, dstOffsets.Element1, dstMipW, dstMipH); + ImageBlit region = new() { SrcSubresource = srcSl, @@ -121,6 +138,8 @@ namespace Ryujinx.Graphics.Vulkan Image dstImage, TextureCreateInfo srcInfo, TextureCreateInfo dstInfo, + TextureCreateInfo srcStorageInfo, + TextureCreateInfo dstStorageInfo, int srcViewLayer, int dstViewLayer, int srcViewLevel, @@ -151,6 +170,8 @@ namespace Ryujinx.Graphics.Vulkan dstImage, srcInfo, dstInfo, + srcStorageInfo, + dstStorageInfo, srcViewLayer, dstViewLayer, srcViewLevel, @@ -186,6 +207,8 @@ namespace Ryujinx.Graphics.Vulkan Image dstImage, TextureCreateInfo srcInfo, TextureCreateInfo dstInfo, + TextureCreateInfo srcStorageInfo, + TextureCreateInfo dstStorageInfo, int srcViewLayer, int dstViewLayer, int srcViewLevel, @@ -314,6 +337,14 @@ namespace Ryujinx.Graphics.Vulkan int copyWidth = sizeInBlocks ? BitUtils.DivRoundUp(width, blockWidth) : width; int copyHeight = sizeInBlocks ? BitUtils.DivRoundUp(height, blockHeight) : height; + int srcMipW = Math.Max(1, srcStorageInfo.Width >> (srcViewLevel + srcLevel + level)); + int srcMipH = Math.Max(1, srcStorageInfo.Height >> (srcViewLevel + srcLevel + level)); + int dstMipW = Math.Max(1, dstStorageInfo.Width >> (dstViewLevel + dstLevel + level)); + int dstMipH = Math.Max(1, dstStorageInfo.Height >> (dstViewLevel + dstLevel + level)); + + copyWidth = Math.Min(copyWidth, Math.Min(srcMipW, dstMipW)); + copyHeight = Math.Min(copyHeight, Math.Min(srcMipH, dstMipH)); + Extent3D extent = new((uint)copyWidth, (uint)copyHeight, (uint)srcDepth); if (srcInfo.Samples > 1 && srcInfo.Samples != dstInfo.Samples) diff --git a/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs b/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs index 46cd5b4be..b102efaf2 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs @@ -67,6 +67,8 @@ namespace Ryujinx.Graphics.Vulkan public VkFormat VkFormat { get; } + public ImageUsageFlags UsageFlags { get; } + public unsafe TextureStorage( VulkanRenderer gd, Device device, @@ -93,7 +95,8 @@ namespace Ryujinx.Graphics.Vulkan SampleCountFlags sampleCountFlags = ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)info.Samples); - ImageUsageFlags usage = GetImageUsage(info.Format, gd.Capabilities, isMsImageStorageSupported, true); + ImageUsageFlags usage = GetImageUsage(info.Format, gd.Capabilities, isMsImageStorageSupported); + UsageFlags = usage; ImageCreateFlags flags = ImageCreateFlags.CreateMutableFormatBit | ImageCreateFlags.CreateExtendedUsageBit; @@ -159,7 +162,7 @@ namespace Ryujinx.Graphics.Vulkan _imageAuto = new Auto(new DisposableImage(_gd.Api, device, _image)); - InitialTransition(ImageLayout.Preinitialized, ImageLayout.General); + InitialTransition(ImageLayout.Undefined, ImageLayout.General); } _slices = new TextureSliceInfo[levels * _depthOrLayers]; @@ -307,7 +310,7 @@ namespace Ryujinx.Graphics.Vulkan } } - public static ImageUsageFlags GetImageUsage(Format format, in HardwareCapabilities capabilities, bool isMsImageStorageSupported, bool extendedUsage) + public static ImageUsageFlags GetImageUsage(Format format, in HardwareCapabilities capabilities, bool isMsImageStorageSupported) { ImageUsageFlags usage = DefaultUsageFlags; @@ -320,7 +323,7 @@ namespace Ryujinx.Graphics.Vulkan usage |= ImageUsageFlags.ColorAttachmentBit; } - if ((format.IsImageCompatible && isMsImageStorageSupported) || extendedUsage) + if (format.IsImageCompatible && isMsImageStorageSupported) { usage |= ImageUsageFlags.StorageBit; } diff --git a/src/Ryujinx.Graphics.Vulkan/TextureView.cs b/src/Ryujinx.Graphics.Vulkan/TextureView.cs index 4513c804f..b6c0b8369 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureView.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureView.cs @@ -64,7 +64,7 @@ namespace Ryujinx.Graphics.Vulkan bool isMsImageStorageSupported = gd.Capabilities.SupportsShaderStorageImageMultisample || !info.Target.IsMultisample; VkFormat format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format, isMsImageStorageSupported); - ImageUsageFlags usage = TextureStorage.GetImageUsage(info.Format, gd.Capabilities, isMsImageStorageSupported, false); + ImageUsageFlags usage = TextureStorage.GetImageUsage(info.Format, gd.Capabilities, isMsImageStorageSupported) & storage.UsageFlags; uint levels = (uint)info.Levels; uint layers = (uint)info.GetLayers(); @@ -133,6 +133,8 @@ namespace Ryujinx.Graphics.Vulkan shaderUsage |= ImageUsageFlags.StorageBit; } + shaderUsage &= storage.UsageFlags; + _imageView = CreateImageView(componentMapping, subresourceRange, type, shaderUsage); // Framebuffer attachments and storage images requires a identity component mapping. @@ -257,6 +259,8 @@ namespace Ryujinx.Graphics.Vulkan dstImage, src.Info, dst.Info, + src.Storage.Info, + dst.Storage.Info, src.FirstLayer, dst.FirstLayer, src.FirstLevel, @@ -310,6 +314,8 @@ namespace Ryujinx.Graphics.Vulkan dstImage, src.Info, dst.Info, + src.Storage.Info, + dst.Storage.Info, src.FirstLayer, dst.FirstLayer, src.FirstLevel, @@ -385,6 +391,8 @@ namespace Ryujinx.Graphics.Vulkan dst.GetImage().Get(cbs).Value, src.Info, dst.Info, + src.Storage.Info, + dst.Storage.Info, src.FirstLayer, dst.FirstLayer, src.FirstLevel, @@ -410,6 +418,8 @@ namespace Ryujinx.Graphics.Vulkan dst.GetImage().Get(cbs).Value, src.Info, dst.Info, + src.Storage.Info, + dst.Storage.Info, srcRegion, dstRegion, src.FirstLayer, @@ -463,6 +473,8 @@ namespace Ryujinx.Graphics.Vulkan dstImage.Get(cbs).Value, src.Info, dst.Info, + src.Storage.Info, + dst.Storage.Info, srcRegion, dstRegion, src.FirstLayer, diff --git a/src/Ryujinx.Graphics.Vulkan/VertexBufferState.cs b/src/Ryujinx.Graphics.Vulkan/VertexBufferState.cs index 236ab8721..da4edaa6a 100644 --- a/src/Ryujinx.Graphics.Vulkan/VertexBufferState.cs +++ b/src/Ryujinx.Graphics.Vulkan/VertexBufferState.cs @@ -68,9 +68,7 @@ namespace Ryujinx.Graphics.Vulkan int stride = (_stride + (alignment - 1)) & -alignment; int newSize = (_size / _stride) * stride; - Buffer buffer = autoBuffer.Get(cbs, 0, newSize).Value; - - updater.BindVertexBuffer(cbs, binding, buffer, 0, (ulong)newSize, (ulong)stride); + updater.BindVertexBuffer(cbs, binding, autoBuffer, 0, newSize, (ulong)stride); _buffer = autoBuffer; @@ -93,11 +91,7 @@ namespace Ryujinx.Graphics.Vulkan if (autoBuffer != null) { - int offset = _offset; - bool mirrorable = _size <= VertexBufferMaxMirrorable; - Buffer buffer = mirrorable ? autoBuffer.GetMirrorable(cbs, ref offset, _size, out _).Value : autoBuffer.Get(cbs, offset, _size).Value; - - updater.BindVertexBuffer(cbs, binding, buffer, (ulong)offset, (ulong)_size, (ulong)_stride); + updater.BindVertexBuffer(cbs, binding, autoBuffer, _offset, _size, (ulong)_stride); } } diff --git a/src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs b/src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs index 94269dd76..8927d2264 100644 --- a/src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs +++ b/src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs @@ -15,6 +15,10 @@ namespace Ryujinx.Graphics.Vulkan private readonly NativeArray _sizes; private readonly NativeArray _strides; + private readonly Auto[] _bufferAutos; + private readonly int[] _bufferOffsetsForGet; + private readonly int[] _bufferSizesForGet; + public VertexBufferUpdater(VulkanRenderer gd) { _gd = gd; @@ -23,9 +27,13 @@ namespace Ryujinx.Graphics.Vulkan _offsets = new NativeArray(Constants.MaxVertexBuffers); _sizes = new NativeArray(Constants.MaxVertexBuffers); _strides = new NativeArray(Constants.MaxVertexBuffers); + + _bufferAutos = new Auto[Constants.MaxVertexBuffers]; + _bufferOffsetsForGet = new int[Constants.MaxVertexBuffers]; + _bufferSizesForGet = new int[Constants.MaxVertexBuffers]; } - public void BindVertexBuffer(CommandBufferScoped cbs, uint binding, VkBuffer buffer, ulong offset, ulong size, ulong stride) + public void BindVertexBuffer(CommandBufferScoped cbs, uint binding, Auto autoBuffer, int offset, int size, ulong stride) { if (_count == 0) { @@ -39,9 +47,11 @@ namespace Ryujinx.Graphics.Vulkan int index = (int)_count; - _buffers[index] = buffer; - _offsets[index] = offset; - _sizes[index] = size; + _bufferAutos[index] = autoBuffer; + _bufferOffsetsForGet[index] = offset; + _bufferSizesForGet[index] = size; + _offsets[index] = (ulong)offset; + _sizes[index] = (ulong)size; _strides[index] = stride; _count++; @@ -51,6 +61,12 @@ namespace Ryujinx.Graphics.Vulkan { if (_count != 0) { + for (int i = 0; i < _count; i++) + { + _buffers[i] = _bufferAutos[i].Get(cbs, _bufferOffsetsForGet[i], _bufferSizesForGet[i]).Value; + _bufferAutos[i] = null; + } + if (_gd.Capabilities.SupportsExtendedDynamicState) { _gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2( diff --git a/src/Ryujinx.Graphics.Vulkan/Window.cs b/src/Ryujinx.Graphics.Vulkan/Window.cs index 0a0d970c1..eb8d433be 100644 --- a/src/Ryujinx.Graphics.Vulkan/Window.cs +++ b/src/Ryujinx.Graphics.Vulkan/Window.cs @@ -391,12 +391,12 @@ namespace Ryujinx.Graphics.Vulkan { if (_effect != null) { + _gd.FlushAllCommands(); _gd.CommandBufferPool.Return( cbs, null, [PipelineStageFlags.ColorAttachmentOutputBit], null); - _gd.FlushAllCommands(); cbs.GetFence().Wait(); cbs = _gd.CommandBufferPool.Rent(); } @@ -455,6 +455,8 @@ namespace Ryujinx.Graphics.Vulkan ImageLayout.General, ImageLayout.PresentSrcKhr); + _gd.FlushAllCommands(); + _gd.CommandBufferPool.Return( cbs, [_imageAvailableSemaphores[semaphoreIndex]], From e756ad4556773ddf5b1d955e8372f0c736ab8337 Mon Sep 17 00:00:00 2001 From: Babib3l Date: Sat, 16 May 2026 01:11:06 +0000 Subject: [PATCH 6/7] Fix ProcessLoader stale PID validation against kernel process table (#102) This PR adresses the following issue : `ProcessLoader.ActiveApplication` could return invalid results when `_latestPid` pointed to a process that no longer existed in the kernel's process table. The original exception path was commented out and bypassed (by sh0inx?) with `GetValueOrDefault` to prevent UI lockups, but this only resolved the symptoms without fixing the root cause. This was due to sevral factors : - `_latestPid` was never reset or validated against the actual process state - ProcessLoader maintained its own `_processesByPid` dictionary separate from the kernel's `KernelContext.Processes` - No cleanups happened when processes exited or were terminated - ProcessLoader state could drift out of sync with the kernel process table **Solution/Fixes** - Validate` _latestPid` against the kernel process table before returning `ActiveApplication` - Check process state (Exited/Exiting) and automatically clear stale references - Add thread-safe cleanup methods (`ClearProcess`, `ClearAllProcesses`) - Integrate `ClearAllProcesses` into Switch.Dispose for proper shutdown cleanup - Add warning logs when stale PID is detected and cleared for debugging **Code Changes**: - `ProcessLoader.cs`: Add `_pidLock`, update `ActiveApplication` with validation, add cleanup methods - `Switch.cs`: Call `Processes.ClearAllProcesses()` in Dispose() Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/102 --- .../Loaders/Processes/ProcessLoader.cs | 92 +++++++++++++++++-- src/Ryujinx.HLE/Switch.cs | 1 + 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs index 900703f6e..f217ecd0b 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs @@ -28,21 +28,61 @@ namespace Ryujinx.HLE.Loaders.Processes private ulong _latestPid; + private readonly object _pidLock = new(); + #nullable enable public ProcessResult? ActiveApplication { get { - return _processesByPid.GetValueOrDefault(_latestPid); - - // Using this if statement locks up the UI and prevents a new game from loading. - // Haven't quite deduced why yet. - - if (!_processesByPid.TryGetValue(_latestPid, out ProcessResult value)) - throw new RyujinxException( - $"The HLE Process map did not have a process with ID {_latestPid}. Are you missing firmware?"); + lock (_pidLock) + { + // Check if _latestPid is still valid + if (_latestPid == 0) + { + return null; + } - return value; + // Verify process still exists in kernel (authoritative source) + if (!_device.System.KernelContext.Processes.TryGetValue(_latestPid, out HOS.Kernel.Process.KProcess? kernelProcess)) + { + // Process no longer exists in kernel, clear stale state + Logger.Warning?.Print(LogClass.Loader, + $"ActiveApplication PID {_latestPid} no longer exists in kernel, clearing stale state"); + + _processesByPid.TryRemove(_latestPid, out _); + _latestPid = 0; + TitleIDs.CurrentApplication.Value = null; + + return null; + } + + // Verify process still exists in ProcessLoader's dictionary + if (_processesByPid.TryGetValue(_latestPid, out ProcessResult? processResult)) + { + // Additional check: verify process state + if (kernelProcess.State == HOS.Kernel.Process.ProcessState.Exited || + kernelProcess.State == HOS.Kernel.Process.ProcessState.Exiting) + { + Logger.Warning?.Print(LogClass.Loader, + $"ActiveApplication PID {_latestPid} is in state {kernelProcess.State}, clearing"); + + _processesByPid.TryRemove(_latestPid, out _); + _latestPid = 0; + TitleIDs.CurrentApplication.Value = null; + + return null; + } + + return processResult; + } + + // Fallback: clear stale PID if not in our dictionary + Logger.Warning?.Print(LogClass.Loader, + $"ActiveApplication PID {_latestPid} not in ProcessLoader dictionary, clearing"); + _latestPid = 0; + return null; + } } } #nullable disable @@ -285,5 +325,39 @@ namespace Ryujinx.HLE.Loaders.Processes return false; } + + /// + /// Clears a specific process from the ProcessLoader's tracking. + /// This should be called when a process exits or is terminated. + /// + /// The process ID to clear + public void ClearProcess(ulong pid) + { + lock (_pidLock) + { + if (_processesByPid.TryRemove(pid, out _)) + { + if (_latestPid == pid) + { + _latestPid = 0; + TitleIDs.CurrentApplication.Value = null; + } + } + } + } + + /// + /// Clears all processes from the ProcessLoader's tracking. + /// This should be called during system shutdown. + /// + public void ClearAllProcesses() + { + lock (_pidLock) + { + _processesByPid.Clear(); + _latestPid = 0; + TitleIDs.CurrentApplication.Value = null; + } + } } } diff --git a/src/Ryujinx.HLE/Switch.cs b/src/Ryujinx.HLE/Switch.cs index 850c8b5fa..90af47988 100644 --- a/src/Ryujinx.HLE/Switch.cs +++ b/src/Ryujinx.HLE/Switch.cs @@ -183,6 +183,7 @@ namespace Ryujinx.HLE { if (disposing) { + Processes.ClearAllProcesses(); System.Dispose(); AudioDeviceDriver.Dispose(); FileSystem.Dispose(); From 3473044c6e4b30ef98208a23dd9003b8ab53a647 Mon Sep 17 00:00:00 2001 From: Babib3l Date: Sat, 16 May 2026 13:28:02 +0000 Subject: [PATCH 7/7] New French Translations (#101) French translations + capital letters on spanish translations Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/101 --- assets/Locales/Root.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/Locales/Root.json b/assets/Locales/Root.json index 8e3d25049..757ddeec8 100644 --- a/assets/Locales/Root.json +++ b/assets/Locales/Root.json @@ -6107,8 +6107,8 @@ "de_DE": "", "el_GR": "", "en_US": "Enable Net Logs", - "es_ES": "Habilitar registros de red.", - "fr_FR": "", + "es_ES": "Habilitar Registros de Red.", + "fr_FR": "Activer les Journaux Réseau.", "he_IL": "", "it_IT": "", "ja_JP": "", @@ -17108,7 +17108,7 @@ "el_GR": "", "en_US": "Prints network log messages in the console.", "es_ES": "Imprimir registros de red en la consola.", - "fr_FR": "", + "fr_FR": "Affiche les journaux réseau dans la console.", "he_IL": "", "it_IT": "", "ja_JP": "",