mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-01-13 06:09:11 +00:00
Merge branch 'Ryujinx:master' into features/crash-verification-ex
This commit is contained in:
commit
a906e91101
467 changed files with 6413 additions and 5841 deletions
|
@ -35,12 +35,12 @@ EXECUTABLE_SUB_PATH=Contents/MacOS/Ryujinx
|
|||
rm -rf "$TEMP_DIRECTORY"
|
||||
mkdir -p "$TEMP_DIRECTORY"
|
||||
|
||||
DOTNET_COMMON_ARGS="-p:DebugType=embedded -p:Version=$VERSION -p:SourceRevisionId=$SOURCE_REVISION_ID --self-contained true $EXTRA_ARGS"
|
||||
DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS)
|
||||
|
||||
dotnet restore
|
||||
dotnet build -c $CONFIGURATION src/Ryujinx.Ava
|
||||
dotnet publish -c $CONFIGURATION -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" $DOTNET_COMMON_ARGS src/Ryujinx.Ava
|
||||
dotnet publish -c $CONFIGURATION -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" $DOTNET_COMMON_ARGS src/Ryujinx.Ava
|
||||
dotnet build -c "$CONFIGURATION" src/Ryujinx.Ava
|
||||
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Ava
|
||||
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Ava
|
||||
|
||||
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
|
||||
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
|
||||
|
@ -104,10 +104,10 @@ fi
|
|||
|
||||
echo "Creating archive"
|
||||
pushd "$OUTPUT_DIRECTORY"
|
||||
tar --exclude "Ryujinx.app/Contents/MacOS/Ryujinx" -cvf $RELEASE_TAR_FILE_NAME Ryujinx.app 1> /dev/null
|
||||
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" $RELEASE_TAR_FILE_NAME "Ryujinx.app/Contents/MacOS/Ryujinx" "Ryujinx.app/Contents/MacOS/Ryujinx"
|
||||
gzip -9 < $RELEASE_TAR_FILE_NAME > $RELEASE_TAR_FILE_NAME.gz
|
||||
rm $RELEASE_TAR_FILE_NAME
|
||||
tar --exclude "Ryujinx.app/Contents/MacOS/Ryujinx" -cvf "$RELEASE_TAR_FILE_NAME" Ryujinx.app 1> /dev/null
|
||||
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "Ryujinx.app/Contents/MacOS/Ryujinx" "Ryujinx.app/Contents/MacOS/Ryujinx"
|
||||
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
|
||||
rm "$RELEASE_TAR_FILE_NAME"
|
||||
popd
|
||||
|
||||
echo "Done"
|
|
@ -5,7 +5,7 @@ set -e
|
|||
INSTALL_DIRECTORY=$1
|
||||
NEW_APP_DIRECTORY=$2
|
||||
APP_PID=$3
|
||||
APP_ARGUMENTS="${@:4}"
|
||||
APP_ARGUMENTS=("${@:4}")
|
||||
|
||||
error_handler() {
|
||||
local lineno="$1"
|
||||
|
@ -33,7 +33,7 @@ trap 'error_handler ${LINENO}' ERR
|
|||
|
||||
attempt=0
|
||||
while true; do
|
||||
if lsof -p $APP_PID +r 1 &>/dev/null || ps -p "$APP_PID" &>/dev/null; then
|
||||
if lsof -p "$APP_PID" +r 1 &>/dev/null || ps -p "$APP_PID" &>/dev/null; then
|
||||
if [ "$attempt" -eq 4 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
@ -53,5 +53,5 @@ mv "$NEW_APP_DIRECTORY" "$INSTALL_DIRECTORY"
|
|||
if [ "$#" -le 3 ]; then
|
||||
open -a "$INSTALL_DIRECTORY"
|
||||
else
|
||||
open -a "$INSTALL_DIRECTORY" --args "$APP_ARGUMENTS"
|
||||
open -a "$INSTALL_DIRECTORY" --args "${APP_ARGUMENTS[@]}"
|
||||
fi
|
|
@ -33,6 +33,7 @@ using Ryujinx.HLE.HOS.SystemState;
|
|||
using Ryujinx.HLE.Loaders.Processes;
|
||||
using Ryujinx.Input;
|
||||
using Ryujinx.Input.HLE;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using Ryujinx.Ui.Common;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using Ryujinx.Ui.Common.Helper;
|
||||
|
@ -696,7 +697,7 @@ namespace Ryujinx.Ava
|
|||
|
||||
DiscordIntegrationModule.SwitchToPlayingState(Device.Processes.ActiveApplication.ProgramIdText, Device.Processes.ActiveApplication.Name);
|
||||
|
||||
_viewModel.ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText, appMetadata =>
|
||||
ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText, appMetadata =>
|
||||
{
|
||||
appMetadata.LastPlayed = DateTime.UtcNow;
|
||||
});
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace Ryujinx.Ava.UI.Controls
|
|||
{
|
||||
viewModel.SelectedApplication.Favorite = !viewModel.SelectedApplication.Favorite;
|
||||
|
||||
viewModel.ApplicationLibrary.LoadAndSaveMetaData(viewModel.SelectedApplication.TitleId, appMetadata =>
|
||||
ApplicationLibrary.LoadAndSaveMetaData(viewModel.SelectedApplication.TitleId, appMetadata =>
|
||||
{
|
||||
appMetadata.Favorite = viewModel.SelectedApplication.Favorite;
|
||||
});
|
||||
|
|
|
@ -3,6 +3,7 @@ using LibHac.Ncm;
|
|||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Ava.UI.Windows;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
@ -74,7 +75,7 @@ namespace Ryujinx.Ava.UI.Models
|
|||
}
|
||||
else
|
||||
{
|
||||
var appMetadata = MainWindow.MainWindowViewModel.ApplicationLibrary.LoadAndSaveMetaData(TitleIdString);
|
||||
var appMetadata = ApplicationLibrary.LoadAndSaveMetaData(TitleIdString);
|
||||
Title = appMetadata.Title ?? TitleIdString;
|
||||
}
|
||||
|
||||
|
|
|
@ -239,28 +239,28 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||
IPlatformHandle CreateMacOS()
|
||||
{
|
||||
// Create a new CAMetalLayer.
|
||||
IntPtr layerClass = ObjectiveC.objc_getClass("CAMetalLayer");
|
||||
IntPtr metalLayer = ObjectiveC.IntPtr_objc_msgSend(layerClass, "alloc");
|
||||
ObjectiveC.objc_msgSend(metalLayer, "init");
|
||||
ObjectiveC.Object layerObject = new("CAMetalLayer");
|
||||
ObjectiveC.Object metalLayer = layerObject.GetFromMessage("alloc");
|
||||
metalLayer.SendMessage("init");
|
||||
|
||||
// Create a child NSView to render into.
|
||||
IntPtr nsViewClass = ObjectiveC.objc_getClass("NSView");
|
||||
IntPtr child = ObjectiveC.IntPtr_objc_msgSend(nsViewClass, "alloc");
|
||||
ObjectiveC.objc_msgSend(child, "init", new ObjectiveC.NSRect(0, 0, 0, 0));
|
||||
ObjectiveC.Object nsViewObject = new("NSView");
|
||||
ObjectiveC.Object child = nsViewObject.GetFromMessage("alloc");
|
||||
child.SendMessage("init", new ObjectiveC.NSRect(0, 0, 0, 0));
|
||||
|
||||
// Make its renderer our metal layer.
|
||||
ObjectiveC.objc_msgSend(child, "setWantsLayer:", 1);
|
||||
ObjectiveC.objc_msgSend(child, "setLayer:", metalLayer);
|
||||
ObjectiveC.objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor);
|
||||
child.SendMessage("setWantsLayer:", 1);
|
||||
child.SendMessage("setLayer:", metalLayer);
|
||||
metalLayer.SendMessage("setContentsScale:", Program.DesktopScaleFactor);
|
||||
|
||||
// Ensure the scale factor is up to date.
|
||||
_updateBoundsCallback = rect =>
|
||||
{
|
||||
ObjectiveC.objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor);
|
||||
metalLayer.SendMessage("setContentsScale:", Program.DesktopScaleFactor);
|
||||
};
|
||||
|
||||
IntPtr nsView = child;
|
||||
MetalLayer = metalLayer;
|
||||
IntPtr nsView = child.ObjPtr;
|
||||
MetalLayer = metalLayer.ObjPtr;
|
||||
NsView = nsView;
|
||||
|
||||
return new PlatformHandle(nsView, "NSView");
|
||||
|
|
|
@ -7,9 +7,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// <summary>
|
||||
/// An Augmented Interval Tree based off of the "TreeDictionary"'s Red-Black Tree. Allows fast overlap checking of ranges.
|
||||
/// </summary>
|
||||
/// <typeparam name="K">Key</typeparam>
|
||||
/// <typeparam name="V">Value</typeparam>
|
||||
public class IntervalTree<K, V> : IntrusiveRedBlackTreeImpl<IntervalTreeNode<K, V>> where K : IComparable<K>
|
||||
/// <typeparam name="TKey">Key</typeparam>
|
||||
/// <typeparam name="TValue">Value</typeparam>
|
||||
public class IntervalTree<TKey, TValue> : IntrusiveRedBlackTreeImpl<IntervalTreeNode<TKey, TValue>> where TKey : IComparable<TKey>
|
||||
{
|
||||
private const int ArrayGrowthSize = 32;
|
||||
|
||||
|
@ -22,11 +22,11 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="overlaps">Overlaps array to place results in</param>
|
||||
/// <returns>Number of values found</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
public int Get(K key, ref V[] overlaps)
|
||||
public int Get(TKey key, ref TValue[] overlaps)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
IntervalTreeNode<K, V> node = GetNode(key);
|
||||
IntervalTreeNode<TKey, TValue> node = GetNode(key);
|
||||
|
||||
if (node == null)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ namespace Ryujinx.Common.Collections
|
|||
}
|
||||
|
||||
int overlapsCount = 0;
|
||||
foreach (RangeNode<K, V> value in node.Values)
|
||||
foreach (RangeNode<TKey, TValue> value in node.Values)
|
||||
{
|
||||
overlaps[overlapsCount++] = value.Value;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="overlapCount">Index to start writing results into the array. Defaults to 0</param>
|
||||
/// <returns>Number of values found</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="start"/> or <paramref name="end"/> is null</exception>
|
||||
public int Get(K start, K end, ref V[] overlaps, int overlapCount = 0)
|
||||
public int Get(TKey start, TKey end, ref TValue[] overlaps, int overlapCount = 0)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(start);
|
||||
ArgumentNullException.ThrowIfNull(end);
|
||||
|
@ -73,7 +73,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="end">End of the range to insert</param>
|
||||
/// <param name="value">Value to add</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="start"/>, <paramref name="end"/> or <paramref name="value"/> are null</exception>
|
||||
public void Add(K start, K end, V value)
|
||||
public void Add(TKey start, TKey end, TValue value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(start);
|
||||
ArgumentNullException.ThrowIfNull(end);
|
||||
|
@ -89,7 +89,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="value">Value to remove</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
/// <returns>Number of deleted values</returns>
|
||||
public int Remove(K key, V value)
|
||||
public int Remove(TKey key, TValue value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
|
@ -104,9 +104,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// Adds all the nodes in the dictionary into <paramref name="list"/>.
|
||||
/// </summary>
|
||||
/// <returns>A list of all RangeNodes sorted by Key Order</returns>
|
||||
public List<RangeNode<K, V>> AsList()
|
||||
public List<RangeNode<TKey, TValue>> AsList()
|
||||
{
|
||||
List<RangeNode<K, V>> list = new List<RangeNode<K, V>>();
|
||||
List<RangeNode<TKey, TValue>> list = new();
|
||||
|
||||
AddToList(Root, list);
|
||||
|
||||
|
@ -122,7 +122,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// </summary>
|
||||
/// <param name="node">The node to search for RangeNodes within</param>
|
||||
/// <param name="list">The list to add RangeNodes to</param>
|
||||
private void AddToList(IntervalTreeNode<K, V> node, List<RangeNode<K, V>> list)
|
||||
private void AddToList(IntervalTreeNode<TKey, TValue> node, List<RangeNode<TKey, TValue>> list)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
|
@ -142,11 +142,11 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key of the node to get</param>
|
||||
/// <returns>Node reference in the tree</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
private IntervalTreeNode<K, V> GetNode(K key)
|
||||
private IntervalTreeNode<TKey, TValue> GetNode(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
IntervalTreeNode<K, V> node = Root;
|
||||
IntervalTreeNode<TKey, TValue> node = Root;
|
||||
while (node != null)
|
||||
{
|
||||
int cmp = key.CompareTo(node.Start);
|
||||
|
@ -173,7 +173,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="end">End of the range</param>
|
||||
/// <param name="overlaps">Overlaps array to place results in</param>
|
||||
/// <param name="overlapCount">Overlaps count to update</param>
|
||||
private void GetValues(IntervalTreeNode<K, V> node, K start, K end, ref V[] overlaps, ref int overlapCount)
|
||||
private void GetValues(IntervalTreeNode<TKey, TValue> node, TKey start, TKey end, ref TValue[] overlaps, ref int overlapCount)
|
||||
{
|
||||
if (node == null || start.CompareTo(node.Max) >= 0)
|
||||
{
|
||||
|
@ -188,7 +188,7 @@ namespace Ryujinx.Common.Collections
|
|||
if (start.CompareTo(node.End) < 0)
|
||||
{
|
||||
// Contains this node. Add overlaps to list.
|
||||
foreach (RangeNode<K,V> overlap in node.Values)
|
||||
foreach (RangeNode<TKey, TValue> overlap in node.Values)
|
||||
{
|
||||
if (start.CompareTo(overlap.End) < 0)
|
||||
{
|
||||
|
@ -212,9 +212,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="start">Start of the range to insert</param>
|
||||
/// <param name="end">End of the range to insert</param>
|
||||
/// <param name="value">Value to insert</param>
|
||||
private void Insert(K start, K end, V value)
|
||||
private void Insert(TKey start, TKey end, TValue value)
|
||||
{
|
||||
IntervalTreeNode<K, V> newNode = BSTInsert(start, end, value);
|
||||
IntervalTreeNode<TKey, TValue> newNode = BSTInsert(start, end, value);
|
||||
RestoreBalanceAfterInsertion(newNode);
|
||||
}
|
||||
|
||||
|
@ -223,10 +223,10 @@ namespace Ryujinx.Common.Collections
|
|||
/// This should only be called if the max increases - not for rebalancing or removals.
|
||||
/// </summary>
|
||||
/// <param name="node">The node to start propagating from</param>
|
||||
private void PropagateIncrease(IntervalTreeNode<K, V> node)
|
||||
private static void PropagateIncrease(IntervalTreeNode<TKey, TValue> node)
|
||||
{
|
||||
K max = node.Max;
|
||||
IntervalTreeNode<K, V> ptr = node;
|
||||
TKey max = node.Max;
|
||||
IntervalTreeNode<TKey, TValue> ptr = node;
|
||||
|
||||
while ((ptr = ptr.Parent) != null)
|
||||
{
|
||||
|
@ -246,13 +246,13 @@ namespace Ryujinx.Common.Collections
|
|||
/// This fully recalculates the max value from all children when there is potential for it to decrease.
|
||||
/// </summary>
|
||||
/// <param name="node">The node to start propagating from</param>
|
||||
private void PropagateFull(IntervalTreeNode<K, V> node)
|
||||
private static void PropagateFull(IntervalTreeNode<TKey, TValue> node)
|
||||
{
|
||||
IntervalTreeNode<K, V> ptr = node;
|
||||
IntervalTreeNode<TKey, TValue> ptr = node;
|
||||
|
||||
do
|
||||
{
|
||||
K max = ptr.End;
|
||||
TKey max = ptr.End;
|
||||
|
||||
if (ptr.Left != null && ptr.Left.Max.CompareTo(max) > 0)
|
||||
{
|
||||
|
@ -278,10 +278,10 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="end">End of the range to insert</param>
|
||||
/// <param name="value">Value to insert</param>
|
||||
/// <returns>The inserted Node</returns>
|
||||
private IntervalTreeNode<K, V> BSTInsert(K start, K end, V value)
|
||||
private IntervalTreeNode<TKey, TValue> BSTInsert(TKey start, TKey end, TValue value)
|
||||
{
|
||||
IntervalTreeNode<K, V> parent = null;
|
||||
IntervalTreeNode<K, V> node = Root;
|
||||
IntervalTreeNode<TKey, TValue> parent = null;
|
||||
IntervalTreeNode<TKey, TValue> node = Root;
|
||||
|
||||
while (node != null)
|
||||
{
|
||||
|
@ -297,7 +297,7 @@ namespace Ryujinx.Common.Collections
|
|||
}
|
||||
else
|
||||
{
|
||||
node.Values.Add(new RangeNode<K, V>(start, end, value));
|
||||
node.Values.Add(new RangeNode<TKey, TValue>(start, end, value));
|
||||
|
||||
if (end.CompareTo(node.End) > 0)
|
||||
{
|
||||
|
@ -313,7 +313,7 @@ namespace Ryujinx.Common.Collections
|
|||
return node;
|
||||
}
|
||||
}
|
||||
IntervalTreeNode<K, V> newNode = new IntervalTreeNode<K, V>(start, end, value, parent);
|
||||
IntervalTreeNode<TKey, TValue> newNode = new(start, end, value, parent);
|
||||
if (newNode.Parent == null)
|
||||
{
|
||||
Root = newNode;
|
||||
|
@ -338,9 +338,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key to search for</param>
|
||||
/// <param name="value">Value to delete</param>
|
||||
/// <returns>Number of deleted values</returns>
|
||||
private int Delete(K key, V value)
|
||||
private int Delete(TKey key, TValue value)
|
||||
{
|
||||
IntervalTreeNode<K, V> nodeToDelete = GetNode(key);
|
||||
IntervalTreeNode<TKey, TValue> nodeToDelete = GetNode(key);
|
||||
|
||||
if (nodeToDelete == null)
|
||||
{
|
||||
|
@ -362,7 +362,7 @@ namespace Ryujinx.Common.Collections
|
|||
return removed;
|
||||
}
|
||||
|
||||
IntervalTreeNode<K, V> replacementNode;
|
||||
IntervalTreeNode<TKey, TValue> replacementNode;
|
||||
|
||||
if (LeftOf(nodeToDelete) == null || RightOf(nodeToDelete) == null)
|
||||
{
|
||||
|
@ -373,7 +373,7 @@ namespace Ryujinx.Common.Collections
|
|||
replacementNode = PredecessorOf(nodeToDelete);
|
||||
}
|
||||
|
||||
IntervalTreeNode<K, V> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
||||
IntervalTreeNode<TKey, TValue> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
||||
|
||||
if (tmp != null)
|
||||
{
|
||||
|
@ -413,7 +413,7 @@ namespace Ryujinx.Common.Collections
|
|||
|
||||
#endregion
|
||||
|
||||
protected override void RotateLeft(IntervalTreeNode<K, V> node)
|
||||
protected override void RotateLeft(IntervalTreeNode<TKey, TValue> node)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
|
@ -423,7 +423,7 @@ namespace Ryujinx.Common.Collections
|
|||
}
|
||||
}
|
||||
|
||||
protected override void RotateRight(IntervalTreeNode<K, V> node)
|
||||
protected override void RotateRight(IntervalTreeNode<TKey, TValue> node)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
|
@ -433,7 +433,7 @@ namespace Ryujinx.Common.Collections
|
|||
}
|
||||
}
|
||||
|
||||
public bool ContainsKey(K key)
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
|
@ -444,15 +444,15 @@ namespace Ryujinx.Common.Collections
|
|||
/// <summary>
|
||||
/// Represents a value and its start and end keys.
|
||||
/// </summary>
|
||||
/// <typeparam name="K"></typeparam>
|
||||
/// <typeparam name="V"></typeparam>
|
||||
public readonly struct RangeNode<K, V>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
public readonly struct RangeNode<TKey, TValue>
|
||||
{
|
||||
public readonly K Start;
|
||||
public readonly K End;
|
||||
public readonly V Value;
|
||||
public readonly TKey Start;
|
||||
public readonly TKey End;
|
||||
public readonly TValue Value;
|
||||
|
||||
public RangeNode(K start, K end, V value)
|
||||
public RangeNode(TKey start, TKey end, TValue value)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
|
@ -463,36 +463,36 @@ namespace Ryujinx.Common.Collections
|
|||
/// <summary>
|
||||
/// Represents a node in the IntervalTree which contains start and end keys of type K, and a value of generic type V.
|
||||
/// </summary>
|
||||
/// <typeparam name="K">Key type of the node</typeparam>
|
||||
/// <typeparam name="V">Value type of the node</typeparam>
|
||||
public class IntervalTreeNode<K, V> : IntrusiveRedBlackTreeNode<IntervalTreeNode<K, V>>
|
||||
/// <typeparam name="TKey">Key type of the node</typeparam>
|
||||
/// <typeparam name="TValue">Value type of the node</typeparam>
|
||||
public class IntervalTreeNode<TKey, TValue> : IntrusiveRedBlackTreeNode<IntervalTreeNode<TKey, TValue>>
|
||||
{
|
||||
/// <summary>
|
||||
/// The start of the range.
|
||||
/// </summary>
|
||||
internal K Start;
|
||||
internal TKey Start;
|
||||
|
||||
/// <summary>
|
||||
/// The end of the range - maximum of all in the Values list.
|
||||
/// </summary>
|
||||
internal K End;
|
||||
internal TKey End;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum end value of this node and all its children.
|
||||
/// </summary>
|
||||
internal K Max;
|
||||
internal TKey Max;
|
||||
|
||||
/// <summary>
|
||||
/// Values contained on the node that shares a common Start value.
|
||||
/// </summary>
|
||||
internal List<RangeNode<K, V>> Values;
|
||||
internal List<RangeNode<TKey, TValue>> Values;
|
||||
|
||||
internal IntervalTreeNode(K start, K end, V value, IntervalTreeNode<K, V> parent)
|
||||
internal IntervalTreeNode(TKey start, TKey end, TValue value, IntervalTreeNode<TKey, TValue> parent)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
Max = end;
|
||||
Values = new List<RangeNode<K, V>> { new RangeNode<K, V>(start, end, value) };
|
||||
Values = new List<RangeNode<TKey, TValue>> { new RangeNode<TKey, TValue>(start, end, value) };
|
||||
Parent = parent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,11 +180,6 @@ namespace Ryujinx.Common.Collections
|
|||
parent.Right = child;
|
||||
}
|
||||
|
||||
if (ParentOf(element) == old)
|
||||
{
|
||||
parent = element;
|
||||
}
|
||||
|
||||
element.Color = old.Color;
|
||||
element.Left = old.Left;
|
||||
element.Right = old.Right;
|
||||
|
@ -258,11 +253,11 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="tree">Tree to search at</param>
|
||||
/// <param name="key">Key of the node to be found</param>
|
||||
/// <returns>Node that is equal to <paramref name="key"/></returns>
|
||||
public static N GetNodeByKey<N, K>(this IntrusiveRedBlackTree<N> tree, K key)
|
||||
where N : IntrusiveRedBlackTreeNode<N>, IComparable<N>, IComparable<K>
|
||||
where K : struct
|
||||
public static TNode GetNodeByKey<TNode, TKey>(this IntrusiveRedBlackTree<TNode> tree, TKey key)
|
||||
where TNode : IntrusiveRedBlackTreeNode<TNode>, IComparable<TNode>, IComparable<TKey>
|
||||
where TKey : struct
|
||||
{
|
||||
N node = tree.RootNode;
|
||||
TNode node = tree.RootNode;
|
||||
while (node != null)
|
||||
{
|
||||
int cmp = node.CompareTo(key);
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Ryujinx.Common.Collections
|
|||
{
|
||||
protected const bool Black = true;
|
||||
protected const bool Red = false;
|
||||
protected T Root = null;
|
||||
protected T Root;
|
||||
|
||||
internal T RootNode => Root;
|
||||
|
||||
|
|
|
@ -8,9 +8,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// <summary>
|
||||
/// Dictionary that provides the ability for O(logN) Lookups for keys that exist in the Dictionary, and O(logN) lookups for keys immediately greater than or less than a specified key.
|
||||
/// </summary>
|
||||
/// <typeparam name="K">Key</typeparam>
|
||||
/// <typeparam name="V">Value</typeparam>
|
||||
public class TreeDictionary<K, V> : IntrusiveRedBlackTreeImpl<Node<K, V>>, IDictionary<K, V> where K : IComparable<K>
|
||||
/// <typeparam name="TKey">Key</typeparam>
|
||||
/// <typeparam name="TValue">Value</typeparam>
|
||||
public class TreeDictionary<TKey, TValue> : IntrusiveRedBlackTreeImpl<Node<TKey, TValue>>, IDictionary<TKey, TValue> where TKey : IComparable<TKey>
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
|
@ -20,11 +20,11 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key of the node value to get</param>
|
||||
/// <returns>Value associated w/ <paramref name="key"/></returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
public V Get(K key)
|
||||
public TValue Get(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
Node<K, V> node = GetNode(key);
|
||||
Node<TKey, TValue> node = GetNode(key);
|
||||
|
||||
if (node == null)
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key of the node to add</param>
|
||||
/// <param name="value">Value of the node to add</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> or <paramref name="value"/> are null</exception>
|
||||
public void Add(K key, V value)
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
|
@ -55,7 +55,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// </summary>
|
||||
/// <param name="key">Key of the node to remove</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
public void Remove(K key)
|
||||
public void Remove(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
|
@ -71,9 +71,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key for which to find the floor value of</param>
|
||||
/// <returns>Key of node immediately less than <paramref name="key"/></returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
public K Floor(K key)
|
||||
public TKey Floor(TKey key)
|
||||
{
|
||||
Node<K, V> node = FloorNode(key);
|
||||
Node<TKey, TValue> node = FloorNode(key);
|
||||
if (node != null)
|
||||
{
|
||||
return node.Key;
|
||||
|
@ -87,9 +87,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key for which to find the ceiling node of</param>
|
||||
/// <returns>Key of node immediately greater than <paramref name="key"/></returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
public K Ceiling(K key)
|
||||
public TKey Ceiling(TKey key)
|
||||
{
|
||||
Node<K, V> node = CeilingNode(key);
|
||||
Node<TKey, TValue> node = CeilingNode(key);
|
||||
if (node != null)
|
||||
{
|
||||
return node.Key;
|
||||
|
@ -102,12 +102,12 @@ namespace Ryujinx.Common.Collections
|
|||
/// </summary>
|
||||
/// <param name="key">Key to find the successor of</param>
|
||||
/// <returns>Value</returns>
|
||||
public K SuccessorOf(K key)
|
||||
public TKey SuccessorOf(TKey key)
|
||||
{
|
||||
Node<K, V> node = GetNode(key);
|
||||
Node<TKey, TValue> node = GetNode(key);
|
||||
if (node != null)
|
||||
{
|
||||
Node<K, V> successor = SuccessorOf(node);
|
||||
Node<TKey, TValue> successor = SuccessorOf(node);
|
||||
|
||||
return successor != null ? successor.Key : default;
|
||||
}
|
||||
|
@ -119,12 +119,12 @@ namespace Ryujinx.Common.Collections
|
|||
/// </summary>
|
||||
/// <param name="key">Key to find the predecessor of</param>
|
||||
/// <returns>Value</returns>
|
||||
public K PredecessorOf(K key)
|
||||
public TKey PredecessorOf(TKey key)
|
||||
{
|
||||
Node<K, V> node = GetNode(key);
|
||||
Node<TKey, TValue> node = GetNode(key);
|
||||
if (node != null)
|
||||
{
|
||||
Node<K, V> predecessor = PredecessorOf(node);
|
||||
Node<TKey, TValue> predecessor = PredecessorOf(node);
|
||||
|
||||
return predecessor != null ? predecessor.Key : default;
|
||||
}
|
||||
|
@ -137,19 +137,19 @@ namespace Ryujinx.Common.Collections
|
|||
/// The key/value pairs will be added in Level Order.
|
||||
/// </summary>
|
||||
/// <param name="list">List to add the tree pairs into</param>
|
||||
public List<KeyValuePair<K, V>> AsLevelOrderList()
|
||||
public List<KeyValuePair<TKey, TValue>> AsLevelOrderList()
|
||||
{
|
||||
List<KeyValuePair<K, V>> list = new List<KeyValuePair<K, V>>();
|
||||
List<KeyValuePair<TKey, TValue>> list = new();
|
||||
|
||||
Queue<Node<K, V>> nodes = new Queue<Node<K, V>>();
|
||||
Queue<Node<TKey, TValue>> nodes = new();
|
||||
|
||||
if (this.Root != null)
|
||||
{
|
||||
nodes.Enqueue(this.Root);
|
||||
}
|
||||
while (nodes.TryDequeue(out Node<K, V> node))
|
||||
while (nodes.TryDequeue(out Node<TKey, TValue> node))
|
||||
{
|
||||
list.Add(new KeyValuePair<K, V>(node.Key, node.Value));
|
||||
list.Add(new KeyValuePair<TKey, TValue>(node.Key, node.Value));
|
||||
if (node.Left != null)
|
||||
{
|
||||
nodes.Enqueue(node.Left);
|
||||
|
@ -166,9 +166,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// Adds all the nodes in the dictionary into <paramref name="list"/>.
|
||||
/// </summary>
|
||||
/// <returns>A list of all KeyValuePairs sorted by Key Order</returns>
|
||||
public List<KeyValuePair<K, V>> AsList()
|
||||
public List<KeyValuePair<TKey, TValue>> AsList()
|
||||
{
|
||||
List<KeyValuePair<K, V>> list = new List<KeyValuePair<K, V>>();
|
||||
List<KeyValuePair<TKey, TValue>> list = new();
|
||||
|
||||
AddToList(Root, list);
|
||||
|
||||
|
@ -184,7 +184,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// </summary>
|
||||
/// <param name="node">The node to search for nodes within</param>
|
||||
/// <param name="list">The list to add node to</param>
|
||||
private void AddToList(Node<K, V> node, List<KeyValuePair<K, V>> list)
|
||||
private void AddToList(Node<TKey, TValue> node, List<KeyValuePair<TKey, TValue>> list)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
|
@ -193,7 +193,7 @@ namespace Ryujinx.Common.Collections
|
|||
|
||||
AddToList(node.Left, list);
|
||||
|
||||
list.Add(new KeyValuePair<K, V>(node.Key, node.Value));
|
||||
list.Add(new KeyValuePair<TKey, TValue>(node.Key, node.Value));
|
||||
|
||||
AddToList(node.Right, list);
|
||||
}
|
||||
|
@ -204,11 +204,11 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key of the node to get</param>
|
||||
/// <returns>Node reference in the tree</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
private Node<K, V> GetNode(K key)
|
||||
private Node<TKey, TValue> GetNode(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
Node<K, V> node = Root;
|
||||
Node<TKey, TValue> node = Root;
|
||||
while (node != null)
|
||||
{
|
||||
int cmp = key.CompareTo(node.Key);
|
||||
|
@ -235,9 +235,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// </summary>
|
||||
/// <param name="key">Key of the node to insert</param>
|
||||
/// <param name="value">Value of the node to insert</param>
|
||||
private void Insert(K key, V value)
|
||||
private void Insert(TKey key, TValue value)
|
||||
{
|
||||
Node<K, V> newNode = BSTInsert(key, value);
|
||||
Node<TKey, TValue> newNode = BSTInsert(key, value);
|
||||
RestoreBalanceAfterInsertion(newNode);
|
||||
}
|
||||
|
||||
|
@ -251,10 +251,10 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key of the node to insert</param>
|
||||
/// <param name="value">Value of the node to insert</param>
|
||||
/// <returns>The inserted Node</returns>
|
||||
private Node<K, V> BSTInsert(K key, V value)
|
||||
private Node<TKey, TValue> BSTInsert(TKey key, TValue value)
|
||||
{
|
||||
Node<K, V> parent = null;
|
||||
Node<K, V> node = Root;
|
||||
Node<TKey, TValue> parent = null;
|
||||
Node<TKey, TValue> node = Root;
|
||||
|
||||
while (node != null)
|
||||
{
|
||||
|
@ -274,7 +274,7 @@ namespace Ryujinx.Common.Collections
|
|||
return node;
|
||||
}
|
||||
}
|
||||
Node<K, V> newNode = new Node<K, V>(key, value, parent);
|
||||
Node<TKey, TValue> newNode = new(key, value, parent);
|
||||
if (newNode.Parent == null)
|
||||
{
|
||||
Root = newNode;
|
||||
|
@ -296,14 +296,17 @@ namespace Ryujinx.Common.Collections
|
|||
/// </summary>
|
||||
/// <param name="key">Key of the node to delete</param>
|
||||
/// <returns>The deleted Node</returns>
|
||||
private Node<K, V> Delete(K key)
|
||||
private Node<TKey, TValue> Delete(TKey key)
|
||||
{
|
||||
// O(1) Retrieval
|
||||
Node<K, V> nodeToDelete = GetNode(key);
|
||||
Node<TKey, TValue> nodeToDelete = GetNode(key);
|
||||
|
||||
if (nodeToDelete == null) return null;
|
||||
if (nodeToDelete == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Node<K, V> replacementNode;
|
||||
Node<TKey, TValue> replacementNode;
|
||||
|
||||
if (LeftOf(nodeToDelete) == null || RightOf(nodeToDelete) == null)
|
||||
{
|
||||
|
@ -314,7 +317,7 @@ namespace Ryujinx.Common.Collections
|
|||
replacementNode = PredecessorOf(nodeToDelete);
|
||||
}
|
||||
|
||||
Node<K, V> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
||||
Node<TKey, TValue> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
||||
|
||||
if (tmp != null)
|
||||
{
|
||||
|
@ -354,11 +357,11 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key for which to find the floor node of</param>
|
||||
/// <returns>Node whose key is immediately less than or equal to <paramref name="key"/>, or null if no such node is found.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
private Node<K, V> FloorNode(K key)
|
||||
private Node<TKey, TValue> FloorNode(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
Node<K, V> tmp = Root;
|
||||
Node<TKey, TValue> tmp = Root;
|
||||
|
||||
while (tmp != null)
|
||||
{
|
||||
|
@ -382,8 +385,8 @@ namespace Ryujinx.Common.Collections
|
|||
}
|
||||
else
|
||||
{
|
||||
Node<K, V> parent = tmp.Parent;
|
||||
Node<K, V> ptr = tmp;
|
||||
Node<TKey, TValue> parent = tmp.Parent;
|
||||
Node<TKey, TValue> ptr = tmp;
|
||||
while (parent != null && ptr == parent.Left)
|
||||
{
|
||||
ptr = parent;
|
||||
|
@ -406,11 +409,11 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key for which to find the ceiling node of</param>
|
||||
/// <returns>Node whose key is immediately greater than or equal to <paramref name="key"/>, or null if no such node is found.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
private Node<K, V> CeilingNode(K key)
|
||||
private Node<TKey, TValue> CeilingNode(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
Node<K, V> tmp = Root;
|
||||
Node<TKey, TValue> tmp = Root;
|
||||
|
||||
while (tmp != null)
|
||||
{
|
||||
|
@ -434,8 +437,8 @@ namespace Ryujinx.Common.Collections
|
|||
}
|
||||
else
|
||||
{
|
||||
Node<K, V> parent = tmp.Parent;
|
||||
Node<K, V> ptr = tmp;
|
||||
Node<TKey, TValue> parent = tmp.Parent;
|
||||
Node<TKey, TValue> ptr = tmp;
|
||||
while (parent != null && ptr == parent.Right)
|
||||
{
|
||||
ptr = parent;
|
||||
|
@ -457,44 +460,44 @@ namespace Ryujinx.Common.Collections
|
|||
#region Interface Implementations
|
||||
|
||||
// Method descriptions are not provided as they are already included as part of the interface.
|
||||
public bool ContainsKey(K key)
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
return GetNode(key) != null;
|
||||
}
|
||||
|
||||
bool IDictionary<K, V>.Remove(K key)
|
||||
bool IDictionary<TKey, TValue>.Remove(TKey key)
|
||||
{
|
||||
int count = Count;
|
||||
Remove(key);
|
||||
return count > Count;
|
||||
}
|
||||
|
||||
public bool TryGetValue(K key, [MaybeNullWhen(false)] out V value)
|
||||
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
Node<K, V> node = GetNode(key);
|
||||
Node<TKey, TValue> node = GetNode(key);
|
||||
value = node != null ? node.Value : default;
|
||||
return node != null;
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<K, V> item)
|
||||
public void Add(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(item.Key);
|
||||
|
||||
Add(item.Key, item.Value);
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<K, V> item)
|
||||
public bool Contains(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
if (item.Key == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Node<K, V> node = GetNode(item.Key);
|
||||
Node<TKey, TValue> node = GetNode(item.Key);
|
||||
if (node != null)
|
||||
{
|
||||
return node.Key.Equals(item.Key) && node.Value.Equals(item.Value);
|
||||
|
@ -502,27 +505,27 @@ namespace Ryujinx.Common.Collections
|
|||
return false;
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex)
|
||||
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||
{
|
||||
if (arrayIndex < 0 || array.Length - arrayIndex < this.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(arrayIndex));
|
||||
}
|
||||
|
||||
SortedList<K, V> list = GetKeyValues();
|
||||
SortedList<TKey, TValue> list = GetKeyValues();
|
||||
|
||||
int offset = 0;
|
||||
|
||||
for (int i = arrayIndex; i < array.Length && offset < list.Count; i++)
|
||||
{
|
||||
array[i] = new KeyValuePair<K, V>(list.Keys[i], list.Values[i]);
|
||||
array[i] = new KeyValuePair<TKey, TValue>(list.Keys[i], list.Values[i]);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<K, V> item)
|
||||
public bool Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
Node<K, V> node = GetNode(item.Key);
|
||||
Node<TKey, TValue> node = GetNode(item.Key);
|
||||
|
||||
if (node == null)
|
||||
{
|
||||
|
@ -539,7 +542,7 @@ namespace Ryujinx.Common.Collections
|
|||
return false;
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
|
||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||
{
|
||||
return GetKeyValues().GetEnumerator();
|
||||
}
|
||||
|
@ -549,13 +552,13 @@ namespace Ryujinx.Common.Collections
|
|||
return GetKeyValues().GetEnumerator();
|
||||
}
|
||||
|
||||
public ICollection<K> Keys => GetKeyValues().Keys;
|
||||
public ICollection<TKey> Keys => GetKeyValues().Keys;
|
||||
|
||||
public ICollection<V> Values => GetKeyValues().Values;
|
||||
public ICollection<TValue> Values => GetKeyValues().Values;
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public V this[K key]
|
||||
public TValue this[TKey key]
|
||||
{
|
||||
get => Get(key);
|
||||
set => Add(key, value);
|
||||
|
@ -569,16 +572,16 @@ namespace Ryujinx.Common.Collections
|
|||
/// Returns a sorted list of all the node keys / values in the tree.
|
||||
/// </summary>
|
||||
/// <returns>List of node keys</returns>
|
||||
private SortedList<K, V> GetKeyValues()
|
||||
private SortedList<TKey, TValue> GetKeyValues()
|
||||
{
|
||||
SortedList<K, V> set = new SortedList<K, V>();
|
||||
Queue<Node<K, V>> queue = new Queue<Node<K, V>>();
|
||||
SortedList<TKey, TValue> set = new();
|
||||
Queue<Node<TKey, TValue>> queue = new();
|
||||
if (Root != null)
|
||||
{
|
||||
queue.Enqueue(Root);
|
||||
}
|
||||
|
||||
while (queue.TryDequeue(out Node<K, V> node))
|
||||
while (queue.TryDequeue(out Node<TKey, TValue> node))
|
||||
{
|
||||
set.Add(node.Key, node.Value);
|
||||
if (null != node.Left)
|
||||
|
@ -600,14 +603,14 @@ namespace Ryujinx.Common.Collections
|
|||
/// <summary>
|
||||
/// Represents a node in the TreeDictionary which contains a key and value of generic type K and V, respectively.
|
||||
/// </summary>
|
||||
/// <typeparam name="K">Key of the node</typeparam>
|
||||
/// <typeparam name="V">Value of the node</typeparam>
|
||||
public class Node<K, V> : IntrusiveRedBlackTreeNode<Node<K, V>> where K : IComparable<K>
|
||||
/// <typeparam name="TKey">Key of the node</typeparam>
|
||||
/// <typeparam name="TValue">Value of the node</typeparam>
|
||||
public class Node<TKey, TValue> : IntrusiveRedBlackTreeNode<Node<TKey, TValue>> where TKey : IComparable<TKey>
|
||||
{
|
||||
internal K Key;
|
||||
internal V Value;
|
||||
internal TKey Key;
|
||||
internal TValue Value;
|
||||
|
||||
internal Node(K key, V value, Node<K, V> parent)
|
||||
internal Node(TKey key, TValue value, Node<TKey, TValue> parent)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
|
|
|
@ -11,6 +11,6 @@ namespace Ryujinx.Common.Configuration
|
|||
SmaaLow,
|
||||
SmaaMedium,
|
||||
SmaaHigh,
|
||||
SmaaUltra
|
||||
SmaaUltra,
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ namespace Ryujinx.Common.Configuration
|
|||
{
|
||||
UserProfile,
|
||||
Portable,
|
||||
Custom
|
||||
Custom,
|
||||
}
|
||||
|
||||
public static LaunchMode Mode { get; private set; }
|
||||
|
@ -34,7 +34,7 @@ namespace Ryujinx.Common.Configuration
|
|||
private const string DefaultModsDir = "mods";
|
||||
|
||||
public static string CustomModsPath { get; set; }
|
||||
public static string CustomSdModsPath {get; set; }
|
||||
public static string CustomSdModsPath { get; set; }
|
||||
public static string CustomNandPath { get; set; } // TODO: Actually implement this into VFS
|
||||
public static string CustomSdCardPath { get; set; } // TODO: Actually implement this into VFS
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.Common.Configuration
|
|||
Fixed16x10,
|
||||
Fixed21x9,
|
||||
Fixed32x9,
|
||||
Stretched
|
||||
Stretched,
|
||||
}
|
||||
|
||||
public static class AspectRatioExtensions
|
||||
|
@ -25,12 +25,14 @@ namespace Ryujinx.Common.Configuration
|
|||
{
|
||||
return aspectRatio switch
|
||||
{
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
AspectRatio.Fixed4x3 => 4.0f,
|
||||
AspectRatio.Fixed16x9 => 16.0f,
|
||||
AspectRatio.Fixed16x10 => 16.0f,
|
||||
AspectRatio.Fixed21x9 => 21.0f,
|
||||
AspectRatio.Fixed32x9 => 32.0f,
|
||||
_ => 16.0f
|
||||
_ => 16.0f,
|
||||
#pragma warning restore IDE0055
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -38,12 +40,14 @@ namespace Ryujinx.Common.Configuration
|
|||
{
|
||||
return aspectRatio switch
|
||||
{
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
AspectRatio.Fixed4x3 => 3.0f,
|
||||
AspectRatio.Fixed16x9 => 9.0f,
|
||||
AspectRatio.Fixed16x10 => 10.0f,
|
||||
AspectRatio.Fixed21x9 => 9.0f,
|
||||
AspectRatio.Fixed32x9 => 9.0f,
|
||||
_ => 9.0f
|
||||
_ => 9.0f,
|
||||
#pragma warning restore IDE0055
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -51,12 +55,14 @@ namespace Ryujinx.Common.Configuration
|
|||
{
|
||||
return aspectRatio switch
|
||||
{
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
AspectRatio.Fixed4x3 => "4:3",
|
||||
AspectRatio.Fixed16x9 => "16:9",
|
||||
AspectRatio.Fixed16x10 => "16:10",
|
||||
AspectRatio.Fixed21x9 => "21:9",
|
||||
AspectRatio.Fixed32x9 => "32:9",
|
||||
_ => "Stretched"
|
||||
_ => "Stretched",
|
||||
#pragma warning restore IDE0055
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,6 @@ namespace Ryujinx.Common.Configuration.Hid.Controller
|
|||
SingleLeftTrigger1,
|
||||
SingleRightTrigger1,
|
||||
|
||||
Count
|
||||
Count,
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ using System.Text.Json.Serialization;
|
|||
|
||||
namespace Ryujinx.Common.Configuration.Hid.Controller
|
||||
{
|
||||
public class GenericControllerInputConfig<Button, Stick> : GenericInputConfigurationCommon<Button> where Button : unmanaged where Stick : unmanaged
|
||||
public class GenericControllerInputConfig<TButton, TStick> : GenericInputConfigurationCommon<TButton> where TButton : unmanaged where TStick : unmanaged
|
||||
{
|
||||
[JsonIgnore]
|
||||
private float _deadzoneLeft;
|
||||
|
@ -16,12 +16,12 @@ namespace Ryujinx.Common.Configuration.Hid.Controller
|
|||
/// <summary>
|
||||
/// Left JoyCon Controller Stick Bindings
|
||||
/// </summary>
|
||||
public JoyconConfigControllerStick<Button, Stick> LeftJoyconStick { get; set; }
|
||||
public JoyconConfigControllerStick<TButton, TStick> LeftJoyconStick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Right JoyCon Controller Stick Bindings
|
||||
/// </summary>
|
||||
public JoyconConfigControllerStick<Button, Stick> RightJoyconStick { get; set; }
|
||||
public JoyconConfigControllerStick<TButton, TStick> RightJoyconStick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Controller Left Analog Stick Deadzone
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
namespace Ryujinx.Common.Configuration.Hid.Controller
|
||||
{
|
||||
public class JoyconConfigControllerStick<Button, Stick> where Button: unmanaged where Stick: unmanaged
|
||||
public class JoyconConfigControllerStick<TButton, TStick> where TButton : unmanaged where TStick : unmanaged
|
||||
{
|
||||
public Stick Joystick { get; set; }
|
||||
public TStick Joystick { get; set; }
|
||||
public bool InvertStickX { get; set; }
|
||||
public bool InvertStickY { get; set; }
|
||||
public bool Rotate90CW { get; set; }
|
||||
public Button StickButton { get; set; }
|
||||
public TButton StickButton { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
|||
{
|
||||
class JsonMotionConfigControllerConverter : JsonConverter<MotionConfigController>
|
||||
{
|
||||
private static readonly MotionConfigJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||
private static readonly MotionConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||
|
||||
private static MotionInputBackendType GetMotionInputBackendType(ref Utf8JsonReader reader)
|
||||
{
|
||||
|
@ -55,8 +55,8 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
|||
|
||||
return motionBackendType switch
|
||||
{
|
||||
MotionInputBackendType.GamepadDriver => JsonSerializer.Deserialize(ref reader, SerializerContext.StandardMotionConfigController),
|
||||
MotionInputBackendType.CemuHook => JsonSerializer.Deserialize(ref reader, SerializerContext.CemuHookMotionConfigController),
|
||||
MotionInputBackendType.GamepadDriver => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardMotionConfigController),
|
||||
MotionInputBackendType.CemuHook => JsonSerializer.Deserialize(ref reader, _serializerContext.CemuHookMotionConfigController),
|
||||
_ => throw new InvalidOperationException($"Unknown backend type {motionBackendType}"),
|
||||
};
|
||||
}
|
||||
|
@ -66,10 +66,10 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
|||
switch (value.MotionBackend)
|
||||
{
|
||||
case MotionInputBackendType.GamepadDriver:
|
||||
JsonSerializer.Serialize(writer, value as StandardMotionConfigController, SerializerContext.StandardMotionConfigController);
|
||||
JsonSerializer.Serialize(writer, value as StandardMotionConfigController, _serializerContext.StandardMotionConfigController);
|
||||
break;
|
||||
case MotionInputBackendType.CemuHook:
|
||||
JsonSerializer.Serialize(writer, value as CemuHookMotionConfigController, SerializerContext.CemuHookMotionConfigController);
|
||||
JsonSerializer.Serialize(writer, value as CemuHookMotionConfigController, _serializerContext.CemuHookMotionConfigController);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException($"Unknown motion backend type {value.MotionBackend}");
|
||||
|
|
|
@ -10,6 +10,6 @@ namespace Ryujinx.Common.Configuration.Hid.Controller
|
|||
Left,
|
||||
Right,
|
||||
|
||||
Count
|
||||
Count,
|
||||
}
|
||||
}
|
|
@ -18,6 +18,6 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||
Invalid = 1 << 5,
|
||||
Pokeball = 1 << 6,
|
||||
SystemExternal = 1 << 29,
|
||||
System = 1 << 30
|
||||
System = 1 << 30,
|
||||
}
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
namespace Ryujinx.Common.Configuration.Hid
|
||||
{
|
||||
public class GenericInputConfigurationCommon<Button> : InputConfig where Button : unmanaged
|
||||
public class GenericInputConfigurationCommon<TButton> : InputConfig where TButton : unmanaged
|
||||
{
|
||||
/// <summary>
|
||||
/// Left JoyCon Controller Bindings
|
||||
/// </summary>
|
||||
public LeftJoyconCommonConfig<Button> LeftJoycon { get; set; }
|
||||
public LeftJoyconCommonConfig<TButton> LeftJoycon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Right JoyCon Controller Bindings
|
||||
/// </summary>
|
||||
public RightJoyconCommonConfig<Button> RightJoycon { get; set; }
|
||||
public RightJoyconCommonConfig<TButton> RightJoycon { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||
{
|
||||
public class JsonInputConfigConverter : JsonConverter<InputConfig>
|
||||
{
|
||||
private static readonly InputConfigJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||
|
||||
private static InputBackendType GetInputBackendType(ref Utf8JsonReader reader)
|
||||
{
|
||||
|
@ -57,8 +57,8 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||
|
||||
return backendType switch
|
||||
{
|
||||
InputBackendType.WindowKeyboard => JsonSerializer.Deserialize(ref reader, SerializerContext.StandardKeyboardInputConfig),
|
||||
InputBackendType.GamepadSDL2 => JsonSerializer.Deserialize(ref reader, SerializerContext.StandardControllerInputConfig),
|
||||
InputBackendType.WindowKeyboard => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardKeyboardInputConfig),
|
||||
InputBackendType.GamepadSDL2 => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardControllerInputConfig),
|
||||
_ => throw new InvalidOperationException($"Unknown backend type {backendType}"),
|
||||
};
|
||||
}
|
||||
|
@ -68,10 +68,10 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||
switch (value.Backend)
|
||||
{
|
||||
case InputBackendType.WindowKeyboard:
|
||||
JsonSerializer.Serialize(writer, value as StandardKeyboardInputConfig, SerializerContext.StandardKeyboardInputConfig);
|
||||
JsonSerializer.Serialize(writer, value as StandardKeyboardInputConfig, _serializerContext.StandardKeyboardInputConfig);
|
||||
break;
|
||||
case InputBackendType.GamepadSDL2:
|
||||
JsonSerializer.Serialize(writer, value as StandardControllerInputConfig, SerializerContext.StandardControllerInputConfig);
|
||||
JsonSerializer.Serialize(writer, value as StandardControllerInputConfig, _serializerContext.StandardControllerInputConfig);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException($"Unknown backend type {value.Backend}");
|
||||
|
|
|
@ -138,6 +138,6 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||
BackSlash,
|
||||
Unbound,
|
||||
|
||||
Count
|
||||
Count,
|
||||
}
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
namespace Ryujinx.Common.Configuration.Hid.Keyboard
|
||||
{
|
||||
public class GenericKeyboardInputConfig<Key> : GenericInputConfigurationCommon<Key> where Key : unmanaged
|
||||
public class GenericKeyboardInputConfig<TKey> : GenericInputConfigurationCommon<TKey> where TKey : unmanaged
|
||||
{
|
||||
/// <summary>
|
||||
/// Left JoyCon Controller Stick Bindings
|
||||
/// </summary>
|
||||
public JoyconConfigKeyboardStick<Key> LeftJoyconStick { get; set; }
|
||||
public JoyconConfigKeyboardStick<TKey> LeftJoyconStick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Right JoyCon Controller Stick Bindings
|
||||
/// </summary>
|
||||
public JoyconConfigKeyboardStick<Key> RightJoyconStick { get; set; }
|
||||
public JoyconConfigKeyboardStick<TKey> RightJoyconStick { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
namespace Ryujinx.Common.Configuration.Hid.Keyboard
|
||||
{
|
||||
public class JoyconConfigKeyboardStick<Key> where Key: unmanaged
|
||||
public class JoyconConfigKeyboardStick<TKey> where TKey : unmanaged
|
||||
{
|
||||
public Key StickUp { get; set; }
|
||||
public Key StickDown { get; set; }
|
||||
public Key StickLeft { get; set; }
|
||||
public Key StickRight { get; set; }
|
||||
public Key StickButton { get; set; }
|
||||
public TKey StickUp { get; set; }
|
||||
public TKey StickDown { get; set; }
|
||||
public TKey StickLeft { get; set; }
|
||||
public TKey StickRight { get; set; }
|
||||
public TKey StickButton { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
namespace Ryujinx.Common.Configuration.Hid
|
||||
{
|
||||
public class LeftJoyconCommonConfig<Button>
|
||||
public class LeftJoyconCommonConfig<TButton>
|
||||
{
|
||||
public Button ButtonMinus { get; set; }
|
||||
public Button ButtonL { get; set; }
|
||||
public Button ButtonZl { get; set; }
|
||||
public Button ButtonSl { get; set; }
|
||||
public Button ButtonSr { get; set; }
|
||||
public Button DpadUp { get; set; }
|
||||
public Button DpadDown { get; set; }
|
||||
public Button DpadLeft { get; set; }
|
||||
public Button DpadRight { get; set; }
|
||||
public TButton ButtonMinus { get; set; }
|
||||
public TButton ButtonL { get; set; }
|
||||
public TButton ButtonZl { get; set; }
|
||||
public TButton ButtonSl { get; set; }
|
||||
public TButton ButtonSr { get; set; }
|
||||
public TButton DpadUp { get; set; }
|
||||
public TButton DpadDown { get; set; }
|
||||
public TButton DpadLeft { get; set; }
|
||||
public TButton DpadRight { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,6 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||
Player8 = 7,
|
||||
Handheld = 8,
|
||||
Unknown = 9,
|
||||
Auto = 10 // Shouldn't be used directly
|
||||
Auto = 10, // Shouldn't be used directly
|
||||
}
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
namespace Ryujinx.Common.Configuration.Hid
|
||||
{
|
||||
public class RightJoyconCommonConfig<Button>
|
||||
public class RightJoyconCommonConfig<TButton>
|
||||
{
|
||||
public Button ButtonPlus { get; set; }
|
||||
public Button ButtonR { get; set; }
|
||||
public Button ButtonZr { get; set; }
|
||||
public Button ButtonSl { get; set; }
|
||||
public Button ButtonSr { get; set; }
|
||||
public Button ButtonX { get; set; }
|
||||
public Button ButtonB { get; set; }
|
||||
public Button ButtonY { get; set; }
|
||||
public Button ButtonA { get; set; }
|
||||
public TButton ButtonPlus { get; set; }
|
||||
public TButton ButtonR { get; set; }
|
||||
public TButton ButtonZr { get; set; }
|
||||
public TButton ButtonSl { get; set; }
|
||||
public TButton ButtonSr { get; set; }
|
||||
public TButton ButtonX { get; set; }
|
||||
public TButton ButtonB { get; set; }
|
||||
public TButton ButtonY { get; set; }
|
||||
public TButton ButtonA { get; set; }
|
||||
}
|
||||
}
|
|
@ -4,6 +4,6 @@ namespace Ryujinx.Common.Configuration
|
|||
{
|
||||
Never,
|
||||
OnIdle,
|
||||
Always
|
||||
Always,
|
||||
}
|
||||
}
|
|
@ -8,6 +8,6 @@ namespace Ryujinx.Common.Configuration
|
|||
{
|
||||
Bilinear,
|
||||
Nearest,
|
||||
Fsr
|
||||
Fsr,
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
@ -7,8 +6,7 @@ namespace Ryujinx.Common
|
|||
{
|
||||
public static class BinaryReaderExtensions
|
||||
{
|
||||
public unsafe static T ReadStruct<T>(this BinaryReader reader)
|
||||
where T : unmanaged
|
||||
public static T ReadStruct<T>(this BinaryReader reader) where T : unmanaged
|
||||
{
|
||||
return MemoryMarshal.Cast<byte, T>(reader.ReadBytes(Unsafe.SizeOf<T>()))[0];
|
||||
}
|
||||
|
|
|
@ -6,8 +6,7 @@ namespace Ryujinx.Common
|
|||
{
|
||||
public static class BinaryWriterExtensions
|
||||
{
|
||||
public unsafe static void WriteStruct<T>(this BinaryWriter writer, T value)
|
||||
where T : unmanaged
|
||||
public static void WriteStruct<T>(this BinaryWriter writer, T value) where T : unmanaged
|
||||
{
|
||||
ReadOnlySpan<byte> data = MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.Common.GraphicsDriver.NVAPI
|
|||
Set(text);
|
||||
}
|
||||
|
||||
public string Get()
|
||||
public readonly string Get()
|
||||
{
|
||||
fixed (byte* data = _data)
|
||||
{
|
||||
|
@ -29,7 +29,7 @@ namespace Ryujinx.Common.GraphicsDriver.NVAPI
|
|||
}
|
||||
}
|
||||
|
||||
public void Set(string text)
|
||||
public readonly void Set(string text)
|
||||
{
|
||||
text += '\0';
|
||||
fixed (char* textPtr = text)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Ryujinx.Common.GraphicsDriver.NVAPI
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
unsafe struct NvdrsApplicationV4
|
||||
struct NvdrsApplicationV4
|
||||
{
|
||||
public uint Version;
|
||||
public uint IsPredefined;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Ryujinx.Common.GraphicsDriver.NVAPI
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
unsafe struct NvdrsProfile
|
||||
struct NvdrsProfile
|
||||
{
|
||||
public uint Version;
|
||||
public NvapiUnicodeString ProfileName;
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Ryujinx.Common.GraphicsDriver.NVAPI
|
|||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0x3020)]
|
||||
unsafe struct NvdrsSetting
|
||||
struct NvdrsSetting
|
||||
{
|
||||
[FieldOffset(0x0)]
|
||||
public uint Version;
|
||||
|
|
|
@ -97,27 +97,26 @@ namespace Ryujinx.Common.GraphicsDriver
|
|||
|
||||
Check(NvAPI_DRS_LoadSettings(handle));
|
||||
|
||||
IntPtr profileHandle;
|
||||
|
||||
// Check if the profile already exists.
|
||||
|
||||
int status = NvAPI_DRS_FindProfileByName(handle, new NvapiUnicodeString(ProfileName), out profileHandle);
|
||||
int status = NvAPI_DRS_FindProfileByName(handle, new NvapiUnicodeString(ProfileName), out nint profileHandle);
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
NvdrsProfile profile = new NvdrsProfile {
|
||||
NvdrsProfile profile = new()
|
||||
{
|
||||
Version = MakeVersion<NvdrsProfile>(1),
|
||||
IsPredefined = 0,
|
||||
GpuSupport = uint.MaxValue
|
||||
GpuSupport = uint.MaxValue,
|
||||
};
|
||||
profile.ProfileName.Set(ProfileName);
|
||||
Check(NvAPI_DRS_CreateProfile(handle, ref profile, out profileHandle));
|
||||
|
||||
NvdrsApplicationV4 application = new NvdrsApplicationV4
|
||||
NvdrsApplicationV4 application = new()
|
||||
{
|
||||
Version = MakeVersion<NvdrsApplicationV4>(4),
|
||||
IsPredefined = 0,
|
||||
Flags = 3 // IsMetro, IsCommandLine
|
||||
Flags = 3, // IsMetro, IsCommandLine
|
||||
};
|
||||
application.AppName.Set("Ryujinx.exe");
|
||||
application.UserFriendlyName.Set("Ryujinx");
|
||||
|
@ -127,7 +126,7 @@ namespace Ryujinx.Common.GraphicsDriver
|
|||
Check(NvAPI_DRS_CreateApplication(handle, profileHandle, ref application));
|
||||
}
|
||||
|
||||
NvdrsSetting setting = new NvdrsSetting
|
||||
NvdrsSetting setting = new()
|
||||
{
|
||||
Version = MakeVersion<NvdrsSetting>(1),
|
||||
SettingId = Nvapi.OglThreadControlId,
|
||||
|
@ -136,7 +135,7 @@ namespace Ryujinx.Common.GraphicsDriver
|
|||
IsCurrentPredefined = 0,
|
||||
IsPredefinedValid = 0,
|
||||
CurrentValue = targetValue,
|
||||
PredefinedValue = targetValue
|
||||
PredefinedValue = targetValue,
|
||||
};
|
||||
|
||||
Check(NvAPI_DRS_SetSetting(handle, profileHandle, ref setting));
|
||||
|
@ -154,10 +153,8 @@ namespace Ryujinx.Common.GraphicsDriver
|
|||
{
|
||||
return Marshal.GetDelegateForFunctionPointer<T>(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Ryujinx.Common
|
|||
High = high;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
public readonly override string ToString()
|
||||
{
|
||||
return $"{High:x16}{Low:x16}";
|
||||
}
|
||||
|
@ -30,17 +30,17 @@ namespace Ryujinx.Common
|
|||
return !x.Equals(y);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public readonly override bool Equals(object obj)
|
||||
{
|
||||
return obj is Hash128 hash128 && Equals(hash128);
|
||||
}
|
||||
|
||||
public bool Equals(Hash128 cmpObj)
|
||||
public readonly bool Equals(Hash128 cmpObj)
|
||||
{
|
||||
return Low == cmpObj.Low && High == cmpObj.High;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
public readonly override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Low, High);
|
||||
}
|
||||
|
|
|
@ -5,11 +5,11 @@ namespace Ryujinx.Common.Logging.Formatters
|
|||
{
|
||||
internal class DefaultLogFormatter : ILogFormatter
|
||||
{
|
||||
private static readonly ObjectPool<StringBuilder> StringBuilderPool = SharedPools.Default<StringBuilder>();
|
||||
private static readonly ObjectPool<StringBuilder> _stringBuilderPool = SharedPools.Default<StringBuilder>();
|
||||
|
||||
public string Format(LogEventArgs args)
|
||||
{
|
||||
StringBuilder sb = StringBuilderPool.Allocate();
|
||||
StringBuilder sb = _stringBuilderPool.Allocate();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -44,7 +44,7 @@ namespace Ryujinx.Common.Logging.Formatters
|
|||
}
|
||||
finally
|
||||
{
|
||||
StringBuilderPool.Release(sb);
|
||||
_stringBuilderPool.Release(sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Ryujinx.Common.Logging.Formatters
|
|||
{
|
||||
internal static class DynamicObjectFormatter
|
||||
{
|
||||
private static readonly ObjectPool<StringBuilder> StringBuilderPool = SharedPools.Default<StringBuilder>();
|
||||
private static readonly ObjectPool<StringBuilder> _stringBuilderPool = SharedPools.Default<StringBuilder>();
|
||||
|
||||
public static string? Format(object? dynamicObject)
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ namespace Ryujinx.Common.Logging.Formatters
|
|||
return null;
|
||||
}
|
||||
|
||||
StringBuilder sb = StringBuilderPool.Allocate();
|
||||
StringBuilder sb = _stringBuilderPool.Allocate();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -26,7 +26,7 @@ namespace Ryujinx.Common.Logging.Formatters
|
|||
}
|
||||
finally
|
||||
{
|
||||
StringBuilderPool.Release(sb);
|
||||
_stringBuilderPool.Release(sb);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ namespace Ryujinx.Common.Logging.Formatters
|
|||
|
||||
if (typeof(Array).IsAssignableFrom(prop.PropertyType))
|
||||
{
|
||||
Array? array = (Array?) prop.GetValue(dynamicObject);
|
||||
Array? array = (Array?)prop.GetValue(dynamicObject);
|
||||
|
||||
if (array is not null)
|
||||
{
|
||||
|
|
|
@ -71,6 +71,6 @@ namespace Ryujinx.Common.Logging
|
|||
SurfaceFlinger,
|
||||
TamperMachine,
|
||||
Ui,
|
||||
Vic
|
||||
Vic,
|
||||
}
|
||||
}
|
|
@ -10,11 +10,11 @@ namespace Ryujinx.Common.Logging
|
|||
{
|
||||
public static class Logger
|
||||
{
|
||||
private static readonly Stopwatch m_Time;
|
||||
private static readonly Stopwatch _time;
|
||||
|
||||
private static readonly bool[] m_EnabledClasses;
|
||||
private static readonly bool[] _enabledClasses;
|
||||
|
||||
private static readonly List<ILogTarget> m_LogTargets;
|
||||
private static readonly List<ILogTarget> _logTargets;
|
||||
|
||||
private static readonly StdErrAdapter _stdErrAdapter;
|
||||
|
||||
|
@ -32,27 +32,27 @@ namespace Ryujinx.Common.Logging
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void PrintMsg(LogClass logClass, string message)
|
||||
{
|
||||
if (m_EnabledClasses[(int)logClass])
|
||||
if (_enabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, "", message)));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, "", message)));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Print(LogClass logClass, string message, [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (m_EnabledClasses[(int)logClass])
|
||||
if (_enabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message)));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message)));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Print(LogClass logClass, string message, object data, [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (m_EnabledClasses[(int)logClass])
|
||||
if (_enabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message), data));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message), data));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,47 +60,47 @@ namespace Ryujinx.Common.Logging
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void PrintStack(LogClass logClass, string message, [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (m_EnabledClasses[(int)logClass])
|
||||
if (_enabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message), new StackTrace(true)));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message), new StackTrace(true)));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void PrintStub(LogClass logClass, string message = "", [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (m_EnabledClasses[(int)logClass])
|
||||
if (_enabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed. " + message)));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed. " + message)));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void PrintStub(LogClass logClass, object data, [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (m_EnabledClasses[(int)logClass])
|
||||
if (_enabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed."), data));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed."), data));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void PrintStub(LogClass logClass, string message, object data, [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (m_EnabledClasses[(int)logClass])
|
||||
if (_enabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed. " + message), data));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed. " + message), data));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void PrintRawMsg(string message)
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, message));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, message));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static string FormatMessage(LogClass Class, string Caller, string Message) => $"{Class} {Caller}: {Message}";
|
||||
private static string FormatMessage(LogClass logClass, string caller, string message) => $"{logClass} {caller}: {message}";
|
||||
}
|
||||
|
||||
public static Log? Debug { get; private set; }
|
||||
|
@ -115,16 +115,16 @@ namespace Ryujinx.Common.Logging
|
|||
|
||||
static Logger()
|
||||
{
|
||||
m_EnabledClasses = new bool[Enum.GetNames<LogClass>().Length];
|
||||
_enabledClasses = new bool[Enum.GetNames<LogClass>().Length];
|
||||
|
||||
for (int index = 0; index < m_EnabledClasses.Length; index++)
|
||||
for (int index = 0; index < _enabledClasses.Length; index++)
|
||||
{
|
||||
m_EnabledClasses[index] = true;
|
||||
_enabledClasses[index] = true;
|
||||
}
|
||||
|
||||
m_LogTargets = new List<ILogTarget>();
|
||||
_logTargets = new List<ILogTarget>();
|
||||
|
||||
m_Time = Stopwatch.StartNew();
|
||||
_time = Stopwatch.StartNew();
|
||||
|
||||
// Logger should log to console by default
|
||||
AddTarget(new AsyncLogTargetWrapper(
|
||||
|
@ -145,12 +145,12 @@ namespace Ryujinx.Common.Logging
|
|||
|
||||
public static void RestartTime()
|
||||
{
|
||||
m_Time.Restart();
|
||||
_time.Restart();
|
||||
}
|
||||
|
||||
private static ILogTarget GetTarget(string targetName)
|
||||
{
|
||||
foreach (var target in m_LogTargets)
|
||||
foreach (var target in _logTargets)
|
||||
{
|
||||
if (target.Name.Equals(targetName))
|
||||
{
|
||||
|
@ -163,7 +163,7 @@ namespace Ryujinx.Common.Logging
|
|||
|
||||
public static void AddTarget(ILogTarget target)
|
||||
{
|
||||
m_LogTargets.Add(target);
|
||||
_logTargets.Add(target);
|
||||
|
||||
Updated += target.Log;
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ namespace Ryujinx.Common.Logging
|
|||
{
|
||||
Updated -= logTarget.Log;
|
||||
|
||||
m_LogTargets.Remove(logTarget);
|
||||
_logTargets.Remove(logTarget);
|
||||
|
||||
logTarget.Dispose();
|
||||
}
|
||||
|
@ -188,18 +188,18 @@ namespace Ryujinx.Common.Logging
|
|||
|
||||
_stdErrAdapter.Dispose();
|
||||
|
||||
foreach (var target in m_LogTargets)
|
||||
foreach (var target in _logTargets)
|
||||
{
|
||||
target.Dispose();
|
||||
}
|
||||
|
||||
m_LogTargets.Clear();
|
||||
_logTargets.Clear();
|
||||
}
|
||||
|
||||
public static IReadOnlyCollection<LogLevel> GetEnabledLevels()
|
||||
{
|
||||
var logs = new Log?[] { Debug, Info, Warning, Error, Guest, AccessLog, Stub, Trace };
|
||||
List<LogLevel> levels = new List<LogLevel>(logs.Length);
|
||||
var logs = new[] { Debug, Info, Warning, Error, Guest, AccessLog, Stub, Trace };
|
||||
List<LogLevel> levels = new(logs.Length);
|
||||
foreach (var log in logs)
|
||||
{
|
||||
if (log.HasValue)
|
||||
|
@ -215,21 +215,23 @@ namespace Ryujinx.Common.Logging
|
|||
{
|
||||
switch (logLevel)
|
||||
{
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
case LogLevel.Debug : Debug = enabled ? new Log(LogLevel.Debug) : new Log?(); break;
|
||||
case LogLevel.Info : Info = enabled ? new Log(LogLevel.Info) : new Log?(); break;
|
||||
case LogLevel.Warning : Warning = enabled ? new Log(LogLevel.Warning) : new Log?(); break;
|
||||
case LogLevel.Error : Error = enabled ? new Log(LogLevel.Error) : new Log?(); break;
|
||||
case LogLevel.Guest : Guest = enabled ? new Log(LogLevel.Guest) : new Log?(); break;
|
||||
case LogLevel.AccessLog : AccessLog = enabled ? new Log(LogLevel.AccessLog): new Log?(); break;
|
||||
case LogLevel.AccessLog : AccessLog = enabled ? new Log(LogLevel.AccessLog) : new Log?(); break;
|
||||
case LogLevel.Stub : Stub = enabled ? new Log(LogLevel.Stub) : new Log?(); break;
|
||||
case LogLevel.Trace : Trace = enabled ? new Log(LogLevel.Trace) : new Log?(); break;
|
||||
default: throw new ArgumentException("Unknown Log Level");
|
||||
#pragma warning restore IDE0055
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetEnable(LogClass logClass, bool enabled)
|
||||
{
|
||||
m_EnabledClasses[(int)logClass] = enabled;
|
||||
_enabledClasses[(int)logClass] = enabled;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,16 +14,16 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
/// <summary>
|
||||
/// Discard the overflowing item
|
||||
/// </summary>
|
||||
Discard = 1
|
||||
Discard = 1,
|
||||
}
|
||||
|
||||
public class AsyncLogTargetWrapper : ILogTarget
|
||||
{
|
||||
private ILogTarget _target;
|
||||
private readonly ILogTarget _target;
|
||||
|
||||
private Thread _messageThread;
|
||||
private readonly Thread _messageThread;
|
||||
|
||||
private BlockingCollection<LogEventArgs> _messageQueue;
|
||||
private readonly BlockingCollection<LogEventArgs> _messageQueue;
|
||||
|
||||
private readonly int _overflowTimeout;
|
||||
|
||||
|
@ -39,7 +39,8 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
_messageQueue = new BlockingCollection<LogEventArgs>(queueLimit);
|
||||
_overflowTimeout = overflowAction == AsyncLogTargetOverflowAction.Block ? -1 : 0;
|
||||
|
||||
_messageThread = new Thread(() => {
|
||||
_messageThread = new Thread(() =>
|
||||
{
|
||||
while (!_messageQueue.IsCompleted)
|
||||
{
|
||||
try
|
||||
|
@ -55,10 +56,11 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
// on the next iteration.
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_messageThread.Name = "Logger.MessageThread";
|
||||
_messageThread.IsBackground = true;
|
||||
})
|
||||
{
|
||||
Name = "Logger.MessageThread",
|
||||
IsBackground = true,
|
||||
};
|
||||
_messageThread.Start();
|
||||
}
|
||||
|
||||
|
@ -72,6 +74,7 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
_messageQueue.CompleteAdding();
|
||||
_messageThread.Join();
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
|
||||
string ILogTarget.Name { get => _name; }
|
||||
|
||||
private static ConsoleColor GetLogColor(LogLevel level) => level switch {
|
||||
private static ConsoleColor GetLogColor(LogLevel level) => level switch
|
||||
{
|
||||
LogLevel.Info => ConsoleColor.White,
|
||||
LogLevel.Warning => ConsoleColor.Yellow,
|
||||
LogLevel.Error => ConsoleColor.Red,
|
||||
|
@ -36,6 +37,7 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
Console.ResetColor();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
public FileLogTarget(string path, string name, FileShare fileShare, FileMode fileMode)
|
||||
{
|
||||
// Ensure directory is present
|
||||
DirectoryInfo logDir = new DirectoryInfo(Path.Combine(path, "Logs"));
|
||||
DirectoryInfo logDir = new(Path.Combine(path, "Logs"));
|
||||
logDir.Create();
|
||||
|
||||
// Clean up old logs, should only keep 3
|
||||
|
@ -33,7 +33,7 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
string version = ReleaseInformation.GetVersion();
|
||||
|
||||
// Get path for the current time
|
||||
path = Path.Combine(logDir.FullName, $"Ryujinx_{version}_{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.log");
|
||||
path = Path.Combine(logDir.FullName, $"Ryujinx_{version}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log");
|
||||
|
||||
_name = name;
|
||||
_logWriter = new StreamWriter(File.Open(path, fileMode, FileAccess.Write, fileShare));
|
||||
|
@ -48,6 +48,7 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
_logWriter.WriteLine("---- End of Log ----");
|
||||
_logWriter.Flush();
|
||||
_logWriter.Dispose();
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.Common.Logging.Targets
|
||||
{
|
||||
public class JsonLogTarget : ILogTarget
|
||||
{
|
||||
private Stream _stream;
|
||||
private bool _leaveOpen;
|
||||
private string _name;
|
||||
private readonly Stream _stream;
|
||||
private readonly bool _leaveOpen;
|
||||
private readonly string _name;
|
||||
|
||||
string ILogTarget.Name { get => _name; }
|
||||
|
||||
|
@ -31,6 +32,7 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
if (!_leaveOpen)
|
||||
{
|
||||
_stream.Dispose();
|
||||
|
|
|
@ -16,12 +16,12 @@ namespace Ryujinx.Common.Memory
|
|||
/// <summary>
|
||||
/// Null pointer.
|
||||
/// </summary>
|
||||
public static ArrayPtr<T> Null => new ArrayPtr<T>() { _ptr = IntPtr.Zero };
|
||||
public static ArrayPtr<T> Null => new() { _ptr = IntPtr.Zero };
|
||||
|
||||
/// <summary>
|
||||
/// True if the pointer is null, false otherwise.
|
||||
/// </summary>
|
||||
public bool IsNull => _ptr == IntPtr.Zero;
|
||||
public readonly bool IsNull => _ptr == IntPtr.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Number of elements on the array.
|
||||
|
@ -37,7 +37,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// </remarks>
|
||||
/// <param name="index">Index of the element</param>
|
||||
/// <returns>Reference to the element at the given index</returns>
|
||||
public ref T this[int index] => ref Unsafe.AsRef<T>((T*)_ptr + index);
|
||||
public readonly ref T this[int index] => ref Unsafe.AsRef<T>((T*)_ptr + index);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new array from a given reference.
|
||||
|
@ -81,7 +81,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// </summary>
|
||||
/// <param name="start">Index where the new array should start</param>
|
||||
/// <returns>New array starting at the specified position</returns>
|
||||
public ArrayPtr<T> Slice(int start) => new ArrayPtr<T>(ref this[start], Length - start);
|
||||
public ArrayPtr<T> Slice(int start) => new(ref this[start], Length - start);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a span from the array.
|
||||
|
@ -93,19 +93,19 @@ namespace Ryujinx.Common.Memory
|
|||
/// Gets the array base pointer.
|
||||
/// </summary>
|
||||
/// <returns>Base pointer</returns>
|
||||
public T* ToPointer() => (T*)_ptr;
|
||||
public readonly T* ToPointer() => (T*)_ptr;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public readonly override bool Equals(object obj)
|
||||
{
|
||||
return obj is ArrayPtr<T> other && Equals(other);
|
||||
}
|
||||
|
||||
public bool Equals([AllowNull] ArrayPtr<T> other)
|
||||
public readonly bool Equals([AllowNull] ArrayPtr<T> other)
|
||||
{
|
||||
return _ptr == other._ptr && Length == other.Length;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
public readonly override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(_ptr, Length);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// </summary>
|
||||
public sealed partial class ByteMemoryPool
|
||||
{
|
||||
private static readonly ByteMemoryPool _shared = new ByteMemoryPool();
|
||||
private static readonly ByteMemoryPool _shared = new();
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a <see cref="ByteMemoryPool"/> instance. Private to force access through
|
||||
|
@ -27,7 +27,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// <summary>
|
||||
/// Returns the maximum buffer size supported by this pool.
|
||||
/// </summary>
|
||||
public int MaxBufferSize => Array.MaxLength;
|
||||
public static int MaxBufferSize => Array.MaxLength;
|
||||
|
||||
/// <summary>
|
||||
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
|
||||
|
@ -36,7 +36,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public IMemoryOwner<byte> Rent(long length)
|
||||
public static IMemoryOwner<byte> Rent(long length)
|
||||
=> RentImpl(checked((int)length));
|
||||
|
||||
/// <summary>
|
||||
|
@ -46,7 +46,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public IMemoryOwner<byte> Rent(ulong length)
|
||||
public static IMemoryOwner<byte> Rent(ulong length)
|
||||
=> RentImpl(checked((int)length));
|
||||
|
||||
/// <summary>
|
||||
|
@ -56,7 +56,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public IMemoryOwner<byte> Rent(int length)
|
||||
public static IMemoryOwner<byte> Rent(int length)
|
||||
=> RentImpl(length);
|
||||
|
||||
/// <summary>
|
||||
|
@ -66,7 +66,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public IMemoryOwner<byte> RentCleared(long length)
|
||||
public static IMemoryOwner<byte> RentCleared(long length)
|
||||
=> RentCleared(checked((int)length));
|
||||
|
||||
/// <summary>
|
||||
|
@ -76,7 +76,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public IMemoryOwner<byte> RentCleared(ulong length)
|
||||
public static IMemoryOwner<byte> RentCleared(ulong length)
|
||||
=> RentCleared(checked((int)length));
|
||||
|
||||
/// <summary>
|
||||
|
@ -86,7 +86,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public IMemoryOwner<byte> RentCleared(int length)
|
||||
public static IMemoryOwner<byte> RentCleared(int length)
|
||||
{
|
||||
var buffer = RentImpl(length);
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace Ryujinx.Common.Memory
|
|||
{
|
||||
public static class MemoryStreamManager
|
||||
{
|
||||
private static readonly RecyclableMemoryStreamManager _shared = new RecyclableMemoryStreamManager();
|
||||
private static readonly RecyclableMemoryStreamManager _shared = new();
|
||||
|
||||
/// <summary>
|
||||
/// We don't expose the <c>RecyclableMemoryStreamManager</c> directly because version 2.x
|
||||
|
@ -19,7 +19,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// </summary>
|
||||
/// <returns>A <c>RecyclableMemoryStream</c></returns>
|
||||
public static RecyclableMemoryStream GetStream()
|
||||
=> new RecyclableMemoryStream(_shared);
|
||||
=> new(_shared);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a new <c>MemoryStream</c> object with the contents copied from the provided
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers;
|
||||
|
||||
namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||
|
@ -14,15 +13,15 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||
public int WriteLock;
|
||||
public int ReaderCount;
|
||||
|
||||
public static int WriteLockOffset;
|
||||
public static int ReaderCountOffset;
|
||||
public static readonly int WriteLockOffset;
|
||||
public static readonly int ReaderCountOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Populates the field offsets for use when emitting native code.
|
||||
/// </summary>
|
||||
static NativeReaderWriterLock()
|
||||
{
|
||||
NativeReaderWriterLock instance = new NativeReaderWriterLock();
|
||||
NativeReaderWriterLock instance = new();
|
||||
|
||||
WriteLockOffset = OffsetOf(ref instance, ref instance.WriteLock);
|
||||
ReaderCountOffset = OffsetOf(ref instance, ref instance.ReaderCount);
|
||||
|
@ -35,7 +34,9 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||
{
|
||||
// Must take write lock for a very short time to become a reader.
|
||||
|
||||
while (Interlocked.CompareExchange(ref WriteLock, 1, 0) != 0) { }
|
||||
while (Interlocked.CompareExchange(ref WriteLock, 1, 0) != 0)
|
||||
{
|
||||
}
|
||||
|
||||
Interlocked.Increment(ref ReaderCount);
|
||||
|
||||
|
@ -60,11 +61,15 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||
|
||||
Interlocked.Decrement(ref ReaderCount);
|
||||
|
||||
while (Interlocked.CompareExchange(ref WriteLock, 1, 0) != 0) { }
|
||||
while (Interlocked.CompareExchange(ref WriteLock, 1, 0) != 0)
|
||||
{
|
||||
}
|
||||
|
||||
// Wait for reader count to drop to 0, then take the lock again as the only reader.
|
||||
|
||||
while (Interlocked.CompareExchange(ref ReaderCount, 1, 0) != 0) { }
|
||||
while (Interlocked.CompareExchange(ref ReaderCount, 1, 0) != 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
|
||||
using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers;
|
||||
|
||||
namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||
|
@ -35,7 +33,7 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||
|
||||
[SupportedOSPlatform("windows")]
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs (UnmanagedType.Bool)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static partial bool CloseHandle(IntPtr hObject);
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
|
@ -48,7 +46,7 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||
/// </summary>
|
||||
static unsafe PartialUnmapState()
|
||||
{
|
||||
PartialUnmapState instance = new PartialUnmapState();
|
||||
PartialUnmapState instance = new();
|
||||
|
||||
PartialUnmapLockOffset = OffsetOf(ref instance, ref instance.PartialUnmapLock);
|
||||
PartialUnmapsCountOffset = OffsetOf(ref instance, ref instance.PartialUnmapsCount);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers;
|
||||
|
||||
namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||
|
@ -18,15 +17,15 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||
public Array20<int> ThreadIds;
|
||||
public Array20<T> Structs;
|
||||
|
||||
public static int ThreadIdsOffset;
|
||||
public static int StructsOffset;
|
||||
public static readonly int ThreadIdsOffset;
|
||||
public static readonly int StructsOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Populates the field offsets for use when emitting native code.
|
||||
/// </summary>
|
||||
static ThreadLocalMap()
|
||||
{
|
||||
ThreadLocalMap<T> instance = new ThreadLocalMap<T>();
|
||||
ThreadLocalMap<T> instance = new();
|
||||
|
||||
ThreadIdsOffset = OffsetOf(ref instance, ref instance.ThreadIds);
|
||||
StructsOffset = OffsetOf(ref instance, ref instance.Structs);
|
||||
|
|
|
@ -15,17 +15,17 @@ namespace Ryujinx.Common.Memory
|
|||
/// <summary>
|
||||
/// Null pointer.
|
||||
/// </summary>
|
||||
public static Ptr<T> Null => new Ptr<T>() { _ptr = IntPtr.Zero };
|
||||
public static Ptr<T> Null => new() { _ptr = IntPtr.Zero };
|
||||
|
||||
/// <summary>
|
||||
/// True if the pointer is null, false otherwise.
|
||||
/// </summary>
|
||||
public bool IsNull => _ptr == IntPtr.Zero;
|
||||
public readonly bool IsNull => _ptr == IntPtr.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a reference to the value.
|
||||
/// </summary>
|
||||
public ref T Value => ref Unsafe.AsRef<T>((void*)_ptr);
|
||||
public readonly ref T Value => ref Unsafe.AsRef<T>((void*)_ptr);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new pointer to an unmanaged resource.
|
||||
|
@ -40,17 +40,17 @@ namespace Ryujinx.Common.Memory
|
|||
_ptr = (IntPtr)Unsafe.AsPointer(ref value);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public readonly override bool Equals(object obj)
|
||||
{
|
||||
return obj is Ptr<T> other && Equals(other);
|
||||
}
|
||||
|
||||
public bool Equals([AllowNull] Ptr<T> other)
|
||||
public readonly bool Equals([AllowNull] Ptr<T> other)
|
||||
{
|
||||
return _ptr == other._ptr;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
public readonly override int GetHashCode()
|
||||
{
|
||||
return _ptr.GetHashCode();
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace Ryujinx.Common.Memory
|
|||
{
|
||||
private ReadOnlySpan<byte> _input;
|
||||
|
||||
public int Length => _input.Length;
|
||||
public readonly int Length => _input.Length;
|
||||
|
||||
public SpanReader(ReadOnlySpan<byte> input)
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ namespace Ryujinx.Common.Memory
|
|||
{
|
||||
T value = MemoryMarshal.Cast<byte, T>(_input)[0];
|
||||
|
||||
_input = _input.Slice(Unsafe.SizeOf<T>());
|
||||
_input = _input[Unsafe.SizeOf<T>()..];
|
||||
|
||||
return value;
|
||||
}
|
||||
|
@ -37,16 +37,16 @@ namespace Ryujinx.Common.Memory
|
|||
|
||||
value = MemoryMarshal.Cast<byte, T>(_input)[0];
|
||||
|
||||
_input = _input.Slice(valueSize);
|
||||
_input = _input[valueSize..];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> GetSpan(int size)
|
||||
{
|
||||
ReadOnlySpan<byte> data = _input.Slice(0, size);
|
||||
ReadOnlySpan<byte> data = _input[..size];
|
||||
|
||||
_input = _input.Slice(size);
|
||||
_input = _input[size..];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -56,19 +56,19 @@ namespace Ryujinx.Common.Memory
|
|||
return GetSpan((int)Math.Min((uint)_input.Length, (uint)size));
|
||||
}
|
||||
|
||||
public T ReadAt<T>(int offset) where T : unmanaged
|
||||
public readonly T ReadAt<T>(int offset) where T : unmanaged
|
||||
{
|
||||
return MemoryMarshal.Cast<byte, T>(_input.Slice(offset))[0];
|
||||
return MemoryMarshal.Cast<byte, T>(_input[offset..])[0];
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> GetSpanAt(int offset, int size)
|
||||
public readonly ReadOnlySpan<byte> GetSpanAt(int offset, int size)
|
||||
{
|
||||
return _input.Slice(offset, size);
|
||||
}
|
||||
|
||||
public void Skip(int size)
|
||||
{
|
||||
_input = _input.Slice(size);
|
||||
_input = _input[size..];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ namespace Ryujinx.Common.Memory
|
|||
{
|
||||
private Span<byte> _output;
|
||||
|
||||
public int Length => _output.Length;
|
||||
public readonly int Length => _output.Length;
|
||||
|
||||
public SpanWriter(Span<byte> output)
|
||||
{
|
||||
|
@ -18,28 +18,28 @@ namespace Ryujinx.Common.Memory
|
|||
public void Write<T>(T value) where T : unmanaged
|
||||
{
|
||||
MemoryMarshal.Cast<byte, T>(_output)[0] = value;
|
||||
_output = _output.Slice(Unsafe.SizeOf<T>());
|
||||
_output = _output[Unsafe.SizeOf<T>()..];
|
||||
}
|
||||
|
||||
public void Write(ReadOnlySpan<byte> data)
|
||||
{
|
||||
data.CopyTo(_output.Slice(0, data.Length));
|
||||
_output = _output.Slice(data.Length);
|
||||
data.CopyTo(_output[..data.Length]);
|
||||
_output = _output[data.Length..];
|
||||
}
|
||||
|
||||
public void WriteAt<T>(int offset, T value) where T : unmanaged
|
||||
public readonly void WriteAt<T>(int offset, T value) where T : unmanaged
|
||||
{
|
||||
MemoryMarshal.Cast<byte, T>(_output.Slice(offset))[0] = value;
|
||||
MemoryMarshal.Cast<byte, T>(_output[offset..])[0] = value;
|
||||
}
|
||||
|
||||
public void WriteAt(int offset, ReadOnlySpan<byte> data)
|
||||
public readonly void WriteAt(int offset, ReadOnlySpan<byte> data)
|
||||
{
|
||||
data.CopyTo(_output.Slice(offset, data.Length));
|
||||
}
|
||||
|
||||
public void Skip(int size)
|
||||
{
|
||||
_output = _output.Slice(size);
|
||||
_output = _output[size..];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,654 +1,658 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#pragma warning disable CS0169, IDE0051 // Remove unused private member
|
||||
namespace Ryujinx.Common.Memory
|
||||
{
|
||||
public struct Array1<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
T _e0;
|
||||
public int Length => 1;
|
||||
public readonly int Length => 1;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 1);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array2<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array1<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 2;
|
||||
public readonly int Length => 2;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 2);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array3<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array2<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 3;
|
||||
public readonly int Length => 3;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 3);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array4<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array3<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 4;
|
||||
public readonly int Length => 4;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 4);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array5<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array4<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 5;
|
||||
public readonly int Length => 5;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 5);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array6<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array5<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 6;
|
||||
public readonly int Length => 6;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 6);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array7<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array6<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 7;
|
||||
public readonly int Length => 7;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 7);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array8<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array7<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 8;
|
||||
public readonly int Length => 8;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 8);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array9<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array8<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 9;
|
||||
public readonly int Length => 9;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 9);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array10<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array9<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 10;
|
||||
public readonly int Length => 10;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 10);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array11<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array10<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 11;
|
||||
public readonly int Length => 11;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 11);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array12<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array11<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 12;
|
||||
public readonly int Length => 12;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 12);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array13<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array12<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 13;
|
||||
public readonly int Length => 13;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 13);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array14<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array13<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 14;
|
||||
public readonly int Length => 14;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 14);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array15<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array14<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 15;
|
||||
public readonly int Length => 15;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 15);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array16<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array15<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 16;
|
||||
public readonly int Length => 16;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 16);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array17<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array16<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 17;
|
||||
public readonly int Length => 17;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 17);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array18<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array17<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 18;
|
||||
public readonly int Length => 18;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 18);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array19<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array18<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 19;
|
||||
public readonly int Length => 19;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 19);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array20<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array19<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 20;
|
||||
public readonly int Length => 20;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 20);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array21<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array20<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 21;
|
||||
public readonly int Length => 21;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 21);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array22<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array21<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 22;
|
||||
public readonly int Length => 22;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 22);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array23<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array22<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 23;
|
||||
public readonly int Length => 23;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 23);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array24<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array23<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 24;
|
||||
|
||||
public readonly int Length => 24;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 24);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array25<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array24<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 25;
|
||||
|
||||
public readonly int Length => 25;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 25);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array26<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array25<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 26;
|
||||
|
||||
public readonly int Length => 26;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 26);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array27<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array26<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 27;
|
||||
|
||||
public readonly int Length => 27;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 27);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array28<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array27<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 28;
|
||||
|
||||
public readonly int Length => 28;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 28);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array29<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array28<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 29;
|
||||
|
||||
public readonly int Length => 29;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 29);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array30<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array29<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 30;
|
||||
|
||||
public readonly int Length => 30;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 30);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array31<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array30<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 31;
|
||||
|
||||
public readonly int Length => 31;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 31);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array32<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array31<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 32;
|
||||
|
||||
public readonly int Length => 32;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 32);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array33<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array32<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 33;
|
||||
|
||||
public readonly int Length => 33;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 33);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array34<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array33<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 34;
|
||||
|
||||
public readonly int Length => 34;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 34);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array35<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array34<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 35;
|
||||
|
||||
public readonly int Length => 35;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 35);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array36<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array35<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 36;
|
||||
|
||||
public readonly int Length => 36;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 36);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array37<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array36<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 37;
|
||||
|
||||
public readonly int Length => 37;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 37);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array38<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array37<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 38;
|
||||
|
||||
public readonly int Length => 38;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 38);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array39<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array38<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 39;
|
||||
|
||||
public readonly int Length => 39;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 39);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array40<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array39<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 40;
|
||||
|
||||
public readonly int Length => 40;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 40);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array41<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array40<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 41;
|
||||
|
||||
public readonly int Length => 41;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 41);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array42<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array41<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 42;
|
||||
|
||||
public readonly int Length => 42;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 42);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array43<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array42<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 43;
|
||||
|
||||
public readonly int Length => 43;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 43);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array44<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array43<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 44;
|
||||
|
||||
public readonly int Length => 44;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 44);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array45<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array44<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 45;
|
||||
|
||||
public readonly int Length => 45;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 45);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array46<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array45<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 46;
|
||||
|
||||
public readonly int Length => 46;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 46);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array47<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array46<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 47;
|
||||
|
||||
public readonly int Length => 47;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 47);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array48<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array47<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 48;
|
||||
|
||||
public readonly int Length => 48;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 48);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array49<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array48<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 49;
|
||||
|
||||
public readonly int Length => 49;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 49);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array50<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array49<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 50;
|
||||
|
||||
public readonly int Length => 50;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 50);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array51<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array50<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 51;
|
||||
|
||||
public readonly int Length => 51;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 51);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array52<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array51<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 52;
|
||||
|
||||
public readonly int Length => 52;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 52);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array53<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array52<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 53;
|
||||
|
||||
public readonly int Length => 53;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 53);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array54<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array53<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 54;
|
||||
|
||||
public readonly int Length => 54;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 54);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array55<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array54<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 55;
|
||||
|
||||
public readonly int Length => 55;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 55);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array56<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array55<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 56;
|
||||
|
||||
public readonly int Length => 56;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 56);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array57<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array56<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 57;
|
||||
|
||||
public readonly int Length => 57;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 57);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array58<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array57<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 58;
|
||||
|
||||
public readonly int Length => 58;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 58);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array59<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array58<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 59;
|
||||
|
||||
public readonly int Length => 59;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 59);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array60<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array59<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 60;
|
||||
public readonly int Length => 60;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 60);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array61<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array60<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 61;
|
||||
public readonly int Length => 61;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 61);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array62<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array61<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 62;
|
||||
public readonly int Length => 62;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 62);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array63<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array62<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 63;
|
||||
public readonly int Length => 63;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 63);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array64<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array63<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 64;
|
||||
public readonly int Length => 64;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 64);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array73<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array64<T> _other;
|
||||
Array8<T> _other2;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 73;
|
||||
public readonly int Length => 73;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 73);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array127<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
T _e0;
|
||||
Array64<T> _other;
|
||||
Array62<T> _other2;
|
||||
public readonly int Length => 127;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array128<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
T _e0;
|
||||
Array64<T> _other;
|
||||
Array63<T> _other2;
|
||||
public readonly int Length => 128;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array256<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
T _e0;
|
||||
Array128<T> _other;
|
||||
Array127<T> _other2;
|
||||
public readonly int Length => 256;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0169, IDE0051
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Ryujinx.Common.Memory
|
|||
|
||||
byte _element;
|
||||
|
||||
public int Length => Size;
|
||||
public readonly int Length => Size;
|
||||
public ref byte this[int index] => ref AsSpan()[index];
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ namespace Ryujinx.Common.Memory
|
|||
|
||||
byte _element;
|
||||
|
||||
public int Length => Size;
|
||||
public readonly int Length => Size;
|
||||
public ref byte this[int index] => ref AsSpan()[index];
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ namespace Ryujinx.Common.Memory
|
|||
|
||||
byte _element;
|
||||
|
||||
public int Length => Size;
|
||||
public readonly int Length => Size;
|
||||
public ref byte this[int index] => ref AsSpan()[index];
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ namespace Ryujinx.Common.Memory
|
|||
|
||||
byte _element;
|
||||
|
||||
public int Length => Size;
|
||||
public readonly int Length => Size;
|
||||
public ref byte this[int index] => ref AsSpan()[index];
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size);
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ namespace Ryujinx.Common.Memory
|
|||
|
||||
byte _element;
|
||||
|
||||
public int Length => Size;
|
||||
public readonly int Length => Size;
|
||||
public ref byte this[int index] => ref AsSpan()[index];
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size);
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ namespace Ryujinx.Common.Memory
|
|||
|
||||
byte _element;
|
||||
|
||||
public int Length => Size;
|
||||
public readonly int Length => Size;
|
||||
public ref byte this[int index] => ref AsSpan()[index];
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
using System.Diagnostics;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
public static class PerformanceCounter
|
||||
{
|
||||
private static double _ticksToNs;
|
||||
private static readonly double _ticksToNs;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the number of ticks in 1 day.
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
private static class DefaultPool<T>
|
||||
where T : class, new()
|
||||
{
|
||||
public static readonly ObjectPool<T> Instance = new ObjectPool<T>(() => new T(), 20);
|
||||
public static readonly ObjectPool<T> Instance = new(() => new T(), 20);
|
||||
}
|
||||
|
||||
public static ObjectPool<T> Default<T>()
|
||||
|
|
|
@ -9,10 +9,7 @@ namespace Ryujinx.Common.Pools
|
|||
|
||||
public static ref T[] Get()
|
||||
{
|
||||
if (_array == null)
|
||||
{
|
||||
_array = new T[1];
|
||||
}
|
||||
_array ??= new T[1];
|
||||
|
||||
return ref _array;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ namespace Ryujinx.Common
|
|||
{
|
||||
public class ReactiveObject<T>
|
||||
{
|
||||
private ReaderWriterLock _readerWriterLock = new ReaderWriterLock();
|
||||
private bool _isInitialized = false;
|
||||
private readonly ReaderWriterLock _readerWriterLock = new();
|
||||
private bool _isInitialized;
|
||||
private T _value;
|
||||
|
||||
public event EventHandler<ReactiveEventArgs<T>> Event;
|
||||
|
|
|
@ -9,11 +9,11 @@ namespace Ryujinx.Common
|
|||
{
|
||||
private const string FlatHubChannelOwner = "flathub";
|
||||
|
||||
public static string BuildVersion = "%%RYUJINX_BUILD_VERSION%%";
|
||||
public static string BuildGitHash = "%%RYUJINX_BUILD_GIT_HASH%%";
|
||||
public static string ReleaseChannelName = "%%RYUJINX_TARGET_RELEASE_CHANNEL_NAME%%";
|
||||
public static string ReleaseChannelOwner = "%%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER%%";
|
||||
public static string ReleaseChannelRepo = "%%RYUJINX_TARGET_RELEASE_CHANNEL_REPO%%";
|
||||
public const string BuildVersion = "%%RYUJINX_BUILD_VERSION%%";
|
||||
public const string BuildGitHash = "%%RYUJINX_BUILD_GIT_HASH%%";
|
||||
public const string ReleaseChannelName = "%%RYUJINX_TARGET_RELEASE_CHANNEL_NAME%%";
|
||||
public const string ReleaseChannelOwner = "%%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER%%";
|
||||
public const string ReleaseChannelRepo = "%%RYUJINX_TARGET_RELEASE_CHANNEL_REPO%%";
|
||||
|
||||
public static bool IsValid()
|
||||
{
|
||||
|
@ -34,11 +34,9 @@ namespace Ryujinx.Common
|
|||
{
|
||||
return BuildVersion;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
||||
}
|
||||
}
|
||||
|
||||
#if FORCE_EXTERNAL_BASE_DIR
|
||||
public static string GetBaseApplicationDirectory()
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Ryujinx.Common.SystemInfo
|
|||
{
|
||||
["model name"] = null,
|
||||
["Processor"] = null,
|
||||
["Hardware"] = null
|
||||
["Hardware"] = null,
|
||||
};
|
||||
|
||||
ParseKeyValues("/proc/cpuinfo", cpuDict);
|
||||
|
@ -31,7 +31,7 @@ namespace Ryujinx.Common.SystemInfo
|
|||
var memDict = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["MemTotal"] = null,
|
||||
["MemAvailable"] = null
|
||||
["MemAvailable"] = null,
|
||||
};
|
||||
|
||||
ParseKeyValues("/proc/meminfo", memDict);
|
||||
|
@ -56,14 +56,17 @@ namespace Ryujinx.Common.SystemInfo
|
|||
|
||||
int count = itemDict.Count;
|
||||
|
||||
using (StreamReader file = new StreamReader(filePath))
|
||||
{
|
||||
using StreamReader file = new(filePath);
|
||||
|
||||
string line;
|
||||
while ((line = file.ReadLine()) != null)
|
||||
{
|
||||
string[] kvPair = line.Split(':', 2, StringSplitOptions.TrimEntries);
|
||||
|
||||
if (kvPair.Length < 2) continue;
|
||||
if (kvPair.Length < 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string key = kvPair[0];
|
||||
|
||||
|
@ -71,7 +74,9 @@ namespace Ryujinx.Common.SystemInfo
|
|||
{
|
||||
itemDict[key] = kvPair[1];
|
||||
|
||||
if (--count <= 0) break;
|
||||
if (--count <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,14 +14,14 @@ namespace Ryujinx.Common.SystemInfo
|
|||
{
|
||||
string cpuName = GetCpuidCpuName();
|
||||
|
||||
if (cpuName == null && sysctlbyname("machdep.cpu.brand_string", out cpuName) != 0)
|
||||
if (cpuName == null && SysctlByName("machdep.cpu.brand_string", out cpuName) != 0)
|
||||
{
|
||||
cpuName = "Unknown";
|
||||
}
|
||||
|
||||
ulong totalRAM = 0;
|
||||
|
||||
if (sysctlbyname("hw.memsize", ref totalRAM) != 0) // Bytes
|
||||
if (SysctlByName("hw.memsize", ref totalRAM) != 0) // Bytes
|
||||
{
|
||||
totalRAM = 0;
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ namespace Ryujinx.Common.SystemInfo
|
|||
[LibraryImport(SystemLibraryName, SetLastError = true)]
|
||||
private static partial int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string name, IntPtr oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
|
||||
|
||||
private static int sysctlbyname(string name, IntPtr oldValue, ref ulong oldSize)
|
||||
private static int SysctlByName(string name, IntPtr oldValue, ref ulong oldSize)
|
||||
{
|
||||
if (sysctlbyname(name, oldValue, ref oldSize, IntPtr.Zero, 0) == -1)
|
||||
{
|
||||
|
@ -77,23 +77,23 @@ namespace Ryujinx.Common.SystemInfo
|
|||
return 0;
|
||||
}
|
||||
|
||||
private static int sysctlbyname<T>(string name, ref T oldValue)
|
||||
private static int SysctlByName<T>(string name, ref T oldValue)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
ulong oldValueSize = (ulong)Unsafe.SizeOf<T>();
|
||||
|
||||
return sysctlbyname(name, (IntPtr)Unsafe.AsPointer(ref oldValue), ref oldValueSize);
|
||||
return SysctlByName(name, (IntPtr)Unsafe.AsPointer(ref oldValue), ref oldValueSize);
|
||||
}
|
||||
}
|
||||
|
||||
private static int sysctlbyname(string name, out string oldValue)
|
||||
private static int SysctlByName(string name, out string oldValue)
|
||||
{
|
||||
oldValue = default;
|
||||
|
||||
ulong strSize = 0;
|
||||
|
||||
int res = sysctlbyname(name, IntPtr.Zero, ref strSize);
|
||||
int res = SysctlByName(name, IntPtr.Zero, ref strSize);
|
||||
|
||||
if (res == 0)
|
||||
{
|
||||
|
@ -103,7 +103,7 @@ namespace Ryujinx.Common.SystemInfo
|
|||
{
|
||||
fixed (byte* rawDataPtr = rawData)
|
||||
{
|
||||
res = sysctlbyname(name, (IntPtr)rawDataPtr, ref strSize);
|
||||
res = SysctlByName(name, (IntPtr)rawDataPtr, ref strSize);
|
||||
}
|
||||
|
||||
if (res == 0)
|
||||
|
@ -152,6 +152,6 @@ namespace Ryujinx.Common.SystemInfo
|
|||
}
|
||||
|
||||
[LibraryImport(SystemLibraryName, SetLastError = true)]
|
||||
private static partial int host_statistics64(uint host_priv, int host_flavor, ref VMStatistics64 host_info64_out, ref uint host_info64_outCnt);
|
||||
private static partial int host_statistics64(uint hostPriv, int hostFlavor, ref VMStatistics64 hostInfo64Out, ref uint hostInfo64OutCnt);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,13 +43,11 @@ namespace Ryujinx.Common.SystemInfo
|
|||
{
|
||||
return new MacOSSystemInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Logger.Error?.Print(LogClass.Application, "SystemInfo unsupported on this platform");
|
||||
|
||||
return new SystemInfo();
|
||||
}
|
||||
}
|
||||
|
||||
// x86 exposes a 48 byte ASCII "CPU brand" string via CPUID leaves 0x80000002-0x80000004.
|
||||
internal static string GetCpuidCpuName()
|
||||
|
|
|
@ -17,15 +17,13 @@ namespace Ryujinx.Common.SystemInfo
|
|||
|
||||
private static (ulong Total, ulong Available) GetMemoryStats()
|
||||
{
|
||||
MemoryStatusEx memStatus = new MemoryStatusEx();
|
||||
MemoryStatusEx memStatus = new();
|
||||
if (GlobalMemoryStatusEx(ref memStatus))
|
||||
{
|
||||
return (memStatus.TotalPhys, memStatus.AvailPhys); // Bytes
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Logger.Error?.Print(LogClass.Application, $"GlobalMemoryStatusEx failed. Error {Marshal.GetLastWin32Error():X}");
|
||||
}
|
||||
|
||||
return (0, 0);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Ryujinx.Common.SystemInterop
|
|||
{
|
||||
ES_CONTINUOUS = 0x80000000,
|
||||
ES_DISPLAY_REQUIRED = 0x00000002,
|
||||
ES_SYSTEM_REQUIRED = 0x00000001
|
||||
ES_SYSTEM_REQUIRED = 0x00000001,
|
||||
}
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
|
|
|
@ -63,14 +63,14 @@ namespace Ryujinx.Common.SystemInterop
|
|||
string dpiString = Marshal.PtrToStringAnsi(XGetDefault(display, "Xft", "dpi"));
|
||||
if (dpiString == null || !double.TryParse(dpiString, NumberStyles.Any, CultureInfo.InvariantCulture, out userDpiScale))
|
||||
{
|
||||
userDpiScale = (double)XDisplayWidth(display, 0) * 25.4 / (double)XDisplayWidthMM(display, 0);
|
||||
userDpiScale = XDisplayWidth(display, 0) * 25.4 / XDisplayWidthMM(display, 0);
|
||||
}
|
||||
XCloseDisplay(display);
|
||||
_ = XCloseDisplay(display);
|
||||
}
|
||||
else if (xdgSessionType == "wayland")
|
||||
{
|
||||
// TODO
|
||||
Logger.Warning?.Print(LogClass.Application, $"Couldn't determine monitor DPI: Wayland not yet supported");
|
||||
Logger.Warning?.Print(LogClass.Application, "Couldn't determine monitor DPI: Wayland not yet supported");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -28,14 +28,14 @@ namespace Ryujinx.Common.SystemInterop
|
|||
{
|
||||
public int GdiplusVersion;
|
||||
|
||||
#pragma warning disable CS0649
|
||||
#pragma warning disable CS0649 // Field is never assigned to
|
||||
public IntPtr DebugEventCallback;
|
||||
public int SuppressBackgroundThread;
|
||||
public int SuppressExternalCodecs;
|
||||
public int StartupParameters;
|
||||
#pragma warning restore CS0649
|
||||
|
||||
public static StartupInputEx Default => new StartupInputEx
|
||||
public static StartupInputEx Default => new()
|
||||
{
|
||||
// We assume Windows 8 and upper
|
||||
GdiplusVersion = 2,
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.Common.SystemInterop
|
|||
{
|
||||
public partial class StdErrAdapter : IDisposable
|
||||
{
|
||||
private bool _disposable = false;
|
||||
private bool _disposable;
|
||||
private Stream _pipeReader;
|
||||
private Stream _pipeWriter;
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
|
@ -54,8 +54,10 @@ namespace Ryujinx.Common.SystemInterop
|
|||
}
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
if (_disposable)
|
||||
{
|
||||
_disposable = false;
|
||||
|
@ -70,11 +72,6 @@ namespace Ryujinx.Common.SystemInterop
|
|||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int dup2(int fd, int fd2);
|
||||
|
||||
|
@ -89,18 +86,16 @@ namespace Ryujinx.Common.SystemInterop
|
|||
{
|
||||
return (pipefd[0], pipefd[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
throw new();
|
||||
}
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("linux")]
|
||||
[SupportedOSPlatform("macos")]
|
||||
private static Stream CreateFileDescriptorStream(int fd)
|
||||
{
|
||||
return new FileStream(
|
||||
new SafeFileHandle((IntPtr)fd, ownsHandle: true),
|
||||
new SafeFileHandle(fd, ownsHandle: true),
|
||||
FileAccess.ReadWrite
|
||||
);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Ryujinx.Common.SystemInterop
|
|||
{
|
||||
public uint wPeriodMin;
|
||||
public uint wPeriodMax;
|
||||
};
|
||||
}
|
||||
|
||||
[LibraryImport("winmm.dll", EntryPoint = "timeGetDevCaps", SetLastError = true)]
|
||||
private static partial uint TimeGetDevCaps(ref TimeCaps timeCaps, uint sizeTimeCaps);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
|
@ -48,10 +47,10 @@ namespace Ryujinx.Common
|
|||
|
||||
private static ulong ReverseBits64(ulong value)
|
||||
{
|
||||
value = ((value & 0xaaaaaaaaaaaaaaaa) >> 1 ) | ((value & 0x5555555555555555) << 1 );
|
||||
value = ((value & 0xcccccccccccccccc) >> 2 ) | ((value & 0x3333333333333333) << 2 );
|
||||
value = ((value & 0xf0f0f0f0f0f0f0f0) >> 4 ) | ((value & 0x0f0f0f0f0f0f0f0f) << 4 );
|
||||
value = ((value & 0xff00ff00ff00ff00) >> 8 ) | ((value & 0x00ff00ff00ff00ff) << 8 );
|
||||
value = ((value & 0xaaaaaaaaaaaaaaaa) >> 1) | ((value & 0x5555555555555555) << 1);
|
||||
value = ((value & 0xcccccccccccccccc) >> 2) | ((value & 0x3333333333333333) << 2);
|
||||
value = ((value & 0xf0f0f0f0f0f0f0f0) >> 4) | ((value & 0x0f0f0f0f0f0f0f0f) << 4);
|
||||
value = ((value & 0xff00ff00ff00ff00) >> 8) | ((value & 0x00ff00ff00ff00ff) << 8);
|
||||
value = ((value & 0xffff0000ffff0000) >> 16) | ((value & 0x0000ffff0000ffff) << 16);
|
||||
|
||||
return (value >> 32) | (value << 32);
|
||||
|
|
|
@ -9,8 +9,8 @@ namespace Ryujinx.Common.Utilities
|
|||
[StructLayout(LayoutKind.Sequential, Size = 16)]
|
||||
public struct Buffer16
|
||||
{
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy0;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy1;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong _dummy0;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong _dummy1;
|
||||
|
||||
public byte this[int i]
|
||||
{
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
@ -10,11 +9,11 @@ namespace Ryujinx.Common
|
|||
{
|
||||
public static class EmbeddedResources
|
||||
{
|
||||
private readonly static Assembly ResourceAssembly;
|
||||
private readonly static Assembly _resourceAssembly;
|
||||
|
||||
static EmbeddedResources()
|
||||
{
|
||||
ResourceAssembly = Assembly.GetAssembly(typeof(EmbeddedResources));
|
||||
_resourceAssembly = Assembly.GetAssembly(typeof(EmbeddedResources));
|
||||
}
|
||||
|
||||
public static byte[] Read(string filename)
|
||||
|
@ -33,8 +32,7 @@ namespace Ryujinx.Common
|
|||
|
||||
public static byte[] Read(Assembly assembly, string filename)
|
||||
{
|
||||
using (var stream = GetStream(assembly, filename))
|
||||
{
|
||||
using var stream = GetStream(assembly, filename);
|
||||
if (stream == null)
|
||||
{
|
||||
return null;
|
||||
|
@ -42,12 +40,10 @@ namespace Ryujinx.Common
|
|||
|
||||
return StreamUtils.StreamToBytes(stream);
|
||||
}
|
||||
}
|
||||
|
||||
public async static Task<byte[]> ReadAsync(Assembly assembly, string filename)
|
||||
{
|
||||
using (var stream = GetStream(assembly, filename))
|
||||
{
|
||||
using var stream = GetStream(assembly, filename);
|
||||
if (stream == null)
|
||||
{
|
||||
return null;
|
||||
|
@ -55,7 +51,6 @@ namespace Ryujinx.Common
|
|||
|
||||
return await StreamUtils.StreamToBytesAsync(stream);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ReadAllText(string filename)
|
||||
{
|
||||
|
@ -73,35 +68,27 @@ namespace Ryujinx.Common
|
|||
|
||||
public static string ReadAllText(Assembly assembly, string filename)
|
||||
{
|
||||
using (var stream = GetStream(assembly, filename))
|
||||
{
|
||||
using var stream = GetStream(assembly, filename);
|
||||
if (stream == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
using var reader = new StreamReader(stream);
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async static Task<string> ReadAllTextAsync(Assembly assembly, string filename)
|
||||
{
|
||||
using (var stream = GetStream(assembly, filename))
|
||||
{
|
||||
using var stream = GetStream(assembly, filename);
|
||||
if (stream == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
using var reader = new StreamReader(stream);
|
||||
return await reader.ReadToEndAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Stream GetStream(string filename)
|
||||
{
|
||||
|
@ -112,8 +99,8 @@ namespace Ryujinx.Common
|
|||
|
||||
public static Stream GetStream(Assembly assembly, string filename)
|
||||
{
|
||||
var namespace_ = assembly.GetName().Name;
|
||||
var manifestUri = namespace_ + "." + filename.Replace('/', '.');
|
||||
var @namespace = assembly.GetName().Name;
|
||||
var manifestUri = @namespace + "." + filename.Replace('/', '.');
|
||||
|
||||
var stream = assembly.GetManifestResourceStream(manifestUri);
|
||||
|
||||
|
@ -142,7 +129,7 @@ namespace Ryujinx.Common
|
|||
}
|
||||
}
|
||||
|
||||
return (ResourceAssembly, filename);
|
||||
return (_resourceAssembly, filename);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ namespace Ryujinx.Common
|
|||
{
|
||||
public static class HexUtils
|
||||
{
|
||||
private static readonly char[] HexChars = "0123456789ABCDEF".ToCharArray();
|
||||
private static readonly char[] _hexChars = "0123456789ABCDEF".ToCharArray();
|
||||
|
||||
private const int HexTableColumnWidth = 8;
|
||||
private const int HexTableColumnSpace = 3;
|
||||
|
@ -39,18 +39,18 @@ namespace Ryujinx.Common
|
|||
|
||||
int expectedLines = (bytesLength + bytesPerLine - 1) / bytesPerLine;
|
||||
|
||||
StringBuilder result = new StringBuilder(expectedLines * lineLength);
|
||||
StringBuilder result = new(expectedLines * lineLength);
|
||||
|
||||
for (int i = 0; i < bytesLength; i += bytesPerLine)
|
||||
{
|
||||
line[0] = HexChars[(i >> 28) & 0xF];
|
||||
line[1] = HexChars[(i >> 24) & 0xF];
|
||||
line[2] = HexChars[(i >> 20) & 0xF];
|
||||
line[3] = HexChars[(i >> 16) & 0xF];
|
||||
line[4] = HexChars[(i >> 12) & 0xF];
|
||||
line[5] = HexChars[(i >> 8) & 0xF];
|
||||
line[6] = HexChars[(i >> 4) & 0xF];
|
||||
line[7] = HexChars[(i >> 0) & 0xF];
|
||||
line[0] = _hexChars[(i >> 28) & 0xF];
|
||||
line[1] = _hexChars[(i >> 24) & 0xF];
|
||||
line[2] = _hexChars[(i >> 20) & 0xF];
|
||||
line[3] = _hexChars[(i >> 16) & 0xF];
|
||||
line[4] = _hexChars[(i >> 12) & 0xF];
|
||||
line[5] = _hexChars[(i >> 8) & 0xF];
|
||||
line[6] = _hexChars[(i >> 4) & 0xF];
|
||||
line[7] = _hexChars[(i >> 0) & 0xF];
|
||||
|
||||
int hexColumn = firstHexColumn;
|
||||
int charColumn = firstCharColumn;
|
||||
|
@ -72,8 +72,8 @@ namespace Ryujinx.Common
|
|||
{
|
||||
byte b = bytes[i + j];
|
||||
|
||||
line[hexColumn] = HexChars[(b >> 4) & 0xF];
|
||||
line[hexColumn + 1] = HexChars[b & 0xF];
|
||||
line[hexColumn] = _hexChars[(b >> 4) & 0xF];
|
||||
line[hexColumn + 1] = _hexChars[b & 0xF];
|
||||
line[charColumn] = (b < 32 ? '·' : (char)b);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Ryujinx.Common.Utilities
|
|||
{
|
||||
public class JsonHelper
|
||||
{
|
||||
private static readonly JsonNamingPolicy SnakeCasePolicy = new SnakeCaseNamingPolicy();
|
||||
private static readonly JsonNamingPolicy _snakeCasePolicy = new SnakeCaseNamingPolicy();
|
||||
private const int DefaultFileWriteBufferSize = 4096;
|
||||
|
||||
/// <summary>
|
||||
|
@ -21,11 +21,11 @@ namespace Ryujinx.Common.Utilities
|
|||
{
|
||||
JsonSerializerOptions options = new()
|
||||
{
|
||||
DictionaryKeyPolicy = SnakeCasePolicy,
|
||||
PropertyNamingPolicy = SnakeCasePolicy,
|
||||
DictionaryKeyPolicy = _snakeCasePolicy,
|
||||
PropertyNamingPolicy = _snakeCasePolicy,
|
||||
WriteIndented = indented,
|
||||
AllowTrailingCommas = true,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip
|
||||
ReadCommentHandling = JsonCommentHandling.Skip,
|
||||
};
|
||||
|
||||
return options;
|
||||
|
|
|
@ -12,11 +12,9 @@ namespace Ryujinx.Common.Utilities
|
|||
{
|
||||
return Format(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return obj.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public static string Format(MessagePackObject obj)
|
||||
{
|
||||
|
@ -179,19 +177,17 @@ namespace Ryujinx.Common.Utilities
|
|||
{
|
||||
return unchecked((char)('0' + b));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return unchecked((char)('A' + (b - 10)));
|
||||
}
|
||||
}
|
||||
|
||||
internal class IndentedStringBuilder
|
||||
{
|
||||
const string DefaultIndent = " ";
|
||||
|
||||
private int _indentCount = 0;
|
||||
private int _newLineIndex = 0;
|
||||
private StringBuilder _builder;
|
||||
private int _indentCount;
|
||||
private int _newLineIndex;
|
||||
private readonly StringBuilder _builder;
|
||||
|
||||
public string IndentString { get; set; } = DefaultIndent;
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using Microsoft.IO;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -10,22 +9,21 @@ namespace Ryujinx.Common.Utilities
|
|||
{
|
||||
public static byte[] StreamToBytes(Stream input)
|
||||
{
|
||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
||||
{
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
|
||||
|
||||
input.CopyTo(stream);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<byte[]> StreamToBytesAsync(Stream input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
||||
{
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
|
||||
await input.CopyToAsync(stream, cancellationToken);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,8 +31,7 @@ namespace Ryujinx.Common
|
|||
private const ulong Prime64_4 = 0x85EBCA77C2B2AE63UL;
|
||||
private const ulong Prime64_5 = 0x27D4EB2F165667C5UL;
|
||||
|
||||
private static readonly ulong[] Xxh3InitAcc = new ulong[]
|
||||
{
|
||||
private static readonly ulong[] _xxh3InitAcc = {
|
||||
Prime32_3,
|
||||
Prime64_1,
|
||||
Prime64_2,
|
||||
|
@ -40,7 +39,7 @@ namespace Ryujinx.Common
|
|||
Prime64_4,
|
||||
Prime32_2,
|
||||
Prime64_5,
|
||||
Prime32_1
|
||||
Prime32_1,
|
||||
};
|
||||
|
||||
private static ReadOnlySpan<byte> Xxh3KSecret => new byte[]
|
||||
|
@ -56,23 +55,24 @@ namespace Ryujinx.Common
|
|||
0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,
|
||||
0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e,
|
||||
0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce,
|
||||
0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e
|
||||
0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,
|
||||
};
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ulong Mult32To64(ulong x, ulong y)
|
||||
{
|
||||
return (ulong)(uint)x * (ulong)(uint)y;
|
||||
return (uint)x * (ulong)(uint)y;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static Hash128 Mult64To128(ulong lhs, ulong rhs)
|
||||
{
|
||||
ulong high = Math.BigMul(lhs, rhs, out ulong low);
|
||||
|
||||
return new Hash128
|
||||
{
|
||||
Low = low,
|
||||
High = high
|
||||
High = high,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,7 @@ namespace Ryujinx.Common
|
|||
private static ulong Mul128Fold64(ulong lhs, ulong rhs)
|
||||
{
|
||||
Hash128 product = Mult64To128(lhs, rhs);
|
||||
|
||||
return product.Low ^ product.High;
|
||||
}
|
||||
|
||||
|
@ -87,6 +88,7 @@ namespace Ryujinx.Common
|
|||
private static ulong XorShift64(ulong v64, int shift)
|
||||
{
|
||||
Debug.Assert(0 <= shift && shift < 64);
|
||||
|
||||
return v64 ^ (v64 >> shift);
|
||||
}
|
||||
|
||||
|
@ -96,6 +98,7 @@ namespace Ryujinx.Common
|
|||
h64 = XorShift64(h64, 37);
|
||||
h64 *= 0x165667919E3779F9UL;
|
||||
h64 = XorShift64(h64, 32);
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
|
@ -107,6 +110,7 @@ namespace Ryujinx.Common
|
|||
h64 ^= h64 >> 29;
|
||||
h64 *= Prime64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
|
@ -165,8 +169,8 @@ namespace Ryujinx.Common
|
|||
{
|
||||
for (int i = 0; i < AccNb; i++)
|
||||
{
|
||||
ulong dataVal = BinaryPrimitives.ReadUInt64LittleEndian(input.Slice(i * sizeof(ulong)));
|
||||
ulong dataKey = dataVal ^ BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(i * sizeof(ulong)));
|
||||
ulong dataVal = BinaryPrimitives.ReadUInt64LittleEndian(input[(i * sizeof(ulong))..]);
|
||||
ulong dataKey = dataVal ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[(i * sizeof(ulong))..]);
|
||||
acc[i ^ 1] += dataVal;
|
||||
acc[i] += Mult32To64((uint)dataKey, dataKey >> 32);
|
||||
}
|
||||
|
@ -236,7 +240,7 @@ namespace Ryujinx.Common
|
|||
{
|
||||
for (int i = 0; i < AccNb; i++)
|
||||
{
|
||||
ulong key64 = BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(i * sizeof(ulong)));
|
||||
ulong key64 = BinaryPrimitives.ReadUInt64LittleEndian(secret[(i * sizeof(ulong))..]);
|
||||
ulong acc64 = acc[i];
|
||||
acc64 = XorShift64(acc64, 47);
|
||||
acc64 ^= key64;
|
||||
|
@ -251,8 +255,8 @@ namespace Ryujinx.Common
|
|||
{
|
||||
for (int n = 0; n < nbStripes; n++)
|
||||
{
|
||||
ReadOnlySpan<byte> inData = input.Slice(n * StripeLen);
|
||||
Xxh3Accumulate512(acc, inData, secret.Slice(n * SecretConsumeRate));
|
||||
ReadOnlySpan<byte> inData = input[(n * StripeLen)..];
|
||||
Xxh3Accumulate512(acc, inData, secret[(n * SecretConsumeRate)..]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,18 +270,18 @@ namespace Ryujinx.Common
|
|||
|
||||
for (int n = 0; n < nbBlocks; n++)
|
||||
{
|
||||
Xxh3Accumulate(acc, input.Slice(n * blockLen), secret, nbStripesPerBlock);
|
||||
Xxh3ScrambleAcc(acc, secret.Slice(secret.Length - StripeLen));
|
||||
Xxh3Accumulate(acc, input[(n * blockLen)..], secret, nbStripesPerBlock);
|
||||
Xxh3ScrambleAcc(acc, secret[^StripeLen..]);
|
||||
}
|
||||
|
||||
Debug.Assert(input.Length > StripeLen);
|
||||
|
||||
int nbStripes = (input.Length - 1 - (blockLen * nbBlocks)) / StripeLen;
|
||||
Debug.Assert(nbStripes <= (secret.Length / SecretConsumeRate));
|
||||
Xxh3Accumulate(acc, input.Slice(nbBlocks * blockLen), secret, nbStripes);
|
||||
Xxh3Accumulate(acc, input[(nbBlocks * blockLen)..], secret, nbStripes);
|
||||
|
||||
ReadOnlySpan<byte> p = input.Slice(input.Length - StripeLen);
|
||||
Xxh3Accumulate512(acc, p, secret.Slice(secret.Length - StripeLen - SecretLastAccStart));
|
||||
ReadOnlySpan<byte> p = input[^StripeLen..];
|
||||
Xxh3Accumulate512(acc, p, secret[(secret.Length - StripeLen - SecretLastAccStart)..]);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
@ -285,7 +289,7 @@ namespace Ryujinx.Common
|
|||
{
|
||||
return Mul128Fold64(
|
||||
acc[0] ^ BinaryPrimitives.ReadUInt64LittleEndian(secret),
|
||||
acc[1] ^ BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(8)));
|
||||
acc[1] ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[8..]));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
@ -295,7 +299,7 @@ namespace Ryujinx.Common
|
|||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
result64 += Xxh3Mix2Accs(acc.Slice(2 * i), secret.Slice(16 * i));
|
||||
result64 += Xxh3Mix2Accs(acc[(2 * i)..], secret[(16 * i)..]);
|
||||
}
|
||||
|
||||
return Xxh3Avalanche(result64);
|
||||
|
@ -305,7 +309,7 @@ namespace Ryujinx.Common
|
|||
private static Hash128 Xxh3HashLong128bInternal(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret)
|
||||
{
|
||||
Span<ulong> acc = stackalloc ulong[AccNb];
|
||||
Xxh3InitAcc.CopyTo(acc);
|
||||
_xxh3InitAcc.CopyTo(acc);
|
||||
|
||||
Xxh3HashLongInternalLoop(acc, input, secret);
|
||||
|
||||
|
@ -314,11 +318,11 @@ namespace Ryujinx.Common
|
|||
|
||||
return new Hash128
|
||||
{
|
||||
Low = Xxh3MergeAccs(acc, secret.Slice(SecretMergeAccsStart), (ulong)input.Length * Prime64_1),
|
||||
Low = Xxh3MergeAccs(acc, secret[SecretMergeAccsStart..], (ulong)input.Length * Prime64_1),
|
||||
High = Xxh3MergeAccs(
|
||||
acc,
|
||||
secret.Slice(secret.Length - acc.Length * sizeof(ulong) - SecretMergeAccsStart),
|
||||
~((ulong)input.Length * Prime64_2))
|
||||
secret[(secret.Length - acc.Length * sizeof(ulong) - SecretMergeAccsStart)..],
|
||||
~((ulong)input.Length * Prime64_2)),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -332,15 +336,15 @@ namespace Ryujinx.Common
|
|||
|
||||
uint combinedL = ((uint)c1 << 16) | ((uint)c2 << 24) | c3 | ((uint)input.Length << 8);
|
||||
uint combinedH = BitOperations.RotateLeft(BinaryPrimitives.ReverseEndianness(combinedL), 13);
|
||||
ulong bitFlipL = (BinaryPrimitives.ReadUInt32LittleEndian(secret) ^ BinaryPrimitives.ReadUInt32LittleEndian(secret.Slice(4))) + seed;
|
||||
ulong bitFlipH = (BinaryPrimitives.ReadUInt32LittleEndian(secret.Slice(8)) ^ BinaryPrimitives.ReadUInt32LittleEndian(secret.Slice(12))) - seed;
|
||||
ulong bitFlipL = (BinaryPrimitives.ReadUInt32LittleEndian(secret) ^ BinaryPrimitives.ReadUInt32LittleEndian(secret[4..])) + seed;
|
||||
ulong bitFlipH = (BinaryPrimitives.ReadUInt32LittleEndian(secret[8..]) ^ BinaryPrimitives.ReadUInt32LittleEndian(secret[12..])) - seed;
|
||||
ulong keyedLo = combinedL ^ bitFlipL;
|
||||
ulong keyedHi = combinedH ^ bitFlipH;
|
||||
|
||||
return new Hash128
|
||||
{
|
||||
Low = Xxh64Avalanche(keyedLo),
|
||||
High = Xxh64Avalanche(keyedHi)
|
||||
High = Xxh64Avalanche(keyedHi),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -351,9 +355,9 @@ namespace Ryujinx.Common
|
|||
seed ^= BinaryPrimitives.ReverseEndianness((uint)seed) << 32;
|
||||
|
||||
uint inputLo = BinaryPrimitives.ReadUInt32LittleEndian(input);
|
||||
uint inputHi = BinaryPrimitives.ReadUInt32LittleEndian(input.Slice(input.Length - 4));
|
||||
uint inputHi = BinaryPrimitives.ReadUInt32LittleEndian(input[^4..]);
|
||||
ulong input64 = inputLo + ((ulong)inputHi << 32);
|
||||
ulong bitFlip = (BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(16)) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(24))) + seed;
|
||||
ulong bitFlip = (BinaryPrimitives.ReadUInt64LittleEndian(secret[16..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[24..])) + seed;
|
||||
ulong keyed = input64 ^ bitFlip;
|
||||
|
||||
Hash128 m128 = Mult64To128(keyed, Prime64_1 + ((ulong)input.Length << 2));
|
||||
|
@ -365,6 +369,7 @@ namespace Ryujinx.Common
|
|||
m128.Low *= 0x9FB21C651E98DF25UL;
|
||||
m128.Low = XorShift64(m128.Low, 28);
|
||||
m128.High = Xxh3Avalanche(m128.High);
|
||||
|
||||
return m128;
|
||||
}
|
||||
|
||||
|
@ -372,10 +377,10 @@ namespace Ryujinx.Common
|
|||
{
|
||||
Debug.Assert(9 <= input.Length && input.Length <= 16);
|
||||
|
||||
ulong bitFlipL = (BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(32)) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(40))) - seed;
|
||||
ulong bitFlipH = (BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(48)) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(56))) + seed;
|
||||
ulong bitFlipL = (BinaryPrimitives.ReadUInt64LittleEndian(secret[32..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[40..])) - seed;
|
||||
ulong bitFlipH = (BinaryPrimitives.ReadUInt64LittleEndian(secret[48..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[56..])) + seed;
|
||||
ulong inputLo = BinaryPrimitives.ReadUInt64LittleEndian(input);
|
||||
ulong inputHi = BinaryPrimitives.ReadUInt64LittleEndian(input.Slice(input.Length - 8));
|
||||
ulong inputHi = BinaryPrimitives.ReadUInt64LittleEndian(input[^8..]);
|
||||
|
||||
Hash128 m128 = Mult64To128(inputLo ^ inputHi ^ bitFlipL, Prime64_1);
|
||||
m128.Low += ((ulong)input.Length - 1) << 54;
|
||||
|
@ -387,6 +392,7 @@ namespace Ryujinx.Common
|
|||
h128.High += m128.High * Prime64_2;
|
||||
h128.Low = Xxh3Avalanche(h128.Low);
|
||||
h128.High = Xxh3Avalanche(h128.High);
|
||||
|
||||
return h128;
|
||||
}
|
||||
|
||||
|
@ -398,40 +404,43 @@ namespace Ryujinx.Common
|
|||
{
|
||||
return Xxh3Len9To16128b(input, secret, seed);
|
||||
}
|
||||
else if (input.Length >= 4)
|
||||
|
||||
if (input.Length >= 4)
|
||||
{
|
||||
return Xxh3Len4To8128b(input, secret, seed);
|
||||
}
|
||||
else if (input.Length != 0)
|
||||
|
||||
if (input.Length != 0)
|
||||
{
|
||||
return Xxh3Len1To3128b(input, secret, seed);
|
||||
}
|
||||
else
|
||||
{
|
||||
Hash128 h128 = new Hash128();
|
||||
ulong bitFlipL = BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(64)) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(72));
|
||||
ulong bitFlipH = BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(80)) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(88));
|
||||
|
||||
Hash128 h128 = new();
|
||||
ulong bitFlipL = BinaryPrimitives.ReadUInt64LittleEndian(secret[64..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[72..]);
|
||||
ulong bitFlipH = BinaryPrimitives.ReadUInt64LittleEndian(secret[80..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[88..]);
|
||||
h128.Low = Xxh64Avalanche(seed ^ bitFlipL);
|
||||
h128.High = Xxh64Avalanche(seed ^ bitFlipH);
|
||||
|
||||
return h128;
|
||||
}
|
||||
}
|
||||
|
||||
private static ulong Xxh3Mix16b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
|
||||
{
|
||||
ulong inputLo = BinaryPrimitives.ReadUInt64LittleEndian(input);
|
||||
ulong inputHi = BinaryPrimitives.ReadUInt64LittleEndian(input.Slice(8));
|
||||
ulong inputHi = BinaryPrimitives.ReadUInt64LittleEndian(input[8..]);
|
||||
|
||||
return Mul128Fold64(
|
||||
inputLo ^ (BinaryPrimitives.ReadUInt64LittleEndian(secret) + seed),
|
||||
inputHi ^ (BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(8)) - seed));
|
||||
inputHi ^ (BinaryPrimitives.ReadUInt64LittleEndian(secret[8..]) - seed));
|
||||
}
|
||||
|
||||
private static Hash128 Xxh128Mix32b(Hash128 acc, ReadOnlySpan<byte> input, ReadOnlySpan<byte> input2, ReadOnlySpan<byte> secret, ulong seed)
|
||||
{
|
||||
acc.Low += Xxh3Mix16b(input, secret, seed);
|
||||
acc.Low ^= BinaryPrimitives.ReadUInt64LittleEndian(input2) + BinaryPrimitives.ReadUInt64LittleEndian(input2.Slice(8));
|
||||
acc.High += Xxh3Mix16b(input2, secret.Slice(16), seed);
|
||||
acc.High ^= BinaryPrimitives.ReadUInt64LittleEndian(input) + BinaryPrimitives.ReadUInt64LittleEndian(input.Slice(8));
|
||||
acc.Low ^= BinaryPrimitives.ReadUInt64LittleEndian(input2) + BinaryPrimitives.ReadUInt64LittleEndian(input2[8..]);
|
||||
acc.High += Xxh3Mix16b(input2, secret[16..], seed);
|
||||
acc.High ^= BinaryPrimitives.ReadUInt64LittleEndian(input) + BinaryPrimitives.ReadUInt64LittleEndian(input[8..]);
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
|
@ -440,10 +449,10 @@ namespace Ryujinx.Common
|
|||
Debug.Assert(secret.Length >= SecretSizeMin);
|
||||
Debug.Assert(16 < input.Length && input.Length <= 128);
|
||||
|
||||
Hash128 acc = new Hash128
|
||||
Hash128 acc = new()
|
||||
{
|
||||
Low = (ulong)input.Length * Prime64_1,
|
||||
High = 0
|
||||
High = 0,
|
||||
};
|
||||
|
||||
if (input.Length > 32)
|
||||
|
@ -452,21 +461,22 @@ namespace Ryujinx.Common
|
|||
{
|
||||
if (input.Length > 96)
|
||||
{
|
||||
acc = Xxh128Mix32b(acc, input.Slice(48), input.Slice(input.Length - 64), secret.Slice(96), seed);
|
||||
acc = Xxh128Mix32b(acc, input[48..], input[^64..], secret[96..], seed);
|
||||
}
|
||||
acc = Xxh128Mix32b(acc, input.Slice(32), input.Slice(input.Length - 48), secret.Slice(64), seed);
|
||||
acc = Xxh128Mix32b(acc, input[32..], input[^48..], secret[64..], seed);
|
||||
}
|
||||
acc = Xxh128Mix32b(acc, input.Slice(16), input.Slice(input.Length - 32), secret.Slice(32), seed);
|
||||
acc = Xxh128Mix32b(acc, input[16..], input[^32..], secret[32..], seed);
|
||||
}
|
||||
acc = Xxh128Mix32b(acc, input, input.Slice(input.Length - 16), secret, seed);
|
||||
acc = Xxh128Mix32b(acc, input, input[^16..], secret, seed);
|
||||
|
||||
Hash128 h128 = new Hash128
|
||||
Hash128 h128 = new()
|
||||
{
|
||||
Low = acc.Low + acc.High,
|
||||
High = acc.Low * Prime64_1 + acc.High * Prime64_4 + ((ulong)input.Length - seed) * Prime64_2
|
||||
High = acc.Low * Prime64_1 + acc.High * Prime64_4 + ((ulong)input.Length - seed) * Prime64_2,
|
||||
};
|
||||
h128.Low = Xxh3Avalanche(h128.Low);
|
||||
h128.High = 0UL - Xxh3Avalanche(h128.High);
|
||||
|
||||
return h128;
|
||||
}
|
||||
|
||||
|
@ -475,7 +485,7 @@ namespace Ryujinx.Common
|
|||
Debug.Assert(secret.Length >= SecretSizeMin);
|
||||
Debug.Assert(128 < input.Length && input.Length <= 240);
|
||||
|
||||
Hash128 acc = new Hash128();
|
||||
Hash128 acc = new();
|
||||
|
||||
int nbRounds = input.Length / 32;
|
||||
acc.Low = (ulong)input.Length * Prime64_1;
|
||||
|
@ -483,7 +493,7 @@ namespace Ryujinx.Common
|
|||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
acc = Xxh128Mix32b(acc, input.Slice(32 * i), input.Slice(32 * i + 16), secret.Slice(32 * i), seed);
|
||||
acc = Xxh128Mix32b(acc, input[(32 * i)..], input[(32 * i + 16)..], secret[(32 * i)..], seed);
|
||||
}
|
||||
|
||||
acc.Low = Xxh3Avalanche(acc.Low);
|
||||
|
@ -492,18 +502,19 @@ namespace Ryujinx.Common
|
|||
|
||||
for (int i = 4; i < nbRounds; i++)
|
||||
{
|
||||
acc = Xxh128Mix32b(acc, input.Slice(32 * i), input.Slice(32 * i + 16), secret.Slice(MidSizeStartOffset + 32 * (i - 4)), seed);
|
||||
acc = Xxh128Mix32b(acc, input[(32 * i)..], input[(32 * i + 16)..], secret[(MidSizeStartOffset + 32 * (i - 4))..], seed);
|
||||
}
|
||||
|
||||
acc = Xxh128Mix32b(acc, input.Slice(input.Length - 16), input.Slice(input.Length - 32), secret.Slice(SecretSizeMin - MidSizeLastOffset - 16), 0UL - seed);
|
||||
acc = Xxh128Mix32b(acc, input[^16..], input[^32..], secret[(SecretSizeMin - MidSizeLastOffset - 16)..], 0UL - seed);
|
||||
|
||||
Hash128 h128 = new Hash128
|
||||
Hash128 h128 = new()
|
||||
{
|
||||
Low = acc.Low + acc.High,
|
||||
High = acc.Low * Prime64_1 + acc.High * Prime64_4 + ((ulong)input.Length - seed) * Prime64_2
|
||||
High = acc.Low * Prime64_1 + acc.High * Prime64_4 + ((ulong)input.Length - seed) * Prime64_2,
|
||||
};
|
||||
h128.Low = Xxh3Avalanche(h128.Low);
|
||||
h128.High = 0UL - Xxh3Avalanche(h128.High);
|
||||
|
||||
return h128;
|
||||
}
|
||||
|
||||
|
@ -515,19 +526,19 @@ namespace Ryujinx.Common
|
|||
{
|
||||
return Xxh3Len0To16128b(input, secret, seed);
|
||||
}
|
||||
else if (input.Length <= 128)
|
||||
|
||||
if (input.Length <= 128)
|
||||
{
|
||||
return Xxh3Len17To128128b(input, secret, seed);
|
||||
}
|
||||
else if (input.Length <= 240)
|
||||
|
||||
if (input.Length <= 240)
|
||||
{
|
||||
return Xxh3Len129To240128b(input, secret, seed);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return Xxh3HashLong128bInternal(input, secret);
|
||||
}
|
||||
}
|
||||
|
||||
public static Hash128 ComputeHash(ReadOnlySpan<byte> input)
|
||||
{
|
||||
|
|
|
@ -7,15 +7,13 @@ namespace Ryujinx.Cpu
|
|||
{
|
||||
public class AddressSpace : IDisposable
|
||||
{
|
||||
private const ulong PageSize = 0x1000;
|
||||
|
||||
private const int DefaultBlockAlignment = 1 << 20;
|
||||
|
||||
private enum MappingType : byte
|
||||
{
|
||||
None,
|
||||
Private,
|
||||
Shared
|
||||
Shared,
|
||||
}
|
||||
|
||||
private class Mapping : IntrusiveRedBlackTreeNode<Mapping>, IComparable<Mapping>
|
||||
|
@ -37,7 +35,7 @@ namespace Ryujinx.Cpu
|
|||
ulong leftSize = splitAddress - Address;
|
||||
ulong rightSize = EndAddress - splitAddress;
|
||||
|
||||
Mapping left = new Mapping(Address, leftSize, Type);
|
||||
Mapping left = new(Address, leftSize, Type);
|
||||
|
||||
Address = splitAddress;
|
||||
Size = rightSize;
|
||||
|
@ -93,7 +91,7 @@ namespace Ryujinx.Cpu
|
|||
|
||||
(var leftAllocation, PrivateAllocation) = PrivateAllocation.Split(leftSize);
|
||||
|
||||
PrivateMapping left = new PrivateMapping(Address, leftSize, leftAllocation);
|
||||
PrivateMapping left = new(Address, leftSize, leftAllocation);
|
||||
|
||||
Address = splitAddress;
|
||||
Size = rightSize;
|
||||
|
@ -181,7 +179,7 @@ namespace Ryujinx.Cpu
|
|||
{
|
||||
addressSpace = null;
|
||||
|
||||
MemoryAllocationFlags asFlags = MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible;
|
||||
const MemoryAllocationFlags asFlags = MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible;
|
||||
|
||||
ulong minAddressSpaceSize = Math.Min(asSize, 1UL << 36);
|
||||
|
||||
|
@ -391,8 +389,6 @@ namespace Ryujinx.Cpu
|
|||
ulong vaAligned = BitUtils.AlignDown(va, alignment);
|
||||
ulong endAddressAligned = BitUtils.AlignUp(endAddress, alignment);
|
||||
|
||||
ulong sizeAligned = endAddressAligned - vaAligned;
|
||||
|
||||
PrivateMapping map = _privateTree.GetNode(new PrivateMapping(va, 1UL, default));
|
||||
|
||||
for (; map != null; map = map.Successor)
|
||||
|
@ -436,8 +432,6 @@ namespace Ryujinx.Cpu
|
|||
return;
|
||||
}
|
||||
|
||||
ulong alignedSize = endAddressAligned - vaAligned;
|
||||
|
||||
PrivateMapping map = _privateTree.GetNode(new PrivateMapping(va, 1UL, default));
|
||||
|
||||
for (; map != null; map = map.Successor)
|
||||
|
@ -495,6 +489,8 @@ namespace Ryujinx.Cpu
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
_privateMemoryAllocator?.Dispose();
|
||||
Base.Dispose();
|
||||
Mirror.Dispose();
|
||||
|
|
|
@ -42,6 +42,6 @@ namespace Ryujinx.Cpu.AppleHv.Arm
|
|||
WatchpointSameEl = 0b110101,
|
||||
BkptAarch32 = 0b111000,
|
||||
VectorCatchAarch32 = 0b111010,
|
||||
BrkAarch64 = 0b111100
|
||||
BrkAarch64 = 0b111100,
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
public class DummyDiskCacheLoadState : IDiskCacheLoadState
|
||||
{
|
||||
#pragma warning disable CS0067
|
||||
#pragma warning disable CS0067 // The event is never used
|
||||
/// <inheritdoc/>
|
||||
public event Action<LoadState, int, int> StateChanged;
|
||||
#pragma warning restore CS0067
|
||||
|
|
|
@ -18,18 +18,16 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
private const ulong AllocationGranule = 1UL << 14;
|
||||
|
||||
private readonly ulong _asBase;
|
||||
private readonly ulong _asSize;
|
||||
private readonly ulong _backingSize;
|
||||
|
||||
private readonly HvAddressSpaceRange _userRange;
|
||||
private readonly HvAddressSpaceRange _kernelRange;
|
||||
|
||||
private MemoryBlock _kernelCodeBlock;
|
||||
private readonly MemoryBlock _kernelCodeBlock;
|
||||
|
||||
public HvAddressSpace(MemoryBlock backingMemory, ulong asSize)
|
||||
{
|
||||
(_asBase, var ipaAllocator) = HvVm.CreateAddressSpace(backingMemory);
|
||||
_asSize = asSize;
|
||||
_backingSize = backingMemory.Size;
|
||||
|
||||
_userRange = new HvAddressSpaceRange(ipaAllocator);
|
||||
|
@ -58,20 +56,20 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
_kernelCodeBlock.Write(KernelRegionEretOffset, 0xD69F03E0u); // ERET
|
||||
|
||||
ulong kernelCodePa = ipaAllocator.Allocate(AllocationGranule);
|
||||
HvApi.hv_vm_map((ulong)_kernelCodeBlock.Pointer, kernelCodePa, AllocationGranule, hv_memory_flags_t.HV_MEMORY_READ | hv_memory_flags_t.HV_MEMORY_EXEC).ThrowOnError();
|
||||
HvApi.hv_vm_map((ulong)_kernelCodeBlock.Pointer, kernelCodePa, AllocationGranule, HvMemoryFlags.Read | HvMemoryFlags.Exec).ThrowOnError();
|
||||
|
||||
_kernelRange.Map(KernelRegionCodeOffset, kernelCodePa, KernelRegionCodeSize, ApFlags.UserNoneKernelReadExecute);
|
||||
}
|
||||
|
||||
public void InitializeMmu(ulong vcpu)
|
||||
{
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu, hv_sys_reg_t.HV_SYS_REG_VBAR_EL1, KernelRegionBase + KernelRegionCodeOffset);
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu, HvSysReg.VBAR_EL1, KernelRegionBase + KernelRegionCodeOffset);
|
||||
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu, hv_sys_reg_t.HV_SYS_REG_TTBR0_EL1, _userRange.GetIpaBase());
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu, hv_sys_reg_t.HV_SYS_REG_TTBR1_EL1, _kernelRange.GetIpaBase());
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu, hv_sys_reg_t.HV_SYS_REG_MAIR_EL1, 0xffUL);
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu, hv_sys_reg_t.HV_SYS_REG_TCR_EL1, 0x00000011B5193519UL);
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu, hv_sys_reg_t.HV_SYS_REG_SCTLR_EL1, 0x0000000034D5D925UL);
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu, HvSysReg.TTBR0_EL1, _userRange.GetIpaBase());
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu, HvSysReg.TTBR1_EL1, _kernelRange.GetIpaBase());
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu, HvSysReg.MAIR_EL1, 0xffUL);
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu, HvSysReg.TCR_EL1, 0x00000011B5193519UL);
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu, HvSysReg.SCTLR_EL1, 0x0000000034D5D925UL);
|
||||
}
|
||||
|
||||
public bool GetAndClearUserTlbInvalidationPending()
|
||||
|
@ -115,7 +113,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
MemoryPermission.ReadAndWrite => ApFlags.UserReadWriteKernelReadWrite,
|
||||
MemoryPermission.ReadAndExecute => ApFlags.UserReadExecuteKernelRead,
|
||||
MemoryPermission.ReadWriteExecute => ApFlags.UserReadWriteExecuteKernelReadWrite,
|
||||
_ => throw new ArgumentException($"Permission \"{permission}\" is invalid.")
|
||||
_ => throw new ArgumentException($"Permission \"{permission}\" is invalid."),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
ulong size = (ulong)count * sizeof(ulong);
|
||||
Allocation = blockAllocator.Allocate(size, PageSize);
|
||||
|
||||
AsSpan().Fill(0UL);
|
||||
AsSpan().Clear();
|
||||
|
||||
if (hasNext)
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
}
|
||||
}
|
||||
|
||||
public unsafe Span<ulong> AsSpan()
|
||||
public Span<ulong> AsSpan()
|
||||
{
|
||||
return MemoryMarshal.Cast<byte, ulong>(Allocation.Memory.GetSpan(Allocation.Offset, (int)Allocation.Size));
|
||||
}
|
||||
|
@ -52,12 +52,10 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
|
||||
private int _tlbInvalidationPending;
|
||||
|
||||
private readonly HvIpaAllocator _ipaAllocator;
|
||||
private readonly HvMemoryBlockAllocator _blockAllocator;
|
||||
|
||||
public HvAddressSpaceRange(HvIpaAllocator ipaAllocator)
|
||||
{
|
||||
_ipaAllocator = ipaAllocator;
|
||||
_blockAllocator = new HvMemoryBlockAllocator(ipaAllocator, (int)AllocationGranule);
|
||||
}
|
||||
|
||||
|
@ -129,7 +127,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
ulong endVa = (va + size + PageMask) & ~((ulong)PageMask);
|
||||
va &= ~((ulong)PageMask);
|
||||
|
||||
(ulong blockSize, int blockShift) = GetBlockSizeAndShift(depth);
|
||||
(ulong blockSize, _) = GetBlockSizeAndShift(depth);
|
||||
|
||||
while (va < endVa)
|
||||
{
|
||||
|
@ -138,7 +136,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
|
||||
int l = (int)(va >> (PageBits + (2 - depth) * LevelBits)) & LevelMask;
|
||||
|
||||
PtLevel nextTable = level.Next != null ? level.Next[l] : null;
|
||||
PtLevel nextTable = level.Next?[l];
|
||||
|
||||
if (nextTable != null)
|
||||
{
|
||||
|
@ -190,7 +188,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
ulong endVa = (va + size + PageSize - 1) & ~((ulong)PageSize - 1);
|
||||
va &= ~((ulong)PageSize - 1);
|
||||
|
||||
(ulong blockSize, int blockShift) = GetBlockSizeAndShift(depth);
|
||||
(ulong blockSize, _) = GetBlockSizeAndShift(depth);
|
||||
|
||||
while (va < endVa)
|
||||
{
|
||||
|
@ -204,7 +202,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
// First check if the region is mapped.
|
||||
if ((pte & 3) != 0)
|
||||
{
|
||||
PtLevel nextTable = level.Next != null ? level.Next[l] : null;
|
||||
PtLevel nextTable = level.Next?[l];
|
||||
|
||||
if (nextTable != null)
|
||||
{
|
||||
|
@ -240,10 +238,10 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
pte &= ~3UL;
|
||||
pte |= (depth == 2 ? 3UL : 1UL);
|
||||
|
||||
PtLevel level = new PtLevel(_blockAllocator, LevelCount, depth < 2);
|
||||
PtLevel level = new(_blockAllocator, LevelCount, depth < 2);
|
||||
Span<ulong> currentLevel = level.AsSpan();
|
||||
|
||||
(ulong blockSize, int blockShift) = GetBlockSizeAndShift(depth);
|
||||
(_, int blockShift) = GetBlockSizeAndShift(depth);
|
||||
|
||||
// Fill in the blocks.
|
||||
for (int i = 0; i < LevelCount; i++)
|
||||
|
@ -334,7 +332,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
|
||||
if ((currentTable[index] & 1) == 0)
|
||||
{
|
||||
PtLevel nextLevel = new PtLevel(_blockAllocator, LevelCount, hasNext);
|
||||
PtLevel nextLevel = new(_blockAllocator, LevelCount, hasNext);
|
||||
|
||||
currentTable[index] = (nextLevel.Address & ~(ulong)PageMask) | 3UL;
|
||||
level.Next[index] = nextLevel;
|
||||
|
@ -347,7 +345,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
}
|
||||
}
|
||||
|
||||
private void WriteBlock(PtLevel level, int index, int depth, ulong pa, ulong attr)
|
||||
private static void WriteBlock(PtLevel level, int index, int depth, ulong pa, ulong attr)
|
||||
{
|
||||
Span<ulong> currentTable = level.AsSpan();
|
||||
|
||||
|
|
|
@ -1,245 +1,244 @@
|
|||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Cpu.AppleHv
|
||||
{
|
||||
struct hv_vcpu_exit_exception_t
|
||||
struct HvVcpuExitException
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public ulong syndrome;
|
||||
public ulong virtual_address;
|
||||
public ulong physical_address;
|
||||
#pragma warning disable CS0649 // Field is never assigned to
|
||||
public ulong Syndrome;
|
||||
public ulong VirtualAddress;
|
||||
public ulong PhysicalAddress;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
struct hv_vcpu_exit_t
|
||||
struct HvVcpuExit
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public uint reason;
|
||||
public hv_vcpu_exit_exception_t exception;
|
||||
#pragma warning disable CS0649 // Field is never assigned to
|
||||
public uint Reason;
|
||||
public HvVcpuExitException Exception;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
enum hv_reg_t : uint
|
||||
enum HvReg : uint
|
||||
{
|
||||
HV_REG_X0,
|
||||
HV_REG_X1,
|
||||
HV_REG_X2,
|
||||
HV_REG_X3,
|
||||
HV_REG_X4,
|
||||
HV_REG_X5,
|
||||
HV_REG_X6,
|
||||
HV_REG_X7,
|
||||
HV_REG_X8,
|
||||
HV_REG_X9,
|
||||
HV_REG_X10,
|
||||
HV_REG_X11,
|
||||
HV_REG_X12,
|
||||
HV_REG_X13,
|
||||
HV_REG_X14,
|
||||
HV_REG_X15,
|
||||
HV_REG_X16,
|
||||
HV_REG_X17,
|
||||
HV_REG_X18,
|
||||
HV_REG_X19,
|
||||
HV_REG_X20,
|
||||
HV_REG_X21,
|
||||
HV_REG_X22,
|
||||
HV_REG_X23,
|
||||
HV_REG_X24,
|
||||
HV_REG_X25,
|
||||
HV_REG_X26,
|
||||
HV_REG_X27,
|
||||
HV_REG_X28,
|
||||
HV_REG_X29,
|
||||
HV_REG_FP = HV_REG_X29,
|
||||
HV_REG_X30,
|
||||
HV_REG_LR = HV_REG_X30,
|
||||
HV_REG_PC,
|
||||
HV_REG_FPCR,
|
||||
HV_REG_FPSR,
|
||||
HV_REG_CPSR,
|
||||
X0,
|
||||
X1,
|
||||
X2,
|
||||
X3,
|
||||
X4,
|
||||
X5,
|
||||
X6,
|
||||
X7,
|
||||
X8,
|
||||
X9,
|
||||
X10,
|
||||
X11,
|
||||
X12,
|
||||
X13,
|
||||
X14,
|
||||
X15,
|
||||
X16,
|
||||
X17,
|
||||
X18,
|
||||
X19,
|
||||
X20,
|
||||
X21,
|
||||
X22,
|
||||
X23,
|
||||
X24,
|
||||
X25,
|
||||
X26,
|
||||
X27,
|
||||
X28,
|
||||
X29,
|
||||
FP = X29,
|
||||
X30,
|
||||
LR = X30,
|
||||
PC,
|
||||
FPCR,
|
||||
FPSR,
|
||||
CPSR,
|
||||
}
|
||||
|
||||
enum hv_simd_fp_reg_t : uint
|
||||
enum HvSimdFPReg : uint
|
||||
{
|
||||
HV_SIMD_FP_REG_Q0,
|
||||
HV_SIMD_FP_REG_Q1,
|
||||
HV_SIMD_FP_REG_Q2,
|
||||
HV_SIMD_FP_REG_Q3,
|
||||
HV_SIMD_FP_REG_Q4,
|
||||
HV_SIMD_FP_REG_Q5,
|
||||
HV_SIMD_FP_REG_Q6,
|
||||
HV_SIMD_FP_REG_Q7,
|
||||
HV_SIMD_FP_REG_Q8,
|
||||
HV_SIMD_FP_REG_Q9,
|
||||
HV_SIMD_FP_REG_Q10,
|
||||
HV_SIMD_FP_REG_Q11,
|
||||
HV_SIMD_FP_REG_Q12,
|
||||
HV_SIMD_FP_REG_Q13,
|
||||
HV_SIMD_FP_REG_Q14,
|
||||
HV_SIMD_FP_REG_Q15,
|
||||
HV_SIMD_FP_REG_Q16,
|
||||
HV_SIMD_FP_REG_Q17,
|
||||
HV_SIMD_FP_REG_Q18,
|
||||
HV_SIMD_FP_REG_Q19,
|
||||
HV_SIMD_FP_REG_Q20,
|
||||
HV_SIMD_FP_REG_Q21,
|
||||
HV_SIMD_FP_REG_Q22,
|
||||
HV_SIMD_FP_REG_Q23,
|
||||
HV_SIMD_FP_REG_Q24,
|
||||
HV_SIMD_FP_REG_Q25,
|
||||
HV_SIMD_FP_REG_Q26,
|
||||
HV_SIMD_FP_REG_Q27,
|
||||
HV_SIMD_FP_REG_Q28,
|
||||
HV_SIMD_FP_REG_Q29,
|
||||
HV_SIMD_FP_REG_Q30,
|
||||
HV_SIMD_FP_REG_Q31,
|
||||
Q0,
|
||||
Q1,
|
||||
Q2,
|
||||
Q3,
|
||||
Q4,
|
||||
Q5,
|
||||
Q6,
|
||||
Q7,
|
||||
Q8,
|
||||
Q9,
|
||||
Q10,
|
||||
Q11,
|
||||
Q12,
|
||||
Q13,
|
||||
Q14,
|
||||
Q15,
|
||||
Q16,
|
||||
Q17,
|
||||
Q18,
|
||||
Q19,
|
||||
Q20,
|
||||
Q21,
|
||||
Q22,
|
||||
Q23,
|
||||
Q24,
|
||||
Q25,
|
||||
Q26,
|
||||
Q27,
|
||||
Q28,
|
||||
Q29,
|
||||
Q30,
|
||||
Q31,
|
||||
}
|
||||
|
||||
enum hv_sys_reg_t : ushort
|
||||
enum HvSysReg : ushort
|
||||
{
|
||||
HV_SYS_REG_DBGBVR0_EL1 = 0x8004,
|
||||
HV_SYS_REG_DBGBCR0_EL1 = 0x8005,
|
||||
HV_SYS_REG_DBGWVR0_EL1 = 0x8006,
|
||||
HV_SYS_REG_DBGWCR0_EL1 = 0x8007,
|
||||
HV_SYS_REG_DBGBVR1_EL1 = 0x800c,
|
||||
HV_SYS_REG_DBGBCR1_EL1 = 0x800d,
|
||||
HV_SYS_REG_DBGWVR1_EL1 = 0x800e,
|
||||
HV_SYS_REG_DBGWCR1_EL1 = 0x800f,
|
||||
HV_SYS_REG_MDCCINT_EL1 = 0x8010,
|
||||
HV_SYS_REG_MDSCR_EL1 = 0x8012,
|
||||
HV_SYS_REG_DBGBVR2_EL1 = 0x8014,
|
||||
HV_SYS_REG_DBGBCR2_EL1 = 0x8015,
|
||||
HV_SYS_REG_DBGWVR2_EL1 = 0x8016,
|
||||
HV_SYS_REG_DBGWCR2_EL1 = 0x8017,
|
||||
HV_SYS_REG_DBGBVR3_EL1 = 0x801c,
|
||||
HV_SYS_REG_DBGBCR3_EL1 = 0x801d,
|
||||
HV_SYS_REG_DBGWVR3_EL1 = 0x801e,
|
||||
HV_SYS_REG_DBGWCR3_EL1 = 0x801f,
|
||||
HV_SYS_REG_DBGBVR4_EL1 = 0x8024,
|
||||
HV_SYS_REG_DBGBCR4_EL1 = 0x8025,
|
||||
HV_SYS_REG_DBGWVR4_EL1 = 0x8026,
|
||||
HV_SYS_REG_DBGWCR4_EL1 = 0x8027,
|
||||
HV_SYS_REG_DBGBVR5_EL1 = 0x802c,
|
||||
HV_SYS_REG_DBGBCR5_EL1 = 0x802d,
|
||||
HV_SYS_REG_DBGWVR5_EL1 = 0x802e,
|
||||
HV_SYS_REG_DBGWCR5_EL1 = 0x802f,
|
||||
HV_SYS_REG_DBGBVR6_EL1 = 0x8034,
|
||||
HV_SYS_REG_DBGBCR6_EL1 = 0x8035,
|
||||
HV_SYS_REG_DBGWVR6_EL1 = 0x8036,
|
||||
HV_SYS_REG_DBGWCR6_EL1 = 0x8037,
|
||||
HV_SYS_REG_DBGBVR7_EL1 = 0x803c,
|
||||
HV_SYS_REG_DBGBCR7_EL1 = 0x803d,
|
||||
HV_SYS_REG_DBGWVR7_EL1 = 0x803e,
|
||||
HV_SYS_REG_DBGWCR7_EL1 = 0x803f,
|
||||
HV_SYS_REG_DBGBVR8_EL1 = 0x8044,
|
||||
HV_SYS_REG_DBGBCR8_EL1 = 0x8045,
|
||||
HV_SYS_REG_DBGWVR8_EL1 = 0x8046,
|
||||
HV_SYS_REG_DBGWCR8_EL1 = 0x8047,
|
||||
HV_SYS_REG_DBGBVR9_EL1 = 0x804c,
|
||||
HV_SYS_REG_DBGBCR9_EL1 = 0x804d,
|
||||
HV_SYS_REG_DBGWVR9_EL1 = 0x804e,
|
||||
HV_SYS_REG_DBGWCR9_EL1 = 0x804f,
|
||||
HV_SYS_REG_DBGBVR10_EL1 = 0x8054,
|
||||
HV_SYS_REG_DBGBCR10_EL1 = 0x8055,
|
||||
HV_SYS_REG_DBGWVR10_EL1 = 0x8056,
|
||||
HV_SYS_REG_DBGWCR10_EL1 = 0x8057,
|
||||
HV_SYS_REG_DBGBVR11_EL1 = 0x805c,
|
||||
HV_SYS_REG_DBGBCR11_EL1 = 0x805d,
|
||||
HV_SYS_REG_DBGWVR11_EL1 = 0x805e,
|
||||
HV_SYS_REG_DBGWCR11_EL1 = 0x805f,
|
||||
HV_SYS_REG_DBGBVR12_EL1 = 0x8064,
|
||||
HV_SYS_REG_DBGBCR12_EL1 = 0x8065,
|
||||
HV_SYS_REG_DBGWVR12_EL1 = 0x8066,
|
||||
HV_SYS_REG_DBGWCR12_EL1 = 0x8067,
|
||||
HV_SYS_REG_DBGBVR13_EL1 = 0x806c,
|
||||
HV_SYS_REG_DBGBCR13_EL1 = 0x806d,
|
||||
HV_SYS_REG_DBGWVR13_EL1 = 0x806e,
|
||||
HV_SYS_REG_DBGWCR13_EL1 = 0x806f,
|
||||
HV_SYS_REG_DBGBVR14_EL1 = 0x8074,
|
||||
HV_SYS_REG_DBGBCR14_EL1 = 0x8075,
|
||||
HV_SYS_REG_DBGWVR14_EL1 = 0x8076,
|
||||
HV_SYS_REG_DBGWCR14_EL1 = 0x8077,
|
||||
HV_SYS_REG_DBGBVR15_EL1 = 0x807c,
|
||||
HV_SYS_REG_DBGBCR15_EL1 = 0x807d,
|
||||
HV_SYS_REG_DBGWVR15_EL1 = 0x807e,
|
||||
HV_SYS_REG_DBGWCR15_EL1 = 0x807f,
|
||||
HV_SYS_REG_MIDR_EL1 = 0xc000,
|
||||
HV_SYS_REG_MPIDR_EL1 = 0xc005,
|
||||
HV_SYS_REG_ID_AA64PFR0_EL1 = 0xc020,
|
||||
HV_SYS_REG_ID_AA64PFR1_EL1 = 0xc021,
|
||||
HV_SYS_REG_ID_AA64DFR0_EL1 = 0xc028,
|
||||
HV_SYS_REG_ID_AA64DFR1_EL1 = 0xc029,
|
||||
HV_SYS_REG_ID_AA64ISAR0_EL1 = 0xc030,
|
||||
HV_SYS_REG_ID_AA64ISAR1_EL1 = 0xc031,
|
||||
HV_SYS_REG_ID_AA64MMFR0_EL1 = 0xc038,
|
||||
HV_SYS_REG_ID_AA64MMFR1_EL1 = 0xc039,
|
||||
HV_SYS_REG_ID_AA64MMFR2_EL1 = 0xc03a,
|
||||
HV_SYS_REG_SCTLR_EL1 = 0xc080,
|
||||
HV_SYS_REG_CPACR_EL1 = 0xc082,
|
||||
HV_SYS_REG_TTBR0_EL1 = 0xc100,
|
||||
HV_SYS_REG_TTBR1_EL1 = 0xc101,
|
||||
HV_SYS_REG_TCR_EL1 = 0xc102,
|
||||
HV_SYS_REG_APIAKEYLO_EL1 = 0xc108,
|
||||
HV_SYS_REG_APIAKEYHI_EL1 = 0xc109,
|
||||
HV_SYS_REG_APIBKEYLO_EL1 = 0xc10a,
|
||||
HV_SYS_REG_APIBKEYHI_EL1 = 0xc10b,
|
||||
HV_SYS_REG_APDAKEYLO_EL1 = 0xc110,
|
||||
HV_SYS_REG_APDAKEYHI_EL1 = 0xc111,
|
||||
HV_SYS_REG_APDBKEYLO_EL1 = 0xc112,
|
||||
HV_SYS_REG_APDBKEYHI_EL1 = 0xc113,
|
||||
HV_SYS_REG_APGAKEYLO_EL1 = 0xc118,
|
||||
HV_SYS_REG_APGAKEYHI_EL1 = 0xc119,
|
||||
HV_SYS_REG_SPSR_EL1 = 0xc200,
|
||||
HV_SYS_REG_ELR_EL1 = 0xc201,
|
||||
HV_SYS_REG_SP_EL0 = 0xc208,
|
||||
HV_SYS_REG_AFSR0_EL1 = 0xc288,
|
||||
HV_SYS_REG_AFSR1_EL1 = 0xc289,
|
||||
HV_SYS_REG_ESR_EL1 = 0xc290,
|
||||
HV_SYS_REG_FAR_EL1 = 0xc300,
|
||||
HV_SYS_REG_PAR_EL1 = 0xc3a0,
|
||||
HV_SYS_REG_MAIR_EL1 = 0xc510,
|
||||
HV_SYS_REG_AMAIR_EL1 = 0xc518,
|
||||
HV_SYS_REG_VBAR_EL1 = 0xc600,
|
||||
HV_SYS_REG_CONTEXTIDR_EL1 = 0xc681,
|
||||
HV_SYS_REG_TPIDR_EL1 = 0xc684,
|
||||
HV_SYS_REG_CNTKCTL_EL1 = 0xc708,
|
||||
HV_SYS_REG_CSSELR_EL1 = 0xd000,
|
||||
HV_SYS_REG_TPIDR_EL0 = 0xde82,
|
||||
HV_SYS_REG_TPIDRRO_EL0 = 0xde83,
|
||||
HV_SYS_REG_CNTV_CTL_EL0 = 0xdf19,
|
||||
HV_SYS_REG_CNTV_CVAL_EL0 = 0xdf1a,
|
||||
HV_SYS_REG_SP_EL1 = 0xe208,
|
||||
DBGBVR0_EL1 = 0x8004,
|
||||
DBGBCR0_EL1 = 0x8005,
|
||||
DBGWVR0_EL1 = 0x8006,
|
||||
DBGWCR0_EL1 = 0x8007,
|
||||
DBGBVR1_EL1 = 0x800c,
|
||||
DBGBCR1_EL1 = 0x800d,
|
||||
DBGWVR1_EL1 = 0x800e,
|
||||
DBGWCR1_EL1 = 0x800f,
|
||||
MDCCINT_EL1 = 0x8010,
|
||||
MDSCR_EL1 = 0x8012,
|
||||
DBGBVR2_EL1 = 0x8014,
|
||||
DBGBCR2_EL1 = 0x8015,
|
||||
DBGWVR2_EL1 = 0x8016,
|
||||
DBGWCR2_EL1 = 0x8017,
|
||||
DBGBVR3_EL1 = 0x801c,
|
||||
DBGBCR3_EL1 = 0x801d,
|
||||
DBGWVR3_EL1 = 0x801e,
|
||||
DBGWCR3_EL1 = 0x801f,
|
||||
DBGBVR4_EL1 = 0x8024,
|
||||
DBGBCR4_EL1 = 0x8025,
|
||||
DBGWVR4_EL1 = 0x8026,
|
||||
DBGWCR4_EL1 = 0x8027,
|
||||
DBGBVR5_EL1 = 0x802c,
|
||||
DBGBCR5_EL1 = 0x802d,
|
||||
DBGWVR5_EL1 = 0x802e,
|
||||
DBGWCR5_EL1 = 0x802f,
|
||||
DBGBVR6_EL1 = 0x8034,
|
||||
DBGBCR6_EL1 = 0x8035,
|
||||
DBGWVR6_EL1 = 0x8036,
|
||||
DBGWCR6_EL1 = 0x8037,
|
||||
DBGBVR7_EL1 = 0x803c,
|
||||
DBGBCR7_EL1 = 0x803d,
|
||||
DBGWVR7_EL1 = 0x803e,
|
||||
DBGWCR7_EL1 = 0x803f,
|
||||
DBGBVR8_EL1 = 0x8044,
|
||||
DBGBCR8_EL1 = 0x8045,
|
||||
DBGWVR8_EL1 = 0x8046,
|
||||
DBGWCR8_EL1 = 0x8047,
|
||||
DBGBVR9_EL1 = 0x804c,
|
||||
DBGBCR9_EL1 = 0x804d,
|
||||
DBGWVR9_EL1 = 0x804e,
|
||||
DBGWCR9_EL1 = 0x804f,
|
||||
DBGBVR10_EL1 = 0x8054,
|
||||
DBGBCR10_EL1 = 0x8055,
|
||||
DBGWVR10_EL1 = 0x8056,
|
||||
DBGWCR10_EL1 = 0x8057,
|
||||
DBGBVR11_EL1 = 0x805c,
|
||||
DBGBCR11_EL1 = 0x805d,
|
||||
DBGWVR11_EL1 = 0x805e,
|
||||
DBGWCR11_EL1 = 0x805f,
|
||||
DBGBVR12_EL1 = 0x8064,
|
||||
DBGBCR12_EL1 = 0x8065,
|
||||
DBGWVR12_EL1 = 0x8066,
|
||||
DBGWCR12_EL1 = 0x8067,
|
||||
DBGBVR13_EL1 = 0x806c,
|
||||
DBGBCR13_EL1 = 0x806d,
|
||||
DBGWVR13_EL1 = 0x806e,
|
||||
DBGWCR13_EL1 = 0x806f,
|
||||
DBGBVR14_EL1 = 0x8074,
|
||||
DBGBCR14_EL1 = 0x8075,
|
||||
DBGWVR14_EL1 = 0x8076,
|
||||
DBGWCR14_EL1 = 0x8077,
|
||||
DBGBVR15_EL1 = 0x807c,
|
||||
DBGBCR15_EL1 = 0x807d,
|
||||
DBGWVR15_EL1 = 0x807e,
|
||||
DBGWCR15_EL1 = 0x807f,
|
||||
MIDR_EL1 = 0xc000,
|
||||
MPIDR_EL1 = 0xc005,
|
||||
ID_AA64PFR0_EL1 = 0xc020,
|
||||
ID_AA64PFR1_EL1 = 0xc021,
|
||||
ID_AA64DFR0_EL1 = 0xc028,
|
||||
ID_AA64DFR1_EL1 = 0xc029,
|
||||
ID_AA64ISAR0_EL1 = 0xc030,
|
||||
ID_AA64ISAR1_EL1 = 0xc031,
|
||||
ID_AA64MMFR0_EL1 = 0xc038,
|
||||
ID_AA64MMFR1_EL1 = 0xc039,
|
||||
ID_AA64MMFR2_EL1 = 0xc03a,
|
||||
SCTLR_EL1 = 0xc080,
|
||||
CPACR_EL1 = 0xc082,
|
||||
TTBR0_EL1 = 0xc100,
|
||||
TTBR1_EL1 = 0xc101,
|
||||
TCR_EL1 = 0xc102,
|
||||
APIAKEYLO_EL1 = 0xc108,
|
||||
APIAKEYHI_EL1 = 0xc109,
|
||||
APIBKEYLO_EL1 = 0xc10a,
|
||||
APIBKEYHI_EL1 = 0xc10b,
|
||||
APDAKEYLO_EL1 = 0xc110,
|
||||
APDAKEYHI_EL1 = 0xc111,
|
||||
APDBKEYLO_EL1 = 0xc112,
|
||||
APDBKEYHI_EL1 = 0xc113,
|
||||
APGAKEYLO_EL1 = 0xc118,
|
||||
APGAKEYHI_EL1 = 0xc119,
|
||||
SPSR_EL1 = 0xc200,
|
||||
ELR_EL1 = 0xc201,
|
||||
SP_EL0 = 0xc208,
|
||||
AFSR0_EL1 = 0xc288,
|
||||
AFSR1_EL1 = 0xc289,
|
||||
ESR_EL1 = 0xc290,
|
||||
FAR_EL1 = 0xc300,
|
||||
PAR_EL1 = 0xc3a0,
|
||||
MAIR_EL1 = 0xc510,
|
||||
AMAIR_EL1 = 0xc518,
|
||||
VBAR_EL1 = 0xc600,
|
||||
CONTEXTIDR_EL1 = 0xc681,
|
||||
TPIDR_EL1 = 0xc684,
|
||||
CNTKCTL_EL1 = 0xc708,
|
||||
CSSELR_EL1 = 0xd000,
|
||||
TPIDR_EL0 = 0xde82,
|
||||
TPIDRRO_EL0 = 0xde83,
|
||||
CNTV_CTL_EL0 = 0xdf19,
|
||||
CNTV_CVAL_EL0 = 0xdf1a,
|
||||
SP_EL1 = 0xe208,
|
||||
}
|
||||
|
||||
enum hv_memory_flags_t : ulong
|
||||
enum HvMemoryFlags : ulong
|
||||
{
|
||||
HV_MEMORY_READ = 1UL << 0,
|
||||
HV_MEMORY_WRITE = 1UL << 1,
|
||||
HV_MEMORY_EXEC = 1UL << 2
|
||||
Read = 1UL << 0,
|
||||
Write = 1UL << 1,
|
||||
Exec = 1UL << 2,
|
||||
}
|
||||
|
||||
enum hv_result_t : uint
|
||||
enum HvResult : uint
|
||||
{
|
||||
HV_SUCCESS = 0,
|
||||
HV_ERROR = 0xfae94001,
|
||||
HV_BUSY = 0xfae94002,
|
||||
HV_BAD_ARGUMENT = 0xfae94003,
|
||||
HV_NO_RESOURCES = 0xfae94005,
|
||||
HV_NO_DEVICE = 0xfae94006,
|
||||
HV_DENIED = 0xfae94007,
|
||||
HV_UNSUPPORTED = 0xfae9400f
|
||||
Success = 0,
|
||||
Error = 0xfae94001,
|
||||
Busy = 0xfae94002,
|
||||
BadArgument = 0xfae94003,
|
||||
NoResources = 0xfae94005,
|
||||
NoDevice = 0xfae94006,
|
||||
Denied = 0xfae94007,
|
||||
Unsupported = 0xfae9400f,
|
||||
}
|
||||
|
||||
enum hv_interrupt_type_t : uint
|
||||
enum HvInterruptType : uint
|
||||
{
|
||||
HV_INTERRUPT_TYPE_IRQ,
|
||||
HV_INTERRUPT_TYPE_FIQ
|
||||
IRQ,
|
||||
FIQ,
|
||||
}
|
||||
|
||||
struct hv_simd_fp_uchar16_t
|
||||
struct HvSimdFPUchar16
|
||||
{
|
||||
public ulong Low;
|
||||
public ulong High;
|
||||
|
@ -247,9 +246,9 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
|
||||
static class HvResultExtensions
|
||||
{
|
||||
public static void ThrowOnError(this hv_result_t result)
|
||||
public static void ThrowOnError(this HvResult result)
|
||||
{
|
||||
if (result != hv_result_t.HV_SUCCESS)
|
||||
if (result != HvResult.Success)
|
||||
{
|
||||
throw new Exception($"Unexpected result \"{result}\".");
|
||||
}
|
||||
|
@ -261,60 +260,60 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
public const string LibraryName = "/System/Library/Frameworks/Hypervisor.framework/Hypervisor";
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vm_get_max_vcpu_count(out uint max_vcpu_count);
|
||||
public static partial HvResult hv_vm_get_max_vcpu_count(out uint max_vcpu_count);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vm_create(IntPtr config);
|
||||
public static partial HvResult hv_vm_create(IntPtr config);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vm_destroy();
|
||||
public static partial HvResult hv_vm_destroy();
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vm_map(ulong addr, ulong ipa, ulong size, hv_memory_flags_t flags);
|
||||
public static partial HvResult hv_vm_map(ulong addr, ulong ipa, ulong size, HvMemoryFlags flags);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vm_unmap(ulong ipa, ulong size);
|
||||
public static partial HvResult hv_vm_unmap(ulong ipa, ulong size);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vm_protect(ulong ipa, ulong size, hv_memory_flags_t flags);
|
||||
public static partial HvResult hv_vm_protect(ulong ipa, ulong size, HvMemoryFlags flags);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public unsafe static partial hv_result_t hv_vcpu_create(out ulong vcpu, ref hv_vcpu_exit_t* exit, IntPtr config);
|
||||
public unsafe static partial HvResult hv_vcpu_create(out ulong vcpu, ref HvVcpuExit* exit, IntPtr config);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public unsafe static partial hv_result_t hv_vcpu_destroy(ulong vcpu);
|
||||
public unsafe static partial HvResult hv_vcpu_destroy(ulong vcpu);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_run(ulong vcpu);
|
||||
public static partial HvResult hv_vcpu_run(ulong vcpu);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpus_exit(ref ulong vcpus, uint vcpu_count);
|
||||
public static partial HvResult hv_vcpus_exit(ref ulong vcpus, uint vcpu_count);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_set_vtimer_mask(ulong vcpu, [MarshalAs(UnmanagedType.Bool)] bool vtimer_is_masked);
|
||||
public static partial HvResult hv_vcpu_set_vtimer_mask(ulong vcpu, [MarshalAs(UnmanagedType.Bool)] bool vtimer_is_masked);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_get_reg(ulong vcpu, hv_reg_t reg, out ulong value);
|
||||
public static partial HvResult hv_vcpu_get_reg(ulong vcpu, HvReg reg, out ulong value);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_set_reg(ulong vcpu, hv_reg_t reg, ulong value);
|
||||
public static partial HvResult hv_vcpu_set_reg(ulong vcpu, HvReg reg, ulong value);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_get_simd_fp_reg(ulong vcpu, hv_simd_fp_reg_t reg, out hv_simd_fp_uchar16_t value);
|
||||
public static partial HvResult hv_vcpu_get_simd_fp_reg(ulong vcpu, HvSimdFPReg reg, out HvSimdFPUchar16 value);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_set_simd_fp_reg(ulong vcpu, hv_simd_fp_reg_t reg, hv_simd_fp_uchar16_t value); // DO NOT USE DIRECTLY!
|
||||
public static partial HvResult hv_vcpu_set_simd_fp_reg(ulong vcpu, HvSimdFPReg reg, HvSimdFPUchar16 value); // DO NOT USE DIRECTLY!
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_get_sys_reg(ulong vcpu, hv_sys_reg_t reg, out ulong value);
|
||||
public static partial HvResult hv_vcpu_get_sys_reg(ulong vcpu, HvSysReg reg, out ulong value);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_set_sys_reg(ulong vcpu, hv_sys_reg_t reg, ulong value);
|
||||
public static partial HvResult hv_vcpu_set_sys_reg(ulong vcpu, HvSysReg reg, ulong value);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_get_pending_interrupt(ulong vcpu, hv_interrupt_type_t type, [MarshalAs(UnmanagedType.Bool)] out bool pending);
|
||||
public static partial HvResult hv_vcpu_get_pending_interrupt(ulong vcpu, HvInterruptType type, [MarshalAs(UnmanagedType.Bool)] out bool pending);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_set_pending_interrupt(ulong vcpu, hv_interrupt_type_t type, [MarshalAs(UnmanagedType.Bool)] bool pending);
|
||||
public static partial HvResult hv_vcpu_set_pending_interrupt(ulong vcpu, HvInterruptType type, [MarshalAs(UnmanagedType.Bool)] bool pending);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using ARMeilleure.Memory;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Cpu.AppleHv
|
||||
{
|
||||
|
@ -14,10 +13,6 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
_memoryManager = (HvMemoryManager)memory;
|
||||
}
|
||||
|
||||
private void UnmapHandler(ulong address, ulong size)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
|
||||
{
|
||||
|
|
|
@ -125,17 +125,17 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
HvVcpu vcpu = HvVcpuPool.Instance.Create(memoryManager.AddressSpace, _shadowContext, SwapContext);
|
||||
|
||||
HvApi.hv_vcpu_set_reg(vcpu.Handle, hv_reg_t.HV_REG_PC, address).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_reg(vcpu.Handle, HvReg.PC, address).ThrowOnError();
|
||||
|
||||
while (Running)
|
||||
{
|
||||
HvApi.hv_vcpu_run(vcpu.Handle).ThrowOnError();
|
||||
|
||||
uint reason = vcpu.ExitInfo->reason;
|
||||
uint reason = vcpu.ExitInfo->Reason;
|
||||
|
||||
if (reason == 1)
|
||||
{
|
||||
uint hvEsr = (uint)vcpu.ExitInfo->exception.syndrome;
|
||||
uint hvEsr = (uint)vcpu.ExitInfo->Exception.Syndrome;
|
||||
ExceptionClass hvEc = (ExceptionClass)(hvEsr >> 26);
|
||||
|
||||
if (hvEc != ExceptionClass.HvcAarch64)
|
||||
|
@ -144,7 +144,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
}
|
||||
|
||||
address = SynchronousException(memoryManager, ref vcpu);
|
||||
HvApi.hv_vcpu_set_reg(vcpu.Handle, hv_reg_t.HV_REG_PC, address).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_reg(vcpu.Handle, HvReg.PC, address).ThrowOnError();
|
||||
}
|
||||
else if (reason == 0)
|
||||
{
|
||||
|
@ -168,8 +168,8 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
ulong vcpuHandle = vcpu.Handle;
|
||||
|
||||
HvApi.hv_vcpu_get_sys_reg(vcpuHandle, hv_sys_reg_t.HV_SYS_REG_ELR_EL1, out ulong elr).ThrowOnError();
|
||||
HvApi.hv_vcpu_get_sys_reg(vcpuHandle, hv_sys_reg_t.HV_SYS_REG_ESR_EL1, out ulong esr).ThrowOnError();
|
||||
HvApi.hv_vcpu_get_sys_reg(vcpuHandle, HvSysReg.ELR_EL1, out ulong elr).ThrowOnError();
|
||||
HvApi.hv_vcpu_get_sys_reg(vcpuHandle, HvSysReg.ESR_EL1, out ulong esr).ThrowOnError();
|
||||
|
||||
ExceptionClass ec = (ExceptionClass)((uint)esr >> 26);
|
||||
|
||||
|
@ -180,7 +180,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
break;
|
||||
case ExceptionClass.TrappedMsrMrsSystem:
|
||||
InstructionTrap((uint)esr);
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpuHandle, hv_sys_reg_t.HV_SYS_REG_ELR_EL1, elr + 4UL).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpuHandle, HvSysReg.ELR_EL1, elr + 4UL).ThrowOnError();
|
||||
break;
|
||||
case ExceptionClass.SvcAarch64:
|
||||
ReturnToPool(vcpu);
|
||||
|
@ -204,7 +204,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
}
|
||||
}
|
||||
|
||||
private void DataAbort(MemoryTracking tracking, ulong vcpu, uint esr)
|
||||
private static void DataAbort(MemoryTracking tracking, ulong vcpu, uint esr)
|
||||
{
|
||||
bool write = (esr & (1u << 6)) != 0;
|
||||
bool farValid = (esr & (1u << 10)) == 0;
|
||||
|
@ -212,7 +212,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
|
||||
if (farValid)
|
||||
{
|
||||
HvApi.hv_vcpu_get_sys_reg(vcpu, hv_sys_reg_t.HV_SYS_REG_FAR_EL1, out ulong far).ThrowOnError();
|
||||
HvApi.hv_vcpu_get_sys_reg(vcpu, HvSysReg.FAR_EL1, out ulong far).ThrowOnError();
|
||||
|
||||
ulong size = 1UL << accessSizeLog2;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ using ARMeilleure.State;
|
|||
|
||||
namespace Ryujinx.Cpu.AppleHv
|
||||
{
|
||||
unsafe class HvExecutionContextShadow : IHvExecutionContext
|
||||
class HvExecutionContextShadow : IHvExecutionContext
|
||||
{
|
||||
public ulong Pc { get; set; }
|
||||
public ulong ElrEl1 { get; set; }
|
||||
|
|
|
@ -8,10 +8,10 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
class HvExecutionContextVcpu : IHvExecutionContext
|
||||
{
|
||||
private static MemoryBlock _setSimdFpRegFuncMem;
|
||||
private delegate hv_result_t SetSimdFpReg(ulong vcpu, hv_simd_fp_reg_t reg, in V128 value, IntPtr funcPtr);
|
||||
private static SetSimdFpReg _setSimdFpReg;
|
||||
private static IntPtr _setSimdFpRegNativePtr;
|
||||
private static readonly MemoryBlock _setSimdFpRegFuncMem;
|
||||
private delegate HvResult SetSimdFpReg(ulong vcpu, HvSimdFPReg reg, in V128 value, IntPtr funcPtr);
|
||||
private static readonly SetSimdFpReg _setSimdFpReg;
|
||||
private static readonly IntPtr _setSimdFpRegNativePtr;
|
||||
|
||||
static HvExecutionContextVcpu()
|
||||
{
|
||||
|
@ -34,12 +34,12 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
get
|
||||
{
|
||||
HvApi.hv_vcpu_get_reg(_vcpu, hv_reg_t.HV_REG_PC, out ulong pc).ThrowOnError();
|
||||
HvApi.hv_vcpu_get_reg(_vcpu, HvReg.PC, out ulong pc).ThrowOnError();
|
||||
return pc;
|
||||
}
|
||||
set
|
||||
{
|
||||
HvApi.hv_vcpu_set_reg(_vcpu, hv_reg_t.HV_REG_PC, value).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_reg(_vcpu, HvReg.PC, value).ThrowOnError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,12 +47,12 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
get
|
||||
{
|
||||
HvApi.hv_vcpu_get_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_ELR_EL1, out ulong elr).ThrowOnError();
|
||||
HvApi.hv_vcpu_get_sys_reg(_vcpu, HvSysReg.ELR_EL1, out ulong elr).ThrowOnError();
|
||||
return elr;
|
||||
}
|
||||
set
|
||||
{
|
||||
HvApi.hv_vcpu_set_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_ELR_EL1, value).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_sys_reg(_vcpu, HvSysReg.ELR_EL1, value).ThrowOnError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,12 +60,12 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
get
|
||||
{
|
||||
HvApi.hv_vcpu_get_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_ESR_EL1, out ulong esr).ThrowOnError();
|
||||
HvApi.hv_vcpu_get_sys_reg(_vcpu, HvSysReg.ESR_EL1, out ulong esr).ThrowOnError();
|
||||
return esr;
|
||||
}
|
||||
set
|
||||
{
|
||||
HvApi.hv_vcpu_set_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_ESR_EL1, value).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_sys_reg(_vcpu, HvSysReg.ESR_EL1, value).ThrowOnError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,12 +73,12 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
get
|
||||
{
|
||||
HvApi.hv_vcpu_get_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_TPIDR_EL0, out ulong tpidrEl0).ThrowOnError();
|
||||
HvApi.hv_vcpu_get_sys_reg(_vcpu, HvSysReg.TPIDR_EL0, out ulong tpidrEl0).ThrowOnError();
|
||||
return (long)tpidrEl0;
|
||||
}
|
||||
set
|
||||
{
|
||||
HvApi.hv_vcpu_set_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_TPIDR_EL0, (ulong)value).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_sys_reg(_vcpu, HvSysReg.TPIDR_EL0, (ulong)value).ThrowOnError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,12 +86,12 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
get
|
||||
{
|
||||
HvApi.hv_vcpu_get_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_TPIDRRO_EL0, out ulong tpidrroEl0).ThrowOnError();
|
||||
HvApi.hv_vcpu_get_sys_reg(_vcpu, HvSysReg.TPIDRRO_EL0, out ulong tpidrroEl0).ThrowOnError();
|
||||
return (long)tpidrroEl0;
|
||||
}
|
||||
set
|
||||
{
|
||||
HvApi.hv_vcpu_set_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_TPIDRRO_EL0, (ulong)value).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_sys_reg(_vcpu, HvSysReg.TPIDRRO_EL0, (ulong)value).ThrowOnError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,12 +99,12 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
get
|
||||
{
|
||||
HvApi.hv_vcpu_get_reg(_vcpu, hv_reg_t.HV_REG_CPSR, out ulong cpsr).ThrowOnError();
|
||||
HvApi.hv_vcpu_get_reg(_vcpu, HvReg.CPSR, out ulong cpsr).ThrowOnError();
|
||||
return (uint)cpsr;
|
||||
}
|
||||
set
|
||||
{
|
||||
HvApi.hv_vcpu_set_reg(_vcpu, hv_reg_t.HV_REG_CPSR, (ulong)value).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_reg(_vcpu, HvReg.CPSR, (ulong)value).ThrowOnError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,12 +112,12 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
get
|
||||
{
|
||||
HvApi.hv_vcpu_get_reg(_vcpu, hv_reg_t.HV_REG_FPCR, out ulong fpcr).ThrowOnError();
|
||||
HvApi.hv_vcpu_get_reg(_vcpu, HvReg.FPCR, out ulong fpcr).ThrowOnError();
|
||||
return (uint)fpcr;
|
||||
}
|
||||
set
|
||||
{
|
||||
HvApi.hv_vcpu_set_reg(_vcpu, hv_reg_t.HV_REG_FPCR, (ulong)value).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_reg(_vcpu, HvReg.FPCR, (ulong)value).ThrowOnError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,16 +125,16 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
get
|
||||
{
|
||||
HvApi.hv_vcpu_get_reg(_vcpu, hv_reg_t.HV_REG_FPSR, out ulong fpsr).ThrowOnError();
|
||||
HvApi.hv_vcpu_get_reg(_vcpu, HvReg.FPSR, out ulong fpsr).ThrowOnError();
|
||||
return (uint)fpsr;
|
||||
}
|
||||
set
|
||||
{
|
||||
HvApi.hv_vcpu_set_reg(_vcpu, hv_reg_t.HV_REG_FPSR, (ulong)value).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_reg(_vcpu, HvReg.FPSR, (ulong)value).ThrowOnError();
|
||||
}
|
||||
}
|
||||
|
||||
private ulong _vcpu;
|
||||
private readonly ulong _vcpu;
|
||||
private int _interruptRequested;
|
||||
|
||||
public HvExecutionContextVcpu(ulong vcpu)
|
||||
|
@ -146,12 +146,12 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
if (index == 31)
|
||||
{
|
||||
HvApi.hv_vcpu_get_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_SP_EL0, out ulong value).ThrowOnError();
|
||||
HvApi.hv_vcpu_get_sys_reg(_vcpu, HvSysReg.SP_EL0, out ulong value).ThrowOnError();
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
HvApi.hv_vcpu_get_reg(_vcpu, hv_reg_t.HV_REG_X0 + (uint)index, out ulong value).ThrowOnError();
|
||||
HvApi.hv_vcpu_get_reg(_vcpu, HvReg.X0 + (uint)index, out ulong value).ThrowOnError();
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
@ -160,23 +160,23 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
if (index == 31)
|
||||
{
|
||||
HvApi.hv_vcpu_set_sys_reg(_vcpu, hv_sys_reg_t.HV_SYS_REG_SP_EL0, value).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_sys_reg(_vcpu, HvSysReg.SP_EL0, value).ThrowOnError();
|
||||
}
|
||||
else
|
||||
{
|
||||
HvApi.hv_vcpu_set_reg(_vcpu, hv_reg_t.HV_REG_X0 + (uint)index, value).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_reg(_vcpu, HvReg.X0 + (uint)index, value).ThrowOnError();
|
||||
}
|
||||
}
|
||||
|
||||
public V128 GetV(int index)
|
||||
{
|
||||
HvApi.hv_vcpu_get_simd_fp_reg(_vcpu, hv_simd_fp_reg_t.HV_SIMD_FP_REG_Q0 + (uint)index, out hv_simd_fp_uchar16_t value).ThrowOnError();
|
||||
HvApi.hv_vcpu_get_simd_fp_reg(_vcpu, HvSimdFPReg.Q0 + (uint)index, out HvSimdFPUchar16 value).ThrowOnError();
|
||||
return new V128(value.Low, value.High);
|
||||
}
|
||||
|
||||
public void SetV(int index, V128 value)
|
||||
{
|
||||
_setSimdFpReg(_vcpu, hv_simd_fp_reg_t.HV_SIMD_FP_REG_Q0 + (uint)index, value, _setSimdFpRegNativePtr).ThrowOnError();
|
||||
_setSimdFpReg(_vcpu, HvSimdFPReg.Q0 + (uint)index, value, _setSimdFpRegNativePtr).ThrowOnError();
|
||||
}
|
||||
|
||||
public void RequestInterrupt()
|
||||
|
|
|
@ -3,7 +3,7 @@ using System;
|
|||
|
||||
namespace Ryujinx.Cpu.AppleHv
|
||||
{
|
||||
struct HvMemoryBlockAllocation : IDisposable
|
||||
readonly struct HvMemoryBlockAllocation : IDisposable
|
||||
{
|
||||
private readonly HvMemoryBlockAllocator _owner;
|
||||
private readonly HvMemoryBlockAllocator.Block _block;
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
using Ryujinx.Memory;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Cpu.AppleHv
|
||||
{
|
||||
class HvMemoryBlockAllocator : PrivateMemoryAllocatorImpl<HvMemoryBlockAllocator.Block>
|
||||
{
|
||||
private const ulong InvalidOffset = ulong.MaxValue;
|
||||
|
||||
public class Block : PrivateMemoryAllocator.Block
|
||||
{
|
||||
private readonly HvIpaAllocator _ipaAllocator;
|
||||
|
@ -21,7 +18,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
Ipa = ipaAllocator.Allocate(size);
|
||||
}
|
||||
|
||||
HvApi.hv_vm_map((ulong)Memory.Pointer, Ipa, size, hv_memory_flags_t.HV_MEMORY_READ | hv_memory_flags_t.HV_MEMORY_WRITE).ThrowOnError();
|
||||
HvApi.hv_vm_map((ulong)Memory.Pointer, Ipa, size, HvMemoryFlags.Read | HvMemoryFlags.Write).ThrowOnError();
|
||||
}
|
||||
|
||||
public override void Destroy()
|
||||
|
@ -44,7 +41,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
_ipaAllocator = ipaAllocator;
|
||||
}
|
||||
|
||||
public unsafe HvMemoryBlockAllocation Allocate(ulong size, ulong alignment)
|
||||
public HvMemoryBlockAllocation Allocate(ulong size, ulong alignment)
|
||||
{
|
||||
var allocation = Allocate(size, alignment, CreateBlock);
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
|
||||
MappedReplicated = 0x5555555555555555,
|
||||
WriteTrackedReplicated = 0xaaaaaaaaaaaaaaaa,
|
||||
ReadWriteTrackedReplicated = ulong.MaxValue
|
||||
ReadWriteTrackedReplicated = ulong.MaxValue,
|
||||
}
|
||||
|
||||
private readonly InvalidAccessHandler _invalidAccessHandler;
|
||||
|
@ -126,6 +126,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
}
|
||||
}
|
||||
|
||||
#pragma warning disable IDE0051 // Remove unused private member
|
||||
/// <summary>
|
||||
/// Ensures the combination of virtual address and size is part of the addressable space and fully mapped.
|
||||
/// </summary>
|
||||
|
@ -138,6 +139,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
throw new InvalidMemoryRegionException($"Not mapped: va=0x{va:X16}, size=0x{size:X16}");
|
||||
}
|
||||
}
|
||||
#pragma warning restore IDE0051
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags)
|
||||
|
@ -306,7 +308,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
|
||||
size = Math.Min(data.Length, PageSize - (int)(va & PageMask));
|
||||
|
||||
data.Slice(0, size).CopyTo(_backingMemory.GetSpan(pa, size));
|
||||
data[..size].CopyTo(_backingMemory.GetSpan(pa, size));
|
||||
|
||||
offset += size;
|
||||
}
|
||||
|
@ -428,7 +430,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void GetPageBlockRange(ulong pageStart, ulong pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex)
|
||||
private static void GetPageBlockRange(ulong pageStart, ulong pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex)
|
||||
{
|
||||
startMask = ulong.MaxValue << ((int)(pageStart & 31) << 1);
|
||||
endMask = ulong.MaxValue >> (64 - ((int)(pageEnd & 31) << 1));
|
||||
|
@ -606,7 +608,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
|
||||
size = Math.Min(data.Length, PageSize - (int)(va & PageMask));
|
||||
|
||||
_backingMemory.GetSpan(pa, size).CopyTo(data.Slice(0, size));
|
||||
_backingMemory.GetSpan(pa, size).CopyTo(data[..size]);
|
||||
|
||||
offset += size;
|
||||
}
|
||||
|
@ -723,7 +725,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
/// <param name="startVa">The virtual address of the beginning of the first page</param>
|
||||
/// <remarks>This function does not differentiate between allocated and unallocated pages.</remarks>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private int GetPagesCount(ulong va, ulong size, out ulong startVa)
|
||||
private static int GetPagesCount(ulong va, ulong size, out ulong startVa)
|
||||
{
|
||||
// WARNING: Always check if ulong does not overflow during the operations.
|
||||
startVa = va & ~(ulong)PageMask;
|
||||
|
@ -814,7 +816,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
{
|
||||
MemoryPermission.None => MemoryPermission.ReadAndWrite,
|
||||
MemoryPermission.Write => MemoryPermission.Read,
|
||||
_ => MemoryPermission.None
|
||||
_ => MemoryPermission.None,
|
||||
};
|
||||
|
||||
_addressSpace.ReprotectUser(va, size, protection);
|
||||
|
|
|
@ -3,14 +3,14 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
unsafe class HvVcpu
|
||||
{
|
||||
public readonly ulong Handle;
|
||||
public readonly hv_vcpu_exit_t* ExitInfo;
|
||||
public readonly HvVcpuExit* ExitInfo;
|
||||
public readonly IHvExecutionContext ShadowContext;
|
||||
public readonly IHvExecutionContext NativeContext;
|
||||
public readonly bool IsEphemeral;
|
||||
|
||||
public HvVcpu(
|
||||
ulong handle,
|
||||
hv_vcpu_exit_t* exitInfo,
|
||||
HvVcpuExit* exitInfo,
|
||||
IHvExecutionContext shadowContext,
|
||||
IHvExecutionContext nativeContext,
|
||||
bool isEphemeral)
|
||||
|
|
|
@ -17,10 +17,10 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
|
||||
private const int MaxActiveVcpus = 4;
|
||||
|
||||
public static readonly HvVcpuPool Instance = new HvVcpuPool();
|
||||
public static readonly HvVcpuPool Instance = new();
|
||||
|
||||
private int _totalVcpus;
|
||||
private int _maxVcpus;
|
||||
private readonly int _maxVcpus;
|
||||
|
||||
public HvVcpuPool()
|
||||
{
|
||||
|
@ -69,17 +69,17 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
bool isEphemeral = newCount > _maxVcpus - MaxActiveVcpus;
|
||||
|
||||
// Create VCPU.
|
||||
hv_vcpu_exit_t* exitInfo = null;
|
||||
HvVcpuExit* exitInfo = null;
|
||||
HvApi.hv_vcpu_create(out ulong vcpuHandle, ref exitInfo, IntPtr.Zero).ThrowOnError();
|
||||
|
||||
// Enable FP and SIMD instructions.
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpuHandle, hv_sys_reg_t.HV_SYS_REG_CPACR_EL1, 0b11 << 20).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpuHandle, HvSysReg.CPACR_EL1, 0b11 << 20).ThrowOnError();
|
||||
|
||||
addressSpace.InitializeMmu(vcpuHandle);
|
||||
|
||||
HvExecutionContextVcpu nativeContext = new HvExecutionContextVcpu(vcpuHandle);
|
||||
HvExecutionContextVcpu nativeContext = new(vcpuHandle);
|
||||
|
||||
HvVcpu vcpu = new HvVcpu(vcpuHandle, exitInfo, shadowContext, nativeContext, isEphemeral);
|
||||
HvVcpu vcpu = new(vcpuHandle, exitInfo, shadowContext, nativeContext, isEphemeral);
|
||||
|
||||
return vcpu;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
|
||||
private static int _addressSpaces;
|
||||
private static HvIpaAllocator _ipaAllocator;
|
||||
private static object _lock = new object();
|
||||
private static readonly object _lock = new();
|
||||
|
||||
public static (ulong, HvIpaAllocator) CreateAddressSpace(MemoryBlock block)
|
||||
{
|
||||
|
@ -36,7 +36,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
baseAddress = ipaAllocator.Allocate(block.Size, AsIpaAlignment);
|
||||
}
|
||||
|
||||
var rwx = hv_memory_flags_t.HV_MEMORY_READ | hv_memory_flags_t.HV_MEMORY_WRITE | hv_memory_flags_t.HV_MEMORY_EXEC;
|
||||
var rwx = HvMemoryFlags.Read | HvMemoryFlags.Write | HvMemoryFlags.Exec;
|
||||
|
||||
HvApi.hv_vm_map((ulong)block.Pointer, baseAddress, block.Size, rwx).ThrowOnError();
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace Ryujinx.Cpu.Jit
|
|||
PtcLoadingState.Start => LoadState.Unloaded,
|
||||
PtcLoadingState.Loading => LoadState.Loading,
|
||||
PtcLoadingState.Loaded => LoadState.Loaded,
|
||||
_ => throw new ArgumentException($"Invalid load state \"{newState}\".")
|
||||
_ => throw new ArgumentException($"Invalid load state \"{newState}\"."),
|
||||
};
|
||||
|
||||
StateChanged?.Invoke(state, current, total);
|
||||
|
|
|
@ -19,6 +19,10 @@ namespace Ryujinx.Cpu.Jit
|
|||
public void MapAsRx(ulong offset, ulong size) => _impl.Reprotect(offset, size, MemoryPermission.ReadAndExecute);
|
||||
public void MapAsRwx(ulong offset, ulong size) => _impl.Reprotect(offset, size, MemoryPermission.ReadWriteExecute);
|
||||
|
||||
public void Dispose() => _impl.Dispose();
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
_impl.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -84,7 +84,6 @@ namespace Ryujinx.Cpu.Jit
|
|||
|
||||
ulong remainingSize = size;
|
||||
ulong oVa = va;
|
||||
ulong oPa = pa;
|
||||
while (remainingSize != 0)
|
||||
{
|
||||
_pageTable.Write((va / PageSize) * PteSize, PaToPte(pa));
|
||||
|
@ -246,7 +245,7 @@ namespace Ryujinx.Cpu.Jit
|
|||
|
||||
size = Math.Min(data.Length, PageSize - (int)(va & PageMask));
|
||||
|
||||
data.Slice(0, size).CopyTo(_backingMemory.GetSpan(pa, size));
|
||||
data[..size].CopyTo(_backingMemory.GetSpan(pa, size));
|
||||
|
||||
offset += size;
|
||||
}
|
||||
|
@ -298,7 +297,7 @@ namespace Ryujinx.Cpu.Jit
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public unsafe WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false)
|
||||
public WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
|
@ -345,7 +344,7 @@ namespace Ryujinx.Cpu.Jit
|
|||
/// <param name="startVa">The virtual address of the beginning of the first page</param>
|
||||
/// <remarks>This function does not differentiate between allocated and unallocated pages.</remarks>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private int GetPagesCount(ulong va, uint size, out ulong startVa)
|
||||
private static int GetPagesCount(ulong va, uint size, out ulong startVa)
|
||||
{
|
||||
// WARNING: Always check if ulong does not overflow during the operations.
|
||||
startVa = va & ~(ulong)PageMask;
|
||||
|
@ -482,7 +481,7 @@ namespace Ryujinx.Cpu.Jit
|
|||
|
||||
size = Math.Min(data.Length, PageSize - (int)(va & PageMask));
|
||||
|
||||
_backingMemory.GetSpan(pa, size).CopyTo(data.Slice(0, size));
|
||||
_backingMemory.GetSpan(pa, size).CopyTo(data[..size]);
|
||||
|
||||
offset += size;
|
||||
}
|
||||
|
@ -576,6 +575,7 @@ namespace Ryujinx.Cpu.Jit
|
|||
}
|
||||
}
|
||||
|
||||
#pragma warning disable IDE0051 // Remove unused private member
|
||||
private ulong GetPhysicalAddress(ulong va)
|
||||
{
|
||||
// We return -1L if the virtual address is invalid or unmapped.
|
||||
|
@ -586,6 +586,7 @@ namespace Ryujinx.Cpu.Jit
|
|||
|
||||
return GetPhysicalAddressInternal(va);
|
||||
}
|
||||
#pragma warning restore IDE0051
|
||||
|
||||
private ulong GetPhysicalAddressInternal(ulong va)
|
||||
{
|
||||
|
@ -604,7 +605,7 @@ namespace Ryujinx.Cpu.Jit
|
|||
{
|
||||
MemoryPermission.None => 0L,
|
||||
MemoryPermission.Write => 2L << PointerTagBit,
|
||||
_ => 3L << PointerTagBit
|
||||
_ => 3L << PointerTagBit,
|
||||
};
|
||||
|
||||
int pages = GetPagesCount(va, (uint)size, out va);
|
||||
|
@ -698,6 +699,8 @@ namespace Ryujinx.Cpu.Jit
|
|||
/// </summary>
|
||||
protected override void Destroy() => _pageTable.Dispose();
|
||||
|
||||
private void ThrowInvalidMemoryRegionException(string message) => throw new InvalidMemoryRegionException(message);
|
||||
#pragma warning disable IDE0051 // Remove unused private member
|
||||
private static void ThrowInvalidMemoryRegionException(string message) => throw new InvalidMemoryRegionException(message);
|
||||
#pragma warning restore IDE0051
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace Ryujinx.Cpu.Jit
|
|||
|
||||
MappedReplicated = 0x5555555555555555,
|
||||
WriteTrackedReplicated = 0xaaaaaaaaaaaaaaaa,
|
||||
ReadWriteTrackedReplicated = ulong.MaxValue
|
||||
ReadWriteTrackedReplicated = ulong.MaxValue,
|
||||
}
|
||||
|
||||
private readonly InvalidAccessHandler _invalidAccessHandler;
|
||||
|
@ -404,7 +404,7 @@ namespace Ryujinx.Cpu.Jit
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void GetPageBlockRange(ulong pageStart, ulong pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex)
|
||||
private static void GetPageBlockRange(ulong pageStart, ulong pageEnd, out ulong startMask, out ulong endMask, out int pageIndex, out int pageEndIndex)
|
||||
{
|
||||
startMask = ulong.MaxValue << ((int)(pageStart & 31) << 1);
|
||||
endMask = ulong.MaxValue >> (64 - ((int)(pageEnd & 31) << 1));
|
||||
|
@ -606,7 +606,7 @@ namespace Ryujinx.Cpu.Jit
|
|||
/// <param name="startVa">The virtual address of the beginning of the first page</param>
|
||||
/// <remarks>This function does not differentiate between allocated and unallocated pages.</remarks>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private int GetPagesCount(ulong va, ulong size, out ulong startVa)
|
||||
private static int GetPagesCount(ulong va, ulong size, out ulong startVa)
|
||||
{
|
||||
// WARNING: Always check if ulong does not overflow during the operations.
|
||||
startVa = va & ~(ulong)PageMask;
|
||||
|
@ -697,7 +697,7 @@ namespace Ryujinx.Cpu.Jit
|
|||
{
|
||||
MemoryPermission.None => MemoryPermission.ReadAndWrite,
|
||||
MemoryPermission.Write => MemoryPermission.Read,
|
||||
_ => MemoryPermission.None
|
||||
_ => MemoryPermission.None,
|
||||
};
|
||||
|
||||
_addressSpace.Base.Reprotect(va, size, protection, false);
|
||||
|
|
|
@ -7,6 +7,6 @@ namespace Ryujinx.Cpu
|
|||
{
|
||||
Unloaded,
|
||||
Loading,
|
||||
Loaded
|
||||
Loaded,
|
||||
}
|
||||
}
|
|
@ -10,7 +10,6 @@ namespace Ryujinx.Cpu
|
|||
{
|
||||
private delegate bool TrackingEventDelegate(ulong address, ulong size, bool write);
|
||||
|
||||
private readonly MemoryTracking _tracking;
|
||||
private readonly TrackingEventDelegate _trackingEvent;
|
||||
|
||||
private readonly ulong _baseAddress;
|
||||
|
@ -18,12 +17,10 @@ namespace Ryujinx.Cpu
|
|||
|
||||
public MemoryEhMeilleure(MemoryBlock addressSpace, MemoryBlock addressSpaceMirror, MemoryTracking tracking)
|
||||
{
|
||||
_tracking = tracking;
|
||||
|
||||
_baseAddress = (ulong)addressSpace.Pointer;
|
||||
ulong endAddress = _baseAddress + addressSpace.Size;
|
||||
|
||||
_trackingEvent = new TrackingEventDelegate(tracking.VirtualMemoryEvent);
|
||||
_trackingEvent = tracking.VirtualMemoryEvent;
|
||||
bool added = NativeSignalHandler.AddTrackedRegion((nuint)_baseAddress, (nuint)endAddress, Marshal.GetFunctionPointerForDelegate(_trackingEvent));
|
||||
|
||||
if (!added)
|
||||
|
@ -51,6 +48,8 @@ namespace Ryujinx.Cpu
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
NativeSignalHandler.RemoveTrackedRegion((nuint)_baseAddress);
|
||||
|
||||
if (_mirrorAddress != 0)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue