mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-05-16 10:15:46 +00:00
Compare commits
7 Commits
Canary-1.3
...
Canary-1.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e756ad4556 | ||
|
|
58bd19a2f3 | ||
|
|
48888bd014 | ||
|
|
d307afc454 | ||
|
|
134453e62b | ||
|
|
298b6c3959 | ||
|
|
c96433eb13 |
@@ -8,7 +8,7 @@
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.15" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.15" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.15" />
|
||||
<PackageVersion Include="SharpCompress" Version="0.48.0" />
|
||||
<PackageVersion Include="SharpCompress" Version="0.48.1" />
|
||||
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.9.5" />
|
||||
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.9.5" />
|
||||
<PackageVersion Include="Microsoft.Build.Framework" Version="17.11.4" />
|
||||
@@ -51,7 +51,7 @@
|
||||
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="2.0.6" />
|
||||
<PackageVersion Include="Gommon" Version="2.8.1.2" />
|
||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageVersion Include="Sep" Version="0.13.0" />
|
||||
<PackageVersion Include="Sep" Version="0.14.1" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" />
|
||||
|
||||
@@ -596,7 +596,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_CN": "重启模拟",
|
||||
"zh_TW": "重新啟動模擬"
|
||||
}
|
||||
},
|
||||
@@ -6121,7 +6121,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_CN": "开启网络日志",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
@@ -11371,7 +11371,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_CN": "保存",
|
||||
"zh_TW": "儲存"
|
||||
}
|
||||
},
|
||||
@@ -17121,7 +17121,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_CN": "在控制台中显示网络日志",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
@@ -21496,7 +21496,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_CN": "控制台将会在下次启动 Ryujinx 时可用。",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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<Instruction> instPool,
|
||||
GeneratorPool<LiteralInteger> integerPool) : base(SpirvVersionPacked, instPool, integerPool)
|
||||
{
|
||||
WasNonUniformAccessDeclared = false;
|
||||
|
||||
Info = info;
|
||||
AttributeUsage = parameters.AttributeUsage;
|
||||
Definitions = parameters.Definitions;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<DisposableImage>(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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private readonly NativeArray<ulong> _sizes;
|
||||
private readonly NativeArray<ulong> _strides;
|
||||
|
||||
private readonly Auto<DisposableBuffer>[] _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<ulong>(Constants.MaxVertexBuffers);
|
||||
_sizes = new NativeArray<ulong>(Constants.MaxVertexBuffers);
|
||||
_strides = new NativeArray<ulong>(Constants.MaxVertexBuffers);
|
||||
|
||||
_bufferAutos = new Auto<DisposableBuffer>[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<DisposableBuffer> 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(
|
||||
|
||||
@@ -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]],
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears a specific process from the ProcessLoader's tracking.
|
||||
/// This should be called when a process exits or is terminated.
|
||||
/// </summary>
|
||||
/// <param name="pid">The process ID to clear</param>
|
||||
public void ClearProcess(ulong pid)
|
||||
{
|
||||
lock (_pidLock)
|
||||
{
|
||||
if (_processesByPid.TryRemove(pid, out _))
|
||||
{
|
||||
if (_latestPid == pid)
|
||||
{
|
||||
_latestPid = 0;
|
||||
TitleIDs.CurrentApplication.Value = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all processes from the ProcessLoader's tracking.
|
||||
/// This should be called during system shutdown.
|
||||
/// </summary>
|
||||
public void ClearAllProcesses()
|
||||
{
|
||||
lock (_pidLock)
|
||||
{
|
||||
_processesByPid.Clear();
|
||||
_latestPid = 0;
|
||||
TitleIDs.CurrentApplication.Value = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,6 +183,7 @@ namespace Ryujinx.HLE
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Processes.ClearAllProcesses();
|
||||
System.Dispose();
|
||||
AudioDeviceDriver.Dispose();
|
||||
FileSystem.Dispose();
|
||||
|
||||
Reference in New Issue
Block a user