Compare commits

...

8 Commits

Author SHA1 Message Date
gdkchan
b6ac45d36d Fix SPIR-V call out arguments regression (#5767)
* Fix SPIR-V call out arguments regression

* Shader cache version bump
2023-10-06 00:18:30 -03:00
dependabot[bot]
7afae8c699 nuget: bump Microsoft.CodeAnalysis.CSharp from 4.6.0 to 4.7.0 (#5608)
Bumps [Microsoft.CodeAnalysis.CSharp](https://github.com/dotnet/roslyn) from 4.6.0 to 4.7.0.
- [Release notes](https://github.com/dotnet/roslyn/releases)
- [Changelog](https://github.com/dotnet/roslyn/blob/main/docs/Breaking%20API%20Changes.md)
- [Commits](https://github.com/dotnet/roslyn/commits)

---
updated-dependencies:
- dependency-name: Microsoft.CodeAnalysis.CSharp
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-05 13:40:03 +02:00
Marco Carvalho
7835968214 Strings should not be concatenated using '+' in a loop (#5664)
* Strings should not be concatenated using '+' in a loop

* fix IDE0090

* undo GenerateLoadOrStore

* prefer string interpolation

* Update src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs

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

---------

Co-authored-by: Mary <thog@protonmail.com>
2023-10-05 12:41:00 +02:00
gdkchan
0aceb534cb Fix SPIR-V function calls (#5764)
* Fix SPIR-V function calls

* Shader cache version bump
2023-10-04 21:35:26 -03:00
gdkchan
a0af6e4d07 Use unique temporary variables for function call parameters on SPIR-V (#5757)
* Use unique temporary variables for function call parameters on SPIR-V

* Shader cache version bump
2023-10-04 19:46:11 -03:00
jcm
f61b7818c3 Avalonia: Add macOS check for Color Space Passthrough (#5754)
* add macOS check for color passthrough

* use existing IsMacOS property

---------

Co-authored-by: jcm <butt@butts.com>
2023-10-04 19:15:37 +02:00
gdkchan
a2a97e1b11 Implement textureSamples texture query shader instruction (#5750)
* Implement textureSamples texture query shader instruction

* Shader cache version bump
2023-10-03 22:43:11 +00:00
gdkchan
8b2625b0be Decrement nvmap reference count on surface flinger prealloc (#5753) 2023-10-02 22:13:29 +00:00
31 changed files with 308 additions and 168 deletions

View File

@@ -20,7 +20,7 @@
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.3.0-beta.4" /> <PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.3.0-beta.4" />
<PackageVersion Include="LibHac" Version="0.18.0" /> <PackageVersion Include="LibHac" Version="0.18.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" /> <PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" /> <PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.7.2" /> <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" /> <PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" /> <PackageVersion Include="MsgPack.Cli" Version="1.0.1" />

View File

@@ -1,6 +1,7 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Text;
namespace ARMeilleure.Diagnostics namespace ARMeilleure.Diagnostics
{ {
@@ -48,14 +49,15 @@ namespace ARMeilleure.Diagnostics
ulong diff = address - symbol.Start; ulong diff = address - symbol.Start;
ulong rem = diff % symbol.ElementSize; ulong rem = diff % symbol.ElementSize;
result = symbol.Name + "_" + diff / symbol.ElementSize; StringBuilder resultBuilder = new();
resultBuilder.Append($"{symbol.Name}_{diff / symbol.ElementSize}");
if (rem != 0) if (rem != 0)
{ {
result += "+" + rem; resultBuilder.Append($"+{rem}");
} }
_symbols.TryAdd(address, result); _symbols.TryAdd(address, resultBuilder.ToString());
return result; return result;
} }

View File

@@ -327,7 +327,7 @@ namespace Ryujinx.Ava.UI.ViewModels
string imageUrl = _amiiboList.Find(amiibo => amiibo.Equals(selected)).Image; string imageUrl = _amiiboList.Find(amiibo => amiibo.Equals(selected)).Image;
string usageString = ""; StringBuilder usageStringBuilder = new();
for (int i = 0; i < _amiiboList.Count; i++) for (int i = 0; i < _amiiboList.Count; i++)
{ {
@@ -341,20 +341,19 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
foreach (AmiiboApiUsage usageItem in item.AmiiboUsage) foreach (AmiiboApiUsage usageItem in item.AmiiboUsage)
{ {
usageString += Environment.NewLine + usageStringBuilder.Append($"{Environment.NewLine}- {usageItem.Usage.Replace("/", Environment.NewLine + "-")}");
$"- {usageItem.Usage.Replace("/", Environment.NewLine + "-")}";
writable = usageItem.Write; writable = usageItem.Write;
} }
} }
} }
if (usageString.Length == 0) if (usageStringBuilder.Length == 0)
{ {
usageString = LocaleManager.Instance[LocaleKeys.Unknown] + "."; usageStringBuilder.Append($"{LocaleManager.Instance[LocaleKeys.Unknown]}.");
} }
Usage = $"{LocaleManager.Instance[LocaleKeys.Usage]} {(writable ? $" ({LocaleManager.Instance[LocaleKeys.Writable]})" : "")} : {usageString}"; Usage = $"{LocaleManager.Instance[LocaleKeys.Usage]} {(writable ? $" ({LocaleManager.Instance[LocaleKeys.Writable]})" : "")} : {usageStringBuilder}";
} }
} }

View File

@@ -147,6 +147,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool EnableTextureRecompression { get; set; } public bool EnableTextureRecompression { get; set; }
public bool EnableMacroHLE { get; set; } public bool EnableMacroHLE { get; set; }
public bool EnableColorSpacePassthrough { get; set; } public bool EnableColorSpacePassthrough { get; set; }
public bool ColorSpacePassthroughAvailable => IsMacOS;
public bool EnableFileLog { get; set; } public bool EnableFileLog { get; set; }
public bool EnableStub { get; set; } public bool EnableStub { get; set; }
public bool EnableInfo { get; set; } public bool EnableInfo { get; set; }

View File

@@ -73,6 +73,7 @@
<TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" /> <TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" />
</CheckBox> </CheckBox>
<CheckBox IsChecked="{Binding EnableColorSpacePassthrough}" <CheckBox IsChecked="{Binding EnableColorSpacePassthrough}"
IsVisible="{Binding ColorSpacePassthroughAvailable}"
ToolTip.Tip="{locale:Locale SettingsEnableColorSpacePassthroughTooltip}"> ToolTip.Tip="{locale:Locale SettingsEnableColorSpacePassthroughTooltip}">
<TextBlock Text="{locale:Locale SettingsEnableColorSpacePassthrough}" /> <TextBlock Text="{locale:Locale SettingsEnableColorSpacePassthrough}" />
</CheckBox> </CheckBox>
@@ -296,4 +297,4 @@
</StackPanel> </StackPanel>
</Border> </Border>
</ScrollViewer> </ScrollViewer>
</UserControl> </UserControl>

View File

@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2; private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 5682; private const uint CodeGenVersion = 5767;
private const string SharedTocFileName = "shared.toc"; private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data"; private const string SharedDataFileName = "shared.data";

View File

@@ -92,14 +92,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
private static string GetIndentation(int level) private static string GetIndentation(int level)
{ {
string indentation = string.Empty; StringBuilder indentationBuilder = new();
for (int index = 0; index < level; index++) for (int index = 0; index < level; index++)
{ {
indentation += Tab; indentationBuilder.Append(Tab);
} }
return indentation; return indentationBuilder.ToString();
} }
} }
} }

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.InstGenBallot; using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenBallot;
using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenCall; using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenCall;
@@ -67,11 +68,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
int arity = (int)(info.Type & InstType.ArityMask); int arity = (int)(info.Type & InstType.ArityMask);
string args = string.Empty; StringBuilder builder = new();
if (atomic && (operation.StorageKind == StorageKind.StorageBuffer || operation.StorageKind == StorageKind.SharedMemory)) if (atomic && (operation.StorageKind == StorageKind.StorageBuffer || operation.StorageKind == StorageKind.SharedMemory))
{ {
args = GenerateLoadOrStore(context, operation, isStore: false); builder.Append(GenerateLoadOrStore(context, operation, isStore: false));
AggregateType dstType = operation.Inst == Instruction.AtomicMaxS32 || operation.Inst == Instruction.AtomicMinS32 AggregateType dstType = operation.Inst == Instruction.AtomicMaxS32 || operation.Inst == Instruction.AtomicMinS32
? AggregateType.S32 ? AggregateType.S32
@@ -79,7 +80,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
for (int argIndex = operation.SourcesCount - arity + 2; argIndex < operation.SourcesCount; argIndex++) for (int argIndex = operation.SourcesCount - arity + 2; argIndex < operation.SourcesCount; argIndex++)
{ {
args += ", " + GetSoureExpr(context, operation.GetSource(argIndex), dstType); builder.Append($", {GetSoureExpr(context, operation.GetSource(argIndex), dstType)}");
} }
} }
else else
@@ -88,16 +89,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{ {
if (argIndex != 0) if (argIndex != 0)
{ {
args += ", "; builder.Append(", ");
} }
AggregateType dstType = GetSrcVarType(inst, argIndex); AggregateType dstType = GetSrcVarType(inst, argIndex);
args += GetSoureExpr(context, operation.GetSource(argIndex), dstType); builder.Append(GetSoureExpr(context, operation.GetSource(argIndex), dstType));
} }
} }
return info.OpName + '(' + args + ')'; return $"{info.OpName}({builder})";
} }
else if ((info.Type & InstType.Op) != 0) else if ((info.Type & InstType.Op) != 0)
{ {
@@ -184,8 +185,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
case Instruction.TextureSample: case Instruction.TextureSample:
return TextureSample(context, operation); return TextureSample(context, operation);
case Instruction.TextureSize: case Instruction.TextureQuerySamples:
return TextureSize(context, operation); return TextureQuerySamples(context, operation);
case Instruction.TextureQuerySize:
return TextureQuerySize(context, operation);
case Instruction.UnpackDouble2x32: case Instruction.UnpackDouble2x32:
return UnpackDouble2x32(context, operation); return UnpackDouble2x32(context, operation);

View File

@@ -118,7 +118,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Add(Instruction.Subtract, InstType.OpBinary, "-", 2); Add(Instruction.Subtract, InstType.OpBinary, "-", 2);
Add(Instruction.SwizzleAdd, InstType.CallTernary, HelperFunctionNames.SwizzleAdd); Add(Instruction.SwizzleAdd, InstType.CallTernary, HelperFunctionNames.SwizzleAdd);
Add(Instruction.TextureSample, InstType.Special); Add(Instruction.TextureSample, InstType.Special);
Add(Instruction.TextureSize, InstType.Special); Add(Instruction.TextureQuerySamples, InstType.Special);
Add(Instruction.TextureQuerySize, InstType.Special);
Add(Instruction.Truncate, InstType.CallUnary, "trunc"); Add(Instruction.Truncate, InstType.CallUnary, "trunc");
Add(Instruction.UnpackDouble2x32, InstType.Special); Add(Instruction.UnpackDouble2x32, InstType.Special);
Add(Instruction.UnpackHalf2x16, InstType.Special); Add(Instruction.UnpackHalf2x16, InstType.Special);

View File

@@ -517,7 +517,33 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
return texCall; return texCall;
} }
public static string TextureSize(CodeGenContext context, AstOperation operation) public static string TextureQuerySamples(CodeGenContext context, AstOperation operation)
{
AstTextureOperation texOp = (AstTextureOperation)operation;
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
// TODO: Bindless texture support. For now we just return 0.
if (isBindless)
{
return NumberFormatter.FormatInt(0);
}
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
string indexExpr = null;
if (isIndexed)
{
indexExpr = GetSoureExpr(context, texOp.GetSource(0), AggregateType.S32);
}
string samplerName = GetSamplerName(context.Properties, texOp, indexExpr);
return $"textureSamples({samplerName})";
}
public static string TextureQuerySize(CodeGenContext context, AstOperation operation)
{ {
AstTextureOperation texOp = (AstTextureOperation)operation; AstTextureOperation texOp = (AstTextureOperation)operation;
@@ -753,17 +779,18 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
private static string GetMaskMultiDest(int mask) private static string GetMaskMultiDest(int mask)
{ {
string swizzle = "."; StringBuilder swizzleBuilder = new();
swizzleBuilder.Append('.');
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
if ((mask & (1 << i)) != 0) if ((mask & (1 << i)) != 0)
{ {
swizzle += "xyzw"[i]; swizzleBuilder.Append("xyzw"[i]);
} }
} }
return swizzle; return swizzleBuilder.ToString();
} }
} }
} }

View File

@@ -44,7 +44,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
public StructuredFunction CurrentFunction { get; set; } public StructuredFunction CurrentFunction { get; set; }
private readonly Dictionary<AstOperand, Instruction> _locals = new(); private readonly Dictionary<AstOperand, Instruction> _locals = new();
private readonly Dictionary<int, Instruction[]> _localForArgs = new();
private readonly Dictionary<int, Instruction> _funcArgs = new(); private readonly Dictionary<int, Instruction> _funcArgs = new();
private readonly Dictionary<int, (StructuredFunction, Instruction)> _functions = new(); private readonly Dictionary<int, (StructuredFunction, Instruction)> _functions = new();
@@ -112,7 +111,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
IsMainFunction = isMainFunction; IsMainFunction = isMainFunction;
MayHaveReturned = false; MayHaveReturned = false;
_locals.Clear(); _locals.Clear();
_localForArgs.Clear();
_funcArgs.Clear(); _funcArgs.Clear();
} }
@@ -169,11 +167,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
_locals.Add(local, spvLocal); _locals.Add(local, spvLocal);
} }
public void DeclareLocalForArgs(int funcIndex, Instruction[] spvLocals)
{
_localForArgs.Add(funcIndex, spvLocals);
}
public void DeclareArgument(int argIndex, Instruction spvLocal) public void DeclareArgument(int argIndex, Instruction spvLocal)
{ {
_funcArgs.Add(argIndex, spvLocal); _funcArgs.Add(argIndex, spvLocal);
@@ -278,11 +271,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
return _locals[local]; return _locals[local];
} }
public Instruction[] GetLocalForArgsPointers(int funcIndex)
{
return _localForArgs[funcIndex];
}
public Instruction GetArgumentPointer(AstOperand funcArg) public Instruction GetArgumentPointer(AstOperand funcArg)
{ {
return _funcArgs[funcArg.Value]; return _funcArgs[funcArg.Value];

View File

@@ -41,28 +41,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
} }
} }
public static void DeclareLocalForArgs(CodeGenContext context, List<StructuredFunction> functions)
{
for (int funcIndex = 0; funcIndex < functions.Count; funcIndex++)
{
StructuredFunction function = functions[funcIndex];
SpvInstruction[] locals = new SpvInstruction[function.InArguments.Length];
for (int i = 0; i < function.InArguments.Length; i++)
{
var type = function.GetArgumentType(i);
var localPointerType = context.TypePointer(StorageClass.Function, context.GetType(type));
var spvLocal = context.Variable(localPointerType, StorageClass.Function);
context.AddLocalVariable(spvLocal);
locals[i] = spvLocal;
}
context.DeclareLocalForArgs(funcIndex, locals);
}
}
public static void DeclareAll(CodeGenContext context, StructuredProgramInfo info) public static void DeclareAll(CodeGenContext context, StructuredProgramInfo info)
{ {
DeclareConstantBuffers(context, context.Properties.ConstantBuffers.Values); DeclareConstantBuffers(context, context.Properties.ConstantBuffers.Values);

View File

@@ -134,7 +134,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
Add(Instruction.Subtract, GenerateSubtract); Add(Instruction.Subtract, GenerateSubtract);
Add(Instruction.SwizzleAdd, GenerateSwizzleAdd); Add(Instruction.SwizzleAdd, GenerateSwizzleAdd);
Add(Instruction.TextureSample, GenerateTextureSample); Add(Instruction.TextureSample, GenerateTextureSample);
Add(Instruction.TextureSize, GenerateTextureSize); Add(Instruction.TextureQuerySamples, GenerateTextureQuerySamples);
Add(Instruction.TextureQuerySize, GenerateTextureQuerySize);
Add(Instruction.Truncate, GenerateTruncate); Add(Instruction.Truncate, GenerateTruncate);
Add(Instruction.UnpackDouble2x32, GenerateUnpackDouble2x32); Add(Instruction.UnpackDouble2x32, GenerateUnpackDouble2x32);
Add(Instruction.UnpackHalf2x16, GenerateUnpackHalf2x16); Add(Instruction.UnpackHalf2x16, GenerateUnpackHalf2x16);
@@ -310,26 +311,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
var (function, spvFunc) = context.GetFunction(funcId.Value); var (function, spvFunc) = context.GetFunction(funcId.Value);
var args = new SpvInstruction[operation.SourcesCount - 1]; var args = new SpvInstruction[operation.SourcesCount - 1];
var spvLocals = context.GetLocalForArgsPointers(funcId.Value);
for (int i = 0; i < args.Length; i++) for (int i = 0; i < args.Length; i++)
{ {
var operand = operation.GetSource(i + 1); var operand = operation.GetSource(i + 1);
if (i >= function.InArguments.Length) AstOperand local = (AstOperand)operand;
{ Debug.Assert(local.Type == OperandType.LocalVariable);
args[i] = context.GetLocalPointer((AstOperand)operand); args[i] = context.GetLocalPointer(local);
}
else
{
var type = function.GetArgumentType(i);
var value = context.Get(type, operand);
var spvLocal = spvLocals[i];
context.Store(spvLocal, value);
args[i] = spvLocal;
}
} }
var retType = function.ReturnType; var retType = function.ReturnType;
@@ -1492,7 +1481,36 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
return new OperationResult(swizzledResultType, result); return new OperationResult(swizzledResultType, result);
} }
private static OperationResult GenerateTextureSize(CodeGenContext context, AstOperation operation) private static OperationResult GenerateTextureQuerySamples(CodeGenContext context, AstOperation operation)
{
AstTextureOperation texOp = (AstTextureOperation)operation;
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
// TODO: Bindless texture support. For now we just return 0.
if (isBindless)
{
return new OperationResult(AggregateType.S32, context.Constant(context.TypeS32(), 0));
}
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
if (isIndexed)
{
context.GetS32(texOp.GetSource(0));
}
(var imageType, var sampledImageType, var sampledImageVariable) = context.Samplers[texOp.Binding];
var image = context.Load(sampledImageType, sampledImageVariable);
image = context.Image(imageType, image);
SpvInstruction result = context.ImageQuerySamples(context.TypeS32(), image);
return new OperationResult(AggregateType.S32, result);
}
private static OperationResult GenerateTextureQuerySize(CodeGenContext context, AstOperation operation)
{ {
AstTextureOperation texOp = (AstTextureOperation)operation; AstTextureOperation texOp = (AstTextureOperation)operation;

View File

@@ -161,7 +161,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
context.EnterBlock(function.MainBlock); context.EnterBlock(function.MainBlock);
Declarations.DeclareLocals(context, function); Declarations.DeclareLocals(context, function);
Declarations.DeclareLocalForArgs(context, info.Functions);
Generate(context, function.MainBlock); Generate(context, function.MainBlock);

View File

@@ -1094,7 +1094,14 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (isBindless) if (isBindless)
{ {
type = (componentMask & 4) != 0 ? SamplerType.Texture3D : SamplerType.Texture2D; if (query == TexQuery.TexHeaderTextureType)
{
type = SamplerType.Texture2D | SamplerType.Multisample;
}
else
{
type = (componentMask & 4) != 0 ? SamplerType.Texture3D : SamplerType.Texture2D;
}
} }
else else
{ {
@@ -1102,31 +1109,69 @@ namespace Ryujinx.Graphics.Shader.Instructions
} }
TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None; TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None;
int binding;
int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding( switch (query)
Instruction.TextureSize,
type,
TextureFormat.Unknown,
flags,
TextureOperation.DefaultCbufSlot,
imm);
for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
{ {
if ((compMask & 1) != 0) case TexQuery.TexHeaderDimension:
{ binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
Operand d = GetDest(); Instruction.TextureQuerySize,
type,
TextureFormat.Unknown,
flags,
TextureOperation.DefaultCbufSlot,
imm);
if (d == null) for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
{ {
break; if ((compMask & 1) != 0)
{
Operand d = GetDest();
if (d == null)
{
break;
}
context.Copy(d, context.TextureQuerySize(type, flags, binding, compIndex, sources));
}
} }
break;
// TODO: Validate and use query parameter. case TexQuery.TexHeaderTextureType:
Operand res = context.TextureSize(type, flags, binding, compIndex, sources); binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
Instruction.TextureQuerySamples,
type,
TextureFormat.Unknown,
flags,
TextureOperation.DefaultCbufSlot,
imm);
context.Copy(d, res); if ((componentMask & 4) != 0)
} {
// Skip first 2 components if necessary.
if ((componentMask & 1) != 0)
{
GetDest();
}
if ((componentMask & 2) != 0)
{
GetDest();
}
Operand d = GetDest();
if (d != null)
{
context.Copy(d, context.TextureQuerySamples(type, flags, binding, sources));
}
}
break;
default:
context.TranslatorContext.GpuAccessor.Log($"Invalid or unsupported query type \"{query}\".");
break;
} }
} }

View File

@@ -1,10 +1,8 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{ {
[Flags] [Flags]
[SuppressMessage("Design", "CA1069: Enums values should not be duplicated")]
enum Instruction enum Instruction
{ {
Absolute = 1, Absolute = 1,
@@ -118,7 +116,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
Subtract, Subtract,
SwizzleAdd, SwizzleAdd,
TextureSample, TextureSample,
TextureSize, TextureQuerySamples,
TextureQuerySize,
Truncate, Truncate,
UnpackDouble2x32, UnpackDouble2x32,
UnpackHalf2x16, UnpackHalf2x16,
@@ -160,7 +159,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
public static bool IsTextureQuery(this Instruction inst) public static bool IsTextureQuery(this Instruction inst)
{ {
inst &= Instruction.Mask; inst &= Instruction.Mask;
return inst == Instruction.Lod || inst == Instruction.TextureSize; return inst == Instruction.Lod || inst == Instruction.TextureQuerySamples || inst == Instruction.TextureQuerySize;
} }
} }
} }

View File

@@ -124,7 +124,8 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
Add(Instruction.Subtract, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar); Add(Instruction.Subtract, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar);
Add(Instruction.SwizzleAdd, AggregateType.FP32, AggregateType.FP32, AggregateType.FP32, AggregateType.S32); Add(Instruction.SwizzleAdd, AggregateType.FP32, AggregateType.FP32, AggregateType.FP32, AggregateType.S32);
Add(Instruction.TextureSample, AggregateType.FP32); Add(Instruction.TextureSample, AggregateType.FP32);
Add(Instruction.TextureSize, AggregateType.S32, AggregateType.S32, AggregateType.S32); Add(Instruction.TextureQuerySamples, AggregateType.S32, AggregateType.S32);
Add(Instruction.TextureQuerySize, AggregateType.S32, AggregateType.S32, AggregateType.S32);
Add(Instruction.Truncate, AggregateType.Scalar, AggregateType.Scalar); Add(Instruction.Truncate, AggregateType.Scalar, AggregateType.Scalar);
Add(Instruction.UnpackDouble2x32, AggregateType.U32, AggregateType.FP64); Add(Instruction.UnpackDouble2x32, AggregateType.U32, AggregateType.FP64);
Add(Instruction.UnpackHalf2x16, AggregateType.FP32, AggregateType.U32); Add(Instruction.UnpackHalf2x16, AggregateType.FP32, AggregateType.U32);

