Compare commits

...

5 Commits

Author SHA1 Message Date
riperiperi
de3134adbe Vulkan: Explicitly enable precise occlusion queries (#4292)
The only guarantee of the occlusion query type in Vulkan is that it will be zero when no samples pass, and non-zero when any samples pass. Of course, most GPUs implement this by just placing the # of samples in the result and calling it a day. However, this lax restriction means that GPUs could just report a boolean (1/0) or report a value after one is recorded, but before all samples have been counted.

MoltenVK falls in the first category - by default it only reports 1/0 for occlusion queries. Thankfully, there is a feature and flag that you can use to force compatible drivers to provide a "precise" query result, that being the real # of samples passed.

Should fix ink collision in Splatoon 2/3 on MoltenVK.
2023-01-19 00:30:42 +00:00
merry
36d53819a4 NativeSignalHandler: Fix write flag (#4306)
* NativeSignalHandler: Fix write flag

* address comments
2023-01-19 00:13:17 +00:00
Andrey Sukharev
ae4324032a Optimize string memory usage. Use Spans and StringBuilders where possible (#3933)
* Optimize string memory usage. Use ReadOnlySpan<char> and StringBuilder where possible.

* Fix copypaste error

* Code generator review fixes

* Use if statement instead of switch

* Code style fixes

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

* Another code style fix

* Styling fix

Co-authored-by: Mary-nyan <thog@protonmail.com>

* Styling fix

Co-authored-by: gdkchan <gab.dark.100@gmail.com>

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
Co-authored-by: Mary-nyan <thog@protonmail.com>
Co-authored-by: gdkchan <gab.dark.100@gmail.com>
2023-01-18 22:25:16 +00:00
Ac_K
f449895e6d HOS: Load RomFs by pid (#4301)
We currently loading only one RomFs at a time, which could be wrong if one day we want to load more than one guest at time.
This PR fixes that by loading romfs by pid.
2023-01-18 13:50:42 +00:00
TSRBerry
410be95ab6 Fix NRE when disposing AddressSpace with 4KB pages support (#4307) 2023-01-17 14:50:39 +00:00
28 changed files with 262 additions and 119 deletions

View File

@@ -1339,7 +1339,7 @@ namespace ARMeilleure.Decoders
private static void SetT32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp) private static void SetT32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
{ {
string reversedEncoding = encoding.Substring(16) + encoding.Substring(0, 16); string reversedEncoding = $"{encoding.AsSpan(16)}{encoding.AsSpan(0, 16)}";
MakeOp reversedMakeOp = MakeOp reversedMakeOp =
(inst, address, opCode) (inst, address, opCode)
=> makeOp(inst, address, (int)BitOperations.RotateRight((uint)opCode, 16)); => makeOp(inst, address, (int)BitOperations.RotateRight((uint)opCode, 16));
@@ -1353,7 +1353,7 @@ namespace ARMeilleure.Decoders
string thumbEncoding = encoding; string thumbEncoding = encoding;
if (thumbEncoding.StartsWith("<<<<")) if (thumbEncoding.StartsWith("<<<<"))
{ {
thumbEncoding = "1110" + thumbEncoding.Substring(4); thumbEncoding = $"1110{thumbEncoding.AsSpan(4)}";
} }
SetT32(thumbEncoding, name, emitter, makeOpT32); SetT32(thumbEncoding, name, emitter, makeOpT32);
} }
@@ -1365,19 +1365,19 @@ namespace ARMeilleure.Decoders
string thumbEncoding = encoding; string thumbEncoding = encoding;
if (thumbEncoding.StartsWith("11110100")) if (thumbEncoding.StartsWith("11110100"))
{ {
thumbEncoding = "11111001" + encoding.Substring(8); thumbEncoding = $"11111001{encoding.AsSpan(8)}";
} }
else if (thumbEncoding.StartsWith("1111001x")) else if (thumbEncoding.StartsWith("1111001x"))
{ {
thumbEncoding = "111x1111" + encoding.Substring(8); thumbEncoding = $"111x1111{encoding.AsSpan(8)}";
} }
else if (thumbEncoding.StartsWith("11110010")) else if (thumbEncoding.StartsWith("11110010"))
{ {
thumbEncoding = "11101111" + encoding.Substring(8); thumbEncoding = $"11101111{encoding.AsSpan(8)}";
} }
else if (thumbEncoding.StartsWith("11110011")) else if (thumbEncoding.StartsWith("11110011"))
{ {
thumbEncoding = "11111111" + encoding.Substring(8); thumbEncoding = $"11111111{encoding.AsSpan(8)}";
} }
else else
{ {

View File

@@ -109,12 +109,6 @@ namespace ARMeilleure.Signal
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
{ {
// Unix siginfo struct locations.
// NOTE: These are incredibly likely to be different between kernel version and architectures.
config.StructAddressOffset = OperatingSystem.IsMacOS() ? 24 : 16; // si_addr
config.StructWriteOffset = 8; // si_code
_signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateUnixSignalHandler(_handlerConfig)); _signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateUnixSignalHandler(_handlerConfig));
if (customSignalHandlerFactory != null) if (customSignalHandlerFactory != null)
@@ -251,18 +245,88 @@ namespace ARMeilleure.Signal
return context.Copy(inRegionLocal); return context.Copy(inRegionLocal);
} }
private static Operand GenerateUnixFaultAddress(EmitterContext context, Operand sigInfoPtr)
{
ulong structAddressOffset = OperatingSystem.IsMacOS() ? 24ul : 16ul; // si_addr
return context.Load(OperandType.I64, context.Add(sigInfoPtr, Const(structAddressOffset)));
}
private static Operand GenerateUnixWriteFlag(EmitterContext context, Operand ucontextPtr)
{
if (OperatingSystem.IsMacOS())
{
const ulong mcontextOffset = 48; // uc_mcontext
Operand ctxPtr = context.Load(OperandType.I64, context.Add(ucontextPtr, Const(mcontextOffset)));
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
const ulong esrOffset = 8; // __es.__esr
Operand esr = context.Load(OperandType.I64, context.Add(ctxPtr, Const(esrOffset)));
return context.BitwiseAnd(esr, Const(0x40ul));
}
if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
{
const ulong errOffset = 4; // __es.__err
Operand err = context.Load(OperandType.I64, context.Add(ctxPtr, Const(errOffset)));
return context.BitwiseAnd(err, Const(2ul));
}
}
else if (OperatingSystem.IsLinux())
{
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
Operand auxPtr = context.AllocateLocal(OperandType.I64);
Operand loopLabel = Label();
Operand successLabel = Label();
const ulong auxOffset = 464; // uc_mcontext.__reserved
const uint esrMagic = 0x45535201;
context.Copy(auxPtr, context.Add(ucontextPtr, Const(auxOffset)));
context.MarkLabel(loopLabel);
// _aarch64_ctx::magic
Operand magic = context.Load(OperandType.I32, auxPtr);
// _aarch64_ctx::size
Operand size = context.Load(OperandType.I32, context.Add(auxPtr, Const(4ul)));
context.BranchIf(successLabel, magic, Const(esrMagic), Comparison.Equal);
context.Copy(auxPtr, context.Add(auxPtr, context.ZeroExtend32(OperandType.I64, size)));
context.Branch(loopLabel);
context.MarkLabel(successLabel);
// esr_context::esr
Operand esr = context.Load(OperandType.I64, context.Add(auxPtr, Const(8ul)));
return context.BitwiseAnd(esr, Const(0x40ul));
}
if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
{
const int errOffset = 192; // uc_mcontext.gregs[REG_ERR]
Operand err = context.Load(OperandType.I64, context.Add(ucontextPtr, Const(errOffset)));
return context.BitwiseAnd(err, Const(2ul));
}
}
throw new PlatformNotSupportedException();
}
private static UnixExceptionHandler GenerateUnixSignalHandler(IntPtr signalStructPtr) private static UnixExceptionHandler GenerateUnixSignalHandler(IntPtr signalStructPtr)
{ {
EmitterContext context = new EmitterContext(); EmitterContext context = new EmitterContext();
// (int sig, SigInfo* sigInfo, void* ucontext) // (int sig, SigInfo* sigInfo, void* ucontext)
Operand sigInfoPtr = context.LoadArgument(OperandType.I64, 1); Operand sigInfoPtr = context.LoadArgument(OperandType.I64, 1);
Operand ucontextPtr = context.LoadArgument(OperandType.I64, 2);
Operand structAddressOffset = context.Load(OperandType.I64, Const((ulong)signalStructPtr + StructAddressOffset)); Operand faultAddress = GenerateUnixFaultAddress(context, sigInfoPtr);
Operand structWriteOffset = context.Load(OperandType.I64, Const((ulong)signalStructPtr + StructWriteOffset)); Operand writeFlag = GenerateUnixWriteFlag(context, ucontextPtr);
Operand faultAddress = context.Load(OperandType.I64, context.Add(sigInfoPtr, context.ZeroExtend32(OperandType.I64, structAddressOffset)));
Operand writeFlag = context.Load(OperandType.I64, context.Add(sigInfoPtr, context.ZeroExtend32(OperandType.I64, structWriteOffset)));
Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1. Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1.

View File

@@ -183,8 +183,8 @@ namespace ARMeilleure.Translation.PTC
private void PreLoad() private void PreLoad()
{ {
string fileNameActual = string.Concat(CachePathActual, ".cache"); string fileNameActual = $"{CachePathActual}.cache";
string fileNameBackup = string.Concat(CachePathBackup, ".cache"); string fileNameBackup = $"{CachePathBackup}.cache";
FileInfo fileInfoActual = new FileInfo(fileNameActual); FileInfo fileInfoActual = new FileInfo(fileNameActual);
FileInfo fileInfoBackup = new FileInfo(fileNameBackup); FileInfo fileInfoBackup = new FileInfo(fileNameBackup);
@@ -400,8 +400,8 @@ namespace ARMeilleure.Translation.PTC
try try
{ {
string fileNameActual = string.Concat(CachePathActual, ".cache"); string fileNameActual = $"{CachePathActual}.cache";
string fileNameBackup = string.Concat(CachePathBackup, ".cache"); string fileNameBackup = $"{CachePathBackup}.cache";
FileInfo fileInfoActual = new FileInfo(fileNameActual); FileInfo fileInfoActual = new FileInfo(fileNameActual);

View File

@@ -125,8 +125,8 @@ namespace ARMeilleure.Translation.PTC
{ {
_lastHash = default; _lastHash = default;
string fileNameActual = string.Concat(_ptc.CachePathActual, ".info"); string fileNameActual = $"{_ptc.CachePathActual}.info";
string fileNameBackup = string.Concat(_ptc.CachePathBackup, ".info"); string fileNameBackup = $"{_ptc.CachePathBackup}.info";
FileInfo fileInfoActual = new FileInfo(fileNameActual); FileInfo fileInfoActual = new FileInfo(fileNameActual);
FileInfo fileInfoBackup = new FileInfo(fileNameBackup); FileInfo fileInfoBackup = new FileInfo(fileNameBackup);
@@ -246,8 +246,8 @@ namespace ARMeilleure.Translation.PTC
{ {
_waitEvent.Reset(); _waitEvent.Reset();
string fileNameActual = string.Concat(_ptc.CachePathActual, ".info"); string fileNameActual = $"{_ptc.CachePathActual}.info";
string fileNameBackup = string.Concat(_ptc.CachePathBackup, ".info"); string fileNameBackup = $"{_ptc.CachePathBackup}.info";
FileInfo fileInfoActual = new FileInfo(fileNameActual); FileInfo fileInfoActual = new FileInfo(fileNameActual);

View File

@@ -435,7 +435,7 @@ namespace Ryujinx.Ava.UI.ViewModels
if (str.Length > MaxSize) if (str.Length > MaxSize)
{ {
return str.Substring(0, MaxSize - Ellipsis.Length) + Ellipsis; return $"{str.AsSpan(0, MaxSize - Ellipsis.Length)}{Ellipsis}";
} }
return str; return str;

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Globalization;
namespace Ryujinx.Common.Utilities namespace Ryujinx.Common.Utilities
{ {
@@ -6,7 +7,7 @@ namespace Ryujinx.Common.Utilities
{ {
public static UInt128 FromHex(string hex) public static UInt128 FromHex(string hex)
{ {
return new UInt128((ulong)Convert.ToInt64(hex.Substring(0, 16), 16), (ulong)Convert.ToInt64(hex.Substring(16), 16)); return new UInt128(ulong.Parse(hex.AsSpan(0, 16), NumberStyles.HexNumber), ulong.Parse(hex.AsSpan(16), NumberStyles.HexNumber));
} }
public static UInt128 CreateRandom() public static UInt128 CreateRandom()

View File

@@ -462,7 +462,7 @@ namespace Ryujinx.Cpu
public void Dispose() public void Dispose()
{ {
_privateMemoryAllocator.Dispose(); _privateMemoryAllocator?.Dispose();
Base.Dispose(); Base.Dispose();
Mirror.Dispose(); Mirror.Dispose();
} }

View File

@@ -2,6 +2,7 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.StructuredIr; using Ryujinx.Graphics.Shader.StructuredIr;
using Ryujinx.Graphics.Shader.Translation; using Ryujinx.Graphics.Shader.Translation;
using System; using System;
using System.Text;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper; using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo; using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
@@ -44,11 +45,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
bool isArray = (texOp.Type & SamplerType.Array) != 0; bool isArray = (texOp.Type & SamplerType.Array) != 0;
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
string texCall; var texCallBuilder = new StringBuilder();
if (texOp.Inst == Instruction.ImageAtomic) if (texOp.Inst == Instruction.ImageAtomic)
{ {
texCall = (texOp.Flags & TextureFlags.AtomicMask) switch { texCallBuilder.Append((texOp.Flags & TextureFlags.AtomicMask) switch {
TextureFlags.Add => "imageAtomicAdd", TextureFlags.Add => "imageAtomicAdd",
TextureFlags.Minimum => "imageAtomicMin", TextureFlags.Minimum => "imageAtomicMin",
TextureFlags.Maximum => "imageAtomicMax", TextureFlags.Maximum => "imageAtomicMax",
@@ -60,11 +61,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
TextureFlags.Swap => "imageAtomicExchange", TextureFlags.Swap => "imageAtomicExchange",
TextureFlags.CAS => "imageAtomicCompSwap", TextureFlags.CAS => "imageAtomicCompSwap",
_ => "imageAtomicAdd", _ => "imageAtomicAdd",
}; });
} }
else else
{ {
texCall = texOp.Inst == Instruction.ImageLoad ? "imageLoad" : "imageStore"; texCallBuilder.Append(texOp.Inst == Instruction.ImageLoad ? "imageLoad" : "imageStore");
} }
int srcIndex = isBindless ? 1 : 0; int srcIndex = isBindless ? 1 : 0;
@@ -83,7 +84,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr); string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr);
texCall += "(" + imageName; texCallBuilder.Append('(');
texCallBuilder.Append(imageName);
int coordsCount = texOp.Type.GetDimensions(); int coordsCount = texOp.Type.GetDimensions();
@@ -91,7 +93,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
void Append(string str) void Append(string str)
{ {
texCall += ", " + str; texCallBuilder.Append(", ");
texCallBuilder.Append(str);
} }
string ApplyScaling(string vector) string ApplyScaling(string vector)
@@ -107,11 +110,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
if (pCount == 3 && isArray) if (pCount == 3 && isArray)
{ {
// The array index is not scaled, just x and y. // The array index is not scaled, just x and y.
vector = "ivec3(Helper_TexelFetchScale((" + vector + ").xy, " + scaleIndex + "), (" + vector + ").z)"; vector = $"ivec3(Helper_TexelFetchScale(({vector}).xy, {scaleIndex}), ({vector}).z)";
} }
else if (pCount == 2 && !isArray) else if (pCount == 2 && !isArray)
{ {
vector = "Helper_TexelFetchScale(" + vector + ", " + scaleIndex + ")"; vector = $"Helper_TexelFetchScale({vector}, {scaleIndex})";
} }
} }
@@ -127,7 +130,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
elems[index] = Src(AggregateType.S32); elems[index] = Src(AggregateType.S32);
} }
Append(ApplyScaling("ivec" + pCount + "(" + string.Join(", ", elems) + ")")); Append(ApplyScaling($"ivec{pCount}({string.Join(", ", elems)})"));
} }
else else
{ {
@@ -164,7 +167,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
_ => string.Empty _ => string.Empty
}; };
Append(prefix + "vec4(" + string.Join(", ", cElems) + ")"); Append($"{prefix}vec4({string.Join(", ", cElems)})");
} }
if (texOp.Inst == Instruction.ImageAtomic) if (texOp.Inst == Instruction.ImageAtomic)
@@ -185,19 +188,26 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Append(value); Append(value);
texCall += ")"; texCallBuilder.Append(')');
if (type != AggregateType.S32) if (type != AggregateType.S32)
{ {
texCall = "int(" + texCall + ")"; texCallBuilder
.Insert(0, "int(")
.Append(')');
} }
} }
else else
{ {
texCall += ")" + (texOp.Inst == Instruction.ImageLoad ? GetMaskMultiDest(texOp.Index) : ""); texCallBuilder.Append(')');
if (texOp.Inst == Instruction.ImageLoad)
{
texCallBuilder.Append(GetMaskMultiDest(texOp.Index));
}
} }
return texCall; return texCallBuilder.ToString();
} }
public static string LoadAttribute(CodeGenContext context, AstOperation operation) public static string LoadAttribute(CodeGenContext context, AstOperation operation)
@@ -827,7 +837,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
private static string GetMask(int index) private static string GetMask(int index)
{ {
return '.' + "rgba".Substring(index, 1); return $".{"rgba".AsSpan(index, 1)}";
} }
private static string GetMaskMultiDest(int mask) private static string GetMaskMultiDest(int mask)

View File

@@ -1,4 +1,5 @@
using Ryujinx.Graphics.Shader.StructuredIr; using Ryujinx.Graphics.Shader.StructuredIr;
using System;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper; using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo; using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
@@ -49,7 +50,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
private static string GetMask(int index) private static string GetMask(int index)
{ {
return '.' + "xy".Substring(index, 1); return $".{"xy".AsSpan(index, 1)}";
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using Ryujinx.Graphics.Shader.Instructions; using Ryujinx.Graphics.Shader.Instructions;
using System;
namespace Ryujinx.Graphics.Shader.Decoders namespace Ryujinx.Graphics.Shader.Decoders
{ {
@@ -329,18 +330,18 @@ namespace Ryujinx.Graphics.Shader.Decoders
private static void Add(string encoding, InstName name, InstEmitter emitter, InstProps props = InstProps.None) private static void Add(string encoding, InstName name, InstEmitter emitter, InstProps props = InstProps.None)
{ {
encoding = encoding.Substring(0, EncodingBits); ReadOnlySpan<char> encodingPart = encoding.AsSpan(0, EncodingBits);
int bit = encoding.Length - 1; int bit = encodingPart.Length - 1;
int value = 0; int value = 0;
int xMask = 0; int xMask = 0;
int xBits = 0; int xBits = 0;
int[] xPos = new int[encoding.Length]; int[] xPos = new int[encodingPart.Length];
for (int index = 0; index < encoding.Length; index++, bit--) for (int index = 0; index < encodingPart.Length; index++, bit--)
{ {
char chr = encoding[index]; char chr = encodingPart[index];
if (chr == '1') if (chr == '1')
{ {

View File

@@ -28,6 +28,7 @@ namespace Ryujinx.Graphics.Vulkan
public readonly bool SupportsExtendedDynamicState; public readonly bool SupportsExtendedDynamicState;
public readonly bool SupportsMultiView; public readonly bool SupportsMultiView;
public readonly bool SupportsNullDescriptors; public readonly bool SupportsNullDescriptors;
public readonly bool SupportsPreciseOcclusionQueries;
public readonly bool SupportsPushDescriptors; public readonly bool SupportsPushDescriptors;
public readonly bool SupportsTransformFeedback; public readonly bool SupportsTransformFeedback;
public readonly bool SupportsTransformFeedbackQueries; public readonly bool SupportsTransformFeedbackQueries;
@@ -53,6 +54,7 @@ namespace Ryujinx.Graphics.Vulkan
bool supportsPushDescriptors, bool supportsPushDescriptors,
bool supportsTransformFeedback, bool supportsTransformFeedback,
bool supportsTransformFeedbackQueries, bool supportsTransformFeedbackQueries,
bool supportsPreciseOcclusionQueries,
bool supportsGeometryShader, bool supportsGeometryShader,
uint minSubgroupSize, uint minSubgroupSize,
uint maxSubgroupSize, uint maxSubgroupSize,
@@ -74,6 +76,7 @@ namespace Ryujinx.Graphics.Vulkan
SupportsPushDescriptors = supportsPushDescriptors; SupportsPushDescriptors = supportsPushDescriptors;
SupportsTransformFeedback = supportsTransformFeedback; SupportsTransformFeedback = supportsTransformFeedback;
SupportsTransformFeedbackQueries = supportsTransformFeedbackQueries; SupportsTransformFeedbackQueries = supportsTransformFeedbackQueries;
SupportsPreciseOcclusionQueries = supportsPreciseOcclusionQueries;
SupportsGeometryShader = supportsGeometryShader; SupportsGeometryShader = supportsGeometryShader;
MinSubgroupSize = minSubgroupSize; MinSubgroupSize = minSubgroupSize;
MaxSubgroupSize = maxSubgroupSize; MaxSubgroupSize = maxSubgroupSize;

View File

@@ -235,7 +235,7 @@ namespace Ryujinx.Graphics.Vulkan
foreach (var queryPool in _activeQueries) foreach (var queryPool in _activeQueries)
{ {
Gd.Api.CmdResetQueryPool(CommandBuffer, queryPool, 0, 1); Gd.Api.CmdResetQueryPool(CommandBuffer, queryPool, 0, 1);
Gd.Api.CmdBeginQuery(CommandBuffer, queryPool, 0, 0); Gd.Api.CmdBeginQuery(CommandBuffer, queryPool, 0, Gd.Capabilities.SupportsPreciseOcclusionQueries ? QueryControlFlags.PreciseBit : 0);
} }
Restore(); Restore();
@@ -255,7 +255,7 @@ namespace Ryujinx.Graphics.Vulkan
} }
} }
Gd.Api.CmdBeginQuery(CommandBuffer, pool, 0, 0); Gd.Api.CmdBeginQuery(CommandBuffer, pool, 0, Gd.Capabilities.SupportsPreciseOcclusionQueries ? QueryControlFlags.PreciseBit : 0);
_activeQueries.Add(pool); _activeQueries.Add(pool);
} }

View File

@@ -416,6 +416,7 @@ namespace Ryujinx.Graphics.Vulkan
IndependentBlend = true, IndependentBlend = true,
LogicOp = supportedFeatures.LogicOp, LogicOp = supportedFeatures.LogicOp,
MultiViewport = true, MultiViewport = true,
OcclusionQueryPrecise = supportedFeatures.OcclusionQueryPrecise,
PipelineStatisticsQuery = supportedFeatures.PipelineStatisticsQuery, PipelineStatisticsQuery = supportedFeatures.PipelineStatisticsQuery,
SamplerAnisotropy = true, SamplerAnisotropy = true,
ShaderClipDistance = true, ShaderClipDistance = true,

View File

@@ -270,6 +270,7 @@ namespace Ryujinx.Graphics.Vulkan
supportedExtensions.Contains(KhrPushDescriptor.ExtensionName), supportedExtensions.Contains(KhrPushDescriptor.ExtensionName),
supportsTransformFeedback, supportsTransformFeedback,
propertiesTransformFeedback.TransformFeedbackQueries, propertiesTransformFeedback.TransformFeedbackQueries,
features2.Features.OcclusionQueryPrecise,
supportedFeatures.GeometryShader, supportedFeatures.GeometryShader,
propertiesSubgroupSizeControl.MinSubgroupSize, propertiesSubgroupSizeControl.MinSubgroupSize,
propertiesSubgroupSizeControl.MaxSubgroupSize, propertiesSubgroupSizeControl.MaxSubgroupSize,

View File

@@ -16,6 +16,7 @@ using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using System; using System;
using System.Buffers.Text; using System.Buffers.Text;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@@ -35,7 +36,8 @@ namespace Ryujinx.HLE.FileSystem
public EmulatedGameCard GameCard { get; private set; } public EmulatedGameCard GameCard { get; private set; }
public EmulatedSdCard SdCard { get; private set; } public EmulatedSdCard SdCard { get; private set; }
public ModLoader ModLoader { get; private set; } public ModLoader ModLoader { get; private set; }
public Stream RomFs { get; private set; }
private readonly ConcurrentDictionary<ulong, Stream> _romFsByPid;
private static bool _isInitialized = false; private static bool _isInitialized = false;
@@ -55,17 +57,34 @@ namespace Ryujinx.HLE.FileSystem
{ {
ReloadKeySet(); ReloadKeySet();
ModLoader = new ModLoader(); // Should only be created once ModLoader = new ModLoader(); // Should only be created once
_romFsByPid = new ConcurrentDictionary<ulong, Stream>();
} }
public void LoadRomFs(string fileName) public void LoadRomFs(ulong pid, string fileName)
{ {
RomFs = new FileStream(fileName, FileMode.Open, FileAccess.Read); var romfsStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
_romFsByPid.AddOrUpdate(pid, romfsStream, (pid, oldStream) =>
{
oldStream.Close();
return romfsStream;
});
} }
public void SetRomFs(Stream romfsStream) public void SetRomFs(ulong pid, Stream romfsStream)
{ {
RomFs?.Close(); _romFsByPid.AddOrUpdate(pid, romfsStream, (pid, oldStream) =>
RomFs = romfsStream; {
oldStream.Close();
return romfsStream;
});
}
public Stream GetRomFs(ulong pid)
{
return _romFsByPid[pid];
} }
public string GetFullPath(string basePath, string fileName) public string GetFullPath(string basePath, string fileName)
@@ -122,8 +141,8 @@ namespace Ryujinx.HLE.FileSystem
return $"{rawPath}:/"; return $"{rawPath}:/";
} }
string basePath = rawPath.Substring(0, firstSeparatorOffset); var basePath = rawPath.AsSpan(0, firstSeparatorOffset);
string fileName = rawPath.Substring(firstSeparatorOffset + 1); var fileName = rawPath.AsSpan(firstSeparatorOffset + 1);
return $"{basePath}:/{fileName}"; return $"{basePath}:/{fileName}";
} }
@@ -583,7 +602,12 @@ namespace Ryujinx.HLE.FileSystem
{ {
if (disposing) if (disposing)
{ {
RomFs?.Dispose(); foreach (var stream in _romFsByPid.Values)
{
stream.Close();
}
_romFsByPid.Clear();
} }
} }
} }

