Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
d076339e3e | ||
|
837836431d | ||
|
9f555db5cd | ||
|
bf7fa60dfc | ||
|
752b93d3b7 | ||
|
f23b2878cc |
@@ -59,14 +59,18 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ContentWithTargetPath Include="..\distribution\windows\alsoft.ini" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'">
|
||||
<Content Include="..\distribution\windows\alsoft.ini" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>alsoft.ini</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="..\distribution\legal\THIRDPARTY.md">
|
||||
</Content>
|
||||
<Content Include="..\distribution\legal\THIRDPARTY.md">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>THIRDPARTY.md</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
</Content>
|
||||
<Content Include="..\LICENSE.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>LICENSE.txt</TargetPath>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -8,7 +8,7 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||
/// <summary>
|
||||
/// A simple implementation of a ReaderWriterLock which can be used from native code.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct NativeReaderWriterLock
|
||||
{
|
||||
public int WriteLock;
|
||||
|
@@ -7,7 +7,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MsgPack.Cli" Version="1.0.1" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
||||
<PackageReference Include="System.Management" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
private const ushort FileFormatVersionMajor = 1;
|
||||
private const ushort FileFormatVersionMinor = 2;
|
||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||
private const uint CodeGenVersion = 4037;
|
||||
private const uint CodeGenVersion = 4028;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
|
@@ -48,5 +48,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
|
||||
public static int GetConstantUbeOffset(int slot)
|
||||
{
|
||||
return UbeBaseOffset + slot * StorageDescSize;
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,11 +8,14 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
{
|
||||
static class GlobalToStorage
|
||||
{
|
||||
public static void RunPass(BasicBlock block, ShaderConfig config, ref int sbUseMask)
|
||||
public static void RunPass(BasicBlock block, ShaderConfig config, ref int sbUseMask, ref int ubeUseMask)
|
||||
{
|
||||
int sbStart = GetStorageBaseCbOffset(config.Stage);
|
||||
int sbEnd = sbStart + StorageDescsSize;
|
||||
|
||||
int ubeStart = UbeBaseOffset;
|
||||
int ubeEnd = UbeBaseOffset + UbeDescsSize;
|
||||
|
||||
for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next)
|
||||
{
|
||||
for (int index = 0; index < node.Value.SourcesCount; index++)
|
||||
@@ -25,6 +28,16 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
{
|
||||
sbUseMask |= 1 << storageIndex;
|
||||
}
|
||||
|
||||
if (config.Stage == ShaderStage.Compute)
|
||||
{
|
||||
int constantIndex = GetStorageIndex(src, ubeStart, ubeEnd);
|
||||
|
||||
if (constantIndex >= 0)
|
||||
{
|
||||
ubeUseMask |= 1 << constantIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(node.Value is Operation operation))
|
||||
@@ -54,7 +67,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
// so NVN "emulates" more constant buffers using global memory access.
|
||||
// Here we try to replace the global access back to a constant buffer
|
||||
// load.
|
||||
storageIndex = SearchForStorageBase(block, source, UbeBaseOffset, UbeBaseOffset + UbeDescsSize);
|
||||
storageIndex = SearchForStorageBase(block, source, ubeStart, ubeStart + ubeEnd);
|
||||
|
||||
if (storageIndex >= 0)
|
||||
{
|
||||
@@ -64,7 +77,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
}
|
||||
}
|
||||
|
||||
config.SetAccessibleStorageBuffersMask(sbUseMask);
|
||||
config.SetAccessibleBufferMasks(sbUseMask, ubeUseMask);
|
||||
}
|
||||
|
||||
private static LinkedListNode<INode> ReplaceGlobalWithStorage(BasicBlock block, LinkedListNode<INode> node, ShaderConfig config, int storageIndex)
|
||||
|
@@ -12,16 +12,17 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
RunOptimizationPasses(blocks);
|
||||
|
||||
int sbUseMask = 0;
|
||||
int ubeUseMask = 0;
|
||||
|
||||
// Those passes are looking for specific patterns and only needs to run once.
|
||||
for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
|
||||
{
|
||||
GlobalToStorage.RunPass(blocks[blkIndex], config, ref sbUseMask);
|
||||
GlobalToStorage.RunPass(blocks[blkIndex], config, ref sbUseMask, ref ubeUseMask);
|
||||
BindlessToIndexed.RunPass(blocks[blkIndex], config);
|
||||
BindlessElimination.RunPass(blocks[blkIndex], config);
|
||||
}
|
||||
|
||||
config.SetAccessibleStorageBuffersMask(sbUseMask);
|
||||
config.SetAccessibleBufferMasks(sbUseMask, ubeUseMask);
|
||||
|
||||
// Run optimizations one last time to remove any code that is now optimizable after above passes.
|
||||
RunOptimizationPasses(blocks);
|
||||
|
@@ -1,3 +1,4 @@
|
||||
using Ryujinx.Graphics.Shader.Decoders;
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@@ -89,12 +90,42 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
return local;
|
||||
}
|
||||
|
||||
Operand PrependExistingOperation(Operation operation)
|
||||
{
|
||||
Operand local = Local();
|
||||
|
||||
operation.Dest = local;
|
||||
node.List.AddBefore(node, operation);
|
||||
|
||||
return local;
|
||||
}
|
||||
|
||||
Operand addrLow = operation.GetSource(0);
|
||||
Operand addrHigh = operation.GetSource(1);
|
||||
|
||||
Operand sbBaseAddrLow = Const(0);
|
||||
Operand sbSlot = Const(0);
|
||||
|
||||
Operand alignMask = Const(-config.GpuAccessor.QueryHostStorageBufferOffsetAlignment());
|
||||
|
||||
Operand BindingRangeCheck(int cbOffset, out Operand baseAddrLow)
|
||||
{
|
||||
baseAddrLow = Cbuf(0, cbOffset);
|
||||
Operand baseAddrHigh = Cbuf(0, cbOffset + 1);
|
||||
Operand size = Cbuf(0, cbOffset + 2);
|
||||
|
||||
Operand offset = PrependOperation(Instruction.Subtract, addrLow, baseAddrLow);
|
||||
Operand borrow = PrependOperation(Instruction.CompareLessU32, addrLow, baseAddrLow);
|
||||
|
||||
Operand inRangeLow = PrependOperation(Instruction.CompareLessU32, offset, size);
|
||||
|
||||
Operand addrHighBorrowed = PrependOperation(Instruction.Add, addrHigh, borrow);
|
||||
|
||||
Operand inRangeHigh = PrependOperation(Instruction.CompareEqual, addrHighBorrowed, baseAddrHigh);
|
||||
|
||||
return PrependOperation(Instruction.BitwiseAnd, inRangeLow, inRangeHigh);
|
||||
}
|
||||
|
||||
int sbUseMask = config.AccessibleStorageBuffersMask;
|
||||
|
||||
while (sbUseMask != 0)
|
||||
@@ -107,20 +138,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
int cbOffset = GetStorageCbOffset(config.Stage, slot);
|
||||
|
||||
Operand baseAddrLow = Cbuf(0, cbOffset);
|
||||
Operand baseAddrHigh = Cbuf(0, cbOffset + 1);
|
||||
Operand size = Cbuf(0, cbOffset + 2);
|
||||
|
||||
Operand offset = PrependOperation(Instruction.Subtract, addrLow, baseAddrLow);
|
||||
Operand borrow = PrependOperation(Instruction.CompareLessU32, addrLow, baseAddrLow);
|
||||
|
||||
Operand inRangeLow = PrependOperation(Instruction.CompareLessU32, offset, size);
|
||||
|
||||
Operand addrHighBorrowed = PrependOperation(Instruction.Add, addrHigh, borrow);
|
||||
|
||||
Operand inRangeHigh = PrependOperation(Instruction.CompareEqual, addrHighBorrowed, baseAddrHigh);
|
||||
|
||||
Operand inRange = PrependOperation(Instruction.BitwiseAnd, inRangeLow, inRangeHigh);
|
||||
Operand inRange = BindingRangeCheck(cbOffset, out Operand baseAddrLow);
|
||||
|
||||
sbBaseAddrLow = PrependOperation(Instruction.ConditionalSelect, inRange, baseAddrLow, sbBaseAddrLow);
|
||||
sbSlot = PrependOperation(Instruction.ConditionalSelect, inRange, Const(slot), sbSlot);
|
||||
@@ -128,8 +146,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
if (config.AccessibleStorageBuffersMask != 0)
|
||||
{
|
||||
Operand alignMask = Const(-config.GpuAccessor.QueryHostStorageBufferOffsetAlignment());
|
||||
|
||||
Operand baseAddrTrunc = PrependOperation(Instruction.BitwiseAnd, sbBaseAddrLow, alignMask);
|
||||
Operand byteOffset = PrependOperation(Instruction.Subtract, addrLow, baseAddrTrunc);
|
||||
|
||||
@@ -178,6 +194,46 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
storageOp = new Operation(Instruction.Copy, operation.Dest, Const(0));
|
||||
}
|
||||
|
||||
if (operation.Inst == Instruction.LoadGlobal)
|
||||
{
|
||||
int cbeUseMask = config.AccessibleConstantBuffersMask;
|
||||
|
||||
while (cbeUseMask != 0)
|
||||
{
|
||||
int slot = BitOperations.TrailingZeroCount(cbeUseMask);
|
||||
int cbSlot = UbeFirstCbuf + slot;
|
||||
|
||||
cbeUseMask &= ~(1 << slot);
|
||||
|
||||
config.SetUsedConstantBuffer(cbSlot);
|
||||
|
||||
Operand previousResult = PrependExistingOperation(storageOp);
|
||||
|
||||
int cbOffset = GetConstantUbeOffset(slot);
|
||||
|
||||
Operand inRange = BindingRangeCheck(cbOffset, out Operand baseAddrLow);
|
||||
|
||||
Operand baseAddrTruncConst = PrependOperation(Instruction.BitwiseAnd, baseAddrLow, alignMask);
|
||||
Operand byteOffsetConst = PrependOperation(Instruction.Subtract, addrLow, baseAddrTruncConst);
|
||||
|
||||
Operand cbIndex = PrependOperation(Instruction.ShiftRightU32, byteOffsetConst, Const(2));
|
||||
|
||||
Operand[] sourcesCb = new Operand[operation.SourcesCount];
|
||||
|
||||
sourcesCb[0] = Const(cbSlot);
|
||||
sourcesCb[1] = cbIndex;
|
||||
|
||||
for (int index = 2; index < operation.SourcesCount; index++)
|
||||
{
|
||||
sourcesCb[index] = operation.GetSource(index);
|
||||
}
|
||||
|
||||
Operand ldcResult = PrependOperation(Instruction.LoadConstant, sourcesCb);
|
||||
|
||||
storageOp = new Operation(Instruction.ConditionalSelect, operation.Dest, inRange, ldcResult, previousResult);
|
||||
}
|
||||
}
|
||||
|
||||
for (int index = 0; index < operation.SourcesCount; index++)
|
||||
{
|
||||
operation.SetSource(index, null);
|
||||
|
@@ -66,6 +66,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
public UInt128 ThisInputAttributesComponents { get; private set; }
|
||||
|
||||
public int AccessibleStorageBuffersMask { get; private set; }
|
||||
public int AccessibleConstantBuffersMask { get; private set; }
|
||||
|
||||
private int _usedConstantBuffers;
|
||||
private int _usedStorageBuffers;
|
||||
@@ -100,7 +101,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
GpuAccessor = gpuAccessor;
|
||||
Options = options;
|
||||
|
||||
AccessibleStorageBuffersMask = (1 << GlobalMemory.StorageMaxCount) - 1;
|
||||
AccessibleStorageBuffersMask = (1 << GlobalMemory.StorageMaxCount) - 1;
|
||||
AccessibleConstantBuffersMask = (1 << GlobalMemory.UbeMaxCount) - 1;
|
||||
|
||||
UsedInputAttributesPerPatch = new HashSet<int>();
|
||||
UsedOutputAttributesPerPatch = new HashSet<int>();
|
||||
@@ -121,6 +123,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
OutputTopology = outputTopology;
|
||||
MaxOutputVertices = maxOutputVertices;
|
||||
TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
|
||||
|
||||
if (Stage != ShaderStage.Compute)
|
||||
{
|
||||
AccessibleConstantBuffersMask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationOptions options) : this(gpuAccessor, options)
|
||||
@@ -404,9 +411,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
UsedFeatures |= flags;
|
||||
}
|
||||
|
||||
public void SetAccessibleStorageBuffersMask(int mask)
|
||||
public void SetAccessibleBufferMasks(int sbMask, int ubeMask)
|
||||
{
|
||||
AccessibleStorageBuffersMask = mask;
|
||||
AccessibleStorageBuffersMask = sbMask;
|
||||
AccessibleConstantBuffersMask = ubeMask;
|
||||
}
|
||||
|
||||
public void SetUsedConstantBuffer(int slot)
|
||||
|
@@ -39,13 +39,11 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
public readonly string ContainerPath;
|
||||
public readonly string NcaPath;
|
||||
public bool Enabled;
|
||||
|
||||
public AocItem(string containerPath, string ncaPath, bool enabled)
|
||||
public AocItem(string containerPath, string ncaPath)
|
||||
{
|
||||
ContainerPath = containerPath;
|
||||
NcaPath = ncaPath;
|
||||
Enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +51,7 @@ namespace Ryujinx.HLE.FileSystem
|
||||
|
||||
private VirtualFileSystem _virtualFileSystem;
|
||||
|
||||
private readonly object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
public ContentManager(VirtualFileSystem virtualFileSystem)
|
||||
{
|
||||
@@ -226,27 +224,21 @@ namespace Ryujinx.HLE.FileSystem
|
||||
pfs0.OpenFile(ref cnmtFile.Ref(), pfs0.EnumerateEntries().Single().FullPath.ToU8Span(), OpenMode.Read);
|
||||
|
||||
var cnmt = new Cnmt(cnmtFile.Get.AsStream());
|
||||
|
||||
if (cnmt.Type != ContentMetaType.AddOnContent || (cnmt.TitleId & 0xFFFFFFFFFFFFE000) != aocBaseId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string ncaId = BitConverter.ToString(cnmt.ContentEntries[0].NcaId).Replace("-", "").ToLower();
|
||||
if (!_aocData.TryAdd(cnmt.TitleId, new AocItem(containerPath, $"{ncaId}.nca", true)))
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Duplicate AddOnContent detected. TitleId {cnmt.TitleId:X16}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Info?.Print(LogClass.Application, $"Found AddOnContent with TitleId {cnmt.TitleId:X16}");
|
||||
}
|
||||
|
||||
AddAocItem(cnmt.TitleId, containerPath, $"{ncaId}.nca", true);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddAocItem(ulong titleId, string containerPath, string ncaPath, bool enabled)
|
||||
public void AddAocItem(ulong titleId, string containerPath, string ncaPath, bool mergedToContainer = false)
|
||||
{
|
||||
if (!_aocData.TryAdd(titleId, new AocItem(containerPath, ncaPath, enabled)))
|
||||
// TODO: Check Aoc version.
|
||||
if (!_aocData.TryAdd(titleId, new AocItem(containerPath, ncaPath)))
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Duplicate AddOnContent detected. TitleId {titleId:X16}");
|
||||
}
|
||||
@@ -254,25 +246,27 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
Logger.Info?.Print(LogClass.Application, $"Found AddOnContent with TitleId {titleId:X16}");
|
||||
|
||||
using (FileStream fileStream = File.OpenRead(containerPath))
|
||||
using (PartitionFileSystem pfs = new PartitionFileSystem(fileStream.AsStorage()))
|
||||
if (!mergedToContainer)
|
||||
{
|
||||
_virtualFileSystem.ImportTickets(pfs);
|
||||
using FileStream fileStream = File.OpenRead(containerPath);
|
||||
using PartitionFileSystem partitionFileSystem = new(fileStream.AsStorage());
|
||||
|
||||
_virtualFileSystem.ImportTickets(partitionFileSystem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearAocData() => _aocData.Clear();
|
||||
|
||||
public int GetAocCount() => _aocData.Where(e => e.Value.Enabled).Count();
|
||||
public int GetAocCount() => _aocData.Count;
|
||||
|
||||
public IList<ulong> GetAocTitleIds() => _aocData.Where(e => e.Value.Enabled).Select(e => e.Key).ToList();
|
||||
public IList<ulong> GetAocTitleIds() => _aocData.Select(e => e.Key).ToList();
|
||||
|
||||
public bool GetAocDataStorage(ulong aocTitleId, out IStorage aocStorage, IntegrityCheckLevel integrityCheckLevel)
|
||||
{
|
||||
aocStorage = null;
|
||||
|
||||
if (_aocData.TryGetValue(aocTitleId, out AocItem aoc) && aoc.Enabled)
|
||||
if (_aocData.TryGetValue(aocTitleId, out AocItem aoc))
|
||||
{
|
||||
var file = new FileStream(aoc.ContainerPath, FileMode.Open, FileAccess.Read);
|
||||
using var ncaFile = new UniqueRef<IFile>();
|
||||
|
@@ -426,9 +426,9 @@ namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
foreach (DownloadableContentNca downloadableContentNca in downloadableContentContainer.DownloadableContentNcaList)
|
||||
{
|
||||
if (File.Exists(downloadableContentContainer.ContainerPath))
|
||||
if (File.Exists(downloadableContentContainer.ContainerPath) && downloadableContentNca.Enabled)
|
||||
{
|
||||
_device.Configuration.ContentManager.AddAocItem(downloadableContentNca.TitleId, downloadableContentContainer.ContainerPath, downloadableContentNca.FullPath, downloadableContentNca.Enabled);
|
||||
_device.Configuration.ContentManager.AddAocItem(downloadableContentNca.TitleId, downloadableContentContainer.ContainerPath, downloadableContentNca.FullPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -33,10 +33,14 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ContentWithTargetPath Include="..\distribution\legal\THIRDPARTY.md">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>THIRDPARTY.md</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<Content Include="..\distribution\legal\THIRDPARTY.md">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>THIRDPARTY.md</TargetPath>
|
||||
</Content>
|
||||
<Content Include="..\LICENSE.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>LICENSE.txt</TargetPath>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Due to .net core 3.1 embedded resource loading -->
|
||||
|
@@ -49,14 +49,18 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ContentWithTargetPath Include="..\distribution\windows\alsoft.ini" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'">
|
||||
<Content Include="..\distribution\windows\alsoft.ini" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>alsoft.ini</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="..\distribution\legal\THIRDPARTY.md">
|
||||
</Content>
|
||||
<Content Include="..\distribution\legal\THIRDPARTY.md">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>THIRDPARTY.md</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
</Content>
|
||||
<Content Include="..\LICENSE.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>LICENSE.txt</TargetPath>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Due to .net core 3.1 embedded resource loading -->
|
||||
|
@@ -46,7 +46,7 @@ namespace Ryujinx.Ui.Windows
|
||||
SetDefaultSize(740, 400);
|
||||
SetPosition(WindowPosition.Center);
|
||||
|
||||
VBox vbox = new VBox(false, 0);
|
||||
Box vbox = new(Orientation.Vertical, 0);
|
||||
Add(vbox);
|
||||
|
||||
ScrolledWindow scrolledWindow = new ScrolledWindow
|
||||
@@ -55,7 +55,7 @@ namespace Ryujinx.Ui.Windows
|
||||
};
|
||||
scrolledWindow.SetPolicy(PolicyType.Automatic, PolicyType.Automatic);
|
||||
|
||||
HBox hbox = new HBox(false, 0);
|
||||
Box hbox = new(Orientation.Horizontal, 0);
|
||||
|
||||
Button chooseButton = new Button()
|
||||
{
|
||||
|
@@ -52,7 +52,8 @@ namespace Ryujinx.Ui.Windows
|
||||
_selectedLabel = new Label("Selected User Profile:")
|
||||
{
|
||||
Margin = 15,
|
||||
Attributes = new AttrList()
|
||||
Attributes = new AttrList(),
|
||||
Halign = Align.Start
|
||||
};
|
||||
_selectedLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
|
||||
|
||||
@@ -136,7 +137,8 @@ namespace Ryujinx.Ui.Windows
|
||||
_availableUsersLabel = new Label("Available User Profiles:")
|
||||
{
|
||||
Margin = 15,
|
||||
Attributes = new AttrList()
|
||||
Attributes = new AttrList(),
|
||||
Halign = Align.Start
|
||||
};
|
||||
_availableUsersLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
|
||||
|
||||
@@ -226,10 +228,9 @@ namespace Ryujinx.Ui.Windows
|
||||
_usersTreeViewWindow.Add(_usersTreeView);
|
||||
|
||||
_usersTreeViewBox.Add(_usersTreeViewWindow);
|
||||
|
||||
_bottomBox.PackStart(new Gtk.Alignment(-1, 0, 0, 0) { _addButton }, false, false, 0);
|
||||
_bottomBox.PackStart(new Gtk.Alignment(-1, 0, 0, 0) { _deleteButton }, false, false, 0);
|
||||
_bottomBox.PackEnd(new Gtk.Alignment(1, 0, 0, 0) { _closeButton }, false, false, 0);
|
||||
_bottomBox.PackStart(_addButton, false, false, 0);
|
||||
_bottomBox.PackStart(_deleteButton, false, false, 0);
|
||||
_bottomBox.PackEnd(_closeButton, false, false, 0);
|
||||
|
||||
_selectedUserInfoBox.Add(_selectedUserNameEntry);
|
||||
_selectedUserInfoBox.Add(_selectedUserIdLabel);
|
||||
@@ -238,12 +239,12 @@ namespace Ryujinx.Ui.Windows
|
||||
_selectedUserButtonsBox.Add(_changeProfileImageButton);
|
||||
|
||||
_selectedUserBox.Add(_selectedUserImage);
|
||||
_selectedUserBox.PackStart(new Gtk.Alignment(-1, 0, 0, 0) { _selectedUserInfoBox }, true, true, 0);
|
||||
_selectedUserBox.Add(_selectedUserButtonsBox);
|
||||
_selectedUserBox.PackStart(_selectedUserInfoBox, false, false, 0);
|
||||
_selectedUserBox.PackEnd(_selectedUserButtonsBox, false, false, 0);
|
||||
|
||||
_mainBox.PackStart(new Gtk.Alignment(-1, 0, 0, 0) { _selectedLabel }, false, false, 0);
|
||||
_mainBox.PackStart(_selectedLabel, false, false, 0);
|
||||
_mainBox.PackStart(_selectedUserBox, false, true, 0);
|
||||
_mainBox.PackStart(new Gtk.Alignment(-1, 0, 0, 0) { _availableUsersLabel }, false, false, 0);
|
||||
_mainBox.PackStart(_availableUsersLabel, false, false, 0);
|
||||
_mainBox.Add(_usersTreeViewBox);
|
||||
_mainBox.Add(_bottomBox);
|
||||
|
||||
|
Reference in New Issue
Block a user