View File

@@ -2,17 +2,22 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.Translation; using Ryujinx.Graphics.Shader.Translation;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Numerics; using System.Numerics;
namespace Ryujinx.Graphics.Shader.StructuredIr namespace Ryujinx.Graphics.Shader.StructuredIr
{ {
static class StructuredProgram static class StructuredProgram
{ {
// TODO: Eventually it should be possible to specify the parameter types for the function instead of using S32 for everything.
private const AggregateType FuncParameterType = AggregateType.S32;
public static StructuredProgramInfo MakeStructuredProgram( public static StructuredProgramInfo MakeStructuredProgram(
IReadOnlyList<Function> functions, IReadOnlyList<Function> functions,
AttributeUsage attributeUsage, AttributeUsage attributeUsage,
ShaderDefinitions definitions, ShaderDefinitions definitions,
ResourceManager resourceManager, ResourceManager resourceManager,
TargetLanguage targetLanguage,
bool debugMode) bool debugMode)
{ {
StructuredProgramContext context = new(attributeUsage, definitions, resourceManager, debugMode); StructuredProgramContext context = new(attributeUsage, definitions, resourceManager, debugMode);
@@ -23,19 +28,19 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
BasicBlock[] blocks = function.Blocks; BasicBlock[] blocks = function.Blocks;
AggregateType returnType = function.ReturnsValue ? AggregateType.S32 : AggregateType.Void; AggregateType returnType = function.ReturnsValue ? FuncParameterType : AggregateType.Void;
AggregateType[] inArguments = new AggregateType[function.InArgumentsCount]; AggregateType[] inArguments = new AggregateType[function.InArgumentsCount];
AggregateType[] outArguments = new AggregateType[function.OutArgumentsCount]; AggregateType[] outArguments = new AggregateType[function.OutArgumentsCount];
for (int i = 0; i < inArguments.Length; i++) for (int i = 0; i < inArguments.Length; i++)
{ {
inArguments[i] = AggregateType.S32; inArguments[i] = FuncParameterType;
} }
for (int i = 0; i < outArguments.Length; i++) for (int i = 0; i < outArguments.Length; i++)
{ {
outArguments[i] = AggregateType.S32; outArguments[i] = FuncParameterType;
} }
context.EnterFunction(blocks.Length, function.Name, returnType, inArguments, outArguments); context.EnterFunction(blocks.Length, function.Name, returnType, inArguments, outArguments);
@@ -58,7 +63,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
} }
else else
{ {
AddOperation(context, operation); AddOperation(context, operation, targetLanguage, functions);
} }
} }
} }
@@ -73,7 +78,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
return context.Info; return context.Info;
} }
private static void AddOperation(StructuredProgramContext context, Operation operation) private static void AddOperation(StructuredProgramContext context, Operation operation, TargetLanguage targetLanguage, IReadOnlyList<Function> functions)
{ {
Instruction inst = operation.Inst; Instruction inst = operation.Inst;
StorageKind storageKind = operation.StorageKind; StorageKind storageKind = operation.StorageKind;
@@ -114,9 +119,43 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
IAstNode[] sources = new IAstNode[sourcesCount + outDestsCount]; IAstNode[] sources = new IAstNode[sourcesCount + outDestsCount];
for (int index = 0; index < operation.SourcesCount; index++) if (inst == Instruction.Call && targetLanguage == TargetLanguage.Spirv)
{ {
sources[index] = context.GetOperandOrCbLoad(operation.GetSource(index)); // SPIR-V requires that all function parameters are copied to a local variable before the call
// (or at least that's what the Khronos compiler does).
// First one is the function index.
Operand funcIndexOperand = operation.GetSource(0);
Debug.Assert(funcIndexOperand.Type == OperandType.Constant);
int funcIndex = funcIndexOperand.Value;
sources[0] = new AstOperand(OperandType.Constant, funcIndex);
int inArgsCount = functions[funcIndex].InArgumentsCount;
// Remaining ones are parameters, copy them to a temp local variable.
for (int index = 1; index < operation.SourcesCount; index++)
{
IAstNode source = context.GetOperandOrCbLoad(operation.GetSource(index));
if (index - 1 < inArgsCount)
{
AstOperand argTemp = context.NewTemp(FuncParameterType);
context.AddNode(new AstAssignment(argTemp, source));
sources[index] = argTemp;
}
else
{
sources[index] = source;
}
}
}
else
{
for (int index = 0; index < operation.SourcesCount; index++)
{
sources[index] = context.GetOperandOrCbLoad(operation.GetSource(index));
}
} }
for (int index = 0; index < outDestsCount; index++) for (int index = 0; index < outDestsCount; index++)

View File

@@ -897,7 +897,21 @@ namespace Ryujinx.Graphics.Shader.Translation
context.Add(new TextureOperation(Instruction.TextureSample, type, TextureFormat.Unknown, flags, binding, compMask, dests, sources)); context.Add(new TextureOperation(Instruction.TextureSample, type, TextureFormat.Unknown, flags, binding, compMask, dests, sources));
} }
public static Operand TextureSize( public static Operand TextureQuerySamples(
this EmitterContext context,
SamplerType type,
TextureFlags flags,
int binding,
Operand[] sources)
{
Operand dest = Local();
context.Add(new TextureOperation(Instruction.TextureQuerySamples, type, TextureFormat.Unknown, flags, binding, 0, new[] { dest }, sources));
return dest;
}
public static Operand TextureQuerySize(
this EmitterContext context, this EmitterContext context,
SamplerType type, SamplerType type,
TextureFlags flags, TextureFlags flags,
@@ -907,7 +921,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{ {
Operand dest = Local(); Operand dest = Local();
context.Add(new TextureOperation(Instruction.TextureSize, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources)); context.Add(new TextureOperation(Instruction.TextureQuerySize, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources));
return dest; return dest;
} }

View File

@@ -27,9 +27,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
continue; continue;
} }
if (texOp.Inst == Instruction.Lod || if (texOp.Inst == Instruction.TextureSample || texOp.Inst.IsTextureQuery())
texOp.Inst == Instruction.TextureSample ||
texOp.Inst == Instruction.TextureSize)
{ {
Operand bindlessHandle = Utils.FindLastOperation(texOp.GetSource(0), block); Operand bindlessHandle = Utils.FindLastOperation(texOp.GetSource(0), block);
@@ -40,7 +38,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
// as long bindless elimination is successful and we know where the texture descriptor is located. // as long bindless elimination is successful and we know where the texture descriptor is located.
bool rewriteSamplerType = bool rewriteSamplerType =
texOp.Type == SamplerType.TextureBuffer || texOp.Type == SamplerType.TextureBuffer ||
texOp.Inst == Instruction.TextureSize; texOp.Inst == Instruction.TextureQuerySamples ||
texOp.Inst == Instruction.TextureQuerySize;
if (bindlessHandle.Type == OperandType.ConstantBuffer) if (bindlessHandle.Type == OperandType.ConstantBuffer)
{ {

View File

@@ -2,6 +2,7 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
namespace Ryujinx.Graphics.Shader.Translation.Optimizations namespace Ryujinx.Graphics.Shader.Translation.Optimizations
@@ -785,30 +786,31 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
private static string GetFunctionName(Operation baseOp, bool isMultiTarget, IReadOnlyList<uint> targetCbs) private static string GetFunctionName(Operation baseOp, bool isMultiTarget, IReadOnlyList<uint> targetCbs)
{ {
string name = baseOp.Inst.ToString(); StringBuilder nameBuilder = new();
nameBuilder.Append(baseOp.Inst.ToString());
name += baseOp.StorageKind switch nameBuilder.Append(baseOp.StorageKind switch
{ {
StorageKind.GlobalMemoryS8 => "S8", StorageKind.GlobalMemoryS8 => "S8",
StorageKind.GlobalMemoryS16 => "S16", StorageKind.GlobalMemoryS16 => "S16",
StorageKind.GlobalMemoryU8 => "U8", StorageKind.GlobalMemoryU8 => "U8",
StorageKind.GlobalMemoryU16 => "U16", StorageKind.GlobalMemoryU16 => "U16",
_ => string.Empty, _ => string.Empty,
}; });
if (isMultiTarget) if (isMultiTarget)
{ {
name += "Multi"; nameBuilder.Append("Multi");
} }
foreach (uint targetCb in targetCbs) foreach (uint targetCb in targetCbs)
{ {
(int sbCbSlot, int sbCbOffset) = UnpackCbSlotAndOffset(targetCb); (int sbCbSlot, int sbCbOffset) = UnpackCbSlotAndOffset(targetCb);
name += $"_c{sbCbSlot}o{sbCbOffset}"; nameBuilder.Append($"_c{sbCbSlot}o{sbCbOffset}");
} }
return name; return nameBuilder.ToString();
} }
private static bool TryGenerateStorageOp( private static bool TryGenerateStorageOp(

View File

@@ -232,8 +232,8 @@ namespace Ryujinx.Graphics.Shader.Translation
inst &= Instruction.Mask; inst &= Instruction.Mask;
bool isImage = inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.ImageAtomic; bool isImage = inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
bool isWrite = inst == Instruction.ImageStore || inst == Instruction.ImageAtomic; bool isWrite = inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
bool accurateType = inst != Instruction.Lod && inst != Instruction.TextureSize; bool accurateType = !inst.IsTextureQuery();
bool intCoords = isImage || flags.HasFlag(TextureFlags.IntCoords) || inst == Instruction.TextureSize; bool intCoords = isImage || flags.HasFlag(TextureFlags.IntCoords) || inst == Instruction.TextureQuerySize;
bool coherent = flags.HasFlag(TextureFlags.Coherent); bool coherent = flags.HasFlag(TextureFlags.Coherent);
if (!isImage) if (!isImage)

View File

@@ -23,7 +23,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
{ {
node = InsertCoordNormalization(context.Hfm, node, context.ResourceManager, context.GpuAccessor, context.Stage); node = InsertCoordNormalization(context.Hfm, node, context.ResourceManager, context.GpuAccessor, context.Stage);
node = InsertCoordGatherBias(node, context.ResourceManager, context.GpuAccessor); node = InsertCoordGatherBias(node, context.ResourceManager, context.GpuAccessor);
node = InsertConstOffsets(node, context.ResourceManager, context.GpuAccessor); node = InsertConstOffsets(node, context.GpuAccessor, context.Stage);
if (texOp.Type == SamplerType.TextureBuffer && !context.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat()) if (texOp.Type == SamplerType.TextureBuffer && !context.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat())
{ {
@@ -99,7 +99,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
if (texOp.Inst == Instruction.TextureSize && if (texOp.Inst == Instruction.TextureQuerySize &&
texOp.Index < 2 && texOp.Index < 2 &&
!isBindless && !isBindless &&
!isIndexed && !isIndexed &&
@@ -190,7 +190,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
} }
LinkedListNode<INode> textureSizeNode = node.List.AddBefore(node, new TextureOperation( LinkedListNode<INode> textureSizeNode = node.List.AddBefore(node, new TextureOperation(
Instruction.TextureSize, Instruction.TextureQuerySize,
texOp.Type, texOp.Type,
texOp.Format, texOp.Format,
texOp.Flags, texOp.Flags,
@@ -259,7 +259,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
} }
node.List.AddBefore(node, new TextureOperation( node.List.AddBefore(node, new TextureOperation(
Instruction.TextureSize, Instruction.TextureQuerySize,
texOp.Type, texOp.Type,
texOp.Format, texOp.Format,
texOp.Flags, texOp.Flags,
@@ -287,7 +287,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
return node; return node;
} }
private static LinkedListNode<INode> InsertConstOffsets(LinkedListNode<INode> node, ResourceManager resourceManager, IGpuAccessor gpuAccessor) private static LinkedListNode<INode> InsertConstOffsets(LinkedListNode<INode> node, IGpuAccessor gpuAccessor, ShaderStage stage)
{ {
// Non-constant texture offsets are not allowed (according to the spec), // Non-constant texture offsets are not allowed (according to the spec),
// however some GPUs does support that. // however some GPUs does support that.
@@ -440,7 +440,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
sources.CopyTo(newSources, 0); sources.CopyTo(newSources, 0);
Operand[] texSizes = InsertTextureLod(node, texOp, lodSources, bindlessHandle, coordsCount); Operand[] texSizes = InsertTextureLod(node, texOp, lodSources, bindlessHandle, coordsCount, stage);
int destIndex = 0; int destIndex = 0;
@@ -502,7 +502,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
} }
else else
{ {
Operand[] texSizes = InsertTextureLod(node, texOp, lodSources, bindlessHandle, coordsCount); Operand[] texSizes = InsertTextureLod(node, texOp, lodSources, bindlessHandle, coordsCount, stage);
for (int index = 0; index < coordsCount; index++) for (int index = 0; index < coordsCount; index++)
{ {
@@ -554,21 +554,31 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
TextureOperation texOp, TextureOperation texOp,
Operand[] lodSources, Operand[] lodSources,
Operand bindlessHandle, Operand bindlessHandle,
int coordsCount) int coordsCount,
ShaderStage stage)
{ {
Operand[] texSizes = new Operand[coordsCount]; Operand[] texSizes = new Operand[coordsCount];
Operand lod = Local(); Operand lod;
node.List.AddBefore(node, new TextureOperation( if (stage == ShaderStage.Fragment)
Instruction.Lod, {
texOp.Type, lod = Local();
texOp.Format,
texOp.Flags, node.List.AddBefore(node, new TextureOperation(
texOp.Binding, Instruction.Lod,
0, texOp.Type,
new[] { lod }, texOp.Format,
lodSources)); texOp.Flags,
texOp.Binding,
0,
new[] { lod },
lodSources));
}
else
{
lod = Const(0);
}
for (int index = 0; index < coordsCount; index++) for (int index = 0; index < coordsCount; index++)
{ {
@@ -586,7 +596,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
} }
node.List.AddBefore(node, new TextureOperation( node.List.AddBefore(node, new TextureOperation(
Instruction.TextureSize, Instruction.TextureQuerySize,
texOp.Type, texOp.Type,
texOp.Format, texOp.Format,
texOp.Flags, texOp.Flags,

View File

@@ -329,6 +329,7 @@ namespace Ryujinx.Graphics.Shader.Translation
attributeUsage, attributeUsage,
definitions, definitions,
resourceManager, resourceManager,
Options.TargetLanguage,
Options.Flags.HasFlag(TranslationFlags.DebugMode)); Options.Flags.HasFlag(TranslationFlags.DebugMode));
int geometryVerticesPerPrimitive = Definitions.OutputTopology switch int geometryVerticesPerPrimitive = Definitions.OutputTopology switch

View File

@@ -19,6 +19,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Text;
using Path = System.IO.Path; using Path = System.IO.Path;
namespace Ryujinx.HLE.FileSystem namespace Ryujinx.HLE.FileSystem
@@ -817,13 +818,13 @@ namespace Ryujinx.HLE.FileSystem
if (updateNcas.Count > 0) if (updateNcas.Count > 0)
{ {
string extraNcas = string.Empty; StringBuilder extraNcas = new();
foreach (var entry in updateNcas) foreach (var entry in updateNcas)
{ {
foreach (var (type, path) in entry.Value) foreach (var (type, path) in entry.Value)
{ {
extraNcas += path + Environment.NewLine; extraNcas.AppendLine(path);
} }
} }
@@ -954,13 +955,13 @@ namespace Ryujinx.HLE.FileSystem
if (updateNcas.Count > 0) if (updateNcas.Count > 0)
{ {
string extraNcas = string.Empty; StringBuilder extraNcas = new();
foreach (var entry in updateNcas) foreach (var entry in updateNcas)
{ {
foreach (var (type, path) in entry.Value) foreach (var (type, path) in entry.Value)
{ {
extraNcas += path + Environment.NewLine; extraNcas.AppendLine(path);
} }
} }

View File

@@ -436,14 +436,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
uint nameIndex = sym.NameOffset; uint nameIndex = sym.NameOffset;
string name = string.Empty; StringBuilder nameBuilder = new();
for (int chr; (chr = memory.Read<byte>(strTblAddr + nameIndex++)) != 0;) for (int chr; (chr = memory.Read<byte>(strTblAddr + nameIndex++)) != 0;)
{ {
name += (char)chr; nameBuilder.Append((char)chr);
} }
return new ElfSymbol(name, sym.Info, sym.Other, sym.SectionIndex, sym.ValueAddress, sym.Size); return new ElfSymbol(nameBuilder.ToString(), sym.Info, sym.Other, sym.SectionIndex, sym.ValueAddress, sym.Size);
} }
private static ElfSymbol GetSymbol32(IVirtualMemoryManager memory, ulong address, ulong strTblAddr) private static ElfSymbol GetSymbol32(IVirtualMemoryManager memory, ulong address, ulong strTblAddr)
@@ -452,14 +452,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
uint nameIndex = sym.NameOffset; uint nameIndex = sym.NameOffset;
string name = string.Empty; StringBuilder nameBuilder = new();
for (int chr; (chr = memory.Read<byte>(strTblAddr + nameIndex++)) != 0;) for (int chr; (chr = memory.Read<byte>(strTblAddr + nameIndex++)) != 0;)
{ {
name += (char)chr; nameBuilder.Append((char)chr);
} }
return new ElfSymbol(name, sym.Info, sym.Other, sym.SectionIndex, sym.ValueAddress, sym.Size); return new ElfSymbol(nameBuilder.ToString(), sym.Info, sym.Other, sym.SectionIndex, sym.ValueAddress, sym.Size);
} }
} }
} }

View File

@@ -8,6 +8,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
namespace Ryujinx.HLE.HOS.Services.Sm namespace Ryujinx.HLE.HOS.Services.Sm
{ {
@@ -235,7 +236,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
private static string ReadName(ServiceCtx context) private static string ReadName(ServiceCtx context)
{ {
string name = string.Empty; StringBuilder nameBuilder = new();
for (int index = 0; index < 8 && for (int index = 0; index < 8 &&
context.RequestData.BaseStream.Position < context.RequestData.BaseStream.Position <
@@ -245,11 +246,11 @@ namespace Ryujinx.HLE.HOS.Services.Sm
if (chr >= 0x20 && chr < 0x7f) if (chr >= 0x20 && chr < 0x7f)
{ {
name += (char)chr; nameBuilder.Append((char)chr);
} }
} }
return name; return nameBuilder.ToString();
} }
public override void DestroyAtExit() public override void DestroyAtExit()

View File

@@ -669,6 +669,12 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
lock (Core.Lock) lock (Core.Lock)
{ {
// If we are replacing a buffer that has already been queued, make sure we release the references.
if (Core.Slots[slot].BufferState == BufferState.Queued)
{
Core.Slots[slot].GraphicBuffer.Object.DecrementNvMapHandleRefCount(Core.Owner);
}
Core.Slots[slot].BufferState = BufferState.Free; Core.Slots[slot].BufferState = BufferState.Free;
Core.Slots[slot].Fence = AndroidFence.NoFence; Core.Slots[slot].Fence = AndroidFence.NoFence;
Core.Slots[slot].RequestBufferCalled = false; Core.Slots[slot].RequestBufferCalled = false;

View File

@@ -142,7 +142,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
// OpenDisplay(nn::vi::DisplayName) -> u64 display_id // OpenDisplay(nn::vi::DisplayName) -> u64 display_id
public ResultCode OpenDisplay(ServiceCtx context) public ResultCode OpenDisplay(ServiceCtx context)
{ {
string name = ""; StringBuilder nameBuilder = new();
for (int index = 0; index < 8 && context.RequestData.BaseStream.Position < context.RequestData.BaseStream.Length; index++) for (int index = 0; index < 8 && context.RequestData.BaseStream.Position < context.RequestData.BaseStream.Length; index++)
{ {
@@ -150,11 +150,11 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
if (chr >= 0x20 && chr < 0x7f) if (chr >= 0x20 && chr < 0x7f)
{ {
name += (char)chr; nameBuilder.Append((char)chr);
} }
} }
return OpenDisplayImpl(context, name); return OpenDisplayImpl(context, nameBuilder.ToString());
} }
[CommandCmif(1011)] [CommandCmif(1011)]

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
namespace Ryujinx.Horizon.Sdk.Sm namespace Ryujinx.Horizon.Sdk.Sm
{ {
@@ -78,7 +79,7 @@ namespace Ryujinx.Horizon.Sdk.Sm
public override string ToString() public override string ToString()
{ {
string name = string.Empty; StringBuilder nameBuilder = new();
for (int index = 0; index < sizeof(ulong); index++) for (int index = 0; index < sizeof(ulong); index++)
{ {
@@ -89,10 +90,10 @@ namespace Ryujinx.Horizon.Sdk.Sm
break; break;
} }
name += (char)character; nameBuilder.Append((char)character);
} }
return name; return nameBuilder.ToString();
} }
} }
} }

View File

@@ -1,5 +1,6 @@
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Text;
namespace Ryujinx.Ui.LocaleGenerator namespace Ryujinx.Ui.LocaleGenerator
{ {
@@ -15,15 +16,17 @@ namespace Ryujinx.Ui.LocaleGenerator
context.RegisterSourceOutput(contents, (spc, content) => context.RegisterSourceOutput(contents, (spc, content) =>
{ {
var lines = content.Split('\n').Where(x => x.Trim().StartsWith("\"")).Select(x => x.Split(':')[0].Trim().Replace("\"", "")); var lines = content.Split('\n').Where(x => x.Trim().StartsWith("\"")).Select(x => x.Split(':')[0].Trim().Replace("\"", ""));
string enumSource = "namespace Ryujinx.Ava.Common.Locale;\n"; StringBuilder enumSourceBuilder = new();
enumSource += "internal enum LocaleKeys\n{\n"; enumSourceBuilder.AppendLine("namespace Ryujinx.Ava.Common.Locale;");
enumSourceBuilder.AppendLine("internal enum LocaleKeys");
enumSourceBuilder.AppendLine("{");
foreach (var line in lines) foreach (var line in lines)
{ {
enumSource += $" {line},\n"; enumSourceBuilder.AppendLine($" {line},");
} }
enumSource += "}\n"; enumSourceBuilder.AppendLine("}");
spc.AddSource("LocaleKeys", enumSource); spc.AddSource("LocaleKeys", enumSourceBuilder.ToString());
}); });
} }
} }