View File

@@ -24,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
for (int maxStr = text.Length; maxStr >= 0; maxStr--) for (int maxStr = text.Length; maxStr >= 0; maxStr--)
{ {
// This loop will probably will run only once. // This loop will probably will run only once.
bytes = encoding.GetBytes(text.Substring(0, maxStr)); bytes = encoding.GetBytes(text, 0, maxStr);
if (bytes.Length <= maxSize) if (bytes.Length <= maxSize)
{ {
break; break;

View File

@@ -292,20 +292,35 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
_logoPosition = new Point(logoPositionX, logoPositionY); _logoPosition = new Point(logoPositionX, logoPositionY);
} }
private static RectangleF MeasureString(string text, Font font)
private RectangleF MeasureString(string text, Font font)
{ {
RendererOptions options = new RendererOptions(font); RendererOptions options = new RendererOptions(font);
FontRectangle rectangle = TextMeasurer.Measure(text == "" ? " " : text, options);
if (text == "") if (text == "")
{ {
return new RectangleF(0, rectangle.Y, 0, rectangle.Height); FontRectangle emptyRectangle = TextMeasurer.Measure(" ", options);
return new RectangleF(0, emptyRectangle.Y, 0, emptyRectangle.Height);
} }
else
FontRectangle rectangle = TextMeasurer.Measure(text, options);
return new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
}
private static RectangleF MeasureString(ReadOnlySpan<char> text, Font font)
{
RendererOptions options = new RendererOptions(font);
if (text == "")
{ {
return new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); FontRectangle emptyRectangle = TextMeasurer.Measure(" ", options);
return new RectangleF(0, emptyRectangle.Y, 0, emptyRectangle.Height);
} }
FontRectangle rectangle = TextMeasurer.Measure(text, options);
return new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
} }
private void DrawTextBox(IImageProcessingContext context, SoftwareKeyboardUiState state) private void DrawTextBox(IImageProcessingContext context, SoftwareKeyboardUiState state)
@@ -354,8 +369,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
cursorBrush = _selectionBoxBrush; cursorBrush = _selectionBoxBrush;
cursorPen = _selectionBoxPen; cursorPen = _selectionBoxPen;
string textUntilBegin = state.InputText.Substring(0, state.CursorBegin); ReadOnlySpan<char> textUntilBegin = state.InputText.AsSpan(0, state.CursorBegin);
string textUntilEnd = state.InputText.Substring(0, state.CursorEnd); ReadOnlySpan<char> textUntilEnd = state.InputText.AsSpan(0, state.CursorEnd);
var selectionBeginRectangle = MeasureString(textUntilBegin, _inputTextFont); var selectionBeginRectangle = MeasureString(textUntilBegin, _inputTextFont);
var selectionEndRectangle = MeasureString(textUntilEnd , _inputTextFont); var selectionEndRectangle = MeasureString(textUntilEnd , _inputTextFont);
@@ -374,9 +389,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
{ {
// Show the blinking cursor. // Show the blinking cursor.
int cursorBegin = Math.Min(state.InputText.Length, state.CursorBegin); int cursorBegin = Math.Min(state.InputText.Length, state.CursorBegin);
string textUntilCursor = state.InputText.Substring(0, cursorBegin); ReadOnlySpan<char> textUntilCursor = state.InputText.AsSpan(0, cursorBegin);
var cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont); var cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont);
cursorVisible = true; cursorVisible = true;
cursorPositionXLeft = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.X; cursorPositionXLeft = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.X;
@@ -387,7 +402,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
if (state.CursorBegin < state.InputText.Length) if (state.CursorBegin < state.InputText.Length)
{ {
textUntilCursor = state.InputText.Substring(0, cursorBegin + 1); textUntilCursor = state.InputText.AsSpan(0, cursorBegin + 1);
cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont); cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont);
cursorPositionXRight = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.X; cursorPositionXRight = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.X;
} }

View File

@@ -76,11 +76,6 @@ namespace Ryujinx.HLE.HOS
public void LoadCart(string exeFsDir, string romFsFile = null) public void LoadCart(string exeFsDir, string romFsFile = null)
{ {
if (romFsFile != null)
{
_device.Configuration.VirtualFileSystem.LoadRomFs(romFsFile);
}
LocalFileSystem codeFs = new LocalFileSystem(exeFsDir); LocalFileSystem codeFs = new LocalFileSystem(exeFsDir);
MetaLoader metaData = ReadNpdm(codeFs); MetaLoader metaData = ReadNpdm(codeFs);
@@ -95,7 +90,12 @@ namespace Ryujinx.HLE.HOS
EnsureSaveData(new ApplicationId(TitleId)); EnsureSaveData(new ApplicationId(TitleId));
} }
LoadExeFs(codeFs, string.Empty, metaData); ulong pid = LoadExeFs(codeFs, string.Empty, metaData);
if (romFsFile != null)
{
_device.Configuration.VirtualFileSystem.LoadRomFs(pid, romFsFile);
}
} }
public static (Nca main, Nca patch, Nca control) GetGameData(VirtualFileSystem fileSystem, PartitionFileSystem pfs, int programIndex) public static (Nca main, Nca patch, Nca control) GetGameData(VirtualFileSystem fileSystem, PartitionFileSystem pfs, int programIndex)
@@ -491,6 +491,8 @@ namespace Ryujinx.HLE.HOS
_displayVersion = displayVersion; _displayVersion = displayVersion;
ulong pid = LoadExeFs(codeFs, displayVersion, metaData);
if (dataStorage == null) if (dataStorage == null)
{ {
Logger.Warning?.Print(LogClass.Loader, "No RomFS found in NCA"); Logger.Warning?.Print(LogClass.Loader, "No RomFS found in NCA");
@@ -499,7 +501,7 @@ namespace Ryujinx.HLE.HOS
{ {
IStorage newStorage = _device.Configuration.VirtualFileSystem.ModLoader.ApplyRomFsMods(TitleId, dataStorage); IStorage newStorage = _device.Configuration.VirtualFileSystem.ModLoader.ApplyRomFsMods(TitleId, dataStorage);
_device.Configuration.VirtualFileSystem.SetRomFs(newStorage.AsStream(FileAccess.Read)); _device.Configuration.VirtualFileSystem.SetRomFs(pid, newStorage.AsStream(FileAccess.Read));
} }
// Don't create save data for system programs. // Don't create save data for system programs.
@@ -510,8 +512,6 @@ namespace Ryujinx.HLE.HOS
EnsureSaveData(new ApplicationId(TitleId & ~0xFul)); EnsureSaveData(new ApplicationId(TitleId & ~0xFul));
} }
LoadExeFs(codeFs, displayVersion, metaData);
Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {TitleName} v{DisplayVersion} [{TitleIdText}] [{(TitleIs64Bit ? "64-bit" : "32-bit")}]"); Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {TitleName} v{DisplayVersion} [{TitleIdText}] [{(TitleIs64Bit ? "64-bit" : "32-bit")}]");
} }
@@ -579,7 +579,7 @@ namespace Ryujinx.HLE.HOS
} }
} }
private void LoadExeFs(IFileSystem codeFs, string displayVersion, MetaLoader metaData = null, bool isHomebrew = false) private ulong LoadExeFs(IFileSystem codeFs, string displayVersion, MetaLoader metaData = null, bool isHomebrew = false)
{ {
if (_device.Configuration.VirtualFileSystem.ModLoader.ReplaceExefsPartition(TitleId, ref codeFs)) if (_device.Configuration.VirtualFileSystem.ModLoader.ReplaceExefsPartition(TitleId, ref codeFs))
{ {
@@ -654,6 +654,8 @@ namespace Ryujinx.HLE.HOS
DiskCacheLoadState = result.DiskCacheLoadState; DiskCacheLoadState = result.DiskCacheLoadState;
_device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine); _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine);
return result.ProcessId;
} }
public void LoadProgram(string filePath) public void LoadProgram(string filePath)
@@ -665,6 +667,7 @@ namespace Ryujinx.HLE.HOS
bool isNro = Path.GetExtension(filePath).ToLower() == ".nro"; bool isNro = Path.GetExtension(filePath).ToLower() == ".nro";
IExecutable executable; IExecutable executable;
Stream romfsStream = null;
if (isNro) if (isNro)
{ {
@@ -697,7 +700,7 @@ namespace Ryujinx.HLE.HOS
if (romfsSize != 0) if (romfsSize != 0)
{ {
_device.Configuration.VirtualFileSystem.SetRomFs(new HomebrewRomFsStream(input, obj.FileSize + (long)romfsOffset)); romfsStream = new HomebrewRomFsStream(input, obj.FileSize + (long)romfsOffset);
} }
if (nacpSize != 0) if (nacpSize != 0)
@@ -758,6 +761,11 @@ namespace Ryujinx.HLE.HOS
ProgramLoadResult result = ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: executable); ProgramLoadResult result = ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: executable);
if (romfsStream != null)
{
_device.Configuration.VirtualFileSystem.SetRomFs(result.ProcessId, romfsStream);
}
DiskCacheLoadState = result.DiskCacheLoadState; DiskCacheLoadState = result.DiskCacheLoadState;
_device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine); _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine);

View File

@@ -1,4 +1,5 @@
using System.IO; using System.IO;
using System;
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
{ {
@@ -25,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
if (_literalValue[0] == 'n') if (_literalValue[0] == 'n')
{ {
writer.Write("-"); writer.Write("-");
writer.Write(_literalValue.Substring(1)); writer.Write(_literalValue.AsSpan(1));
} }
else else
{ {

View File

@@ -32,9 +32,9 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
private bool ConsumeIf(string toConsume) private bool ConsumeIf(string toConsume)
{ {
string mangledPart = Mangled.Substring(_position); var mangledPart = Mangled.AsSpan(_position);
if (mangledPart.StartsWith(toConsume)) if (mangledPart.StartsWith(toConsume.AsSpan()))
{ {
_position += toConsume.Length; _position += toConsume.Length;
@@ -44,14 +44,14 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
return false; return false;
} }
private string PeekString(int offset = 0, int length = 1) private ReadOnlySpan<char> PeekString(int offset = 0, int length = 1)
{ {
if (_position + offset >= length) if (_position + offset >= length)
{ {
return null; return null;
} }
return Mangled.Substring(_position + offset, length); return Mangled.AsSpan(_position + offset, length);
} }
private char Peek(int offset = 0) private char Peek(int offset = 0)
@@ -101,8 +101,8 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
private int ParseSeqId() private int ParseSeqId()
{ {
string part = Mangled.Substring(_position); ReadOnlySpan<char> part = Mangled.AsSpan(_position);
int seqIdLen = 0; int seqIdLen = 0;
for (; seqIdLen < part.Length; seqIdLen++) for (; seqIdLen < part.Length; seqIdLen++)
{ {
@@ -114,7 +114,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
_position += seqIdLen; _position += seqIdLen;
return FromBase36(part.Substring(0, seqIdLen)); return FromBase36(new string(part[..seqIdLen]));
} }
// <substitution> ::= S <seq-id> _ // <substitution> ::= S <seq-id> _
@@ -900,8 +900,8 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
private int ParsePositiveNumber() private int ParsePositiveNumber()
{ {
string part = Mangled.Substring(_position); ReadOnlySpan<char> part = Mangled.AsSpan(_position);
int numberLength = 0; int numberLength = 0;
for (; numberLength < part.Length; numberLength++) for (; numberLength < part.Length; numberLength++)
{ {
@@ -918,7 +918,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
return -1; return -1;
} }
return int.Parse(part.AsSpan(0, numberLength)); return int.Parse(part[..numberLength]);
} }
private string ParseNumber(bool isSigned = false) private string ParseNumber(bool isSigned = false)
@@ -933,8 +933,8 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
return null; return null;
} }
string part = Mangled.Substring(_position); ReadOnlySpan<char> part = Mangled.AsSpan(_position);
int numberLength = 0; int numberLength = 0;
for (; numberLength < part.Length; numberLength++) for (; numberLength < part.Length; numberLength++)
{ {
@@ -946,7 +946,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
_position += numberLength; _position += numberLength;
return part.Substring(0, numberLength); return new string(part[..numberLength]);
} }
// <source-name> ::= <positive length number> <identifier> // <source-name> ::= <positive length number> <identifier>

View File

@@ -41,17 +41,19 @@ namespace Ryujinx.HLE.HOS
struct ProgramLoadResult struct ProgramLoadResult
{ {
public static ProgramLoadResult Failed => new ProgramLoadResult(false, null, null); public static ProgramLoadResult Failed => new ProgramLoadResult(false, null, null, 0);
public readonly bool Success; public readonly bool Success;
public readonly ProcessTamperInfo TamperInfo; public readonly ProcessTamperInfo TamperInfo;
public readonly IDiskCacheLoadState DiskCacheLoadState; public readonly IDiskCacheLoadState DiskCacheLoadState;
public readonly ulong ProcessId;
public ProgramLoadResult(bool success, ProcessTamperInfo tamperInfo, IDiskCacheLoadState diskCacheLoadState) public ProgramLoadResult(bool success, ProcessTamperInfo tamperInfo, IDiskCacheLoadState diskCacheLoadState, ulong pid)
{ {
Success = success; Success = success;
TamperInfo = tamperInfo; TamperInfo = tamperInfo;
DiskCacheLoadState = diskCacheLoadState; DiskCacheLoadState = diskCacheLoadState;
ProcessId = pid;
} }
} }
@@ -366,7 +368,7 @@ namespace Ryujinx.HLE.HOS
process.MemoryManager.AliasRegionStart, process.MemoryManager.AliasRegionStart,
process.MemoryManager.CodeRegionStart); process.MemoryManager.CodeRegionStart);
return new ProgramLoadResult(true, tamperInfo, processContextFactory.DiskCacheLoadState); return new ProgramLoadResult(true, tamperInfo, processContextFactory.DiskCacheLoadState, process.Pid);
} }
private static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress) private static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)

View File

@@ -1,5 +1,6 @@
using LibHac.Account; using LibHac.Account;
using System; using System;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@@ -35,8 +36,8 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
throw new ArgumentException("Invalid Hex value!", nameof(hex)); throw new ArgumentException("Invalid Hex value!", nameof(hex));
} }
Low = Convert.ToInt64(hex.Substring(16), 16); Low = long.Parse(hex.AsSpan(16), NumberStyles.HexNumber);
High = Convert.ToInt64(hex.Substring(0, 16), 16); High = long.Parse(hex.AsSpan(0, 16), NumberStyles.HexNumber);
} }
public void Write(BinaryWriter binaryWriter) public void Write(BinaryWriter binaryWriter)

View File

@@ -27,6 +27,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
class IFileSystemProxy : DisposableIpcService class IFileSystemProxy : DisposableIpcService
{ {
private SharedRef<LibHac.FsSrv.Sf.IFileSystemProxy> _baseFileSystemProxy; private SharedRef<LibHac.FsSrv.Sf.IFileSystemProxy> _baseFileSystemProxy;
private ulong _pid;
public IFileSystemProxy(ServiceCtx context) : base(context.Device.System.FsServer) public IFileSystemProxy(ServiceCtx context) : base(context.Device.System.FsServer)
{ {
@@ -38,6 +39,8 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// SetCurrentProcess(u64, pid) // SetCurrentProcess(u64, pid)
public ResultCode SetCurrentProcess(ServiceCtx context) public ResultCode SetCurrentProcess(ServiceCtx context)
{ {
_pid = context.Request.HandleDesc.PId;
return ResultCode.Success; return ResultCode.Success;
} }
@@ -702,7 +705,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage // OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage
public ResultCode OpenDataStorageByCurrentProcess(ServiceCtx context) public ResultCode OpenDataStorageByCurrentProcess(ServiceCtx context)
{ {
var storage = context.Device.FileSystem.RomFs.AsStorage(true); var storage = context.Device.FileSystem.GetRomFs(_pid).AsStorage(true);
using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage); using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage);
using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref())); using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref()));
@@ -791,7 +794,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// OpenPatchDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> // OpenPatchDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage>
public ResultCode OpenPatchDataStorageByCurrentProcess(ServiceCtx context) public ResultCode OpenPatchDataStorageByCurrentProcess(ServiceCtx context)
{ {
var storage = context.Device.FileSystem.RomFs.AsStorage(true); var storage = context.Device.FileSystem.GetRomFs(_pid).AsStorage(true);
using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage); using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage);
using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref())); using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref()));
@@ -811,7 +814,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
throw new NotImplementedException($"Accessing storage from other programs is not supported (program index = {programIndex})."); throw new NotImplementedException($"Accessing storage from other programs is not supported (program index = {programIndex}).");
} }
var storage = context.Device.FileSystem.RomFs.AsStorage(true); var storage = context.Device.FileSystem.GetRomFs(_pid).AsStorage(true);
using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage); using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage);
using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref())); using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref()));

View File

@@ -4,6 +4,7 @@ using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Services.Settings; using Ryujinx.HLE.HOS.Services.Settings;
using Ryujinx.HLE.HOS.Services.Sockets.Nsd.Manager; using Ryujinx.HLE.HOS.Services.Sockets.Nsd.Manager;
using Ryujinx.HLE.HOS.Services.Sockets.Nsd.Types; using Ryujinx.HLE.HOS.Services.Sockets.Nsd.Types;
using System;
using System.Text; using System.Text;
namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
@@ -370,7 +371,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
return result; return result;
} }
byte environmentType = identifier.Substring(0, 2) switch byte environmentType = identifier.AsSpan(0, 2) switch
{ {
"lp" => (byte)ApplicationServerEnvironmentType.Lp, "lp" => (byte)ApplicationServerEnvironmentType.Lp,
"sd" => (byte)ApplicationServerEnvironmentType.Sd, "sd" => (byte)ApplicationServerEnvironmentType.Sd,

View File

@@ -4,9 +4,10 @@ namespace Ryujinx.Horizon.Generators
{ {
class CodeGenerator class CodeGenerator
{ {
private const string Indent = " "; private const int IndentLength = 4;
private readonly StringBuilder _sb; private readonly StringBuilder _sb;
private string _currentIndent; private int _currentIndentCount;
public CodeGenerator() public CodeGenerator()
{ {
@@ -32,12 +33,15 @@ namespace Ryujinx.Horizon.Generators
public void IncreaseIndentation() public void IncreaseIndentation()
{ {
_currentIndent += Indent; _currentIndentCount++;
} }
public void DecreaseIndentation() public void DecreaseIndentation()
{ {
_currentIndent = _currentIndent.Substring(0, _currentIndent.Length - Indent.Length); if (_currentIndentCount - 1 >= 0)
{
_currentIndentCount--;
}
} }
public void AppendLine() public void AppendLine()
@@ -47,7 +51,8 @@ namespace Ryujinx.Horizon.Generators
public void AppendLine(string text) public void AppendLine(string text)
{ {
_sb.AppendLine(_currentIndent + text); _sb.Append(' ', IndentLength * _currentIndentCount);
_sb.AppendLine(text);
} }
public override string ToString() public override string ToString()

View File

@@ -417,7 +417,7 @@ namespace Ryujinx.Horizon.Generators.Kernel
private static string GetPrefixedArgName(string name) private static string GetPrefixedArgName(string name)
{ {
return ArgVariablePrefix + name[0].ToString().ToUpperInvariant() + name.Substring(1); return ArgVariablePrefix + char.ToUpperInvariant(name[0]) + name.Substring(1);
} }
private static string GetCanonicalTypeName(Compilation compilation, SyntaxNode syntaxNode) private static string GetCanonicalTypeName(Compilation compilation, SyntaxNode syntaxNode)

View File

@@ -344,7 +344,7 @@ namespace Ryujinx.Ui.Windows
string imageUrl = _amiiboList.FirstOrDefault(amiibo => amiibo.Head + amiibo.Tail == _amiiboCharsComboBox.ActiveId).Image; string imageUrl = _amiiboList.FirstOrDefault(amiibo => amiibo.Head + amiibo.Tail == _amiiboCharsComboBox.ActiveId).Image;
string usageString = ""; var usageStringBuilder = new StringBuilder();
for (int i = 0; i < _amiiboList.Count; i++) for (int i = 0; i < _amiiboList.Count; i++)
{ {
@@ -358,19 +358,20 @@ namespace Ryujinx.Ui.Windows
{ {
foreach (AmiiboApiUsage usageItem in item.AmiiboUsage) foreach (AmiiboApiUsage usageItem in item.AmiiboUsage)
{ {
usageString += Environment.NewLine + $"- {usageItem.Usage.Replace("/", Environment.NewLine + "-")}"; usageStringBuilder.Append(Environment.NewLine);
usageStringBuilder.Append($"- {usageItem.Usage.Replace("/", Environment.NewLine + "-")}");
writable = usageItem.Write; writable = usageItem.Write;
} }
} }
} }
if (usageString.Length == 0) if (usageStringBuilder.Length == 0)
{ {
usageString = "Unknown."; usageStringBuilder.Append("Unknown.");
} }
_gameUsageLabel.Text = $"Usage{(writable ? " (Writable)" : "")} : {usageString}"; _gameUsageLabel.Text = $"Usage{(writable ? " (Writable)" : "")} : {usageStringBuilder}";
} }
} }

View File

@@ -246,7 +246,7 @@ namespace Ryujinx.Ui.Windows
if (str.Length > MaxSize) if (str.Length > MaxSize)
{ {
return str.Substring(0, MaxSize - ShrinkChars.Length) + ShrinkChars; return $"{str.AsSpan(0, MaxSize - ShrinkChars.Length)}{ShrinkChars}";
} }
return str; return str;