Merge branch 'master' of https://github.com/Ryujinx/Ryujinx
This commit is contained in:
commit
2d08f8b738
183 changed files with 11865 additions and 4668 deletions
|
@ -364,6 +364,7 @@ namespace ChocolArm64
|
|||
SetA64("0x00111000100000000110xxxxxxxxxx", AInstEmit.Rev16_V, typeof(AOpCodeSimd));
|
||||
SetA64("0x1011100x100000000010xxxxxxxxxx", AInstEmit.Rev32_V, typeof(AOpCodeSimd));
|
||||
SetA64("0x001110<<100000000010xxxxxxxxxx", AInstEmit.Rev64_V, typeof(AOpCodeSimd));
|
||||
SetA64("0x00111100>>>xxx100011xxxxxxxxxx", AInstEmit.Rshrn_V, typeof(AOpCodeSimdShImm));
|
||||
SetA64("0x101110<<1xxxxx011000xxxxxxxxxx", AInstEmit.Rsubhn_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("0x001110<<1xxxxx011111xxxxxxxxxx", AInstEmit.Saba_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("0x001110<<1xxxxx010100xxxxxxxxxx", AInstEmit.Sabal_V, typeof(AOpCodeSimdReg));
|
||||
|
@ -409,7 +410,14 @@ namespace ChocolArm64
|
|||
SetA64("01111110101xxxxx101101xxxxxxxxxx", AInstEmit.Sqrdmulh_S, typeof(AOpCodeSimdReg));
|
||||
SetA64("0x101110011xxxxx101101xxxxxxxxxx", AInstEmit.Sqrdmulh_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("0x101110101xxxxx101101xxxxxxxxxx", AInstEmit.Sqrdmulh_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("0101111100>>>xxx100111xxxxxxxxxx", AInstEmit.Sqrshrn_S, typeof(AOpCodeSimdShImm));
|
||||
SetA64("0x00111100>>>xxx100111xxxxxxxxxx", AInstEmit.Sqrshrn_V, typeof(AOpCodeSimdShImm));
|
||||
SetA64("0111111100>>>xxx100011xxxxxxxxxx", AInstEmit.Sqrshrun_S, typeof(AOpCodeSimdShImm));
|
||||
SetA64("0x10111100>>>xxx100011xxxxxxxxxx", AInstEmit.Sqrshrun_V, typeof(AOpCodeSimdShImm));
|
||||
SetA64("0101111100>>>xxx100101xxxxxxxxxx", AInstEmit.Sqshrn_S, typeof(AOpCodeSimdShImm));
|
||||
SetA64("0x00111100>>>xxx100101xxxxxxxxxx", AInstEmit.Sqshrn_V, typeof(AOpCodeSimdShImm));
|
||||
SetA64("0111111100>>>xxx100001xxxxxxxxxx", AInstEmit.Sqshrun_S, typeof(AOpCodeSimdShImm));
|
||||
SetA64("0x10111100>>>xxx100001xxxxxxxxxx", AInstEmit.Sqshrun_V, typeof(AOpCodeSimdShImm));
|
||||
SetA64("01011110xx1xxxxx001011xxxxxxxxxx", AInstEmit.Sqsub_S, typeof(AOpCodeSimdReg));
|
||||
SetA64("0>001110<<1xxxxx001011xxxxxxxxxx", AInstEmit.Sqsub_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("01011110<<100001010010xxxxxxxxxx", AInstEmit.Sqxtn_S, typeof(AOpCodeSimd));
|
||||
|
@ -476,6 +484,10 @@ namespace ChocolArm64
|
|||
SetA64("0x101110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Umull_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("01111110xx1xxxxx000011xxxxxxxxxx", AInstEmit.Uqadd_S, typeof(AOpCodeSimdReg));
|
||||
SetA64("0>101110<<1xxxxx000011xxxxxxxxxx", AInstEmit.Uqadd_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("0111111100>>>xxx100111xxxxxxxxxx", AInstEmit.Uqrshrn_S, typeof(AOpCodeSimdShImm));
|
||||
SetA64("0x10111100>>>xxx100111xxxxxxxxxx", AInstEmit.Uqrshrn_V, typeof(AOpCodeSimdShImm));
|
||||
SetA64("0111111100>>>xxx100101xxxxxxxxxx", AInstEmit.Uqshrn_S, typeof(AOpCodeSimdShImm));
|
||||
SetA64("0x10111100>>>xxx100101xxxxxxxxxx", AInstEmit.Uqshrn_V, typeof(AOpCodeSimdShImm));
|
||||
SetA64("01111110xx1xxxxx001011xxxxxxxxxx", AInstEmit.Uqsub_S, typeof(AOpCodeSimdReg));
|
||||
SetA64("0>101110<<1xxxxx001011xxxxxxxxxx", AInstEmit.Uqsub_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("01111110<<100001010010xxxxxxxxxx", AInstEmit.Uqxtn_S, typeof(AOpCodeSimd));
|
||||
|
|
|
@ -2,8 +2,6 @@ using System.Runtime.Intrinsics.X86;
|
|||
|
||||
public static class AOptimizations
|
||||
{
|
||||
public static bool GenerateCallStack = true;
|
||||
|
||||
private static bool UseAllSseIfAvailable = true;
|
||||
|
||||
private static bool UseSseIfAvailable = true;
|
||||
|
|
|
@ -10,11 +10,9 @@ namespace ChocolArm64
|
|||
public AThreadState ThreadState { get; private set; }
|
||||
public AMemory Memory { get; private set; }
|
||||
|
||||
private long EntryPoint;
|
||||
|
||||
private ATranslator Translator;
|
||||
|
||||
private Thread Work;
|
||||
public Thread Work;
|
||||
|
||||
public event EventHandler WorkFinished;
|
||||
|
||||
|
@ -24,13 +22,21 @@ namespace ChocolArm64
|
|||
{
|
||||
this.Translator = Translator;
|
||||
this.Memory = Memory;
|
||||
this.EntryPoint = EntryPoint;
|
||||
|
||||
ThreadState = new AThreadState();
|
||||
|
||||
ThreadState.ExecutionMode = AExecutionMode.AArch64;
|
||||
|
||||
ThreadState.Running = true;
|
||||
|
||||
Work = new Thread(delegate()
|
||||
{
|
||||
Translator.ExecuteSubroutine(this, EntryPoint);
|
||||
|
||||
Memory.RemoveMonitor(ThreadState.Core);
|
||||
|
||||
WorkFinished?.Invoke(this, EventArgs.Empty);
|
||||
});
|
||||
}
|
||||
|
||||
public bool Execute()
|
||||
|
@ -40,15 +46,6 @@ namespace ChocolArm64
|
|||
return false;
|
||||
}
|
||||
|
||||
Work = new Thread(delegate()
|
||||
{
|
||||
Translator.ExecuteSubroutine(this, EntryPoint);
|
||||
|
||||
Memory.RemoveMonitor(ThreadState);
|
||||
|
||||
WorkFinished?.Invoke(this, EventArgs.Empty);
|
||||
});
|
||||
|
||||
Work.Start();
|
||||
|
||||
return true;
|
||||
|
@ -59,6 +56,11 @@ namespace ChocolArm64
|
|||
ThreadState.Running = false;
|
||||
}
|
||||
|
||||
public void RequestInterrupt()
|
||||
{
|
||||
ThreadState.RequestInterrupt();
|
||||
}
|
||||
|
||||
public bool IsCurrentThread()
|
||||
{
|
||||
return Thread.CurrentThread == Work;
|
||||
|
|
|
@ -13,6 +13,8 @@ namespace ChocolArm64
|
|||
{
|
||||
private delegate long AA64Subroutine(AThreadState Register, AMemory Memory);
|
||||
|
||||
private const int MinCallCountForReJit = 250;
|
||||
|
||||
private AA64Subroutine ExecDelegate;
|
||||
|
||||
public static int StateArgIdx { get; private set; }
|
||||
|
@ -32,8 +34,6 @@ namespace ChocolArm64
|
|||
|
||||
private bool NeedsReJit;
|
||||
|
||||
private int MinCallCountForReJit = 250;
|
||||
|
||||
public ATranslatedSub(DynamicMethod Method, List<ARegister> Params)
|
||||
{
|
||||
if (Method == null)
|
||||
|
@ -46,8 +46,8 @@ namespace ChocolArm64
|
|||
throw new ArgumentNullException(nameof(Params));
|
||||
}
|
||||
|
||||
this.Method = Method;
|
||||
this.Params = Params.AsReadOnly();
|
||||
this.Method = Method;
|
||||
this.Params = Params.AsReadOnly();
|
||||
|
||||
Callers = new HashSet<long>();
|
||||
|
||||
|
|
|
@ -1,38 +1,24 @@
|
|||
using ChocolArm64.Decoder;
|
||||
using ChocolArm64.Events;
|
||||
using ChocolArm64.Instruction;
|
||||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.State;
|
||||
using ChocolArm64.Translation;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace ChocolArm64
|
||||
{
|
||||
public class ATranslator
|
||||
{
|
||||
private ConcurrentDictionary<long, ATranslatedSub> CachedSubs;
|
||||
|
||||
private ConcurrentDictionary<long, string> SymbolTable;
|
||||
private ATranslatorCache Cache;
|
||||
|
||||
public event EventHandler<ACpuTraceEventArgs> CpuTrace;
|
||||
|
||||
public bool EnableCpuTrace { get; set; }
|
||||
|
||||
public ATranslator(IReadOnlyDictionary<long, string> SymbolTable = null)
|
||||
public ATranslator()
|
||||
{
|
||||
CachedSubs = new ConcurrentDictionary<long, ATranslatedSub>();
|
||||
|
||||
if (SymbolTable != null)
|
||||
{
|
||||
this.SymbolTable = new ConcurrentDictionary<long, string>(SymbolTable);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SymbolTable = new ConcurrentDictionary<long, string>();
|
||||
}
|
||||
Cache = new ATranslatorCache();
|
||||
}
|
||||
|
||||
internal void ExecuteSubroutine(AThread Thread, long Position)
|
||||
|
@ -70,15 +56,10 @@ namespace ChocolArm64
|
|||
{
|
||||
if (EnableCpuTrace)
|
||||
{
|
||||
if (!SymbolTable.TryGetValue(Position, out string SubName))
|
||||
{
|
||||
SubName = string.Empty;
|
||||
}
|
||||
|
||||
CpuTrace?.Invoke(this, new ACpuTraceEventArgs(Position, SubName));
|
||||
CpuTrace?.Invoke(this, new ACpuTraceEventArgs(Position));
|
||||
}
|
||||
|
||||
if (!CachedSubs.TryGetValue(Position, out ATranslatedSub Sub))
|
||||
if (!Cache.TryGetSubroutine(Position, out ATranslatedSub Sub))
|
||||
{
|
||||
Sub = TranslateTier0(State, Memory, Position);
|
||||
}
|
||||
|
@ -93,37 +74,20 @@ namespace ChocolArm64
|
|||
while (Position != 0 && State.Running);
|
||||
}
|
||||
|
||||
internal bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub)
|
||||
{
|
||||
if (OpCode.Emitter != AInstEmit.Bl)
|
||||
{
|
||||
Sub = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return TryGetCachedSub(((AOpCodeBImmAl)OpCode).Imm, out Sub);
|
||||
}
|
||||
|
||||
internal bool TryGetCachedSub(long Position, out ATranslatedSub Sub)
|
||||
{
|
||||
return CachedSubs.TryGetValue(Position, out Sub);
|
||||
}
|
||||
|
||||
internal bool HasCachedSub(long Position)
|
||||
{
|
||||
return CachedSubs.ContainsKey(Position);
|
||||
return Cache.HasSubroutine(Position);
|
||||
}
|
||||
|
||||
private ATranslatedSub TranslateTier0(AThreadState State, AMemory Memory, long Position)
|
||||
{
|
||||
ABlock Block = ADecoder.DecodeBasicBlock(State, this, Memory, Position);
|
||||
ABlock Block = ADecoder.DecodeBasicBlock(State, Memory, Position);
|
||||
|
||||
ABlock[] Graph = new ABlock[] { Block };
|
||||
|
||||
string SubName = GetSubName(Position);
|
||||
string SubName = GetSubroutineName(Position);
|
||||
|
||||
AILEmitterCtx Context = new AILEmitterCtx(this, Graph, Block, SubName);
|
||||
AILEmitterCtx Context = new AILEmitterCtx(Cache, Graph, Block, SubName);
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -135,7 +99,7 @@ namespace ChocolArm64
|
|||
|
||||
Subroutine.SetType(ATranslatedSubType.SubTier0);
|
||||
|
||||
CachedSubs.AddOrUpdate(Position, Subroutine, (Key, OldVal) => Subroutine);
|
||||
Cache.AddOrUpdate(Position, Subroutine, Block.OpCodes.Count);
|
||||
|
||||
AOpCode LastOp = Block.GetLastOp();
|
||||
|
||||
|
@ -144,13 +108,11 @@ namespace ChocolArm64
|
|||
|
||||
private void TranslateTier1(AThreadState State, AMemory Memory, long Position)
|
||||
{
|
||||
(ABlock[] Graph, ABlock Root) Cfg = ADecoder.DecodeSubroutine(State, this, Memory, Position);
|
||||
(ABlock[] Graph, ABlock Root) = ADecoder.DecodeSubroutine(Cache, State, Memory, Position);
|
||||
|
||||
string SubName = GetSubName(Position);
|
||||
string SubName = GetSubroutineName(Position);
|
||||
|
||||
PropagateName(Cfg.Graph, SubName);
|
||||
|
||||
AILEmitterCtx Context = new AILEmitterCtx(this, Cfg.Graph, Cfg.Root, SubName);
|
||||
AILEmitterCtx Context = new AILEmitterCtx(Cache, Graph, Root, SubName);
|
||||
|
||||
if (Context.CurrBlock.Position != Position)
|
||||
{
|
||||
|
@ -165,11 +127,11 @@ namespace ChocolArm64
|
|||
|
||||
//Mark all methods that calls this method for ReJiting,
|
||||
//since we can now call it directly which is faster.
|
||||
if (CachedSubs.TryGetValue(Position, out ATranslatedSub OldSub))
|
||||
if (Cache.TryGetSubroutine(Position, out ATranslatedSub OldSub))
|
||||
{
|
||||
foreach (long CallerPos in OldSub.GetCallerPositions())
|
||||
{
|
||||
if (CachedSubs.TryGetValue(Position, out ATranslatedSub CallerSub))
|
||||
if (Cache.TryGetSubroutine(Position, out ATranslatedSub CallerSub))
|
||||
{
|
||||
CallerSub.MarkForReJit();
|
||||
}
|
||||
|
@ -180,27 +142,24 @@ namespace ChocolArm64
|
|||
|
||||
Subroutine.SetType(ATranslatedSubType.SubTier1);
|
||||
|
||||
CachedSubs.AddOrUpdate(Position, Subroutine, (Key, OldVal) => Subroutine);
|
||||
Cache.AddOrUpdate(Position, Subroutine, GetGraphInstCount(Graph));
|
||||
}
|
||||
|
||||
private string GetSubName(long Position)
|
||||
private string GetSubroutineName(long Position)
|
||||
{
|
||||
return SymbolTable.GetOrAdd(Position, $"Sub{Position:x16}");
|
||||
return $"Sub{Position:x16}";
|
||||
}
|
||||
|
||||
private void PropagateName(ABlock[] Graph, string Name)
|
||||
private int GetGraphInstCount(ABlock[] Graph)
|
||||
{
|
||||
int Size = 0;
|
||||
|
||||
foreach (ABlock Block in Graph)
|
||||
{
|
||||
AOpCode LastOp = Block.GetLastOp();
|
||||
|
||||
if (LastOp != null &&
|
||||
(LastOp.Emitter == AInstEmit.Bl ||
|
||||
LastOp.Emitter == AInstEmit.Blr))
|
||||
{
|
||||
SymbolTable.TryAdd(LastOp.Position + 4, Name);
|
||||
}
|
||||
Size += Block.OpCodes.Count;
|
||||
}
|
||||
|
||||
return Size;
|
||||
}
|
||||
}
|
||||
}
|
164
ChocolArm64/ATranslatorCache.cs
Normal file
164
ChocolArm64/ATranslatorCache.cs
Normal file
|
@ -0,0 +1,164 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace ChocolArm64
|
||||
{
|
||||
class ATranslatorCache
|
||||
{
|
||||
private const int MaxTotalSize = 2 * 1024 * 256;
|
||||
private const int MaxTimeDelta = 30000;
|
||||
private const int MinCallCountForUpdate = 1000;
|
||||
|
||||
private class CacheBucket
|
||||
{
|
||||
public ATranslatedSub Subroutine { get; private set; }
|
||||
|
||||
public LinkedListNode<long> Node { get; private set; }
|
||||
|
||||
public int CallCount { get; set; }
|
||||
|
||||
public int Size { get; private set; }
|
||||
|
||||
public int Timestamp { get; private set; }
|
||||
|
||||
public CacheBucket(ATranslatedSub Subroutine, LinkedListNode<long> Node, int Size)
|
||||
{
|
||||
this.Subroutine = Subroutine;
|
||||
this.Size = Size;
|
||||
|
||||
UpdateNode(Node);
|
||||
}
|
||||
|
||||
public void UpdateNode(LinkedListNode<long> Node)
|
||||
{
|
||||
this.Node = Node;
|
||||
|
||||
Timestamp = Environment.TickCount;
|
||||
}
|
||||
}
|
||||
|
||||
private ConcurrentDictionary<long, CacheBucket> Cache;
|
||||
|
||||
private LinkedList<long> SortedCache;
|
||||
|
||||
private int TotalSize;
|
||||
|
||||
public ATranslatorCache()
|
||||
{
|
||||
Cache = new ConcurrentDictionary<long, CacheBucket>();
|
||||
|
||||
SortedCache = new LinkedList<long>();
|
||||
}
|
||||
|
||||
public void AddOrUpdate(long Position, ATranslatedSub Subroutine, int Size)
|
||||
{
|
||||
ClearCacheIfNeeded();
|
||||
|
||||
TotalSize += Size;
|
||||
|
||||
lock (SortedCache)
|
||||
{
|
||||
LinkedListNode<long> Node = SortedCache.AddLast(Position);
|
||||
|
||||
CacheBucket NewBucket = new CacheBucket(Subroutine, Node, Size);
|
||||
|
||||
Cache.AddOrUpdate(Position, NewBucket, (Key, Bucket) =>
|
||||
{
|
||||
TotalSize -= Bucket.Size;
|
||||
|
||||
SortedCache.Remove(Bucket.Node);
|
||||
|
||||
return NewBucket;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasSubroutine(long Position)
|
||||
{
|
||||
return Cache.ContainsKey(Position);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryGetSubroutine(long Position, out ATranslatedSub Subroutine)
|
||||
{
|
||||
if (Cache.TryGetValue(Position, out CacheBucket Bucket))
|
||||
{
|
||||
if (Bucket.CallCount++ > MinCallCountForUpdate)
|
||||
{
|
||||
if (Monitor.TryEnter(SortedCache))
|
||||
{
|
||||
try
|
||||
{
|
||||
Bucket.CallCount = 0;
|
||||
|
||||
SortedCache.Remove(Bucket.Node);
|
||||
|
||||
Bucket.UpdateNode(SortedCache.AddLast(Position));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Exit(SortedCache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Subroutine = Bucket.Subroutine;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Subroutine = default(ATranslatedSub);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ClearCacheIfNeeded()
|
||||
{
|
||||
int Timestamp = Environment.TickCount;
|
||||
|
||||
while (TotalSize > MaxTotalSize)
|
||||
{
|
||||
lock (SortedCache)
|
||||
{
|
||||
LinkedListNode<long> Node = SortedCache.First;
|
||||
|
||||
if (Node == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
CacheBucket Bucket = Cache[Node.Value];
|
||||
|
||||
int TimeDelta = RingDelta(Bucket.Timestamp, Timestamp);
|
||||
|
||||
if ((uint)TimeDelta <= (uint)MaxTimeDelta)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (Cache.TryRemove(Node.Value, out Bucket))
|
||||
{
|
||||
TotalSize -= Bucket.Size;
|
||||
|
||||
SortedCache.Remove(Bucket.Node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int RingDelta(int Old, int New)
|
||||
{
|
||||
if ((uint)New < (uint)Old)
|
||||
{
|
||||
return New + (~Old + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return New - Old;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,11 +19,7 @@ namespace ChocolArm64.Decoder
|
|||
OpActivators = new ConcurrentDictionary<Type, OpActivator>();
|
||||
}
|
||||
|
||||
public static ABlock DecodeBasicBlock(
|
||||
AThreadState State,
|
||||
ATranslator Translator,
|
||||
AMemory Memory,
|
||||
long Start)
|
||||
public static ABlock DecodeBasicBlock(AThreadState State, AMemory Memory, long Start)
|
||||
{
|
||||
ABlock Block = new ABlock(Start);
|
||||
|
||||
|
@ -33,10 +29,10 @@ namespace ChocolArm64.Decoder
|
|||
}
|
||||
|
||||
public static (ABlock[] Graph, ABlock Root) DecodeSubroutine(
|
||||
AThreadState State,
|
||||
ATranslator Translator,
|
||||
AMemory Memory,
|
||||
long Start)
|
||||
ATranslatorCache Cache,
|
||||
AThreadState State,
|
||||
AMemory Memory,
|
||||
long Start)
|
||||
{
|
||||
Dictionary<long, ABlock> Visited = new Dictionary<long, ABlock>();
|
||||
Dictionary<long, ABlock> VisitedEnd = new Dictionary<long, ABlock>();
|
||||
|
@ -79,7 +75,7 @@ namespace ChocolArm64.Decoder
|
|||
{
|
||||
if (Op.Emitter == AInstEmit.Bl)
|
||||
{
|
||||
HasCachedSub = Translator.HasCachedSub(Op.Imm);
|
||||
HasCachedSub = Cache.HasSubroutine(Op.Imm);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -6,12 +6,9 @@ namespace ChocolArm64.Events
|
|||
{
|
||||
public long Position { get; private set; }
|
||||
|
||||
public string SubName { get; private set; }
|
||||
|
||||
public ACpuTraceEventArgs(long Position, string SubName)
|
||||
public ACpuTraceEventArgs(long Position)
|
||||
{
|
||||
this.Position = Position;
|
||||
this.SubName = SubName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,14 +35,6 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp;
|
||||
|
||||
if (AOptimizations.GenerateCallStack)
|
||||
{
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
Context.EmitLdc_I8(Op.Imm);
|
||||
|
||||
Context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.EnterMethod));
|
||||
}
|
||||
|
||||
Context.EmitLdc_I(Op.Position + 4);
|
||||
Context.EmitStint(AThreadState.LRIndex);
|
||||
Context.EmitStoreState();
|
||||
|
@ -80,14 +72,6 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
AOpCodeBReg Op = (AOpCodeBReg)Context.CurrOp;
|
||||
|
||||
if (AOptimizations.GenerateCallStack)
|
||||
{
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
|
||||
Context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.EnterMethod));
|
||||
}
|
||||
|
||||
Context.EmitLdc_I(Op.Position + 4);
|
||||
Context.EmitStint(AThreadState.LRIndex);
|
||||
Context.EmitStoreState();
|
||||
|
@ -100,14 +84,6 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
AOpCodeBReg Op = (AOpCodeBReg)Context.CurrOp;
|
||||
|
||||
if (AOptimizations.GenerateCallStack)
|
||||
{
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
|
||||
Context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.JumpMethod));
|
||||
}
|
||||
|
||||
Context.EmitStoreState();
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
|
||||
|
@ -129,13 +105,6 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void Ret(AILEmitterCtx Context)
|
||||
{
|
||||
if (AOptimizations.GenerateCallStack)
|
||||
{
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
Context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.ExitMethod));
|
||||
}
|
||||
|
||||
Context.EmitStoreState();
|
||||
Context.EmitLdint(AThreadState.LRIndex);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using ChocolArm64.Decoder;
|
||||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.State;
|
||||
using ChocolArm64.Translation;
|
||||
using System;
|
||||
using System.Reflection.Emit;
|
||||
|
@ -170,6 +171,8 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Core));
|
||||
|
||||
if (Rn != -1)
|
||||
{
|
||||
Context.EmitLdint(Rn);
|
||||
|
|
|
@ -1199,22 +1199,22 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void Sqxtn_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarSaturatingNarrowOpSxSx(Context, () => { });
|
||||
EmitSaturatingNarrowOp(Context, SaturatingNarrowFlags.ScalarSxSx);
|
||||
}
|
||||
|
||||
public static void Sqxtn_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorSaturatingNarrowOpSxSx(Context, () => { });
|
||||
EmitSaturatingNarrowOp(Context, SaturatingNarrowFlags.VectorSxSx);
|
||||
}
|
||||
|
||||
public static void Sqxtun_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarSaturatingNarrowOpSxZx(Context, () => { });
|
||||
EmitSaturatingNarrowOp(Context, SaturatingNarrowFlags.ScalarSxZx);
|
||||
}
|
||||
|
||||
public static void Sqxtun_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorSaturatingNarrowOpSxZx(Context, () => { });
|
||||
EmitSaturatingNarrowOp(Context, SaturatingNarrowFlags.VectorSxZx);
|
||||
}
|
||||
|
||||
public static void Srhadd_V(AILEmitterCtx Context)
|
||||
|
@ -1455,12 +1455,12 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void Uqxtn_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarSaturatingNarrowOpZxZx(Context, () => { });
|
||||
EmitSaturatingNarrowOp(Context, SaturatingNarrowFlags.ScalarZxZx);
|
||||
}
|
||||
|
||||
public static void Uqxtn_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorSaturatingNarrowOpZxZx(Context, () => { });
|
||||
EmitSaturatingNarrowOp(Context, SaturatingNarrowFlags.VectorZxZx);
|
||||
}
|
||||
|
||||
public static void Urhadd_V(AILEmitterCtx Context)
|
||||
|
|
|
@ -1004,56 +1004,14 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
ScalarSxSx = Scalar | SignedSrc | SignedDst,
|
||||
ScalarSxZx = Scalar | SignedSrc,
|
||||
ScalarZxSx = Scalar | SignedDst,
|
||||
ScalarZxZx = Scalar,
|
||||
|
||||
VectorSxSx = SignedSrc | SignedDst,
|
||||
VectorSxZx = SignedSrc,
|
||||
VectorZxSx = SignedDst,
|
||||
VectorZxZx = 0
|
||||
}
|
||||
|
||||
public static void EmitScalarSaturatingNarrowOpSxSx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.ScalarSxSx);
|
||||
}
|
||||
|
||||
public static void EmitScalarSaturatingNarrowOpSxZx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.ScalarSxZx);
|
||||
}
|
||||
|
||||
public static void EmitScalarSaturatingNarrowOpZxSx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.ScalarZxSx);
|
||||
}
|
||||
|
||||
public static void EmitScalarSaturatingNarrowOpZxZx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.ScalarZxZx);
|
||||
}
|
||||
|
||||
public static void EmitVectorSaturatingNarrowOpSxSx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.VectorSxSx);
|
||||
}
|
||||
|
||||
public static void EmitVectorSaturatingNarrowOpSxZx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.VectorSxZx);
|
||||
}
|
||||
|
||||
public static void EmitVectorSaturatingNarrowOpZxSx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.VectorZxSx);
|
||||
}
|
||||
|
||||
public static void EmitVectorSaturatingNarrowOpZxZx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitSaturatingNarrowOp(Context, Emit, SaturatingNarrowFlags.VectorZxZx);
|
||||
}
|
||||
|
||||
public static void EmitSaturatingNarrowOp(AILEmitterCtx Context, Action Emit, SaturatingNarrowFlags Flags)
|
||||
public static void EmitSaturatingNarrowOp(AILEmitterCtx Context, SaturatingNarrowFlags Flags)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
|
@ -1080,8 +1038,6 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, SignedSrc);
|
||||
|
||||
Emit();
|
||||
|
||||
EmitSatQ(Context, Op.Size, SignedSrc, SignedDst);
|
||||
|
||||
EmitVectorInsertTmp(Context, Part + Index, Op.Size);
|
||||
|
|
|
@ -10,6 +10,11 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
static partial class AInstEmit
|
||||
{
|
||||
public static void Rshrn_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorShrImmNarrowOpZx(Context, Round: true);
|
||||
}
|
||||
|
||||
public static void Shl_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
|
@ -45,9 +50,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void Shrn_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
|
||||
EmitVectorShImmNarrowBinaryZx(Context, () => Context.Emit(OpCodes.Shr_Un), GetImmShr(Op));
|
||||
EmitVectorShrImmNarrowOpZx(Context, Round: false);
|
||||
}
|
||||
|
||||
public static void Sli_V(AILEmitterCtx Context)
|
||||
|
@ -85,26 +88,44 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
public static void Sqrshrn_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.ScalarSxSx);
|
||||
}
|
||||
|
||||
public static void Sqrshrn_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
EmitRoundShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.VectorSxSx);
|
||||
}
|
||||
|
||||
int Shift = GetImmShr(Op);
|
||||
public static void Sqrshrun_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.ScalarSxZx);
|
||||
}
|
||||
|
||||
long RoundConst = 1L << (Shift - 1);
|
||||
public static void Sqrshrun_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.VectorSxZx);
|
||||
}
|
||||
|
||||
Action Emit = () =>
|
||||
{
|
||||
Context.EmitLdc_I8(RoundConst);
|
||||
public static void Sqshrn_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.ScalarSxSx);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
public static void Sqshrn_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.VectorSxSx);
|
||||
}
|
||||
|
||||
Context.EmitLdc_I4(Shift);
|
||||
public static void Sqshrun_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.ScalarSxZx);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.Shr);
|
||||
};
|
||||
|
||||
EmitVectorSaturatingNarrowOpSxSx(Context, Emit);
|
||||
public static void Sqshrun_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.VectorSxZx);
|
||||
}
|
||||
|
||||
public static void Srshr_S(AILEmitterCtx Context)
|
||||
|
@ -159,6 +180,26 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorShrImmOpSx(Context, ShrImmFlags.Accumulate);
|
||||
}
|
||||
|
||||
public static void Uqrshrn_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.ScalarZxZx);
|
||||
}
|
||||
|
||||
public static void Uqrshrn_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitRoundShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.VectorZxZx);
|
||||
}
|
||||
|
||||
public static void Uqshrn_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.ScalarZxZx);
|
||||
}
|
||||
|
||||
public static void Uqshrn_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.VectorZxZx);
|
||||
}
|
||||
|
||||
public static void Urshr_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarShrImmOpZx(Context, ShrImmFlags.Round);
|
||||
|
@ -367,6 +408,138 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
private static void EmitVectorShrImmNarrowOpZx(AILEmitterCtx Context, bool Round)
|
||||
{
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
|
||||
int Shift = GetImmShr(Op);
|
||||
|
||||
long RoundConst = 1L << (Shift - 1);
|
||||
|
||||
int Elems = 8 >> Op.Size;
|
||||
|
||||
int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
|
||||
|
||||
if (Part != 0)
|
||||
{
|
||||
Context.EmitLdvec(Op.Rd);
|
||||
Context.EmitStvectmp();
|
||||
}
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1);
|
||||
|
||||
if (Round)
|
||||
{
|
||||
Context.EmitLdc_I8(RoundConst);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
}
|
||||
|
||||
Context.EmitLdc_I4(Shift);
|
||||
|
||||
Context.Emit(OpCodes.Shr_Un);
|
||||
|
||||
EmitVectorInsertTmp(Context, Part + Index, Op.Size);
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
|
||||
if (Part == 0)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum ShrImmSaturatingNarrowFlags
|
||||
{
|
||||
Scalar = 1 << 0,
|
||||
SignedSrc = 1 << 1,
|
||||
SignedDst = 1 << 2,
|
||||
|
||||
Round = 1 << 3,
|
||||
|
||||
ScalarSxSx = Scalar | SignedSrc | SignedDst,
|
||||
ScalarSxZx = Scalar | SignedSrc,
|
||||
ScalarZxZx = Scalar,
|
||||
|
||||
VectorSxSx = SignedSrc | SignedDst,
|
||||
VectorSxZx = SignedSrc,
|
||||
VectorZxZx = 0
|
||||
}
|
||||
|
||||
private static void EmitRoundShrImmSaturatingNarrowOp(AILEmitterCtx Context, ShrImmSaturatingNarrowFlags Flags)
|
||||
{
|
||||
EmitShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.Round | Flags);
|
||||
}
|
||||
|
||||
private static void EmitShrImmSaturatingNarrowOp(AILEmitterCtx Context, ShrImmSaturatingNarrowFlags Flags)
|
||||
{
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
|
||||
bool Scalar = (Flags & ShrImmSaturatingNarrowFlags.Scalar) != 0;
|
||||
bool SignedSrc = (Flags & ShrImmSaturatingNarrowFlags.SignedSrc) != 0;
|
||||
bool SignedDst = (Flags & ShrImmSaturatingNarrowFlags.SignedDst) != 0;
|
||||
bool Round = (Flags & ShrImmSaturatingNarrowFlags.Round) != 0;
|
||||
|
||||
int Shift = GetImmShr(Op);
|
||||
|
||||
long RoundConst = 1L << (Shift - 1);
|
||||
|
||||
int Elems = !Scalar ? 8 >> Op.Size : 1;
|
||||
|
||||
int Part = !Scalar && (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0;
|
||||
|
||||
if (Scalar)
|
||||
{
|
||||
EmitVectorZeroLowerTmp(Context);
|
||||
}
|
||||
|
||||
if (Part != 0)
|
||||
{
|
||||
Context.EmitLdvec(Op.Rd);
|
||||
Context.EmitStvectmp();
|
||||
}
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, SignedSrc);
|
||||
|
||||
if (Op.Size <= 1 || !Round)
|
||||
{
|
||||
if (Round)
|
||||
{
|
||||
Context.EmitLdc_I8(RoundConst);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
}
|
||||
|
||||
Context.EmitLdc_I4(Shift);
|
||||
|
||||
Context.Emit(SignedSrc ? OpCodes.Shr : OpCodes.Shr_Un);
|
||||
}
|
||||
else /* if (Op.Size == 2 && Round) */
|
||||
{
|
||||
EmitShrImm_64(Context, SignedSrc, RoundConst, Shift); // Shift <= 32
|
||||
}
|
||||
|
||||
EmitSatQ(Context, Op.Size, SignedSrc, SignedDst);
|
||||
|
||||
EmitVectorInsertTmp(Context, Part + Index, Op.Size);
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
|
||||
if (Part == 0)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
// Dst_64 = (Int(Src_64, Signed) + RoundConst) >> Shift;
|
||||
private static void EmitShrImm_64(
|
||||
AILEmitterCtx Context,
|
||||
|
@ -374,11 +547,6 @@ namespace ChocolArm64.Instruction
|
|||
long RoundConst,
|
||||
int Shift)
|
||||
{
|
||||
if (((AOpCodeSimd)Context.CurrOp).Size < 3)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
Context.EmitLdc_I8(RoundConst);
|
||||
Context.EmitLdc_I4(Shift);
|
||||
|
||||
|
@ -387,41 +555,6 @@ namespace ChocolArm64.Instruction
|
|||
: nameof(ASoftFallback.UnsignedShrImm_64));
|
||||
}
|
||||
|
||||
private static void EmitVectorShImmNarrowBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
|
||||
{
|
||||
EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, true);
|
||||
}
|
||||
|
||||
private static void EmitVectorShImmNarrowBinaryZx(AILEmitterCtx Context, Action Emit, int Imm)
|
||||
{
|
||||
EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, false);
|
||||
}
|
||||
|
||||
private static void EmitVectorShImmNarrowBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int Elems = 8 >> Op.Size;
|
||||
|
||||
int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed);
|
||||
|
||||
Context.EmitLdc_I4(Imm);
|
||||
|
||||
Emit();
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size);
|
||||
}
|
||||
|
||||
if (Part == 0)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitVectorShImmWidenBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
|
||||
{
|
||||
EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, true);
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace ChocolArm64.Memory
|
|||
}
|
||||
}
|
||||
|
||||
private Dictionary<AThreadState, ArmMonitor> Monitors;
|
||||
private Dictionary<int, ArmMonitor> Monitors;
|
||||
|
||||
private ConcurrentDictionary<long, IntPtr> ObservedPages;
|
||||
|
||||
|
@ -53,7 +53,7 @@ namespace ChocolArm64.Memory
|
|||
|
||||
public AMemory(IntPtr Ram)
|
||||
{
|
||||
Monitors = new Dictionary<AThreadState, ArmMonitor>();
|
||||
Monitors = new Dictionary<int, ArmMonitor>();
|
||||
|
||||
ObservedPages = new ConcurrentDictionary<long, IntPtr>();
|
||||
|
||||
|
@ -69,17 +69,17 @@ namespace ChocolArm64.Memory
|
|||
}
|
||||
}
|
||||
|
||||
public void RemoveMonitor(AThreadState State)
|
||||
public void RemoveMonitor(int Core)
|
||||
{
|
||||
lock (Monitors)
|
||||
{
|
||||
ClearExclusive(State);
|
||||
ClearExclusive(Core);
|
||||
|
||||
Monitors.Remove(State);
|
||||
Monitors.Remove(Core);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetExclusive(AThreadState ThreadState, long Position)
|
||||
public void SetExclusive(int Core, long Position)
|
||||
{
|
||||
Position &= ~ErgMask;
|
||||
|
||||
|
@ -93,11 +93,11 @@ namespace ChocolArm64.Memory
|
|||
}
|
||||
}
|
||||
|
||||
if (!Monitors.TryGetValue(ThreadState, out ArmMonitor ThreadMon))
|
||||
if (!Monitors.TryGetValue(Core, out ArmMonitor ThreadMon))
|
||||
{
|
||||
ThreadMon = new ArmMonitor();
|
||||
|
||||
Monitors.Add(ThreadState, ThreadMon);
|
||||
Monitors.Add(Core, ThreadMon);
|
||||
}
|
||||
|
||||
ThreadMon.Position = Position;
|
||||
|
@ -105,7 +105,7 @@ namespace ChocolArm64.Memory
|
|||
}
|
||||
}
|
||||
|
||||
public bool TestExclusive(AThreadState ThreadState, long Position)
|
||||
public bool TestExclusive(int Core, long Position)
|
||||
{
|
||||
//Note: Any call to this method also should be followed by a
|
||||
//call to ClearExclusiveForStore if this method returns true.
|
||||
|
@ -113,7 +113,7 @@ namespace ChocolArm64.Memory
|
|||
|
||||
Monitor.Enter(Monitors);
|
||||
|
||||
if (!Monitors.TryGetValue(ThreadState, out ArmMonitor ThreadMon))
|
||||
if (!Monitors.TryGetValue(Core, out ArmMonitor ThreadMon))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -128,9 +128,9 @@ namespace ChocolArm64.Memory
|
|||
return ExState;
|
||||
}
|
||||
|
||||
public void ClearExclusiveForStore(AThreadState ThreadState)
|
||||
public void ClearExclusiveForStore(int Core)
|
||||
{
|
||||
if (Monitors.TryGetValue(ThreadState, out ArmMonitor ThreadMon))
|
||||
if (Monitors.TryGetValue(Core, out ArmMonitor ThreadMon))
|
||||
{
|
||||
ThreadMon.ExState = false;
|
||||
}
|
||||
|
@ -138,11 +138,11 @@ namespace ChocolArm64.Memory
|
|||
Monitor.Exit(Monitors);
|
||||
}
|
||||
|
||||
public void ClearExclusive(AThreadState ThreadState)
|
||||
public void ClearExclusive(int Core)
|
||||
{
|
||||
lock (Monitors)
|
||||
{
|
||||
if (Monitors.TryGetValue(ThreadState, out ArmMonitor ThreadMon))
|
||||
if (Monitors.TryGetValue(Core, out ArmMonitor ThreadMon))
|
||||
{
|
||||
ThreadMon.ExState = false;
|
||||
}
|
||||
|
@ -287,6 +287,14 @@ namespace ChocolArm64.Memory
|
|||
return Data;
|
||||
}
|
||||
|
||||
public void ReadBytes(long Position, byte[] Data, int StartIndex, int Size)
|
||||
{
|
||||
//Note: This will be moved later.
|
||||
EnsureRangeIsValid(Position, (uint)Size);
|
||||
|
||||
Marshal.Copy((IntPtr)Translate(Position), Data, StartIndex, Size);
|
||||
}
|
||||
|
||||
public void WriteSByte(long Position, sbyte Value)
|
||||
{
|
||||
WriteByte(Position, (byte)Value);
|
||||
|
@ -403,6 +411,27 @@ namespace ChocolArm64.Memory
|
|||
Marshal.Copy(Data, 0, (IntPtr)TranslateWrite(Position), Data.Length);
|
||||
}
|
||||
|
||||
public void WriteBytes(long Position, byte[] Data, int StartIndex, int Size)
|
||||
{
|
||||
//Note: This will be moved later.
|
||||
//Using Translate instead of TranslateWrite is on purpose.
|
||||
EnsureRangeIsValid(Position, (uint)Size);
|
||||
|
||||
Marshal.Copy(Data, StartIndex, (IntPtr)Translate(Position), Size);
|
||||
}
|
||||
|
||||
public void CopyBytes(long Src, long Dst, long Size)
|
||||
{
|
||||
//Note: This will be moved later.
|
||||
EnsureRangeIsValid(Src, Size);
|
||||
EnsureRangeIsValid(Dst, Size);
|
||||
|
||||
byte* SrcPtr = Translate(Src);
|
||||
byte* DstPtr = TranslateWrite(Dst);
|
||||
|
||||
Buffer.MemoryCopy(SrcPtr, DstPtr, Size, Size);
|
||||
}
|
||||
|
||||
public void Map(long VA, long PA, long Size)
|
||||
{
|
||||
SetPTEntries(VA, RamPtr + PA, Size);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using ChocolArm64.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
|
||||
namespace ChocolArm64.State
|
||||
|
@ -14,6 +14,8 @@ namespace ChocolArm64.State
|
|||
internal const int ErgSizeLog2 = 4;
|
||||
internal const int DczSizeLog2 = 4;
|
||||
|
||||
private const int MinInstForCheck = 4000000;
|
||||
|
||||
internal AExecutionMode ExecutionMode;
|
||||
|
||||
//AArch32 state.
|
||||
|
@ -41,6 +43,11 @@ namespace ChocolArm64.State
|
|||
public bool Negative;
|
||||
|
||||
public bool Running { get; set; }
|
||||
public int Core { get; set; }
|
||||
|
||||
private bool Interrupted;
|
||||
|
||||
private int SyncCount;
|
||||
|
||||
public long TpidrEl0 { get; set; }
|
||||
public long Tpidr { get; set; }
|
||||
|
@ -73,21 +80,15 @@ namespace ChocolArm64.State
|
|||
}
|
||||
}
|
||||
|
||||
public event EventHandler<EventArgs> Interrupt;
|
||||
public event EventHandler<AInstExceptionEventArgs> Break;
|
||||
public event EventHandler<AInstExceptionEventArgs> SvcCall;
|
||||
public event EventHandler<AInstUndefinedEventArgs> Undefined;
|
||||
|
||||
private Stack<long> CallStack;
|
||||
|
||||
private static Stopwatch TickCounter;
|
||||
|
||||
private static double HostTickFreq;
|
||||
|
||||
public AThreadState()
|
||||
{
|
||||
CallStack = new Stack<long>();
|
||||
}
|
||||
|
||||
static AThreadState()
|
||||
{
|
||||
HostTickFreq = 1.0 / Stopwatch.Frequency;
|
||||
|
@ -97,11 +98,39 @@ namespace ChocolArm64.State
|
|||
TickCounter.Start();
|
||||
}
|
||||
|
||||
internal bool Synchronize()
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal bool Synchronize(int BbWeight)
|
||||
{
|
||||
//Firing a interrupt frequently is expensive, so we only
|
||||
//do it after a given number of instructions has executed.
|
||||
SyncCount += BbWeight;
|
||||
|
||||
if (SyncCount >= MinInstForCheck)
|
||||
{
|
||||
CheckInterrupt();
|
||||
}
|
||||
|
||||
return Running;
|
||||
}
|
||||
|
||||
internal void RequestInterrupt()
|
||||
{
|
||||
Interrupted = true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private void CheckInterrupt()
|
||||
{
|
||||
SyncCount = 0;
|
||||
|
||||
if (Interrupted)
|
||||
{
|
||||
Interrupted = false;
|
||||
|
||||
Interrupt?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnBreak(long Position, int Imm)
|
||||
{
|
||||
Break?.Invoke(this, new AInstExceptionEventArgs(Position, Imm));
|
||||
|
@ -116,27 +145,5 @@ namespace ChocolArm64.State
|
|||
{
|
||||
Undefined?.Invoke(this, new AInstUndefinedEventArgs(Position, RawOpCode));
|
||||
}
|
||||
|
||||
internal void EnterMethod(long Position)
|
||||
{
|
||||
CallStack.Push(Position);
|
||||
}
|
||||
|
||||
internal void ExitMethod()
|
||||
{
|
||||
CallStack.TryPop(out _);
|
||||
}
|
||||
|
||||
internal void JumpMethod(long Position)
|
||||
{
|
||||
CallStack.TryPop(out _);
|
||||
|
||||
CallStack.Push(Position);
|
||||
}
|
||||
|
||||
public long[] GetCallStack()
|
||||
{
|
||||
return CallStack.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ namespace ChocolArm64.Translation
|
|||
{
|
||||
class AILEmitterCtx
|
||||
{
|
||||
private ATranslator Translator;
|
||||
private ATranslatorCache Cache;
|
||||
|
||||
private Dictionary<long, AILLabel> Labels;
|
||||
|
||||
|
@ -40,29 +40,14 @@ namespace ChocolArm64.Translation
|
|||
private const int Tmp5Index = -5;
|
||||
|
||||
public AILEmitterCtx(
|
||||
ATranslator Translator,
|
||||
ABlock[] Graph,
|
||||
ABlock Root,
|
||||
string SubName)
|
||||
ATranslatorCache Cache,
|
||||
ABlock[] Graph,
|
||||
ABlock Root,
|
||||
string SubName)
|
||||
{
|
||||
if (Translator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Translator));
|
||||
}
|
||||
|
||||
if (Graph == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Graph));
|
||||
}
|
||||
|
||||
if (Root == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Root));
|
||||
}
|
||||
|
||||
this.Translator = Translator;
|
||||
this.Graph = Graph;
|
||||
this.Root = Root;
|
||||
this.Cache = Cache ?? throw new ArgumentNullException(nameof(Cache));
|
||||
this.Graph = Graph ?? throw new ArgumentNullException(nameof(Graph));
|
||||
this.Root = Root ?? throw new ArgumentNullException(nameof(Root));
|
||||
|
||||
Labels = new Dictionary<long, AILLabel>();
|
||||
|
||||
|
@ -123,6 +108,8 @@ namespace ChocolArm64.Translation
|
|||
{
|
||||
EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
EmitLdc_I4(CurrBlock.OpCodes.Count);
|
||||
|
||||
EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.Synchronize));
|
||||
|
||||
EmitLdc_I4(0);
|
||||
|
@ -145,7 +132,12 @@ namespace ChocolArm64.Translation
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!Translator.TryGetCachedSub(CurrOp, out ATranslatedSub Sub))
|
||||
if (CurrOp.Emitter != AInstEmit.Bl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Cache.TryGetSubroutine(((AOpCodeBImmAl)CurrOp).Imm, out ATranslatedSub Subroutine))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -155,7 +147,7 @@ namespace ChocolArm64.Translation
|
|||
EmitLdarg(Index);
|
||||
}
|
||||
|
||||
foreach (ARegister Reg in Sub.Params)
|
||||
foreach (ARegister Reg in Subroutine.Params)
|
||||
{
|
||||
switch (Reg.Type)
|
||||
{
|
||||
|
@ -165,9 +157,9 @@ namespace ChocolArm64.Translation
|
|||
}
|
||||
}
|
||||
|
||||
EmitCall(Sub.Method);
|
||||
EmitCall(Subroutine.Method);
|
||||
|
||||
Sub.AddCaller(Root.Position);
|
||||
Subroutine.AddCaller(Root.Position);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -28,16 +28,12 @@ namespace Ryujinx.Audio.OpenAL
|
|||
|
||||
public PlaybackState State { get; set; }
|
||||
|
||||
private bool ShouldCallReleaseCallback;
|
||||
|
||||
private ConcurrentDictionary<long, int> Buffers;
|
||||
|
||||
private Queue<long> QueuedTagsQueue;
|
||||
|
||||
private Queue<long> ReleasedTagsQueue;
|
||||
|
||||
private int LastReleasedCount;
|
||||
|
||||
private bool Disposed;
|
||||
|
||||
public Track(int SampleRate, ALFormat Format, ReleaseCallback Callback)
|
||||
|
@ -59,8 +55,6 @@ namespace Ryujinx.Audio.OpenAL
|
|||
|
||||
public bool ContainsBuffer(long Tag)
|
||||
{
|
||||
SyncQueuedTags();
|
||||
|
||||
foreach (long QueuedTag in QueuedTagsQueue)
|
||||
{
|
||||
if (QueuedTag == Tag)
|
||||
|
@ -72,20 +66,29 @@ namespace Ryujinx.Audio.OpenAL
|
|||
return false;
|
||||
}
|
||||
|
||||
public long[] GetReleasedBuffers(int MaxCount)
|
||||
public long[] GetReleasedBuffers(int Count)
|
||||
{
|
||||
ClearReleased();
|
||||
AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
|
||||
|
||||
ReleasedCount += ReleasedTagsQueue.Count;
|
||||
|
||||
if (Count > ReleasedCount)
|
||||
{
|
||||
Count = ReleasedCount;
|
||||
}
|
||||
|
||||
List<long> Tags = new List<long>();
|
||||
|
||||
HashSet<long> Unique = new HashSet<long>();
|
||||
|
||||
while (MaxCount-- > 0 && ReleasedTagsQueue.TryDequeue(out long Tag))
|
||||
while (Count-- > 0 && ReleasedTagsQueue.TryDequeue(out long Tag))
|
||||
{
|
||||
if (Unique.Add(Tag))
|
||||
{
|
||||
Tags.Add(Tag);
|
||||
}
|
||||
Tags.Add(Tag);
|
||||
}
|
||||
|
||||
while (Count-- > 0 && QueuedTagsQueue.TryDequeue(out long Tag))
|
||||
{
|
||||
AL.SourceUnqueueBuffers(SourceId, 1);
|
||||
|
||||
Tags.Add(Tag);
|
||||
}
|
||||
|
||||
return Tags.ToArray();
|
||||
|
@ -112,67 +115,27 @@ namespace Ryujinx.Audio.OpenAL
|
|||
return Id;
|
||||
}
|
||||
|
||||
public void ClearReleased()
|
||||
public void CallReleaseCallbackIfNeeded()
|
||||
{
|
||||
SyncQueuedTags();
|
||||
|
||||
AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
|
||||
|
||||
CheckReleaseChanges(ReleasedCount);
|
||||
|
||||
if (ReleasedCount > 0)
|
||||
{
|
||||
AL.SourceUnqueueBuffers(SourceId, ReleasedCount);
|
||||
}
|
||||
}
|
||||
//If we signal, then we also need to have released buffers available
|
||||
//to return when GetReleasedBuffers is called.
|
||||
//If playback needs to be re-started due to all buffers being processed,
|
||||
//then OpenAL zeros the counts (ReleasedCount), so we keep it on the queue.
|
||||
while (ReleasedCount-- > 0 && QueuedTagsQueue.TryDequeue(out long Tag))
|
||||
{
|
||||
AL.SourceUnqueueBuffers(SourceId, 1);
|
||||
|
||||
public void CallReleaseCallbackIfNeeded()
|
||||
{
|
||||
CheckReleaseChanges();
|
||||
|
||||
if (ShouldCallReleaseCallback)
|
||||
{
|
||||
ShouldCallReleaseCallback = false;
|
||||
ReleasedTagsQueue.Enqueue(Tag);
|
||||
}
|
||||
|
||||
Callback();
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckReleaseChanges()
|
||||
{
|
||||
AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
|
||||
|
||||
CheckReleaseChanges(ReleasedCount);
|
||||
}
|
||||
|
||||
private void CheckReleaseChanges(int NewReleasedCount)
|
||||
{
|
||||
if (LastReleasedCount != NewReleasedCount)
|
||||
{
|
||||
LastReleasedCount = NewReleasedCount;
|
||||
|
||||
ShouldCallReleaseCallback = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void SyncQueuedTags()
|
||||
{
|
||||
AL.GetSource(SourceId, ALGetSourcei.BuffersQueued, out int QueuedCount);
|
||||
AL.GetSource(SourceId, ALGetSourcei.BuffersProcessed, out int ReleasedCount);
|
||||
|
||||
QueuedCount -= ReleasedCount;
|
||||
|
||||
while (QueuedTagsQueue.Count > QueuedCount)
|
||||
{
|
||||
ReleasedTagsQueue.Enqueue(QueuedTagsQueue.Dequeue());
|
||||
}
|
||||
|
||||
while (ReleasedTagsQueue.Count > MaxReleased)
|
||||
{
|
||||
ReleasedTagsQueue.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
@ -266,7 +229,10 @@ namespace Ryujinx.Audio.OpenAL
|
|||
{
|
||||
if (Tracks.TryRemove(Track, out Track Td))
|
||||
{
|
||||
Td.Dispose();
|
||||
lock (Td)
|
||||
{
|
||||
Td.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,7 +240,10 @@ namespace Ryujinx.Audio.OpenAL
|
|||
{
|
||||
if (Tracks.TryGetValue(Track, out Track Td))
|
||||
{
|
||||
return Td.ContainsBuffer(Tag);
|
||||
lock (Td)
|
||||
{
|
||||
return Td.ContainsBuffer(Tag);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -284,7 +253,10 @@ namespace Ryujinx.Audio.OpenAL
|
|||
{
|
||||
if (Tracks.TryGetValue(Track, out Track Td))
|
||||
{
|
||||
return Td.GetReleasedBuffers(MaxCount);
|
||||
lock (Td)
|
||||
{
|
||||
return Td.GetReleasedBuffers(MaxCount);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -294,15 +266,18 @@ namespace Ryujinx.Audio.OpenAL
|
|||
{
|
||||
if (Tracks.TryGetValue(Track, out Track Td))
|
||||
{
|
||||
int BufferId = Td.AppendBuffer(Tag);
|
||||
lock (Td)
|
||||
{
|
||||
int BufferId = Td.AppendBuffer(Tag);
|
||||
|
||||
int Size = Buffer.Length * Marshal.SizeOf<T>();
|
||||
int Size = Buffer.Length * Marshal.SizeOf<T>();
|
||||
|
||||
AL.BufferData<T>(BufferId, Td.Format, Buffer, Size, Td.SampleRate);
|
||||
AL.BufferData<T>(BufferId, Td.Format, Buffer, Size, Td.SampleRate);
|
||||
|
||||
AL.SourceQueueBuffer(Td.SourceId, BufferId);
|
||||
AL.SourceQueueBuffer(Td.SourceId, BufferId);
|
||||
|
||||
StartPlaybackIfNeeded(Td);
|
||||
StartPlaybackIfNeeded(Td);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -310,9 +285,12 @@ namespace Ryujinx.Audio.OpenAL
|
|||
{
|
||||
if (Tracks.TryGetValue(Track, out Track Td))
|
||||
{
|
||||
Td.State = PlaybackState.Playing;
|
||||
lock (Td)
|
||||
{
|
||||
Td.State = PlaybackState.Playing;
|
||||
|
||||
StartPlaybackIfNeeded(Td);
|
||||
StartPlaybackIfNeeded(Td);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,8 +302,6 @@ namespace Ryujinx.Audio.OpenAL
|
|||
|
||||
if (State != ALSourceState.Playing && Td.State == PlaybackState.Playing)
|
||||
{
|
||||
Td.ClearReleased();
|
||||
|
||||
AL.SourcePlay(Td.SourceId);
|
||||
}
|
||||
}
|
||||
|
@ -334,9 +310,12 @@ namespace Ryujinx.Audio.OpenAL
|
|||
{
|
||||
if (Tracks.TryGetValue(Track, out Track Td))
|
||||
{
|
||||
Td.State = PlaybackState.Stopped;
|
||||
lock (Td)
|
||||
{
|
||||
Td.State = PlaybackState.Stopped;
|
||||
|
||||
AL.SourceStop(Td.SourceId);
|
||||
AL.SourceStop(Td.SourceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
using Ryujinx.Graphics.Texture;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public struct GalImage
|
||||
{
|
||||
public int Width;
|
||||
public int Height;
|
||||
public int TileWidth;
|
||||
public int GobBlockHeight;
|
||||
public int Pitch;
|
||||
|
||||
public GalImageFormat Format;
|
||||
|
||||
public GalImageFormat Format;
|
||||
public GalMemoryLayout Layout;
|
||||
public GalTextureSource XSource;
|
||||
public GalTextureSource YSource;
|
||||
public GalTextureSource ZSource;
|
||||
|
@ -15,19 +20,44 @@ namespace Ryujinx.Graphics.Gal
|
|||
public GalImage(
|
||||
int Width,
|
||||
int Height,
|
||||
int TileWidth,
|
||||
int GobBlockHeight,
|
||||
GalMemoryLayout Layout,
|
||||
GalImageFormat Format,
|
||||
GalTextureSource XSource = GalTextureSource.Red,
|
||||
GalTextureSource YSource = GalTextureSource.Green,
|
||||
GalTextureSource ZSource = GalTextureSource.Blue,
|
||||
GalTextureSource WSource = GalTextureSource.Alpha)
|
||||
{
|
||||
this.Width = Width;
|
||||
this.Height = Height;
|
||||
this.Format = Format;
|
||||
this.XSource = XSource;
|
||||
this.YSource = YSource;
|
||||
this.ZSource = ZSource;
|
||||
this.WSource = WSource;
|
||||
this.Width = Width;
|
||||
this.Height = Height;
|
||||
this.TileWidth = TileWidth;
|
||||
this.GobBlockHeight = GobBlockHeight;
|
||||
this.Layout = Layout;
|
||||
this.Format = Format;
|
||||
this.XSource = XSource;
|
||||
this.YSource = YSource;
|
||||
this.ZSource = ZSource;
|
||||
this.WSource = WSource;
|
||||
|
||||
Pitch = ImageUtils.GetPitch(Format, Width);
|
||||
}
|
||||
|
||||
public bool SizeMatches(GalImage Image)
|
||||
{
|
||||
if (ImageUtils.GetBytesPerPixel(Format) !=
|
||||
ImageUtils.GetBytesPerPixel(Image.Format))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ImageUtils.GetAlignedWidth(this) !=
|
||||
ImageUtils.GetAlignedWidth(Image))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Height == Image.Height;
|
||||
}
|
||||
}
|
||||
}
|
8
Ryujinx.Graphics/Gal/GalMemoryLayout.cs
Normal file
8
Ryujinx.Graphics/Gal/GalMemoryLayout.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public enum GalMemoryLayout
|
||||
{
|
||||
BlockLinear = 0,
|
||||
Pitch = 1
|
||||
}
|
||||
}
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
public GalVertexBinding[] VertexBindings;
|
||||
|
||||
public bool FramebufferSrgb;
|
||||
|
||||
public float FlipX;
|
||||
public float FlipY;
|
||||
|
||||
|
@ -32,6 +34,7 @@
|
|||
public GalCullFace CullFace;
|
||||
|
||||
public bool DepthTestEnabled;
|
||||
public bool DepthWriteEnabled;
|
||||
public GalComparisonOp DepthFunc;
|
||||
|
||||
public bool StencilTestEnabled;
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace Ryujinx.Graphics.Gal
|
|||
R32G32 = 0x4,
|
||||
A8B8G8R8 = 0x8,
|
||||
A2B10G10R10 = 0x9,
|
||||
R16G16 = 0xc,
|
||||
R32 = 0xf,
|
||||
BC6H_SF16 = 0x10,
|
||||
BC6H_UF16 = 0x11,
|
||||
|
@ -26,6 +27,7 @@ namespace Ryujinx.Graphics.Gal
|
|||
Z24S8 = 0x29,
|
||||
ZF32 = 0x2f,
|
||||
ZF32_X24S8 = 0x30,
|
||||
Z16 = 0x3a,
|
||||
Astc2D4x4 = 0x40,
|
||||
Astc2D5x5 = 0x41,
|
||||
Astc2D6x6 = 0x42,
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Gal
|
|||
|
||||
void SetIndexArray(int Size, GalIndexFormat Format);
|
||||
|
||||
void DrawArrays(int First, int PrimCount, GalPrimitiveType PrimType);
|
||||
void DrawArrays(int First, int Count, GalPrimitiveType PrimType);
|
||||
|
||||
void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType);
|
||||
}
|
||||
|
|
|
@ -1,23 +1,17 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public interface IGalRenderTarget
|
||||
{
|
||||
void BindColor(long Key, int Attachment);
|
||||
void BindColor(long Key, int Attachment, GalImage Image);
|
||||
|
||||
void UnbindColor(int Attachment);
|
||||
|
||||
void BindZeta(long Key);
|
||||
void BindZeta(long Key, GalImage Image);
|
||||
|
||||
void UnbindZeta();
|
||||
|
||||
void BindTexture(long Key, int Index);
|
||||
|
||||
void Set(long Key);
|
||||
|
||||
void Set(byte[] Data, int Width, int Height);
|
||||
|
||||
void SetMap(int[] Map);
|
||||
|
||||
void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom);
|
||||
|
@ -40,12 +34,6 @@ namespace Ryujinx.Graphics.Gal
|
|||
int DstX1,
|
||||
int DstY1);
|
||||
|
||||
void GetBufferData(long Key, Action<byte[]> Callback);
|
||||
|
||||
void SetBufferData(
|
||||
long Key,
|
||||
int Width,
|
||||
int Height,
|
||||
byte[] Buffer);
|
||||
void Reinterpret(long Key, GalImage NewImage);
|
||||
}
|
||||
}
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.Graphics.Gal
|
|||
void LockCache();
|
||||
void UnlockCache();
|
||||
|
||||
void Create(long Key, int Size, GalImage Image);
|
||||
|
||||
void Create(long Key, byte[] Data, GalImage Image);
|
||||
|
||||
void CreateFb(long Key, long Size, GalImage Image);
|
||||
bool TryGetImage(long Key, out GalImage Image);
|
||||
|
||||
bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image);
|
||||
|
||||
void Bind(long Key, int Index);
|
||||
void Bind(long Key, int Index, GalImage Image);
|
||||
|
||||
void SetSampler(GalTextureSampler Sampler);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
using System;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
class ImageHandler
|
||||
{
|
||||
private static int CopyBuffer = 0;
|
||||
private static int CopyBufferSize = 0;
|
||||
|
||||
public GalImage Image { get; private set; }
|
||||
|
||||
public int Width => Image.Width;
|
||||
|
@ -16,144 +11,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public GalImageFormat Format => Image.Format;
|
||||
|
||||
public PixelInternalFormat InternalFormat { get; private set; }
|
||||
public PixelFormat PixelFormat { get; private set; }
|
||||
public PixelType PixelType { get; private set; }
|
||||
|
||||
public int Handle { get; private set; }
|
||||
|
||||
private bool Initialized;
|
||||
|
||||
public ImageHandler()
|
||||
{
|
||||
Handle = GL.GenTexture();
|
||||
}
|
||||
|
||||
public ImageHandler(int Handle, GalImage Image)
|
||||
{
|
||||
this.Handle = Handle;
|
||||
|
||||
this.Image = Image;
|
||||
}
|
||||
|
||||
public void EnsureSetup(GalImage NewImage)
|
||||
{
|
||||
if (Width == NewImage.Width &&
|
||||
Height == NewImage.Height &&
|
||||
Format == NewImage.Format &&
|
||||
Initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PixelInternalFormat InternalFmt;
|
||||
PixelFormat PixelFormat;
|
||||
PixelType PixelType;
|
||||
|
||||
if (ImageUtils.IsCompressed(NewImage.Format))
|
||||
{
|
||||
InternalFmt = (PixelInternalFormat)OGLEnumConverter.GetCompressedImageFormat(NewImage.Format);
|
||||
|
||||
PixelFormat = default(PixelFormat);
|
||||
PixelType = default(PixelType);
|
||||
}
|
||||
else
|
||||
{
|
||||
(InternalFmt, PixelFormat, PixelType) = OGLEnumConverter.GetImageFormat(NewImage.Format);
|
||||
}
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
|
||||
if (Initialized)
|
||||
{
|
||||
if (CopyBuffer == 0)
|
||||
{
|
||||
CopyBuffer = GL.GenBuffer();
|
||||
}
|
||||
|
||||
int CurrentSize = Math.Max(ImageUtils.GetSize(NewImage),
|
||||
ImageUtils.GetSize(Image));
|
||||
|
||||
GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyBuffer);
|
||||
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyBuffer);
|
||||
|
||||
if (CopyBufferSize < CurrentSize)
|
||||
{
|
||||
CopyBufferSize = CurrentSize;
|
||||
|
||||
GL.BufferData(BufferTarget.PixelPackBuffer, CurrentSize, IntPtr.Zero, BufferUsageHint.StreamCopy);
|
||||
}
|
||||
|
||||
if (ImageUtils.IsCompressed(Image.Format))
|
||||
{
|
||||
GL.GetCompressedTexImage(TextureTarget.Texture2D, 0, IntPtr.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.GetTexImage(TextureTarget.Texture2D, 0, this.PixelFormat, this.PixelType, IntPtr.Zero);
|
||||
}
|
||||
|
||||
GL.DeleteTexture(Handle);
|
||||
|
||||
Handle = GL.GenTexture();
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
}
|
||||
|
||||
const int MinFilter = (int)TextureMinFilter.Linear;
|
||||
const int MagFilter = (int)TextureMagFilter.Linear;
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
|
||||
|
||||
const int Level = 0;
|
||||
const int Border = 0;
|
||||
|
||||
if (ImageUtils.IsCompressed(NewImage.Format))
|
||||
{
|
||||
Console.WriteLine("Hit");
|
||||
|
||||
GL.CompressedTexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
(InternalFormat)InternalFmt,
|
||||
NewImage.Width,
|
||||
NewImage.Height,
|
||||
Border,
|
||||
ImageUtils.GetSize(NewImage),
|
||||
IntPtr.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
InternalFmt,
|
||||
NewImage.Width,
|
||||
NewImage.Height,
|
||||
Border,
|
||||
PixelFormat,
|
||||
PixelType,
|
||||
IntPtr.Zero);
|
||||
}
|
||||
|
||||
if (Initialized)
|
||||
{
|
||||
GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
|
||||
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0);
|
||||
}
|
||||
|
||||
Image = NewImage;
|
||||
|
||||
this.InternalFormat = InternalFmt;
|
||||
this.PixelFormat = PixelFormat;
|
||||
this.PixelType = PixelType;
|
||||
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
public bool HasColor => ImageUtils.HasColor(Image.Format);
|
||||
public bool HasDepth => ImageUtils.HasDepth(Image.Format);
|
||||
public bool HasStencil => ImageUtils.HasStencil(Image.Format);
|
||||
|
||||
public ImageHandler(int Handle, GalImage Image)
|
||||
{
|
||||
this.Handle = Handle;
|
||||
this.Image = Image;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public CacheBucket(T Value, long DataSize, LinkedListNode<long> Node)
|
||||
{
|
||||
this.Value = Value;
|
||||
this.DataSize = DataSize;
|
||||
this.Node = Node;
|
||||
this.Value = Value;
|
||||
this.DataSize = DataSize;
|
||||
this.Node = Node;
|
||||
|
||||
Timestamp = Environment.TickCount;
|
||||
}
|
||||
|
|
|
@ -149,8 +149,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
case GalImageFormat.R32 | GalImageFormat.Sfloat: return (PixelInternalFormat.R32f, PixelFormat.Red, PixelType.Float);
|
||||
case GalImageFormat.R32 | GalImageFormat.Sint: return (PixelInternalFormat.R32i, PixelFormat.Red, PixelType.Int);
|
||||
case GalImageFormat.R32 | GalImageFormat.Uint: return (PixelInternalFormat.R32ui, PixelFormat.Red, PixelType.UnsignedInt);
|
||||
case GalImageFormat.A1R5G5B5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551);
|
||||
case GalImageFormat.B5G6R5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565);
|
||||
case GalImageFormat.A1R5G5B5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed);
|
||||
case GalImageFormat.B5G6R5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565Reversed);
|
||||
case GalImageFormat.R16G16 | GalImageFormat.Sfloat: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat);
|
||||
case GalImageFormat.R16G16 | GalImageFormat.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short);
|
||||
case GalImageFormat.R16G16 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Byte);
|
||||
|
@ -173,7 +173,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
case GalImageFormat.D24_S8 | GalImageFormat.Unorm: return (PixelInternalFormat.Depth24Stencil8, PixelFormat.DepthStencil, PixelType.UnsignedInt248);
|
||||
case GalImageFormat.D32 | GalImageFormat.Sfloat: return (PixelInternalFormat.DepthComponent32f, PixelFormat.DepthComponent, PixelType.Float);
|
||||
case GalImageFormat.D16 | GalImageFormat.Unorm: return (PixelInternalFormat.DepthComponent16, PixelFormat.DepthComponent, PixelType.UnsignedShort);
|
||||
case GalImageFormat.D32_S8 | GalImageFormat.Uint: return (PixelInternalFormat.Depth32fStencil8, PixelFormat.DepthStencil, PixelType.Float32UnsignedInt248Rev);
|
||||
case GalImageFormat.D32_S8 | GalImageFormat.Sfloat: return (PixelInternalFormat.Depth32fStencil8, PixelFormat.DepthStencil, PixelType.Float32UnsignedInt248Rev);
|
||||
}
|
||||
|
||||
throw new NotImplementedException($"{Format & GalImageFormat.FormatMask} {Format & GalImageFormat.TypeMask}");
|
||||
|
@ -183,16 +183,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalImageFormat.BC6H_UF16 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbBptcUnsignedFloat;
|
||||
case GalImageFormat.BC6H_SF16 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbBptcSignedFloat;
|
||||
case GalImageFormat.BC7 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaBptcUnorm;
|
||||
case GalImageFormat.BC1_RGBA | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaS3tcDxt1Ext;
|
||||
case GalImageFormat.BC2 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaS3tcDxt3Ext;
|
||||
case GalImageFormat.BC3 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaS3tcDxt5Ext;
|
||||
case GalImageFormat.BC4 | GalImageFormat.Snorm: return InternalFormat.CompressedSignedRedRgtc1;
|
||||
case GalImageFormat.BC4 | GalImageFormat.Unorm: return InternalFormat.CompressedRedRgtc1;
|
||||
case GalImageFormat.BC5 | GalImageFormat.Snorm: return InternalFormat.CompressedSignedRgRgtc2;
|
||||
case GalImageFormat.BC5 | GalImageFormat.Unorm: return InternalFormat.CompressedRgRgtc2;
|
||||
case GalImageFormat.BC6H_UF16 | GalImageFormat.Sfloat: return InternalFormat.CompressedRgbBptcUnsignedFloat;
|
||||
case GalImageFormat.BC6H_SF16 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbBptcSignedFloat;
|
||||
case GalImageFormat.BC7 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaBptcUnorm;
|
||||
case GalImageFormat.BC1_RGBA | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaS3tcDxt1Ext;
|
||||
case GalImageFormat.BC2 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaS3tcDxt3Ext;
|
||||
case GalImageFormat.BC3 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaS3tcDxt5Ext;
|
||||
case GalImageFormat.BC4 | GalImageFormat.Snorm: return InternalFormat.CompressedSignedRedRgtc1;
|
||||
case GalImageFormat.BC4 | GalImageFormat.Unorm: return InternalFormat.CompressedRedRgtc1;
|
||||
case GalImageFormat.BC5 | GalImageFormat.Snorm: return InternalFormat.CompressedSignedRgRgtc2;
|
||||
case GalImageFormat.BC5 | GalImageFormat.Unorm: return InternalFormat.CompressedRgRgtc2;
|
||||
}
|
||||
|
||||
throw new NotImplementedException($"{Format & GalImageFormat.FormatMask} {Format & GalImageFormat.TypeMask}");
|
||||
|
|
|
@ -85,6 +85,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
CullFace = GalCullFace.Back,
|
||||
|
||||
DepthTestEnabled = false,
|
||||
DepthWriteEnabled = true,
|
||||
DepthFunc = GalComparisonOp.Less,
|
||||
|
||||
StencilTestEnabled = false,
|
||||
|
@ -126,6 +127,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
BindVertexLayout(New);
|
||||
|
||||
if (New.FramebufferSrgb != Old.FramebufferSrgb)
|
||||
{
|
||||
Enable(EnableCap.FramebufferSrgb, New.FramebufferSrgb);
|
||||
}
|
||||
|
||||
if (New.FlipX != Old.FlipX || New.FlipY != Old.FlipY || New.Instance != Old.Instance)
|
||||
{
|
||||
Shader.SetExtraData(New.FlipX, New.FlipY, New.Instance);
|
||||
|
@ -133,19 +139,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
//Note: Uncomment SetFrontFace and SetCullFace when flipping issues are solved
|
||||
|
||||
//if (New.FrontFace != O.FrontFace)
|
||||
//if (New.FrontFace != Old.FrontFace)
|
||||
//{
|
||||
// GL.FrontFace(OGLEnumConverter.GetFrontFace(New.FrontFace));
|
||||
//}
|
||||
|
||||
//if (New.CullFaceEnabled != O.CullFaceEnabled)
|
||||
//if (New.CullFaceEnabled != Old.CullFaceEnabled)
|
||||
//{
|
||||
// Enable(EnableCap.CullFace, New.CullFaceEnabled);
|
||||
//}
|
||||
|
||||
//if (New.CullFaceEnabled)
|
||||
//{
|
||||
// if (New.CullFace != O.CullFace)
|
||||
// if (New.CullFace != Old.CullFace)
|
||||
// {
|
||||
// GL.CullFace(OGLEnumConverter.GetCullFace(New.CullFace));
|
||||
// }
|
||||
|
@ -156,6 +162,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
Enable(EnableCap.DepthTest, New.DepthTestEnabled);
|
||||
}
|
||||
|
||||
if (New.DepthWriteEnabled != Old.DepthWriteEnabled)
|
||||
{
|
||||
Rasterizer.DepthWriteEnabled = New.DepthWriteEnabled;
|
||||
|
||||
GL.DepthMask(New.DepthWriteEnabled);
|
||||
}
|
||||
|
||||
if (New.DepthTestEnabled)
|
||||
{
|
||||
if (New.DepthFunc != Old.DepthFunc)
|
||||
|
@ -337,6 +350,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
foreach (GalVertexAttrib Attrib in Binding.Attribs)
|
||||
{
|
||||
//Skip uninitialized attributes.
|
||||
if (Attrib.Size == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GL.EnableVertexAttribArray(Attrib.Index);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
||||
|
|
|
@ -5,6 +5,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
class OGLRasterizer : IGalRasterizer
|
||||
{
|
||||
public bool DepthWriteEnabled { set; private get; }
|
||||
|
||||
private int[] VertexBuffers;
|
||||
|
||||
private OGLCachedResource<int> VboCache;
|
||||
|
@ -28,6 +30,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
IboCache = new OGLCachedResource<int>(GL.DeleteBuffer);
|
||||
|
||||
IndexBuffer = new IbInfo();
|
||||
|
||||
DepthWriteEnabled = true;
|
||||
}
|
||||
|
||||
public void LockCaches()
|
||||
|
@ -49,6 +53,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
float Depth,
|
||||
int Stencil)
|
||||
{
|
||||
//OpenGL needs glDepthMask to be enabled to clear it
|
||||
if (!DepthWriteEnabled)
|
||||
{
|
||||
GL.DepthMask(true);
|
||||
}
|
||||
|
||||
GL.ColorMask(
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorRed),
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorGreen),
|
||||
|
@ -68,6 +78,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
}
|
||||
|
||||
GL.ColorMask(true, true, true, true);
|
||||
|
||||
if (!DepthWriteEnabled)
|
||||
{
|
||||
GL.DepthMask(false);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsVboCached(long Key, long DataSize)
|
||||
|
@ -113,14 +128,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
IndexBuffer.ElemSizeLog2 = (int)Format;
|
||||
}
|
||||
|
||||
public void DrawArrays(int First, int PrimCount, GalPrimitiveType PrimType)
|
||||
public void DrawArrays(int First, int Count, GalPrimitiveType PrimType)
|
||||
{
|
||||
if (PrimCount == 0)
|
||||
if (Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, PrimCount);
|
||||
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, Count);
|
||||
}
|
||||
|
||||
public void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType)
|
||||
|
|
|
@ -15,9 +15,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public Rect(int X, int Y, int Width, int Height)
|
||||
{
|
||||
this.X = X;
|
||||
this.Y = Y;
|
||||
this.Width = Width;
|
||||
this.X = X;
|
||||
this.Y = Y;
|
||||
this.Width = Width;
|
||||
this.Height = Height;
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
private OGLTexture Texture;
|
||||
|
||||
private ImageHandler RawTex;
|
||||
private ImageHandler ReadTex;
|
||||
|
||||
private Rect Viewport;
|
||||
|
@ -57,6 +56,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
private int DepthAttachment;
|
||||
private int StencilAttachment;
|
||||
|
||||
private int CopyPBO;
|
||||
|
||||
public OGLRenderTarget(OGLTexture Texture)
|
||||
{
|
||||
ColorAttachments = new int[8];
|
||||
|
@ -64,13 +65,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
this.Texture = Texture;
|
||||
}
|
||||
|
||||
public void BindColor(long Key, int Attachment)
|
||||
public void BindColor(long Key, int Attachment, GalImage Image)
|
||||
{
|
||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||
if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
|
||||
{
|
||||
EnsureFrameBuffer();
|
||||
|
||||
Attach(ref ColorAttachments[Attachment], Tex.Handle, FramebufferAttachment.ColorAttachment0 + Attachment);
|
||||
Attach(ref ColorAttachments[Attachment], CachedImage.Handle, FramebufferAttachment.ColorAttachment0 + Attachment);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -84,40 +85,39 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
Attach(ref ColorAttachments[Attachment], 0, FramebufferAttachment.ColorAttachment0 + Attachment);
|
||||
}
|
||||
|
||||
public void BindZeta(long Key)
|
||||
|
||||
public void BindZeta(long Key, GalImage Image)
|
||||
{
|
||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||
if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
|
||||
{
|
||||
EnsureFrameBuffer();
|
||||
|
||||
if (Tex.HasDepth && Tex.HasStencil)
|
||||
if (CachedImage.HasDepth && CachedImage.HasStencil)
|
||||
{
|
||||
if (DepthAttachment != Tex.Handle ||
|
||||
StencilAttachment != Tex.Handle)
|
||||
if (DepthAttachment != CachedImage.Handle ||
|
||||
StencilAttachment != CachedImage.Handle)
|
||||
{
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
FramebufferAttachment.DepthStencilAttachment,
|
||||
Tex.Handle,
|
||||
CachedImage.Handle,
|
||||
0);
|
||||
|
||||
DepthAttachment = Tex.Handle;
|
||||
|
||||
StencilAttachment = Tex.Handle;
|
||||
DepthAttachment = CachedImage.Handle;
|
||||
StencilAttachment = CachedImage.Handle;
|
||||
}
|
||||
}
|
||||
else if (Tex.HasDepth)
|
||||
else if (CachedImage.HasDepth)
|
||||
{
|
||||
Attach(ref DepthAttachment, Tex.Handle, FramebufferAttachment.DepthAttachment);
|
||||
Attach(ref DepthAttachment, CachedImage.Handle, FramebufferAttachment.DepthAttachment);
|
||||
|
||||
Attach(ref StencilAttachment, 0, FramebufferAttachment.StencilAttachment);
|
||||
}
|
||||
else if (Tex.HasStencil)
|
||||
else if (CachedImage.HasStencil)
|
||||
{
|
||||
Attach(ref DepthAttachment, 0, FramebufferAttachment.DepthAttachment);
|
||||
|
||||
Attach(ref StencilAttachment, Tex.Handle, FramebufferAttachment.StencilAttachment);
|
||||
Attach(ref StencilAttachment, CachedImage.Handle, FramebufferAttachment.StencilAttachment);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -130,12 +130,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment)
|
||||
{
|
||||
if (OldHandle != NewHandle)
|
||||
{
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
FbAttachment,
|
||||
NewHandle,
|
||||
0);
|
||||
|
||||
OldHandle = NewHandle;
|
||||
}
|
||||
}
|
||||
|
||||
public void UnbindZeta()
|
||||
{
|
||||
EnsureFrameBuffer();
|
||||
|
||||
if (DepthAttachment != 0 ||
|
||||
StencilAttachment != 0)
|
||||
if (DepthAttachment != 0 || StencilAttachment != 0)
|
||||
{
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
|
@ -143,44 +156,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
0,
|
||||
0);
|
||||
|
||||
DepthAttachment = 0;
|
||||
|
||||
DepthAttachment = 0;
|
||||
StencilAttachment = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void BindTexture(long Key, int Index)
|
||||
{
|
||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||
{
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(long Key)
|
||||
{
|
||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||
{
|
||||
ReadTex = Tex;
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(byte[] Data, int Width, int Height)
|
||||
{
|
||||
if (RawTex == null)
|
||||
{
|
||||
RawTex = new ImageHandler();
|
||||
}
|
||||
|
||||
RawTex.EnsureSetup(new GalImage(Width, Height, RawFormat));
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, RawTex.Handle);
|
||||
|
||||
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, RawTex.PixelFormat, RawTex.PixelType, Data);
|
||||
|
||||
ReadTex = RawTex;
|
||||
Texture.TryGetImageHandler(Key, out ReadTex);
|
||||
}
|
||||
|
||||
public void SetMap(int[] Map)
|
||||
|
@ -280,13 +263,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
|
||||
int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
|
||||
|
||||
if (SrcFb == 0) SrcFb = GL.GenFramebuffer();
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
|
||||
|
||||
GL.Viewport(0, 0, Window.Width, Window.Height);
|
||||
|
||||
if (SrcFb == 0)
|
||||
{
|
||||
SrcFb = GL.GenFramebuffer();
|
||||
}
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
|
||||
|
||||
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, ReadTex.Handle, 0);
|
||||
|
||||
|
@ -298,7 +283,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.BlitFramebuffer(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear);
|
||||
ClearBufferMask.ColorBufferBit,
|
||||
BlitFramebufferFilter.Linear);
|
||||
|
||||
EnsureFrameBuffer();
|
||||
}
|
||||
|
@ -315,110 +301,123 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
int DstX1,
|
||||
int DstY1)
|
||||
{
|
||||
if (Texture.TryGetImage(SrcKey, out ImageHandler SrcTex) &&
|
||||
Texture.TryGetImage(DstKey, out ImageHandler DstTex))
|
||||
if (Texture.TryGetImageHandler(SrcKey, out ImageHandler SrcTex) &&
|
||||
Texture.TryGetImageHandler(DstKey, out ImageHandler DstTex))
|
||||
{
|
||||
if (SrcTex.HasColor != DstTex.HasColor ||
|
||||
SrcTex.HasDepth != DstTex.HasDepth ||
|
||||
if (SrcTex.HasColor != DstTex.HasColor ||
|
||||
SrcTex.HasDepth != DstTex.HasDepth ||
|
||||
SrcTex.HasStencil != DstTex.HasStencil)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
if (SrcFb == 0)
|
||||
{
|
||||
SrcFb = GL.GenFramebuffer();
|
||||
}
|
||||
|
||||
if (DstFb == 0)
|
||||
{
|
||||
DstFb = GL.GenFramebuffer();
|
||||
}
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb);
|
||||
|
||||
FramebufferAttachment Attachment = GetAttachment(SrcTex);
|
||||
|
||||
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0);
|
||||
GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0);
|
||||
|
||||
BlitFramebufferFilter Filter = BlitFramebufferFilter.Nearest;
|
||||
|
||||
if (SrcTex.HasColor)
|
||||
{
|
||||
CopyTextures(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
SrcTex.Handle,
|
||||
DstTex.Handle,
|
||||
FramebufferAttachment.ColorAttachment0,
|
||||
ClearBufferMask.ColorBufferBit,
|
||||
true);
|
||||
}
|
||||
else if (SrcTex.HasDepth && SrcTex.HasStencil)
|
||||
{
|
||||
CopyTextures(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
SrcTex.Handle,
|
||||
DstTex.Handle,
|
||||
FramebufferAttachment.DepthStencilAttachment,
|
||||
ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit,
|
||||
false);
|
||||
}
|
||||
else if (SrcTex.HasDepth)
|
||||
{
|
||||
CopyTextures(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
SrcTex.Handle,
|
||||
DstTex.Handle,
|
||||
FramebufferAttachment.DepthAttachment,
|
||||
ClearBufferMask.DepthBufferBit,
|
||||
false);
|
||||
}
|
||||
else if (SrcTex.HasStencil)
|
||||
{
|
||||
CopyTextures(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
SrcTex.Handle,
|
||||
DstTex.Handle,
|
||||
FramebufferAttachment.StencilAttachment,
|
||||
ClearBufferMask.StencilBufferBit,
|
||||
false);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||
|
||||
Filter = BlitFramebufferFilter.Linear;
|
||||
}
|
||||
|
||||
ClearBufferMask Mask = GetClearMask(SrcTex);
|
||||
|
||||
GL.Clear(Mask);
|
||||
|
||||
GL.BlitFramebuffer(SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, Mask, Filter);
|
||||
|
||||
EnsureFrameBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
public void GetBufferData(long Key, Action<byte[]> Callback)
|
||||
public void Reinterpret(long Key, GalImage NewImage)
|
||||
{
|
||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||
if (!Texture.TryGetImage(Key, out GalImage OldImage))
|
||||
{
|
||||
byte[] Data = new byte[ImageUtils.GetSize(Tex.Image)];
|
||||
return;
|
||||
}
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
|
||||
if (NewImage.Format == OldImage.Format)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GL.GetTexImage(
|
||||
TextureTarget.Texture2D,
|
||||
0,
|
||||
Tex.PixelFormat,
|
||||
Tex.PixelType,
|
||||
Data);
|
||||
if (CopyPBO == 0)
|
||||
{
|
||||
CopyPBO = GL.GenBuffer();
|
||||
}
|
||||
|
||||
Callback(Data);
|
||||
GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyPBO);
|
||||
|
||||
GL.BufferData(BufferTarget.PixelPackBuffer, Math.Max(ImageUtils.GetSize(OldImage), ImageUtils.GetSize(NewImage)), IntPtr.Zero, BufferUsageHint.StreamCopy);
|
||||
|
||||
if (!Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
(_, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(CachedImage.Format);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle);
|
||||
|
||||
GL.GetTexImage(TextureTarget.Texture2D, 0, Format, Type, IntPtr.Zero);
|
||||
|
||||
GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
|
||||
|
||||
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyPBO);
|
||||
|
||||
Texture.Create(Key, ImageUtils.GetSize(NewImage), NewImage);
|
||||
|
||||
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0);
|
||||
}
|
||||
|
||||
private static FramebufferAttachment GetAttachment(ImageHandler CachedImage)
|
||||
{
|
||||
if (CachedImage.HasColor)
|
||||
{
|
||||
return FramebufferAttachment.ColorAttachment0;
|
||||
}
|
||||
else if (CachedImage.HasDepth && CachedImage.HasStencil)
|
||||
{
|
||||
return FramebufferAttachment.DepthStencilAttachment;
|
||||
}
|
||||
else if (CachedImage.HasDepth)
|
||||
{
|
||||
return FramebufferAttachment.DepthAttachment;
|
||||
}
|
||||
else if (CachedImage.HasStencil)
|
||||
{
|
||||
return FramebufferAttachment.StencilAttachment;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetBufferData(
|
||||
long Key,
|
||||
int Width,
|
||||
int Height,
|
||||
byte[] Buffer)
|
||||
private static ClearBufferMask GetClearMask(ImageHandler CachedImage)
|
||||
{
|
||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
|
||||
|
||||
const int Level = 0;
|
||||
const int Border = 0;
|
||||
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
Tex.InternalFormat,
|
||||
Width,
|
||||
Height,
|
||||
Border,
|
||||
Tex.PixelFormat,
|
||||
Tex.PixelType,
|
||||
Buffer);
|
||||
}
|
||||
return (CachedImage.HasColor ? ClearBufferMask.ColorBufferBit : 0) |
|
||||
(CachedImage.HasDepth ? ClearBufferMask.DepthBufferBit : 0) |
|
||||
(CachedImage.HasStencil ? ClearBufferMask.StencilBufferBit : 0);
|
||||
}
|
||||
|
||||
private void EnsureFrameBuffer()
|
||||
|
@ -430,68 +429,5 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
|
||||
}
|
||||
|
||||
private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment)
|
||||
{
|
||||
if (OldHandle != NewHandle)
|
||||
{
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
FbAttachment,
|
||||
NewHandle,
|
||||
0);
|
||||
|
||||
OldHandle = NewHandle;
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyTextures(
|
||||
int SrcX0,
|
||||
int SrcY0,
|
||||
int SrcX1,
|
||||
int SrcY1,
|
||||
int DstX0,
|
||||
int DstY0,
|
||||
int DstX1,
|
||||
int DstY1,
|
||||
int SrcTexture,
|
||||
int DstTexture,
|
||||
FramebufferAttachment Attachment,
|
||||
ClearBufferMask Mask,
|
||||
bool Color)
|
||||
{
|
||||
if (SrcFb == 0) SrcFb = GL.GenFramebuffer();
|
||||
if (DstFb == 0) DstFb = GL.GenFramebuffer();
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb);
|
||||
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.ReadFramebuffer,
|
||||
Attachment,
|
||||
SrcTexture,
|
||||
0);
|
||||
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
Attachment,
|
||||
DstTexture,
|
||||
0);
|
||||
|
||||
if (Color)
|
||||
{
|
||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||
}
|
||||
|
||||
GL.Clear(Mask);
|
||||
|
||||
GL.BlitFramebuffer(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
Mask,
|
||||
Color ? BlitFramebufferFilter.Linear : BlitFramebufferFilter.Nearest);
|
||||
|
||||
EnsureFrameBuffer();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,17 +28,65 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.DeleteTexture(CachedImage.Handle);
|
||||
}
|
||||
|
||||
public void Create(long Key, byte[] Data, GalImage Image)
|
||||
public void Create(long Key, int Size, GalImage Image)
|
||||
{
|
||||
int Handle = GL.GenTexture();
|
||||
|
||||
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
|
||||
const int Level = 0; //TODO: Support mipmap textures.
|
||||
const int Border = 0;
|
||||
|
||||
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Size);
|
||||
|
||||
GalImageFormat TypeLess = Image.Format & GalImageFormat.FormatMask;
|
||||
|
||||
bool IsASTC = TypeLess >= GalImageFormat.ASTC_BEGIN && TypeLess <= GalImageFormat.ASTC_END;
|
||||
|
||||
if (ImageUtils.IsCompressed(Image.Format) && !IsASTC)
|
||||
{
|
||||
InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format);
|
||||
|
||||
GL.CompressedTexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
InternalFmt,
|
||||
Image.Width,
|
||||
Image.Height,
|
||||
Border,
|
||||
Size,
|
||||
IntPtr.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
(PixelInternalFormat InternalFmt,
|
||||
PixelFormat Format,
|
||||
PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
|
||||
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
InternalFmt,
|
||||
Image.Width,
|
||||
Image.Height,
|
||||
Border,
|
||||
Format,
|
||||
Type,
|
||||
IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
public void Create(long Key, byte[] Data, GalImage Image)
|
||||
{
|
||||
int Handle = GL.GenTexture();
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
|
||||
const int Level = 0; //TODO: Support mipmap textures.
|
||||
const int Border = 0;
|
||||
|
||||
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length);
|
||||
|
||||
GalImageFormat TypeLess = Image.Format & GalImageFormat.FormatMask;
|
||||
|
||||
bool IsASTC = TypeLess >= GalImageFormat.ASTC_BEGIN && TypeLess <= GalImageFormat.ASTC_END;
|
||||
|
@ -62,8 +110,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
//TODO: Use KHR_texture_compression_astc_hdr when available
|
||||
if (IsASTC)
|
||||
{
|
||||
int TextureBlockWidth = GetAstcBlockWidth(Image.Format);
|
||||
int TextureBlockHeight = GetAstcBlockHeight(Image.Format);
|
||||
int TextureBlockWidth = ImageUtils.GetBlockWidth(Image.Format);
|
||||
int TextureBlockHeight = ImageUtils.GetBlockHeight(Image.Format);
|
||||
|
||||
Data = ASTCDecoder.DecodeToRGBA8888(
|
||||
Data,
|
||||
|
@ -85,12 +133,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
Image.Format = GalImageFormat.R8G8 | (Image.Format & GalImageFormat.TypeMask);
|
||||
}
|
||||
|
||||
(PixelInternalFormat InternalFormat, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
|
||||
(PixelInternalFormat InternalFmt,
|
||||
PixelFormat Format,
|
||||
PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
|
||||
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
InternalFormat,
|
||||
InternalFmt,
|
||||
Image.Width,
|
||||
Image.Height,
|
||||
Border,
|
||||
|
@ -98,31 +148,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
Type,
|
||||
Data);
|
||||
}
|
||||
|
||||
int SwizzleR = (int)OGLEnumConverter.GetTextureSwizzle(Image.XSource);
|
||||
int SwizzleG = (int)OGLEnumConverter.GetTextureSwizzle(Image.YSource);
|
||||
int SwizzleB = (int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource);
|
||||
int SwizzleA = (int)OGLEnumConverter.GetTextureSwizzle(Image.WSource);
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, SwizzleR);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, SwizzleG);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleB, SwizzleB);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA);
|
||||
}
|
||||
|
||||
public void CreateFb(long Key, long Size, GalImage Image)
|
||||
public bool TryGetImage(long Key, out GalImage Image)
|
||||
{
|
||||
if (!TryGetImage(Key, out ImageHandler CachedImage))
|
||||
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
|
||||
{
|
||||
CachedImage = new ImageHandler();
|
||||
Image = CachedImage.Image;
|
||||
|
||||
TextureCache.AddOrUpdate(Key, CachedImage, Size);
|
||||
return true;
|
||||
}
|
||||
|
||||
CachedImage.EnsureSetup(Image);
|
||||
Image = default(GalImage);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetImage(long Key, out ImageHandler CachedImage)
|
||||
public bool TryGetImageHandler(long Key, out ImageHandler CachedImage)
|
||||
{
|
||||
if (TextureCache.TryGetValue(Key, out CachedImage))
|
||||
{
|
||||
|
@ -134,76 +176,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
return false;
|
||||
}
|
||||
|
||||
private static int GetAstcBlockWidth(GalImageFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalImageFormat.ASTC_4x4 | GalImageFormat.Unorm: return 4;
|
||||
case GalImageFormat.ASTC_5x5 | GalImageFormat.Unorm: return 5;
|
||||
case GalImageFormat.ASTC_6x6 | GalImageFormat.Unorm: return 6;
|
||||
case GalImageFormat.ASTC_8x8 | GalImageFormat.Unorm: return 8;
|
||||
case GalImageFormat.ASTC_10x10 | GalImageFormat.Unorm: return 10;
|
||||
case GalImageFormat.ASTC_12x12 | GalImageFormat.Unorm: return 12;
|
||||
case GalImageFormat.ASTC_5x4 | GalImageFormat.Unorm: return 5;
|
||||
case GalImageFormat.ASTC_6x5 | GalImageFormat.Unorm: return 6;
|
||||
case GalImageFormat.ASTC_8x6 | GalImageFormat.Unorm: return 8;
|
||||
case GalImageFormat.ASTC_10x8 | GalImageFormat.Unorm: return 10;
|
||||
case GalImageFormat.ASTC_12x10 | GalImageFormat.Unorm: return 12;
|
||||
case GalImageFormat.ASTC_8x5 | GalImageFormat.Unorm: return 8;
|
||||
case GalImageFormat.ASTC_10x5 | GalImageFormat.Unorm: return 10;
|
||||
case GalImageFormat.ASTC_10x6 | GalImageFormat.Unorm: return 10;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Format));
|
||||
}
|
||||
|
||||
private static int GetAstcBlockHeight(GalImageFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalImageFormat.ASTC_4x4 | GalImageFormat.Unorm: return 4;
|
||||
case GalImageFormat.ASTC_5x5 | GalImageFormat.Unorm: return 5;
|
||||
case GalImageFormat.ASTC_6x6 | GalImageFormat.Unorm: return 6;
|
||||
case GalImageFormat.ASTC_8x8 | GalImageFormat.Unorm: return 8;
|
||||
case GalImageFormat.ASTC_10x10 | GalImageFormat.Unorm: return 10;
|
||||
case GalImageFormat.ASTC_12x12 | GalImageFormat.Unorm: return 12;
|
||||
case GalImageFormat.ASTC_5x4 | GalImageFormat.Unorm: return 4;
|
||||
case GalImageFormat.ASTC_6x5 | GalImageFormat.Unorm: return 5;
|
||||
case GalImageFormat.ASTC_8x6 | GalImageFormat.Unorm: return 6;
|
||||
case GalImageFormat.ASTC_10x8 | GalImageFormat.Unorm: return 8;
|
||||
case GalImageFormat.ASTC_12x10 | GalImageFormat.Unorm: return 10;
|
||||
case GalImageFormat.ASTC_8x5 | GalImageFormat.Unorm: return 5;
|
||||
case GalImageFormat.ASTC_10x5 | GalImageFormat.Unorm: return 5;
|
||||
case GalImageFormat.ASTC_10x6 | GalImageFormat.Unorm: return 6;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Format));
|
||||
}
|
||||
|
||||
public bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image)
|
||||
{
|
||||
if (TextureCache.TryGetSize(Key, out long Size) && Size == DataSize)
|
||||
{
|
||||
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
|
||||
{
|
||||
Image = CachedImage.Image;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Image = default(GalImage);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Bind(long Key, int Index)
|
||||
public void Bind(long Key, int Index, GalImage Image)
|
||||
{
|
||||
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
|
||||
{
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle);
|
||||
|
||||
int[] SwizzleRgba = new int[]
|
||||
{
|
||||
(int)OGLEnumConverter.GetTextureSwizzle(Image.XSource),
|
||||
(int)OGLEnumConverter.GetTextureSwizzle(Image.YSource),
|
||||
(int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource),
|
||||
(int)OGLEnumConverter.GetTextureSwizzle(Image.WSource)
|
||||
};
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleRgba, SwizzleRgba);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -360,7 +360,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private void PrintDeclSsy()
|
||||
{
|
||||
SB.AppendLine("uint " + GlslDecl.SsyCursorName + ";");
|
||||
SB.AppendLine("uint " + GlslDecl.SsyCursorName + "= 0;");
|
||||
|
||||
SB.AppendLine("uint " + GlslDecl.SsyStackName + "[" + GlslDecl.SsyStackSize + "];" + Environment.NewLine);
|
||||
}
|
||||
|
@ -641,6 +641,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
default:
|
||||
SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,32 +6,32 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
static partial class ShaderDecode
|
||||
{
|
||||
public static void Bfe_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Bfe_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitBfe(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Bfe_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Bfe_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitBfe(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Bfe_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Bfe_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitBfe(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Fadd_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fadd_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFadd(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Fadd_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fadd_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFadd(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Fadd_I32(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fadd_I32(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode OperA = OpCode.Gpr8();
|
||||
ShaderIrNode OperB = OpCode.Immf32_20();
|
||||
|
@ -49,47 +49,47 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||
}
|
||||
|
||||
public static void Fadd_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fadd_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFadd(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Ffma_CR(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ffma_CR(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFfma(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Ffma_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ffma_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFfma(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Ffma_RC(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ffma_RC(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFfma(Block, OpCode, ShaderOper.RC);
|
||||
}
|
||||
|
||||
public static void Ffma_RR(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ffma_RR(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFfma(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Fmnmx_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fmnmx_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFmnmx(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Fmnmx_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fmnmx_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFmnmx(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Fmnmx_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fmnmx_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFmnmx(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Fmul_I32(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fmul_I32(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode OperA = OpCode.Gpr8();
|
||||
ShaderIrNode OperB = OpCode.Immf32_20();
|
||||
|
@ -99,62 +99,62 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||
}
|
||||
|
||||
public static void Fmul_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fmul_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFmul(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Fmul_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fmul_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFmul(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Fmul_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fmul_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFmul(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Fset_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fset_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFset(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Fset_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fset_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFset(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Fset_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fset_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFset(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Fsetp_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fsetp_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFsetp(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Fsetp_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fsetp_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFsetp(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Fsetp_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fsetp_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFsetp(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Iadd_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iadd_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIadd(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Iadd_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iadd_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIadd(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Iadd_I32(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iadd_I32(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode OperA = OpCode.Gpr8();
|
||||
ShaderIrNode OperB = OpCode.Imm32_20();
|
||||
|
@ -168,42 +168,42 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||
}
|
||||
|
||||
public static void Iadd_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iadd_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIadd(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Iadd3_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iadd3_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIadd3(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Iadd3_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iadd3_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIadd3(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Iadd3_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iadd3_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIadd3(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Imnmx_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Imnmx_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitImnmx(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Imnmx_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Imnmx_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitImnmx(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Imnmx_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Imnmx_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitImnmx(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Ipa(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ipa(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode OperA = OpCode.Abuf28();
|
||||
ShaderIrNode OperB = OpCode.Gpr20();
|
||||
|
@ -217,52 +217,52 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||
}
|
||||
|
||||
public static void Iscadd_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iscadd_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIscadd(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Iscadd_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iscadd_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIscadd(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Iscadd_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iscadd_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIscadd(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Iset_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iset_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIset(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Iset_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iset_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIset(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Iset_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iset_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIset(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Isetp_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Isetp_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIsetp(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Isetp_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Isetp_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIsetp(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Isetp_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Isetp_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIsetp(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Lop_I32(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Lop_I32(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
int SubOp = OpCode.Read(53, 3);
|
||||
|
||||
|
@ -296,22 +296,22 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
public static void Lop_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Lop_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitLop(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Lop_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Lop_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitLop(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Lop_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Lop_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitLop(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Mufu(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Mufu(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
int SubOp = OpCode.Read(20, 0xf);
|
||||
|
||||
|
@ -340,7 +340,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||
}
|
||||
|
||||
public static void Psetp(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Psetp(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
bool NegA = OpCode.Read(15);
|
||||
bool NegB = OpCode.Read(32);
|
||||
|
@ -394,47 +394,47 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
|
||||
}
|
||||
|
||||
public static void Rro_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Rro_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitRro(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Rro_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Rro_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitRro(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Rro_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Rro_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitRro(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Shl_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Shl_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Lsl);
|
||||
}
|
||||
|
||||
public static void Shl_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Shl_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Lsl);
|
||||
}
|
||||
|
||||
public static void Shl_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Shl_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Lsl);
|
||||
}
|
||||
|
||||
public static void Shr_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Shr_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode));
|
||||
}
|
||||
|
||||
public static void Shr_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Shr_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.Imm, GetShrInst(OpCode));
|
||||
}
|
||||
|
||||
public static void Shr_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Shr_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.RR, GetShrInst(OpCode));
|
||||
}
|
||||
|
@ -446,7 +446,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
return Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
||||
}
|
||||
|
||||
public static void Vmad(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Vmad(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode OperA = OpCode.Gpr8();
|
||||
|
||||
|
@ -481,22 +481,22 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Final)));
|
||||
}
|
||||
|
||||
public static void Xmad_CR(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Xmad_CR(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitXmad(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Xmad_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Xmad_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitXmad(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Xmad_RC(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Xmad_RC(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitXmad(Block, OpCode, ShaderOper.RC);
|
||||
}
|
||||
|
||||
public static void Xmad_RR(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Xmad_RR(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitXmad(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
using System;
|
||||
|
||||
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
static partial class ShaderDecode
|
||||
{
|
||||
public static void Bra(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Bra(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
if ((OpCode & 0x20) != 0)
|
||||
{
|
||||
|
@ -15,14 +13,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
int Target = OpCode.Branch();
|
||||
|
||||
ShaderIrOperImm Imm = new ShaderIrOperImm(Target);
|
||||
ShaderIrOperImm Imm = new ShaderIrOperImm(Position + OpCode.Branch());
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Bra, Imm)));
|
||||
}
|
||||
|
||||
public static void Exit(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Exit(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
int CCode = (int)OpCode & 0x1f;
|
||||
|
||||
|
@ -31,15 +27,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Exit)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void Kil(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Kil(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Kil)));
|
||||
}
|
||||
|
||||
public static void Ssy(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ssy(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
if ((OpCode & 0x20) != 0)
|
||||
{
|
||||
|
@ -48,19 +43,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
int Offset = OpCode.Branch();
|
||||
|
||||
int Target = (int)(Position + Offset);
|
||||
|
||||
ShaderIrOperImm Imm = new ShaderIrOperImm(Target);
|
||||
ShaderIrOperImm Imm = new ShaderIrOperImm(Position + OpCode.Branch());
|
||||
|
||||
Block.AddNode(new ShaderIrOp(ShaderIrInst.Ssy, Imm));
|
||||
}
|
||||
|
||||
public static void Sync(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Sync(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
//TODO: Implement Sync condition codes
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Sync)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode, long Position);
|
||||
delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode, int Position);
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
static class ShaderDecodeHelper
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{ RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
|
||||
};
|
||||
|
||||
public static void Ld_A(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ld_A(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode[] Opers = OpCode.Abuf20();
|
||||
|
||||
|
@ -50,7 +50,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
public static void Ld_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ld_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
int CbufPos = OpCode.Read(22, 0x3fff);
|
||||
int CbufIndex = OpCode.Read(36, 0x1f);
|
||||
|
@ -97,7 +97,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
public static void St_A(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void St_A(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode[] Opers = OpCode.Abuf20();
|
||||
|
||||
|
@ -113,7 +113,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
public static void Texq(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Texq(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode OperD = OpCode.Gpr0();
|
||||
ShaderIrNode OperA = OpCode.Gpr8();
|
||||
|
@ -132,12 +132,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperA, Op1))); //Is this right?
|
||||
}
|
||||
|
||||
public static void Tex(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Tex(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTex(Block, OpCode, GprHandle: false);
|
||||
}
|
||||
|
||||
public static void Tex_B(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Tex_B(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTex(Block, OpCode, GprHandle: true);
|
||||
}
|
||||
|
@ -202,12 +202,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
public static void Texs(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Texs(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTexs(Block, OpCode, ShaderIrInst.Texs);
|
||||
}
|
||||
|
||||
public static void Tlds(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Tlds(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTexs(Block, OpCode, ShaderIrInst.Txlf);
|
||||
}
|
||||
|
|
|
@ -25,67 +25,67 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
F64 = 3
|
||||
}
|
||||
|
||||
public static void F2f_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void F2f_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitF2f(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void F2f_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void F2f_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitF2f(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void F2f_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void F2f_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitF2f(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void F2i_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void F2i_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitF2i(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void F2i_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void F2i_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitF2i(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void F2i_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void F2i_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitF2i(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void I2f_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void I2f_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitI2f(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void I2f_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void I2f_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitI2f(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void I2f_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void I2f_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitI2f(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void I2i_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void I2i_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitI2i(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void I2i_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void I2i_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitI2i(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void I2i_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void I2i_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitI2i(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Isberd(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Isberd(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
//This instruction seems to be used to translate from an address to a vertex index in a GS
|
||||
//Stub it as such
|
||||
|
@ -95,50 +95,50 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OpCode.Gpr8())));
|
||||
}
|
||||
|
||||
public static void Mov_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Mov_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrOperCbuf Cbuf = OpCode.Cbuf34();
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Cbuf)));
|
||||
}
|
||||
|
||||
public static void Mov_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Mov_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrOperImm Imm = OpCode.Imm19_20();
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Imm)));
|
||||
}
|
||||
|
||||
public static void Mov_I32(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Mov_I32(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrOperImm Imm = OpCode.Imm32_20();
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Imm)));
|
||||
}
|
||||
|
||||
public static void Mov_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Mov_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrOperGpr Gpr = OpCode.Gpr20();
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Gpr)));
|
||||
}
|
||||
|
||||
public static void Sel_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Sel_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitSel(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Sel_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Sel_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitSel(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Sel_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Sel_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitSel(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Mov_S(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Mov_S(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
Block.AddNode(new ShaderIrCmnt("Stubbed."));
|
||||
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
static partial class ShaderDecode
|
||||
{
|
||||
public static void Out_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Out_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
//TODO: Those registers have to be used for something
|
||||
ShaderIrOperGpr Gpr0 = OpCode.Gpr0();
|
||||
|
|
|
@ -10,12 +10,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public static ShaderIrBlock[] Decode(IGalMemory Memory, long Start)
|
||||
{
|
||||
Dictionary<long, ShaderIrBlock> Visited = new Dictionary<long, ShaderIrBlock>();
|
||||
Dictionary<long, ShaderIrBlock> VisitedEnd = new Dictionary<long, ShaderIrBlock>();
|
||||
Dictionary<int, ShaderIrBlock> Visited = new Dictionary<int, ShaderIrBlock>();
|
||||
Dictionary<int, ShaderIrBlock> VisitedEnd = new Dictionary<int, ShaderIrBlock>();
|
||||
|
||||
Queue<ShaderIrBlock> Blocks = new Queue<ShaderIrBlock>();
|
||||
|
||||
ShaderIrBlock Enqueue(long Position, ShaderIrBlock Source = null)
|
||||
long Beginning = Start + HeaderSize;
|
||||
|
||||
ShaderIrBlock Enqueue(int Position, ShaderIrBlock Source = null)
|
||||
{
|
||||
if (!Visited.TryGetValue(Position, out ShaderIrBlock Output))
|
||||
{
|
||||
|
@ -34,13 +36,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
return Output;
|
||||
}
|
||||
|
||||
ShaderIrBlock Entry = Enqueue(Start + HeaderSize);
|
||||
ShaderIrBlock Entry = Enqueue(0);
|
||||
|
||||
while (Blocks.Count > 0)
|
||||
{
|
||||
ShaderIrBlock Current = Blocks.Dequeue();
|
||||
|
||||
FillBlock(Memory, Current, Start + HeaderSize);
|
||||
FillBlock(Memory, Current, Beginning);
|
||||
|
||||
//Set child blocks. "Branch" is the block the branch instruction
|
||||
//points to (when taken), "Next" is the block at the next address,
|
||||
|
@ -54,20 +56,18 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
if (InnerOp?.Inst == ShaderIrInst.Bra)
|
||||
{
|
||||
int Offset = ((ShaderIrOperImm)InnerOp.OperandA).Value;
|
||||
|
||||
long Target = Current.EndPosition + Offset;
|
||||
int Target = ((ShaderIrOperImm)InnerOp.OperandA).Value;
|
||||
|
||||
Current.Branch = Enqueue(Target, Current);
|
||||
}
|
||||
|
||||
foreach (ShaderIrNode Node in Current.Nodes)
|
||||
{
|
||||
if (Node is ShaderIrOp CurrOp && CurrOp.Inst == ShaderIrInst.Ssy)
|
||||
{
|
||||
int Offset = ((ShaderIrOperImm)CurrOp.OperandA).Value;
|
||||
InnerOp = GetInnermostOp(Node);
|
||||
|
||||
long Target = Offset;
|
||||
if (InnerOp is ShaderIrOp CurrOp && CurrOp.Inst == ShaderIrInst.Ssy)
|
||||
{
|
||||
int Target = ((ShaderIrOperImm)CurrOp.OperandA).Value;
|
||||
|
||||
Current.Branch = Enqueue(Target, Current);
|
||||
}
|
||||
|
@ -112,15 +112,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
while (Visited.Count > 0)
|
||||
{
|
||||
ulong FirstPos = ulong.MaxValue;
|
||||
uint FirstPos = uint.MaxValue;
|
||||
|
||||
foreach (ShaderIrBlock Block in Visited.Values)
|
||||
{
|
||||
if (FirstPos > (ulong)Block.Position)
|
||||
FirstPos = (ulong)Block.Position;
|
||||
if (FirstPos > (uint)Block.Position)
|
||||
FirstPos = (uint)Block.Position;
|
||||
}
|
||||
|
||||
ShaderIrBlock Current = Visited[(long)FirstPos];
|
||||
ShaderIrBlock Current = Visited[(int)FirstPos];
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -138,20 +138,20 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private static void FillBlock(IGalMemory Memory, ShaderIrBlock Block, long Beginning)
|
||||
{
|
||||
long Position = Block.Position;
|
||||
int Position = Block.Position;
|
||||
|
||||
do
|
||||
{
|
||||
//Ignore scheduling instructions, which are written every 32 bytes.
|
||||
if (((Position - Beginning) & 0x1f) == 0)
|
||||
if ((Position & 0x1f) == 0)
|
||||
{
|
||||
Position += 8;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
uint Word0 = (uint)Memory.ReadInt32(Position + 0);
|
||||
uint Word1 = (uint)Memory.ReadInt32(Position + 4);
|
||||
uint Word0 = (uint)Memory.ReadInt32(Position + Beginning + 0);
|
||||
uint Word1 = (uint)Memory.ReadInt32(Position + Beginning + 4);
|
||||
|
||||
Position += 8;
|
||||
|
||||
|
@ -161,7 +161,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
if (AddDbgComments)
|
||||
{
|
||||
string DbgOpCode = $"0x{(Position - Beginning - 8):x16}: 0x{OpCode:x16} ";
|
||||
string DbgOpCode = $"0x{(Position - 8):x16}: 0x{OpCode:x16} ";
|
||||
|
||||
DbgOpCode += (Decode?.Method.Name ?? "???");
|
||||
|
||||
|
@ -169,7 +169,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
int Offset = ((int)(OpCode >> 20) << 8) >> 8;
|
||||
|
||||
long Target = Position + Offset - Beginning;
|
||||
long Target = Position + Offset;
|
||||
|
||||
DbgOpCode += " (0x" + Target.ToString("x16") + ")";
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
class ShaderIrBlock
|
||||
{
|
||||
public long Position { get; set; }
|
||||
public long EndPosition { get; set; }
|
||||
public int Position { get; set; }
|
||||
public int EndPosition { get; set; }
|
||||
|
||||
public ShaderIrBlock Next { get; set; }
|
||||
public ShaderIrBlock Branch { get; set; }
|
||||
|
@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public List<ShaderIrNode> Nodes { get; private set; }
|
||||
|
||||
public ShaderIrBlock(long Position)
|
||||
public ShaderIrBlock(int Position)
|
||||
{
|
||||
this.Position = Position;
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Set("0100110000101x", ShaderDecode.Shr_C);
|
||||
Set("0011100x00101x", ShaderDecode.Shr_I);
|
||||
Set("0101110000101x", ShaderDecode.Shr_R);
|
||||
Set("1110001010010x", ShaderDecode.Ssy);
|
||||
Set("111000101001xx", ShaderDecode.Ssy);
|
||||
Set("1110111111110x", ShaderDecode.St_A);
|
||||
Set("1111000011111x", ShaderDecode.Sync);
|
||||
Set("110000xxxx111x", ShaderDecode.Tex);
|
||||
|
|
140
Ryujinx.Graphics/GpuResourceManager.cs
Normal file
140
Ryujinx.Graphics/GpuResourceManager.cs
Normal file
|
@ -0,0 +1,140 @@
|
|||
using Ryujinx.Graphics.Gal;
|
||||
using Ryujinx.Graphics.Memory;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics
|
||||
{
|
||||
public class GpuResourceManager
|
||||
{
|
||||
private enum ImageType
|
||||
{
|
||||
None,
|
||||
Texture,
|
||||
ColorBuffer,
|
||||
ZetaBuffer
|
||||
}
|
||||
|
||||
private NvGpu Gpu;
|
||||
|
||||
private HashSet<long>[] UploadedKeys;
|
||||
|
||||
private Dictionary<long, ImageType> ImageTypes;
|
||||
|
||||
public GpuResourceManager(NvGpu Gpu)
|
||||
{
|
||||
this.Gpu = Gpu;
|
||||
|
||||
UploadedKeys = new HashSet<long>[(int)NvGpuBufferType.Count];
|
||||
|
||||
for (int Index = 0; Index < UploadedKeys.Length; Index++)
|
||||
{
|
||||
UploadedKeys[Index] = new HashSet<long>();
|
||||
}
|
||||
|
||||
ImageTypes = new Dictionary<long, ImageType>();
|
||||
}
|
||||
|
||||
public void SendColorBuffer(NvGpuVmm Vmm, long Position, int Attachment, GalImage NewImage)
|
||||
{
|
||||
long Size = (uint)ImageUtils.GetSize(NewImage);
|
||||
|
||||
ImageTypes[Position] = ImageType.ColorBuffer;
|
||||
|
||||
if (!TryReuse(Vmm, Position, NewImage))
|
||||
{
|
||||
Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage);
|
||||
}
|
||||
|
||||
Gpu.Renderer.RenderTarget.BindColor(Position, Attachment, NewImage);
|
||||
}
|
||||
|
||||
public void SendZetaBuffer(NvGpuVmm Vmm, long Position, GalImage NewImage)
|
||||
{
|
||||
long Size = (uint)ImageUtils.GetSize(NewImage);
|
||||
|
||||
ImageTypes[Position] = ImageType.ZetaBuffer;
|
||||
|
||||
if (!TryReuse(Vmm, Position, NewImage))
|
||||
{
|
||||
Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage);
|
||||
}
|
||||
|
||||
Gpu.Renderer.RenderTarget.BindZeta(Position, NewImage);
|
||||
}
|
||||
|
||||
public void SendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage, int TexIndex = -1)
|
||||
{
|
||||
PrepareSendTexture(Vmm, Position, NewImage);
|
||||
|
||||
if (TexIndex >= 0)
|
||||
{
|
||||
Gpu.Renderer.Texture.Bind(Position, TexIndex, NewImage);
|
||||
}
|
||||
|
||||
ImageTypes[Position] = ImageType.Texture;
|
||||
}
|
||||
|
||||
private void PrepareSendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage)
|
||||
{
|
||||
long Size = ImageUtils.GetSize(NewImage);
|
||||
|
||||
bool SkipCheck = false;
|
||||
|
||||
if (ImageTypes.TryGetValue(Position, out ImageType OldType))
|
||||
{
|
||||
if (OldType == ImageType.ColorBuffer || OldType == ImageType.ZetaBuffer)
|
||||
{
|
||||
//Avoid data destruction
|
||||
MemoryRegionModified(Vmm, Position, Size, NvGpuBufferType.Texture);
|
||||
|
||||
SkipCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (SkipCheck || !MemoryRegionModified(Vmm, Position, Size, NvGpuBufferType.Texture))
|
||||
{
|
||||
if (TryReuse(Vmm, Position, NewImage))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] Data = ImageUtils.ReadTexture(Vmm, NewImage, Position);
|
||||
|
||||
Gpu.Renderer.Texture.Create(Position, Data, NewImage);
|
||||
}
|
||||
|
||||
private bool TryReuse(NvGpuVmm Vmm, long Position, GalImage NewImage)
|
||||
{
|
||||
if (Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage) && CachedImage.SizeMatches(NewImage))
|
||||
{
|
||||
Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool MemoryRegionModified(NvGpuVmm Vmm, long Position, long Size, NvGpuBufferType Type)
|
||||
{
|
||||
HashSet<long> Uploaded = UploadedKeys[(int)Type];
|
||||
|
||||
if (!Uploaded.Add(Position))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Vmm.IsRegionModified(Position, Size, Type);
|
||||
}
|
||||
|
||||
public void ClearPbCache()
|
||||
{
|
||||
for (int Index = 0; Index < UploadedKeys.Length; Index++)
|
||||
{
|
||||
UploadedKeys[Index].Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,309 +1,82 @@
|
|||
using ChocolArm64.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Memory
|
||||
{
|
||||
class NvGpuVmmCache
|
||||
{
|
||||
private const long RamSize = 4L * 1024 * 1024 * 1024;
|
||||
|
||||
private const int MaxCpCount = 10000;
|
||||
private const int MaxCpTimeDelta = 60000;
|
||||
|
||||
private class CachedPage
|
||||
{
|
||||
private struct Range
|
||||
{
|
||||
public long Start;
|
||||
public long End;
|
||||
|
||||
public Range(long Start, long End)
|
||||
{
|
||||
this.Start = Start;
|
||||
this.End = End;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Range>[] Regions;
|
||||
|
||||
private HashSet<long> ResidencyKeys;
|
||||
|
||||
public LinkedListNode<long> Node { get; set; }
|
||||
|
||||
public int Timestamp { get; private set; }
|
||||
|
||||
public CachedPage()
|
||||
{
|
||||
Regions = new List<Range>[(int)NvGpuBufferType.Count];
|
||||
|
||||
for (int Index = 0; Index < Regions.Length; Index++)
|
||||
{
|
||||
Regions[Index] = new List<Range>();
|
||||
}
|
||||
|
||||
ResidencyKeys = new HashSet<long>();
|
||||
}
|
||||
|
||||
public void AddResidency(long Key)
|
||||
{
|
||||
ResidencyKeys.Add(Key);
|
||||
}
|
||||
|
||||
public void RemoveResidency(HashSet<long>[] Residency, long PageSize)
|
||||
{
|
||||
for (int i = 0; i < (int)NvGpuBufferType.Count; i++)
|
||||
{
|
||||
foreach (Range Region in Regions[i])
|
||||
{
|
||||
foreach (long Key in ResidencyKeys)
|
||||
{
|
||||
Residency[Region.Start / PageSize].Remove(Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool AddRange(long Start, long End, NvGpuBufferType BufferType)
|
||||
{
|
||||
List<Range> BtRegions = Regions[(int)BufferType];
|
||||
|
||||
for (int Index = 0; Index < BtRegions.Count; Index++)
|
||||
{
|
||||
Range Rg = BtRegions[Index];
|
||||
|
||||
if (Start >= Rg.Start && End <= Rg.End)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Start <= Rg.End && Rg.Start <= End)
|
||||
{
|
||||
long MinStart = Math.Min(Rg.Start, Start);
|
||||
long MaxEnd = Math.Max(Rg.End, End);
|
||||
|
||||
BtRegions[Index] = new Range(MinStart, MaxEnd);
|
||||
|
||||
Timestamp = Environment.TickCount;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
BtRegions.Add(new Range(Start, End));
|
||||
|
||||
Timestamp = Environment.TickCount;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int GetTotalCount()
|
||||
{
|
||||
int Count = 0;
|
||||
|
||||
for (int Index = 0; Index < Regions.Length; Index++)
|
||||
{
|
||||
Count += Regions[Index].Count;
|
||||
}
|
||||
|
||||
return Count;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<long, CachedPage> Cache;
|
||||
|
||||
private LinkedList<long> SortedCache;
|
||||
|
||||
private HashSet<long>[] Residency;
|
||||
|
||||
private long ResidencyPageSize;
|
||||
|
||||
private int CpCount;
|
||||
private ValueRangeSet<int> CachedRanges;
|
||||
|
||||
public NvGpuVmmCache()
|
||||
{
|
||||
Cache = new Dictionary<long, CachedPage>();
|
||||
|
||||
SortedCache = new LinkedList<long>();
|
||||
CachedRanges = new ValueRangeSet<int>();
|
||||
}
|
||||
|
||||
public bool IsRegionModified(AMemory Memory, NvGpuBufferType BufferType, long PA, long Size)
|
||||
{
|
||||
(bool[] Modified, long ModifiedCount) = Memory.IsRegionModified(PA, Size);
|
||||
|
||||
PA = Memory.GetPhysicalAddress(PA);
|
||||
|
||||
ClearCachedPagesIfNeeded();
|
||||
|
||||
long PageSize = AMemory.PageSize;
|
||||
|
||||
EnsureResidencyInitialized(PageSize);
|
||||
|
||||
bool HasResidents = AddResidency(PA, Size);
|
||||
|
||||
if (!HasResidents && ModifiedCount == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long Mask = PageSize - 1;
|
||||
|
||||
long ResidencyKey = PA;
|
||||
|
||||
long PAEnd = PA + Size;
|
||||
|
||||
bool RegMod = false;
|
||||
|
||||
//Remove all modified ranges.
|
||||
int Index = 0;
|
||||
|
||||
while (PA < PAEnd)
|
||||
long Position = PA & ~NvGpuVmm.PageMask;
|
||||
|
||||
while (ModifiedCount > 0)
|
||||
{
|
||||
long Key = PA & ~AMemory.PageMask;
|
||||
|
||||
long PAPgEnd = Math.Min((PA + AMemory.PageSize) & ~AMemory.PageMask, PAEnd);
|
||||
|
||||
bool IsCached = Cache.TryGetValue(Key, out CachedPage Cp);
|
||||
|
||||
if (IsCached)
|
||||
if (Modified[Index++])
|
||||
{
|
||||
CpCount -= Cp.GetTotalCount();
|
||||
CachedRanges.Remove(new ValueRange<int>(Position, Position + NvGpuVmm.PageSize));
|
||||
|
||||
SortedCache.Remove(Cp.Node);
|
||||
ModifiedCount--;
|
||||
}
|
||||
|
||||
Position += NvGpuVmm.PageSize;
|
||||
}
|
||||
|
||||
//Mask has the bit set for the current resource type.
|
||||
//If the region is not yet present on the list, then a new ValueRange
|
||||
//is directly added with the current resource type as the only bit set.
|
||||
//Otherwise, it just sets the bit for this new resource type on the current mask.
|
||||
int Mask = 1 << (int)BufferType;
|
||||
|
||||
ValueRange<int> NewCached = new ValueRange<int>(PA, PA + Size);
|
||||
|
||||
ValueRange<int>[] Ranges = CachedRanges.GetAllIntersections(NewCached);
|
||||
|
||||
long LastEnd = NewCached.Start;
|
||||
|
||||
long Coverage = 0;
|
||||
|
||||
for (Index = 0; Index < Ranges.Length; Index++)
|
||||
{
|
||||
ValueRange<int> Current = Ranges[Index];
|
||||
|
||||
long RgStart = Math.Max(Current.Start, NewCached.Start);
|
||||
long RgEnd = Math.Min(Current.End, NewCached.End);
|
||||
|
||||
if ((Current.Value & Mask) == 0)
|
||||
{
|
||||
CachedRanges.Add(new ValueRange<int>(RgStart, RgEnd, Current.Value | Mask));
|
||||
}
|
||||
else
|
||||
{
|
||||
Cp = new CachedPage();
|
||||
|
||||
Cache.Add(Key, Cp);
|
||||
Coverage += RgEnd - RgStart;
|
||||
}
|
||||
|
||||
if (Modified[Index++] && IsCached)
|
||||
if (RgStart > LastEnd)
|
||||
{
|
||||
Cp = new CachedPage();
|
||||
|
||||
Cache[Key] = Cp;
|
||||
CachedRanges.Add(new ValueRange<int>(LastEnd, RgStart, Mask));
|
||||
}
|
||||
|
||||
Cp.AddResidency(ResidencyKey);
|
||||
|
||||
Cp.Node = SortedCache.AddLast(Key);
|
||||
|
||||
RegMod |= Cp.AddRange(PA, PAPgEnd, BufferType);
|
||||
|
||||
CpCount += Cp.GetTotalCount();
|
||||
|
||||
PA = PAPgEnd;
|
||||
LastEnd = RgEnd;
|
||||
}
|
||||
|
||||
return RegMod;
|
||||
}
|
||||
|
||||
private bool AddResidency(long PA, long Size)
|
||||
{
|
||||
long PageSize = ResidencyPageSize;
|
||||
|
||||
long Mask = PageSize - 1;
|
||||
|
||||
long Key = PA;
|
||||
|
||||
bool ResidentFound = false;
|
||||
|
||||
for (long Cursor = PA & ~Mask; Cursor < ((PA + Size + PageSize - 1) & ~Mask); Cursor += PageSize)
|
||||
if (LastEnd < NewCached.End)
|
||||
{
|
||||
long PageIndex = Cursor / PageSize;
|
||||
|
||||
Residency[PageIndex].Add(Key);
|
||||
|
||||
if (Residency[PageIndex].Count > 1)
|
||||
{
|
||||
ResidentFound = true;
|
||||
}
|
||||
CachedRanges.Add(new ValueRange<int>(LastEnd, NewCached.End, Mask));
|
||||
}
|
||||
|
||||
return ResidentFound;
|
||||
}
|
||||
|
||||
private void EnsureResidencyInitialized(long PageSize)
|
||||
{
|
||||
if (Residency == null)
|
||||
{
|
||||
Residency = new HashSet<long>[RamSize / PageSize];
|
||||
|
||||
for (int i = 0; i < Residency.Length; i++)
|
||||
{
|
||||
Residency[i] = new HashSet<long>();
|
||||
}
|
||||
|
||||
ResidencyPageSize = PageSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ResidencyPageSize != PageSize)
|
||||
{
|
||||
throw new InvalidOperationException("Tried to change residency page size");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearCachedPagesIfNeeded()
|
||||
{
|
||||
if (CpCount <= MaxCpCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int Timestamp = Environment.TickCount;
|
||||
|
||||
int TimeDelta;
|
||||
|
||||
do
|
||||
{
|
||||
if (!TryPopOldestCachedPageKey(Timestamp, out long Key))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
CachedPage Cp = Cache[Key];
|
||||
|
||||
Cp.RemoveResidency(Residency, ResidencyPageSize);
|
||||
|
||||
Cache.Remove(Key);
|
||||
|
||||
CpCount -= Cp.GetTotalCount();
|
||||
|
||||
TimeDelta = RingDelta(Cp.Timestamp, Timestamp);
|
||||
}
|
||||
while (CpCount > (MaxCpCount >> 1) || (uint)TimeDelta > (uint)MaxCpTimeDelta);
|
||||
}
|
||||
|
||||
private bool TryPopOldestCachedPageKey(int Timestamp, out long Key)
|
||||
{
|
||||
LinkedListNode<long> Node = SortedCache.First;
|
||||
|
||||
if (Node == null)
|
||||
{
|
||||
Key = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SortedCache.Remove(Node);
|
||||
|
||||
Key = Node.Value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private int RingDelta(int Old, int New)
|
||||
{
|
||||
if ((uint)New < (uint)Old)
|
||||
{
|
||||
return New + (~Old + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return New - Old;
|
||||
}
|
||||
return Coverage != Size;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using Ryujinx.Graphics.Gal;
|
||||
using Ryujinx.Graphics;
|
||||
|
||||
namespace Ryujinx.Graphics
|
||||
{
|
||||
|
@ -7,21 +6,27 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
public IGalRenderer Renderer { get; private set; }
|
||||
|
||||
public GpuResourceManager ResourceManager { get; private set; }
|
||||
|
||||
public NvGpuFifo Fifo { get; private set; }
|
||||
|
||||
public NvGpuEngine2d Engine2d { get; private set; }
|
||||
public NvGpuEngine3d Engine3d { get; private set; }
|
||||
public NvGpuEngineDma EngineDma { get; private set; }
|
||||
internal NvGpuEngine2d Engine2d { get; private set; }
|
||||
internal NvGpuEngine3d Engine3d { get; private set; }
|
||||
internal NvGpuEngineM2mf EngineM2mf { get; private set; }
|
||||
internal NvGpuEngineP2mf EngineP2mf { get; private set; }
|
||||
|
||||
public NvGpu(IGalRenderer Renderer)
|
||||
{
|
||||
this.Renderer = Renderer;
|
||||
|
||||
ResourceManager = new GpuResourceManager(this);
|
||||
|
||||
Fifo = new NvGpuFifo(this);
|
||||
|
||||
Engine2d = new NvGpuEngine2d(this);
|
||||
Engine3d = new NvGpuEngine3d(this);
|
||||
EngineDma = new NvGpuEngineDma(this);
|
||||
Engine2d = new NvGpuEngine2d(this);
|
||||
Engine3d = new NvGpuEngine3d(this);
|
||||
EngineM2mf = new NvGpuEngineM2mf(this);
|
||||
EngineP2mf = new NvGpuEngineP2mf(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
namespace Ryujinx.Graphics.Memory
|
||||
namespace Ryujinx.Graphics
|
||||
{
|
||||
public enum NvGpuBufferType
|
||||
{
|
|
@ -5,7 +5,7 @@ namespace Ryujinx.Graphics
|
|||
_2d = 0x902d,
|
||||
_3d = 0xb197,
|
||||
Compute = 0xb1c0,
|
||||
Kepler = 0xa140,
|
||||
Dma = 0xb0b5
|
||||
P2mf = 0xa140,
|
||||
M2mf = 0xb0b5
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
using Ryujinx.Graphics.Gal;
|
||||
using Ryujinx.Graphics.Memory;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics
|
||||
|
@ -62,25 +61,25 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
CopyOperation Operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation);
|
||||
|
||||
int SrcFormat = ReadRegister(NvGpuEngine2dReg.SrcFormat);
|
||||
bool SrcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0;
|
||||
int SrcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth);
|
||||
int SrcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight);
|
||||
int SrcPitch = ReadRegister(NvGpuEngine2dReg.SrcPitch);
|
||||
int SrcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions);
|
||||
|
||||
int DstFormat = ReadRegister(NvGpuEngine2dReg.DstFormat);
|
||||
bool DstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0;
|
||||
int DstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth);
|
||||
int DstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight);
|
||||
int DstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch);
|
||||
int DstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions);
|
||||
|
||||
TextureSwizzle SrcSwizzle = SrcLinear
|
||||
? TextureSwizzle.Pitch
|
||||
: TextureSwizzle.BlockLinear;
|
||||
GalImageFormat SrcImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)SrcFormat);
|
||||
GalImageFormat DstImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)DstFormat);
|
||||
|
||||
TextureSwizzle DstSwizzle = DstLinear
|
||||
? TextureSwizzle.Pitch
|
||||
: TextureSwizzle.BlockLinear;
|
||||
GalMemoryLayout SrcLayout = GetLayout(SrcLinear);
|
||||
GalMemoryLayout DstLayout = GetLayout(DstLinear);
|
||||
|
||||
int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf);
|
||||
int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
|
||||
|
@ -91,91 +90,41 @@ namespace Ryujinx.Graphics
|
|||
long SrcKey = Vmm.GetPhysicalAddress(SrcAddress);
|
||||
long DstKey = Vmm.GetPhysicalAddress(DstAddress);
|
||||
|
||||
bool IsSrcFb = Gpu.Engine3d.IsFrameBufferPosition(SrcKey);
|
||||
bool IsDstFb = Gpu.Engine3d.IsFrameBufferPosition(DstKey);
|
||||
GalImage SrcTexture = new GalImage(
|
||||
SrcWidth,
|
||||
SrcHeight, 1,
|
||||
SrcBlockHeight,
|
||||
SrcLayout,
|
||||
SrcImgFormat);
|
||||
|
||||
TextureInfo SrcTexture()
|
||||
{
|
||||
return new TextureInfo(
|
||||
SrcAddress,
|
||||
SrcWidth,
|
||||
SrcHeight,
|
||||
SrcPitch,
|
||||
SrcBlockHeight, 1,
|
||||
SrcSwizzle,
|
||||
GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm);
|
||||
}
|
||||
GalImage DstTexture = new GalImage(
|
||||
DstWidth,
|
||||
DstHeight, 1,
|
||||
DstBlockHeight,
|
||||
DstLayout,
|
||||
DstImgFormat);
|
||||
|
||||
TextureInfo DstTexture()
|
||||
{
|
||||
return new TextureInfo(
|
||||
DstAddress,
|
||||
DstWidth,
|
||||
DstHeight,
|
||||
DstPitch,
|
||||
DstBlockHeight, 1,
|
||||
DstSwizzle,
|
||||
GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm);
|
||||
}
|
||||
Gpu.ResourceManager.SendTexture(Vmm, SrcKey, SrcTexture);
|
||||
Gpu.ResourceManager.SendTexture(Vmm, DstKey, DstTexture);
|
||||
|
||||
//TODO: fb -> fb copies, tex -> fb copies, formats other than RGBA8,
|
||||
//make it throw for unimpl stuff (like the copy mode)...
|
||||
if (IsSrcFb && IsDstFb)
|
||||
{
|
||||
//Frame Buffer -> Frame Buffer copy.
|
||||
Gpu.Renderer.RenderTarget.Copy(
|
||||
SrcKey,
|
||||
DstKey,
|
||||
0,
|
||||
0,
|
||||
SrcWidth,
|
||||
SrcHeight,
|
||||
0,
|
||||
0,
|
||||
DstWidth,
|
||||
DstHeight);
|
||||
}
|
||||
if (IsSrcFb)
|
||||
{
|
||||
//Frame Buffer -> Texture copy.
|
||||
Gpu.Renderer.RenderTarget.GetBufferData(SrcKey, (byte[] Buffer) =>
|
||||
{
|
||||
TextureInfo Src = SrcTexture();
|
||||
TextureInfo Dst = DstTexture();
|
||||
Gpu.Renderer.RenderTarget.Copy(
|
||||
SrcKey,
|
||||
DstKey,
|
||||
0,
|
||||
0,
|
||||
SrcWidth,
|
||||
SrcHeight,
|
||||
0,
|
||||
0,
|
||||
DstWidth,
|
||||
DstHeight);
|
||||
}
|
||||
|
||||
if (Src.Width != Dst.Width ||
|
||||
Src.Height != Dst.Height)
|
||||
{
|
||||
throw new NotImplementedException("Texture resizing is not supported");
|
||||
}
|
||||
|
||||
TextureWriter.Write(Vmm, Dst, Buffer);
|
||||
});
|
||||
}
|
||||
else if (IsDstFb)
|
||||
{
|
||||
byte[] Buffer = TextureReader.Read(Vmm, SrcTexture());
|
||||
|
||||
Gpu.Renderer.RenderTarget.SetBufferData(
|
||||
DstKey,
|
||||
DstWidth,
|
||||
DstHeight,
|
||||
Buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Texture -> Texture copy.
|
||||
TextureInfo Src = SrcTexture();
|
||||
TextureInfo Dst = DstTexture();
|
||||
|
||||
if (Src.Width != Dst.Width ||
|
||||
Src.Height != Dst.Height)
|
||||
{
|
||||
throw new NotImplementedException("Texture resizing is not supported");
|
||||
}
|
||||
|
||||
TextureWriter.Write(Vmm, Dst, TextureReader.Read(Vmm, Src));
|
||||
}
|
||||
private static GalMemoryLayout GetLayout(bool Linear)
|
||||
{
|
||||
return Linear
|
||||
? GalMemoryLayout.Pitch
|
||||
: GalMemoryLayout.BlockLinear;
|
||||
}
|
||||
|
||||
private long MakeInt64From2xInt32(NvGpuEngine2dReg Reg)
|
||||
|
|
|
@ -23,8 +23,6 @@ namespace Ryujinx.Graphics
|
|||
|
||||
private ConstBuffer[][] ConstBuffers;
|
||||
|
||||
private HashSet<long> FrameBuffers;
|
||||
|
||||
private List<long>[] UploadedKeys;
|
||||
|
||||
private int CurrentInstance = 0;
|
||||
|
@ -60,8 +58,6 @@ namespace Ryujinx.Graphics
|
|||
ConstBuffers[Index] = new ConstBuffer[18];
|
||||
}
|
||||
|
||||
FrameBuffers = new HashSet<long>();
|
||||
|
||||
UploadedKeys = new List<long>[(int)NvGpuBufferType.Count];
|
||||
|
||||
for (int i = 0; i < UploadedKeys.Length; i++)
|
||||
|
@ -96,7 +92,7 @@ namespace Ryujinx.Graphics
|
|||
|
||||
GalPipelineState State = new GalPipelineState();
|
||||
|
||||
SetFlip(State);
|
||||
SetFrameBuffer(State);
|
||||
SetFrontFace(State);
|
||||
SetCullFace(State);
|
||||
SetDepth(State);
|
||||
|
@ -104,10 +100,7 @@ namespace Ryujinx.Graphics
|
|||
SetAlphaBlending(State);
|
||||
SetPrimitiveRestart(State);
|
||||
|
||||
for (int FbIndex = 0; FbIndex < 8; FbIndex++)
|
||||
{
|
||||
SetFrameBuffer(Vmm, 0);
|
||||
}
|
||||
SetFrameBuffer(Vmm, 0);
|
||||
|
||||
SetZeta(Vmm);
|
||||
|
||||
|
@ -173,9 +166,9 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10);
|
||||
|
||||
int Format = ReadRegister(NvGpuEngine3dReg.FrameBufferNFormat + FbIndex * 0x10);
|
||||
int SurfFormat = ReadRegister(NvGpuEngine3dReg.FrameBufferNFormat + FbIndex * 0x10);
|
||||
|
||||
if (VA == 0 || Format == 0)
|
||||
if (VA == 0 || SurfFormat == 0)
|
||||
{
|
||||
Gpu.Renderer.RenderTarget.UnbindColor(FbIndex);
|
||||
|
||||
|
@ -184,11 +177,15 @@ namespace Ryujinx.Graphics
|
|||
|
||||
long Key = Vmm.GetPhysicalAddress(VA);
|
||||
|
||||
FrameBuffers.Add(Key);
|
||||
|
||||
int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10);
|
||||
int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10);
|
||||
|
||||
int BlockDim = ReadRegister(NvGpuEngine3dReg.FrameBufferNBlockDim + FbIndex * 0x10);
|
||||
|
||||
int GobBlockHeight = 1 << ((BlockDim >> 4) & 7);
|
||||
|
||||
GalMemoryLayout Layout = (GalMemoryLayout)((BlockDim >> 12) & 1);
|
||||
|
||||
float TX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateX + FbIndex * 8);
|
||||
float TY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateY + FbIndex * 8);
|
||||
|
||||
|
@ -201,48 +198,54 @@ namespace Ryujinx.Graphics
|
|||
int VpW = (int)(TX + MathF.Abs(SX)) - VpX;
|
||||
int VpH = (int)(TY + MathF.Abs(SY)) - VpY;
|
||||
|
||||
GalImageFormat ImageFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)Format);
|
||||
GalImageFormat Format = ImageUtils.ConvertSurface((GalSurfaceFormat)SurfFormat);
|
||||
|
||||
GalImage Image = new GalImage(Width, Height, ImageFormat);
|
||||
GalImage Image = new GalImage(Width, Height, 1, GobBlockHeight, Layout, Format);
|
||||
|
||||
long Size = ImageUtils.GetSize(Image);
|
||||
|
||||
Gpu.Renderer.Texture.CreateFb(Key, Size, Image);
|
||||
|
||||
Gpu.Renderer.RenderTarget.BindColor(Key, FbIndex);
|
||||
Gpu.ResourceManager.SendColorBuffer(Vmm, Key, FbIndex, Image);
|
||||
|
||||
Gpu.Renderer.RenderTarget.SetViewport(VpX, VpY, VpW, VpH);
|
||||
}
|
||||
|
||||
private void SetFrameBuffer(GalPipelineState State)
|
||||
{
|
||||
State.FramebufferSrgb = ReadRegisterBool(NvGpuEngine3dReg.FrameBufferSrgb);
|
||||
|
||||
State.FlipX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX);
|
||||
State.FlipY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY);
|
||||
}
|
||||
|
||||
private void SetZeta(NvGpuVmm Vmm)
|
||||
{
|
||||
long ZA = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress);
|
||||
long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress);
|
||||
|
||||
int Format = ReadRegister(NvGpuEngine3dReg.ZetaFormat);
|
||||
int ZetaFormat = ReadRegister(NvGpuEngine3dReg.ZetaFormat);
|
||||
|
||||
bool ZetaEnable = (ReadRegister(NvGpuEngine3dReg.ZetaEnable) & 1) != 0;
|
||||
int BlockDim = ReadRegister(NvGpuEngine3dReg.ZetaBlockDimensions);
|
||||
|
||||
if (ZA == 0 || Format == 0 || !ZetaEnable)
|
||||
int GobBlockHeight = 1 << ((BlockDim >> 4) & 7);
|
||||
|
||||
GalMemoryLayout Layout = (GalMemoryLayout)((BlockDim >> 12) & 1); //?
|
||||
|
||||
bool ZetaEnable = ReadRegisterBool(NvGpuEngine3dReg.ZetaEnable);
|
||||
|
||||
if (VA == 0 || ZetaFormat == 0 || !ZetaEnable)
|
||||
{
|
||||
Gpu.Renderer.RenderTarget.UnbindZeta();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
long Key = Vmm.GetPhysicalAddress(ZA);
|
||||
long Key = Vmm.GetPhysicalAddress(VA);
|
||||
|
||||
int Width = ReadRegister(NvGpuEngine3dReg.ZetaHoriz);
|
||||
int Height = ReadRegister(NvGpuEngine3dReg.ZetaVert);
|
||||
|
||||
GalImageFormat ImageFormat = ImageUtils.ConvertZeta((GalZetaFormat)Format);
|
||||
GalImageFormat Format = ImageUtils.ConvertZeta((GalZetaFormat)ZetaFormat);
|
||||
|
||||
GalImage Image = new GalImage(Width, Height, ImageFormat);
|
||||
GalImage Image = new GalImage(Width, Height, 1, GobBlockHeight, Layout, Format);
|
||||
|
||||
long Size = ImageUtils.GetSize(Image);
|
||||
|
||||
Gpu.Renderer.Texture.CreateFb(Key, Size, Image);
|
||||
|
||||
Gpu.Renderer.RenderTarget.BindZeta(Key);
|
||||
Gpu.ResourceManager.SendZetaBuffer(Vmm, Key, Image);
|
||||
}
|
||||
|
||||
private long[] UploadShaders(NvGpuVmm Vmm)
|
||||
|
@ -322,12 +325,6 @@ namespace Ryujinx.Graphics
|
|||
throw new ArgumentOutOfRangeException(nameof(Program));
|
||||
}
|
||||
|
||||
private void SetFlip(GalPipelineState State)
|
||||
{
|
||||
State.FlipX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX);
|
||||
State.FlipY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY);
|
||||
}
|
||||
|
||||
private void SetFrontFace(GalPipelineState State)
|
||||
{
|
||||
float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX);
|
||||
|
@ -355,7 +352,7 @@ namespace Ryujinx.Graphics
|
|||
|
||||
private void SetCullFace(GalPipelineState State)
|
||||
{
|
||||
State.CullFaceEnabled = (ReadRegister(NvGpuEngine3dReg.CullFaceEnable) & 1) != 0;
|
||||
State.CullFaceEnabled = ReadRegisterBool(NvGpuEngine3dReg.CullFaceEnable);
|
||||
|
||||
if (State.CullFaceEnabled)
|
||||
{
|
||||
|
@ -365,7 +362,9 @@ namespace Ryujinx.Graphics
|
|||
|
||||
private void SetDepth(GalPipelineState State)
|
||||
{
|
||||
State.DepthTestEnabled = (ReadRegister(NvGpuEngine3dReg.DepthTestEnable) & 1) != 0;
|
||||
State.DepthTestEnabled = ReadRegisterBool(NvGpuEngine3dReg.DepthTestEnable);
|
||||
|
||||
State.DepthWriteEnabled = ReadRegisterBool(NvGpuEngine3dReg.DepthWriteEnable);
|
||||
|
||||
if (State.DepthTestEnabled)
|
||||
{
|
||||
|
@ -375,7 +374,7 @@ namespace Ryujinx.Graphics
|
|||
|
||||
private void SetStencil(GalPipelineState State)
|
||||
{
|
||||
State.StencilTestEnabled = (ReadRegister(NvGpuEngine3dReg.StencilEnable) & 1) != 0;
|
||||
State.StencilTestEnabled = ReadRegisterBool(NvGpuEngine3dReg.StencilEnable);
|
||||
|
||||
if (State.StencilTestEnabled)
|
||||
{
|
||||
|
@ -400,11 +399,11 @@ namespace Ryujinx.Graphics
|
|||
private void SetAlphaBlending(GalPipelineState State)
|
||||
{
|
||||
//TODO: Support independent blend properly.
|
||||
State.BlendEnabled = (ReadRegister(NvGpuEngine3dReg.IBlendNEnable) & 1) != 0;
|
||||
State.BlendEnabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable);
|
||||
|
||||
if (State.BlendEnabled)
|
||||
{
|
||||
State.BlendSeparateAlpha = (ReadRegister(NvGpuEngine3dReg.IBlendNSeparateAlpha) & 1) != 0;
|
||||
State.BlendSeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.IBlendNSeparateAlpha);
|
||||
|
||||
State.BlendEquationRgb = (GalBlendEquation)ReadRegister(NvGpuEngine3dReg.IBlendNEquationRgb);
|
||||
State.BlendFuncSrcRgb = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.IBlendNFuncSrcRgb);
|
||||
|
@ -417,7 +416,7 @@ namespace Ryujinx.Graphics
|
|||
|
||||
private void SetPrimitiveRestart(GalPipelineState State)
|
||||
{
|
||||
State.PrimitiveRestartEnabled = (ReadRegister(NvGpuEngine3dReg.PrimRestartEnable) & 1) != 0;
|
||||
State.PrimitiveRestartEnabled = ReadRegisterBool(NvGpuEngine3dReg.PrimRestartEnable);
|
||||
|
||||
if (State.PrimitiveRestartEnabled)
|
||||
{
|
||||
|
@ -427,7 +426,7 @@ namespace Ryujinx.Graphics
|
|||
|
||||
private void SetRenderTargets()
|
||||
{
|
||||
bool SeparateFragData = (ReadRegister(NvGpuEngine3dReg.RTSeparateFragData) & 1) != 0;
|
||||
bool SeparateFragData = ReadRegisterBool(NvGpuEngine3dReg.RTSeparateFragData);
|
||||
|
||||
if (SeparateFragData)
|
||||
{
|
||||
|
@ -504,53 +503,30 @@ namespace Ryujinx.Graphics
|
|||
TicPosition += TicIndex * 0x20;
|
||||
TscPosition += TscIndex * 0x20;
|
||||
|
||||
GalImage Image = TextureFactory.MakeTexture(Vmm, TicPosition);
|
||||
|
||||
GalTextureSampler Sampler = TextureFactory.MakeSampler(Gpu, Vmm, TscPosition);
|
||||
|
||||
long Key = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff;
|
||||
|
||||
if (Image.Layout == GalMemoryLayout.BlockLinear)
|
||||
{
|
||||
Key &= ~0x1ffL;
|
||||
}
|
||||
else if (Image.Layout == GalMemoryLayout.Pitch)
|
||||
{
|
||||
Key &= ~0x1fL;
|
||||
}
|
||||
|
||||
Key = Vmm.GetPhysicalAddress(Key);
|
||||
|
||||
if (Key == -1)
|
||||
{
|
||||
//FIXME: Should'nt ignore invalid addresses.
|
||||
//FIXME: Shouldn't ignore invalid addresses.
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsFrameBufferPosition(Key))
|
||||
{
|
||||
//This texture is a frame buffer texture,
|
||||
//we shouldn't read anything from memory and bind
|
||||
//the frame buffer texture instead, since we're not
|
||||
//really writing anything to memory.
|
||||
Gpu.Renderer.RenderTarget.BindTexture(Key, TexIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
GalImage NewImage = TextureFactory.MakeTexture(Vmm, TicPosition);
|
||||
|
||||
long Size = (uint)ImageUtils.GetSize(NewImage);
|
||||
|
||||
bool HasCachedTexture = false;
|
||||
|
||||
if (Gpu.Renderer.Texture.TryGetCachedTexture(Key, Size, out GalImage Image))
|
||||
{
|
||||
if (NewImage.Equals(Image) && !QueryKeyUpload(Vmm, Key, Size, NvGpuBufferType.Texture))
|
||||
{
|
||||
Gpu.Renderer.Texture.Bind(Key, TexIndex);
|
||||
|
||||
HasCachedTexture = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!HasCachedTexture)
|
||||
{
|
||||
byte[] Data = TextureFactory.GetTextureData(Vmm, TicPosition);
|
||||
|
||||
Gpu.Renderer.Texture.Create(Key, Data, NewImage);
|
||||
}
|
||||
|
||||
Gpu.Renderer.Texture.Bind(Key, TexIndex);
|
||||
}
|
||||
Gpu.ResourceManager.SendTexture(Vmm, Key, Image, TexIndex);
|
||||
|
||||
Gpu.Renderer.Texture.SetSampler(Sampler);
|
||||
}
|
||||
|
@ -661,7 +637,7 @@ namespace Ryujinx.Graphics
|
|||
|
||||
int VertexDivisor = ReadRegister(NvGpuEngine3dReg.VertexArrayNDivisor + Index * 4);
|
||||
|
||||
bool Instanced = (ReadRegister(NvGpuEngine3dReg.VertexArrayNInstance + Index) & 1) != 0;
|
||||
bool Instanced = ReadRegisterBool(NvGpuEngine3dReg.VertexArrayNInstance + Index);
|
||||
|
||||
int Stride = Control & 0xfff;
|
||||
|
||||
|
@ -871,16 +847,16 @@ namespace Ryujinx.Graphics
|
|||
return BitConverter.Int32BitsToSingle(ReadRegister(Reg));
|
||||
}
|
||||
|
||||
private bool ReadRegisterBool(NvGpuEngine3dReg Reg)
|
||||
{
|
||||
return (ReadRegister(Reg) & 1) != 0;
|
||||
}
|
||||
|
||||
private void WriteRegister(NvGpuEngine3dReg Reg, int Value)
|
||||
{
|
||||
Registers[(int)Reg] = Value;
|
||||
}
|
||||
|
||||
public bool IsFrameBufferPosition(long Position)
|
||||
{
|
||||
return FrameBuffers.Contains(Position);
|
||||
}
|
||||
|
||||
private bool QueryKeyUpload(NvGpuVmm Vmm, long Key, long Size, NvGpuBufferType Type)
|
||||
{
|
||||
List<long> Uploaded = UploadedKeys[(int)Type];
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Ryujinx.Graphics
|
|||
FrameBufferNWidth = 0x202,
|
||||
FrameBufferNHeight = 0x203,
|
||||
FrameBufferNFormat = 0x204,
|
||||
FrameBufferNBlockDim = 0x205,
|
||||
ViewportNScaleX = 0x280,
|
||||
ViewportNScaleY = 0x281,
|
||||
ViewportNScaleZ = 0x282,
|
||||
|
@ -34,6 +35,7 @@ namespace Ryujinx.Graphics
|
|||
ZetaArrayMode = 0x48c,
|
||||
DepthTestEnable = 0x4b3,
|
||||
IBlendEnable = 0x4b9,
|
||||
DepthWriteEnable = 0x4ba,
|
||||
DepthTestFunction = 0x4c3,
|
||||
BlendSeparateAlpha = 0x4cf,
|
||||
BlendEquationRgb = 0x4d0,
|
||||
|
@ -62,6 +64,7 @@ namespace Ryujinx.Graphics
|
|||
StencilBackOpZFail = 0x567,
|
||||
StencilBackOpZPass = 0x568,
|
||||
StencilBackFuncFunc = 0x569,
|
||||
FrameBufferSrgb = 0x56e,
|
||||
ShaderAddress = 0x582,
|
||||
VertexBeginGl = 0x586,
|
||||
PrimRestartEnable = 0x591,
|
||||
|
|
|
@ -1,143 +0,0 @@
|
|||
using Ryujinx.Graphics.Memory;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics
|
||||
{
|
||||
public class NvGpuEngineDma : INvGpuEngine
|
||||
{
|
||||
public int[] Registers { get; private set; }
|
||||
|
||||
private NvGpu Gpu;
|
||||
|
||||
private Dictionary<int, NvGpuMethod> Methods;
|
||||
|
||||
public NvGpuEngineDma(NvGpu Gpu)
|
||||
{
|
||||
this.Gpu = Gpu;
|
||||
|
||||
Registers = new int[0x1d6];
|
||||
|
||||
Methods = new Dictionary<int, NvGpuMethod>();
|
||||
|
||||
void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method)
|
||||
{
|
||||
while (Count-- > 0)
|
||||
{
|
||||
Methods.Add(Meth, Method);
|
||||
|
||||
Meth += Stride;
|
||||
}
|
||||
}
|
||||
|
||||
AddMethod(0xc0, 1, 1, Execute);
|
||||
}
|
||||
|
||||
public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||
{
|
||||
if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method))
|
||||
{
|
||||
Method(Vmm, PBEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteRegister(PBEntry);
|
||||
}
|
||||
}
|
||||
|
||||
private void Execute(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||
{
|
||||
int Control = PBEntry.Arguments[0];
|
||||
|
||||
bool SrcLinear = ((Control >> 7) & 1) != 0;
|
||||
bool DstLinear = ((Control >> 8) & 1) != 0;
|
||||
|
||||
long SrcAddress = MakeInt64From2xInt32(NvGpuEngineDmaReg.SrcAddress);
|
||||
long DstAddress = MakeInt64From2xInt32(NvGpuEngineDmaReg.DstAddress);
|
||||
|
||||
int SrcPitch = ReadRegister(NvGpuEngineDmaReg.SrcPitch);
|
||||
int DstPitch = ReadRegister(NvGpuEngineDmaReg.DstPitch);
|
||||
|
||||
int DstBlkDim = ReadRegister(NvGpuEngineDmaReg.DstBlkDim);
|
||||
int DstSizeX = ReadRegister(NvGpuEngineDmaReg.DstSizeX);
|
||||
int DstSizeY = ReadRegister(NvGpuEngineDmaReg.DstSizeY);
|
||||
int DstSizeZ = ReadRegister(NvGpuEngineDmaReg.DstSizeZ);
|
||||
int DstPosXY = ReadRegister(NvGpuEngineDmaReg.DstPosXY);
|
||||
int DstPosZ = ReadRegister(NvGpuEngineDmaReg.DstPosZ);
|
||||
|
||||
int SrcBlkDim = ReadRegister(NvGpuEngineDmaReg.SrcBlkDim);
|
||||
int SrcSizeX = ReadRegister(NvGpuEngineDmaReg.SrcSizeX);
|
||||
int SrcSizeY = ReadRegister(NvGpuEngineDmaReg.SrcSizeY);
|
||||
int SrcSizeZ = ReadRegister(NvGpuEngineDmaReg.SrcSizeZ);
|
||||
int SrcPosXY = ReadRegister(NvGpuEngineDmaReg.SrcPosXY);
|
||||
int SrcPosZ = ReadRegister(NvGpuEngineDmaReg.SrcPosZ);
|
||||
|
||||
int DstPosX = (DstPosXY >> 0) & 0xffff;
|
||||
int DstPosY = (DstPosXY >> 16) & 0xffff;
|
||||
|
||||
int SrcPosX = (SrcPosXY >> 0) & 0xffff;
|
||||
int SrcPosY = (SrcPosXY >> 16) & 0xffff;
|
||||
|
||||
int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf);
|
||||
int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
|
||||
|
||||
ISwizzle SrcSwizzle;
|
||||
|
||||
if (SrcLinear)
|
||||
{
|
||||
SrcSwizzle = new LinearSwizzle(SrcPitch, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
SrcSwizzle = new BlockLinearSwizzle(SrcSizeX, 1, SrcBlockHeight);
|
||||
}
|
||||
|
||||
ISwizzle DstSwizzle;
|
||||
|
||||
if (DstLinear)
|
||||
{
|
||||
DstSwizzle = new LinearSwizzle(DstPitch, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
DstSwizzle = new BlockLinearSwizzle(DstSizeX, 1, DstBlockHeight);
|
||||
}
|
||||
|
||||
for (int Y = 0; Y < DstSizeY; Y++)
|
||||
for (int X = 0; X < DstSizeX; X++)
|
||||
{
|
||||
long SrcOffset = SrcAddress + (uint)SrcSwizzle.GetSwizzleOffset(X, Y);
|
||||
long DstOffset = DstAddress + (uint)DstSwizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
Vmm.WriteByte(DstOffset, Vmm.ReadByte(SrcOffset));
|
||||
}
|
||||
}
|
||||
|
||||
private long MakeInt64From2xInt32(NvGpuEngineDmaReg Reg)
|
||||
{
|
||||
return
|
||||
(long)Registers[(int)Reg + 0] << 32 |
|
||||
(uint)Registers[(int)Reg + 1];
|
||||
}
|
||||
|
||||
private void WriteRegister(NvGpuPBEntry PBEntry)
|
||||
{
|
||||
int ArgsCount = PBEntry.Arguments.Count;
|
||||
|
||||
if (ArgsCount > 0)
|
||||
{
|
||||
Registers[PBEntry.Method] = PBEntry.Arguments[ArgsCount - 1];
|
||||
}
|
||||
}
|
||||
|
||||
private int ReadRegister(NvGpuEngineDmaReg Reg)
|
||||
{
|
||||
return Registers[(int)Reg];
|
||||
}
|
||||
|
||||
private void WriteRegister(NvGpuEngineDmaReg Reg, int Value)
|
||||
{
|
||||
Registers[(int)Reg] = Value;
|
||||
}
|
||||
}
|
||||
}
|
192
Ryujinx.Graphics/NvGpuEngineM2mf.cs
Normal file
192
Ryujinx.Graphics/NvGpuEngineM2mf.cs
Normal file
|
@ -0,0 +1,192 @@
|
|||
using Ryujinx.Graphics.Memory;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics
|
||||
{
|
||||
public class NvGpuEngineM2mf : INvGpuEngine
|
||||
{
|
||||
public int[] Registers { get; private set; }
|
||||
|
||||
private NvGpu Gpu;
|
||||
|
||||
private Dictionary<int, NvGpuMethod> Methods;
|
||||
|
||||
public NvGpuEngineM2mf(NvGpu Gpu)
|
||||
{
|
||||
this.Gpu = Gpu;
|
||||
|
||||
Registers = new int[0x1d6];
|
||||
|
||||
Methods = new Dictionary<int, NvGpuMethod>();
|
||||
|
||||
void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method)
|
||||
{
|
||||
while (Count-- > 0)
|
||||
{
|
||||
Methods.Add(Meth, Method);
|
||||
|
||||
Meth += Stride;
|
||||
}
|
||||
}
|
||||
|
||||
AddMethod(0xc0, 1, 1, Execute);
|
||||
}
|
||||
|
||||
public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||
{
|
||||
if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method))
|
||||
{
|
||||
Method(Vmm, PBEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteRegister(PBEntry);
|
||||
}
|
||||
}
|
||||
|
||||
private void Execute(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||
{
|
||||
//TODO: Some registers and copy modes are still not implemented.
|
||||
int Control = PBEntry.Arguments[0];
|
||||
|
||||
bool SrcLinear = ((Control >> 7) & 1) != 0;
|
||||
bool DstLinear = ((Control >> 8) & 1) != 0;
|
||||
bool Copy2d = ((Control >> 9) & 1) != 0;
|
||||
|
||||
long SrcAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.SrcAddress);
|
||||
long DstAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.DstAddress);
|
||||
|
||||
int SrcPitch = ReadRegister(NvGpuEngineM2mfReg.SrcPitch);
|
||||
int DstPitch = ReadRegister(NvGpuEngineM2mfReg.DstPitch);
|
||||
|
||||
int XCount = ReadRegister(NvGpuEngineM2mfReg.XCount);
|
||||
int YCount = ReadRegister(NvGpuEngineM2mfReg.YCount);
|
||||
|
||||
int Swizzle = ReadRegister(NvGpuEngineM2mfReg.Swizzle);
|
||||
|
||||
int DstBlkDim = ReadRegister(NvGpuEngineM2mfReg.DstBlkDim);
|
||||
int DstSizeX = ReadRegister(NvGpuEngineM2mfReg.DstSizeX);
|
||||
int DstSizeY = ReadRegister(NvGpuEngineM2mfReg.DstSizeY);
|
||||
int DstSizeZ = ReadRegister(NvGpuEngineM2mfReg.DstSizeZ);
|
||||
int DstPosXY = ReadRegister(NvGpuEngineM2mfReg.DstPosXY);
|
||||
int DstPosZ = ReadRegister(NvGpuEngineM2mfReg.DstPosZ);
|
||||
|
||||
int SrcBlkDim = ReadRegister(NvGpuEngineM2mfReg.SrcBlkDim);
|
||||
int SrcSizeX = ReadRegister(NvGpuEngineM2mfReg.SrcSizeX);
|
||||
int SrcSizeY = ReadRegister(NvGpuEngineM2mfReg.SrcSizeY);
|
||||
int SrcSizeZ = ReadRegister(NvGpuEngineM2mfReg.SrcSizeZ);
|
||||
int SrcPosXY = ReadRegister(NvGpuEngineM2mfReg.SrcPosXY);
|
||||
int SrcPosZ = ReadRegister(NvGpuEngineM2mfReg.SrcPosZ);
|
||||
|
||||
int SrcCpp = ((Swizzle >> 20) & 7) + 1;
|
||||
int DstCpp = ((Swizzle >> 24) & 7) + 1;
|
||||
|
||||
int DstPosX = (DstPosXY >> 0) & 0xffff;
|
||||
int DstPosY = (DstPosXY >> 16) & 0xffff;
|
||||
|
||||
int SrcPosX = (SrcPosXY >> 0) & 0xffff;
|
||||
int SrcPosY = (SrcPosXY >> 16) & 0xffff;
|
||||
|
||||
int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf);
|
||||
int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
|
||||
|
||||
long SrcPA = Vmm.GetPhysicalAddress(SrcAddress);
|
||||
long DstPA = Vmm.GetPhysicalAddress(DstAddress);
|
||||
|
||||
if (Copy2d)
|
||||
{
|
||||
if (SrcLinear)
|
||||
{
|
||||
SrcPosX = SrcPosY = SrcPosZ = 0;
|
||||
}
|
||||
|
||||
if (DstLinear)
|
||||
{
|
||||
DstPosX = DstPosY = DstPosZ = 0;
|
||||
}
|
||||
|
||||
if (SrcLinear && DstLinear)
|
||||
{
|
||||
for (int Y = 0; Y < YCount; Y++)
|
||||
{
|
||||
int SrcOffset = (SrcPosY + Y) * SrcPitch + SrcPosX * SrcCpp;
|
||||
int DstOffset = (DstPosY + Y) * DstPitch + DstPosX * DstCpp;
|
||||
|
||||
long Src = SrcPA + (uint)SrcOffset;
|
||||
long Dst = DstPA + (uint)DstOffset;
|
||||
|
||||
Vmm.Memory.CopyBytes(Src, Dst, XCount * SrcCpp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ISwizzle SrcSwizzle;
|
||||
|
||||
if (SrcLinear)
|
||||
{
|
||||
SrcSwizzle = new LinearSwizzle(SrcPitch, SrcCpp);
|
||||
}
|
||||
else
|
||||
{
|
||||
SrcSwizzle = new BlockLinearSwizzle(SrcSizeX, SrcCpp, SrcBlockHeight);
|
||||
}
|
||||
|
||||
ISwizzle DstSwizzle;
|
||||
|
||||
if (DstLinear)
|
||||
{
|
||||
DstSwizzle = new LinearSwizzle(DstPitch, DstCpp);
|
||||
}
|
||||
else
|
||||
{
|
||||
DstSwizzle = new BlockLinearSwizzle(DstSizeX, DstCpp, DstBlockHeight);
|
||||
}
|
||||
|
||||
for (int Y = 0; Y < YCount; Y++)
|
||||
for (int X = 0; X < XCount; X++)
|
||||
{
|
||||
int SrcOffset = SrcSwizzle.GetSwizzleOffset(SrcPosX + X, SrcPosY + Y);
|
||||
int DstOffset = DstSwizzle.GetSwizzleOffset(DstPosX + X, DstPosY + Y);
|
||||
|
||||
long Src = SrcPA + (uint)SrcOffset;
|
||||
long Dst = DstPA + (uint)DstOffset;
|
||||
|
||||
Vmm.Memory.CopyBytes(Src, Dst, SrcCpp);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vmm.Memory.CopyBytes(SrcPA, DstPA, XCount);
|
||||
}
|
||||
}
|
||||
|
||||
private long MakeInt64From2xInt32(NvGpuEngineM2mfReg Reg)
|
||||
{
|
||||
return
|
||||
(long)Registers[(int)Reg + 0] << 32 |
|
||||
(uint)Registers[(int)Reg + 1];
|
||||
}
|
||||
|
||||
private void WriteRegister(NvGpuPBEntry PBEntry)
|
||||
{
|
||||
int ArgsCount = PBEntry.Arguments.Count;
|
||||
|
||||
if (ArgsCount > 0)
|
||||
{
|
||||
Registers[PBEntry.Method] = PBEntry.Arguments[ArgsCount - 1];
|
||||
}
|
||||
}
|
||||
|
||||
private int ReadRegister(NvGpuEngineM2mfReg Reg)
|
||||
{
|
||||
return Registers[(int)Reg];
|
||||
}
|
||||
|
||||
private void WriteRegister(NvGpuEngineM2mfReg Reg, int Value)
|
||||
{
|
||||
Registers[(int)Reg] = Value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,14 @@
|
|||
namespace Ryujinx.Graphics
|
||||
{
|
||||
enum NvGpuEngineDmaReg
|
||||
enum NvGpuEngineM2mfReg
|
||||
{
|
||||
SrcAddress = 0x100,
|
||||
DstAddress = 0x102,
|
||||
SrcPitch = 0x104,
|
||||
DstPitch = 0x105,
|
||||
XCount = 0x106,
|
||||
YCount = 0x107,
|
||||
Swizzle = 0x1c2,
|
||||
DstBlkDim = 0x1c3,
|
||||
DstSizeX = 0x1c4,
|
||||
DstSizeY = 0x1c5,
|
102
Ryujinx.Graphics/NvGpuEngineP2mf.cs
Normal file
102
Ryujinx.Graphics/NvGpuEngineP2mf.cs
Normal file
|
@ -0,0 +1,102 @@
|
|||
using Ryujinx.Graphics.Memory;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Ryujinx.Graphics
|
||||
{
|
||||
public class NvGpuEngineP2mf : INvGpuEngine
|
||||
{
|
||||
public int[] Registers { get; private set; }
|
||||
|
||||
private NvGpu Gpu;
|
||||
|
||||
private Dictionary<int, NvGpuMethod> Methods;
|
||||
|
||||
private ReadOnlyCollection<int> DataBuffer;
|
||||
|
||||
public NvGpuEngineP2mf(NvGpu Gpu)
|
||||
{
|
||||
this.Gpu = Gpu;
|
||||
|
||||
Registers = new int[0x80];
|
||||
|
||||
Methods = new Dictionary<int, NvGpuMethod>();
|
||||
|
||||
void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method)
|
||||
{
|
||||
while (Count-- > 0)
|
||||
{
|
||||
Methods.Add(Meth, Method);
|
||||
|
||||
Meth += Stride;
|
||||
}
|
||||
}
|
||||
|
||||
AddMethod(0x6c, 1, 1, Execute);
|
||||
AddMethod(0x6d, 1, 1, PushData);
|
||||
}
|
||||
|
||||
public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||
{
|
||||
if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method))
|
||||
{
|
||||
Method(Vmm, PBEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteRegister(PBEntry);
|
||||
}
|
||||
}
|
||||
|
||||
private void Execute(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||
{
|
||||
//TODO: Some registers and copy modes are still not implemented.
|
||||
int Control = PBEntry.Arguments[0];
|
||||
|
||||
long DstAddress = MakeInt64From2xInt32(NvGpuEngineP2mfReg.DstAddress);
|
||||
|
||||
int LineLengthIn = ReadRegister(NvGpuEngineP2mfReg.LineLengthIn);
|
||||
|
||||
DataBuffer = null;
|
||||
|
||||
Gpu.Fifo.Step();
|
||||
|
||||
for (int Offset = 0; Offset < LineLengthIn; Offset += 4)
|
||||
{
|
||||
Vmm.WriteInt32(DstAddress + Offset, DataBuffer[Offset >> 2]);
|
||||
}
|
||||
}
|
||||
|
||||
private void PushData(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||
{
|
||||
DataBuffer = PBEntry.Arguments;
|
||||
}
|
||||
|
||||
private long MakeInt64From2xInt32(NvGpuEngineP2mfReg Reg)
|
||||
{
|
||||
return
|
||||
(long)Registers[(int)Reg + 0] << 32 |
|
||||
(uint)Registers[(int)Reg + 1];
|
||||
}
|
||||
|
||||
private void WriteRegister(NvGpuPBEntry PBEntry)
|
||||
{
|
||||
int ArgsCount = PBEntry.Arguments.Count;
|
||||
|
||||
if (ArgsCount > 0)
|
||||
{
|
||||
Registers[PBEntry.Method] = PBEntry.Arguments[ArgsCount - 1];
|
||||
}
|
||||
}
|
||||
|
||||
private int ReadRegister(NvGpuEngineP2mfReg Reg)
|
||||
{
|
||||
return Registers[(int)Reg];
|
||||
}
|
||||
|
||||
private void WriteRegister(NvGpuEngineP2mfReg Reg, int Value)
|
||||
{
|
||||
Registers[(int)Reg] = Value;
|
||||
}
|
||||
}
|
||||
}
|
17
Ryujinx.Graphics/NvGpuEngineP2mfReg.cs
Normal file
17
Ryujinx.Graphics/NvGpuEngineP2mfReg.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
namespace Ryujinx.Graphics
|
||||
{
|
||||
enum NvGpuEngineP2mfReg
|
||||
{
|
||||
LineLengthIn = 0x60,
|
||||
LineCount = 0x61,
|
||||
DstAddress = 0x62,
|
||||
DstPitch = 0x64,
|
||||
DstBlockDim = 0x65,
|
||||
DstWidth = 0x66,
|
||||
DstHeight = 0x67,
|
||||
DstDepth = 0x68,
|
||||
DstZ = 0x69,
|
||||
DstX = 0x6a,
|
||||
DstY = 0x6b
|
||||
}
|
||||
}
|
|
@ -94,6 +94,8 @@ namespace Ryujinx.Graphics
|
|||
|
||||
Gpu.Engine3d.ResetCache();
|
||||
|
||||
Gpu.ResourceManager.ClearPbCache();
|
||||
|
||||
CurrPbEntryIndex = 0;
|
||||
}
|
||||
|
||||
|
@ -103,20 +105,36 @@ namespace Ryujinx.Graphics
|
|||
}
|
||||
|
||||
private void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||
{
|
||||
if ((NvGpuFifoMeth)PBEntry.Method == NvGpuFifoMeth.BindChannel)
|
||||
{
|
||||
NvGpuEngine Engine = (NvGpuEngine)PBEntry.Arguments[0];
|
||||
|
||||
SubChannels[PBEntry.SubChannel] = Engine;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (SubChannels[PBEntry.SubChannel])
|
||||
{
|
||||
case NvGpuEngine._2d: Call2dMethod (Vmm, PBEntry); break;
|
||||
case NvGpuEngine._3d: Call3dMethod (Vmm, PBEntry); break;
|
||||
case NvGpuEngine.P2mf: CallP2mfMethod(Vmm, PBEntry); break;
|
||||
case NvGpuEngine.M2mf: CallM2mfMethod(Vmm, PBEntry); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Call2dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||
{
|
||||
Gpu.Engine2d.CallMethod(Vmm, PBEntry);
|
||||
}
|
||||
|
||||
private void Call3dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||
{
|
||||
if (PBEntry.Method < 0x80)
|
||||
{
|
||||
switch ((NvGpuFifoMeth)PBEntry.Method)
|
||||
{
|
||||
case NvGpuFifoMeth.BindChannel:
|
||||
{
|
||||
NvGpuEngine Engine = (NvGpuEngine)PBEntry.Arguments[0];
|
||||
|
||||
SubChannels[PBEntry.SubChannel] = Engine;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case NvGpuFifoMeth.SetMacroUploadAddress:
|
||||
{
|
||||
CurrMacroPosition = PBEntry.Arguments[0];
|
||||
|
@ -150,25 +168,7 @@ namespace Ryujinx.Graphics
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (SubChannels[PBEntry.SubChannel])
|
||||
{
|
||||
case NvGpuEngine._2d: Call2dMethod (Vmm, PBEntry); break;
|
||||
case NvGpuEngine._3d: Call3dMethod (Vmm, PBEntry); break;
|
||||
case NvGpuEngine.Dma: CallDmaMethod(Vmm, PBEntry); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Call2dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||
{
|
||||
Gpu.Engine2d.CallMethod(Vmm, PBEntry);
|
||||
}
|
||||
|
||||
private void Call3dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||
{
|
||||
if (PBEntry.Method < 0xe00)
|
||||
else if (PBEntry.Method < 0xe00)
|
||||
{
|
||||
Gpu.Engine3d.CallMethod(Vmm, PBEntry);
|
||||
}
|
||||
|
@ -190,9 +190,14 @@ namespace Ryujinx.Graphics
|
|||
}
|
||||
}
|
||||
|
||||
private void CallDmaMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||
private void CallP2mfMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||
{
|
||||
Gpu.EngineDma.CallMethod(Vmm, PBEntry);
|
||||
Gpu.EngineP2mf.CallMethod(Vmm, PBEntry);
|
||||
}
|
||||
|
||||
private void CallM2mfMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||
{
|
||||
Gpu.EngineM2mf.CallMethod(Vmm, PBEntry);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,33 +1,37 @@
|
|||
using Ryujinx.Graphics.Gal;
|
||||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Graphics.Gal;
|
||||
using Ryujinx.Graphics.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
static class ImageUtils
|
||||
public static class ImageUtils
|
||||
{
|
||||
struct ImageDescriptor
|
||||
[Flags]
|
||||
private enum TargetBuffer
|
||||
{
|
||||
public TextureReaderDelegate Reader;
|
||||
Color = 1 << 0,
|
||||
Depth = 1 << 1,
|
||||
Stencil = 1 << 2,
|
||||
|
||||
public bool HasColor;
|
||||
public bool HasDepth;
|
||||
public bool HasStencil;
|
||||
DepthStencil = Depth | Stencil
|
||||
}
|
||||
|
||||
public bool Compressed;
|
||||
private struct ImageDescriptor
|
||||
{
|
||||
public int BytesPerPixel { get; private set; }
|
||||
public int BlockWidth { get; private set; }
|
||||
public int BlockHeight { get; private set; }
|
||||
|
||||
public ImageDescriptor(
|
||||
TextureReaderDelegate Reader,
|
||||
bool HasColor,
|
||||
bool HasDepth,
|
||||
bool HasStencil,
|
||||
bool Compressed)
|
||||
public TargetBuffer Target { get; private set; }
|
||||
|
||||
public ImageDescriptor(int BytesPerPixel, int BlockWidth, int BlockHeight, TargetBuffer Target)
|
||||
{
|
||||
this.Reader = Reader;
|
||||
this.HasColor = HasColor;
|
||||
this.HasDepth = HasDepth;
|
||||
this.HasStencil = HasStencil;
|
||||
this.Compressed = Compressed;
|
||||
this.BytesPerPixel = BytesPerPixel;
|
||||
this.BlockWidth = BlockWidth;
|
||||
this.BlockHeight = BlockHeight;
|
||||
this.Target = Target;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,6 +52,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
{ GalTextureFormat.G8R8, GalImageFormat.G8R8 | Snorm | Unorm | Sint | Uint },
|
||||
{ GalTextureFormat.R16, GalImageFormat.R16 | Snorm | Unorm | Sint | Uint | Sfloat },
|
||||
{ GalTextureFormat.R8, GalImageFormat.R8 | Snorm | Unorm | Sint | Uint },
|
||||
{ GalTextureFormat.R16G16, GalImageFormat.R16G16 | Snorm | Sfloat },
|
||||
{ GalTextureFormat.R32, GalImageFormat.R32 | Sint | Uint | Sfloat },
|
||||
{ GalTextureFormat.A4B4G4R4, GalImageFormat.A4B4G4R4 | Unorm },
|
||||
{ GalTextureFormat.A1B5G5R5, GalImageFormat.A1R5G5B5 | Unorm },
|
||||
|
@ -56,86 +61,87 @@ namespace Ryujinx.Graphics.Texture
|
|||
{ GalTextureFormat.Z24S8, GalImageFormat.D24_S8 | Unorm },
|
||||
{ GalTextureFormat.ZF32, GalImageFormat.D32 | Sfloat },
|
||||
{ GalTextureFormat.ZF32_X24S8, GalImageFormat.D32_S8 | Unorm },
|
||||
{ GalTextureFormat.Z16, GalImageFormat.D16 | Unorm },
|
||||
|
||||
//Compressed formats
|
||||
{ GalTextureFormat.BC6H_SF16, GalImageFormat.BC6H_SF16 | Unorm },
|
||||
{ GalTextureFormat.BC6H_UF16, GalImageFormat.BC6H_UF16 | Unorm },
|
||||
{ GalTextureFormat.BC7U, GalImageFormat.BC7 | Unorm },
|
||||
{ GalTextureFormat.BC1, GalImageFormat.BC1_RGBA | Unorm },
|
||||
{ GalTextureFormat.BC2, GalImageFormat.BC2 | Unorm },
|
||||
{ GalTextureFormat.BC3, GalImageFormat.BC3 | Unorm },
|
||||
{ GalTextureFormat.BC4, GalImageFormat.BC4 | Unorm | Snorm },
|
||||
{ GalTextureFormat.BC5, GalImageFormat.BC5 | Unorm | Snorm },
|
||||
{ GalTextureFormat.Astc2D4x4, GalImageFormat.ASTC_4x4 | Unorm },
|
||||
{ GalTextureFormat.Astc2D5x5, GalImageFormat.ASTC_5x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D6x6, GalImageFormat.ASTC_6x6 | Unorm },
|
||||
{ GalTextureFormat.Astc2D8x8, GalImageFormat.ASTC_8x8 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x10, GalImageFormat.ASTC_10x10 | Unorm },
|
||||
{ GalTextureFormat.Astc2D12x12, GalImageFormat.ASTC_12x12 | Unorm },
|
||||
{ GalTextureFormat.Astc2D5x4, GalImageFormat.ASTC_5x4 | Unorm },
|
||||
{ GalTextureFormat.Astc2D6x5, GalImageFormat.ASTC_6x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D8x6, GalImageFormat.ASTC_8x6 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x8, GalImageFormat.ASTC_10x8 | Unorm },
|
||||
{ GalTextureFormat.Astc2D12x10, GalImageFormat.ASTC_12x10 | Unorm },
|
||||
{ GalTextureFormat.Astc2D8x5, GalImageFormat.ASTC_8x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x5, GalImageFormat.ASTC_10x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x6, GalImageFormat.ASTC_10x6 | Unorm }
|
||||
{ GalTextureFormat.BC6H_SF16, GalImageFormat.BC6H_SF16 | Unorm },
|
||||
{ GalTextureFormat.BC6H_UF16, GalImageFormat.BC6H_UF16 | Sfloat },
|
||||
{ GalTextureFormat.BC7U, GalImageFormat.BC7 | Unorm },
|
||||
{ GalTextureFormat.BC1, GalImageFormat.BC1_RGBA | Unorm },
|
||||
{ GalTextureFormat.BC2, GalImageFormat.BC2 | Unorm },
|
||||
{ GalTextureFormat.BC3, GalImageFormat.BC3 | Unorm },
|
||||
{ GalTextureFormat.BC4, GalImageFormat.BC4 | Unorm | Snorm },
|
||||
{ GalTextureFormat.BC5, GalImageFormat.BC5 | Unorm | Snorm },
|
||||
{ GalTextureFormat.Astc2D4x4, GalImageFormat.ASTC_4x4 | Unorm },
|
||||
{ GalTextureFormat.Astc2D5x5, GalImageFormat.ASTC_5x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D6x6, GalImageFormat.ASTC_6x6 | Unorm },
|
||||
{ GalTextureFormat.Astc2D8x8, GalImageFormat.ASTC_8x8 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x10, GalImageFormat.ASTC_10x10 | Unorm },
|
||||
{ GalTextureFormat.Astc2D12x12, GalImageFormat.ASTC_12x12 | Unorm },
|
||||
{ GalTextureFormat.Astc2D5x4, GalImageFormat.ASTC_5x4 | Unorm },
|
||||
{ GalTextureFormat.Astc2D6x5, GalImageFormat.ASTC_6x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D8x6, GalImageFormat.ASTC_8x6 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x8, GalImageFormat.ASTC_10x8 | Unorm },
|
||||
{ GalTextureFormat.Astc2D12x10, GalImageFormat.ASTC_12x10 | Unorm },
|
||||
{ GalTextureFormat.Astc2D8x5, GalImageFormat.ASTC_8x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x5, GalImageFormat.ASTC_10x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x6, GalImageFormat.ASTC_10x6 | Unorm }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<GalImageFormat, ImageDescriptor> s_ImageTable =
|
||||
new Dictionary<GalImageFormat, ImageDescriptor>()
|
||||
{
|
||||
{ GalImageFormat.R32G32B32A32, new ImageDescriptor(TextureReader.Read16Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.R16G16B16A16, new ImageDescriptor(TextureReader.Read8Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.R32G32, new ImageDescriptor(TextureReader.Read8Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.A8B8G8R8, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.A2B10G10R10, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.R32, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.A4B4G4R4, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.BC6H_SF16, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
||||
{ GalImageFormat.BC6H_UF16, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
||||
{ GalImageFormat.A1R5G5B5, new ImageDescriptor(TextureReader.Read5551, true, false, false, false) },
|
||||
{ GalImageFormat.B5G6R5, new ImageDescriptor(TextureReader.Read565, true, false, false, false) },
|
||||
{ GalImageFormat.BC7, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
||||
{ GalImageFormat.R16G16, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.R8G8, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.G8R8, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.R16, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.R8, new ImageDescriptor(TextureReader.Read1Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.B10G11R11, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.A8B8G8R8_SRGB, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
||||
{ GalImageFormat.BC1_RGBA, new ImageDescriptor(TextureReader.Read8Bpt4x4, true, false, false, true) },
|
||||
{ GalImageFormat.BC2, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
||||
{ GalImageFormat.BC3, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
||||
{ GalImageFormat.BC4, new ImageDescriptor(TextureReader.Read8Bpt4x4, true, false, false, true) },
|
||||
{ GalImageFormat.BC5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_4x4, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_5x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture5x5, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_6x6, new ImageDescriptor(TextureReader.Read16BptCompressedTexture6x6, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_8x8, new ImageDescriptor(TextureReader.Read16BptCompressedTexture8x8, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_10x10, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x10, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_12x12, new ImageDescriptor(TextureReader.Read16BptCompressedTexture12x12, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_5x4, new ImageDescriptor(TextureReader.Read16BptCompressedTexture5x4, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_6x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture6x5, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_8x6, new ImageDescriptor(TextureReader.Read16BptCompressedTexture8x6, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_10x8, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x8, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_12x10, new ImageDescriptor(TextureReader.Read16BptCompressedTexture12x10, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_8x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture8x5, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_10x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x5, true, false, false, true) },
|
||||
{ GalImageFormat.ASTC_10x6, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x6, true, false, false, true) },
|
||||
{
|
||||
{ GalImageFormat.R32G32B32A32, new ImageDescriptor(16, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R16G16B16A16, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R32G32, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.A8B8G8R8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.A2B10G10R10, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R32, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.A4B4G4R4, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC6H_SF16, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC6H_UF16, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.A1R5G5B5, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.B5G6R5, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC7, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R16G16, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R8G8, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.G8R8, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R16, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R8, new ImageDescriptor(1, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.B10G11R11, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.A8B8G8R8_SRGB, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC1_RGBA, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC2, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC3, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC4, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC5, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_4x4, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_5x5, new ImageDescriptor(16, 5, 5, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_6x6, new ImageDescriptor(16, 6, 6, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_8x8, new ImageDescriptor(16, 8, 8, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_10x10, new ImageDescriptor(16, 10, 10, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_12x12, new ImageDescriptor(16, 12, 12, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_5x4, new ImageDescriptor(16, 5, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_6x5, new ImageDescriptor(16, 6, 5, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_8x6, new ImageDescriptor(16, 8, 6, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_10x8, new ImageDescriptor(16, 10, 8, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_12x10, new ImageDescriptor(16, 12, 10, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_8x5, new ImageDescriptor(16, 8, 5, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_10x5, new ImageDescriptor(16, 10, 5, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_10x6, new ImageDescriptor(16, 10, 6, TargetBuffer.Color) },
|
||||
|
||||
{ GalImageFormat.D24_S8, new ImageDescriptor(TextureReader.Read4Bpp, false, true, true, false) },
|
||||
{ GalImageFormat.D32, new ImageDescriptor(TextureReader.Read4Bpp, false, true, false, false) },
|
||||
{ GalImageFormat.D16, new ImageDescriptor(TextureReader.Read2Bpp, false, true, false, false) },
|
||||
{ GalImageFormat.D32_S8, new ImageDescriptor(TextureReader.Read8Bpp, false, true, true, false) },
|
||||
};
|
||||
{ GalImageFormat.D24_S8, new ImageDescriptor(4, 1, 1, TargetBuffer.DepthStencil) },
|
||||
{ GalImageFormat.D32, new ImageDescriptor(4, 1, 1, TargetBuffer.Depth) },
|
||||
{ GalImageFormat.D16, new ImageDescriptor(2, 1, 1, TargetBuffer.Depth) },
|
||||
{ GalImageFormat.D32_S8, new ImageDescriptor(8, 1, 1, TargetBuffer.DepthStencil) },
|
||||
};
|
||||
|
||||
public static GalImageFormat ConvertTexture(
|
||||
GalTextureFormat Format,
|
||||
GalTextureType RType,
|
||||
GalTextureType GType,
|
||||
GalTextureType BType,
|
||||
GalTextureType AType)
|
||||
GalTextureType RType,
|
||||
GalTextureType GType,
|
||||
GalTextureType BType,
|
||||
GalTextureType AType)
|
||||
{
|
||||
if (RType != GType || RType != BType || RType != AType)
|
||||
{
|
||||
|
@ -167,6 +173,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
switch (Format)
|
||||
{
|
||||
case GalSurfaceFormat.RGBA32Float: return GalImageFormat.R32G32B32A32 | Sfloat;
|
||||
case GalSurfaceFormat.RGBA32Uint: return GalImageFormat.R32G32B32A32 | Uint;
|
||||
case GalSurfaceFormat.RGBA16Float: return GalImageFormat.R16G16B16A16 | Sfloat;
|
||||
case GalSurfaceFormat.RG32Float: return GalImageFormat.R32G32 | Sfloat;
|
||||
case GalSurfaceFormat.RG32Sint: return GalImageFormat.R32G32 | Sint;
|
||||
|
@ -184,6 +191,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
case GalSurfaceFormat.RG8Unorm: return GalImageFormat.R8G8 | Unorm;
|
||||
case GalSurfaceFormat.RG8Snorm: return GalImageFormat.R8 | Snorm;
|
||||
case GalSurfaceFormat.R16Float: return GalImageFormat.R16 | Sfloat;
|
||||
case GalSurfaceFormat.R16Unorm: return GalImageFormat.R16 | Unorm;
|
||||
case GalSurfaceFormat.R8Unorm: return GalImageFormat.R8 | Unorm;
|
||||
case GalSurfaceFormat.B5G6R5Unorm: return GalImageFormat.B5G6R5 | Unorm;
|
||||
case GalSurfaceFormat.BGR5A1Unorm: return GalImageFormat.A1R5G5B5 | Unorm;
|
||||
|
@ -199,128 +207,157 @@ namespace Ryujinx.Graphics.Texture
|
|||
case GalZetaFormat.Z32Float: return GalImageFormat.D32 | Sfloat;
|
||||
case GalZetaFormat.S8Z24Unorm: return GalImageFormat.D24_S8 | Unorm;
|
||||
case GalZetaFormat.Z16Unorm: return GalImageFormat.D16 | Unorm;
|
||||
//This one might not be Uint, change when a texture uses this format
|
||||
case GalZetaFormat.Z32S8X24Float: return GalImageFormat.D32_S8 | Uint;
|
||||
case GalZetaFormat.Z24S8Unorm: return GalImageFormat.D24_S8 | Unorm;
|
||||
case GalZetaFormat.Z32S8X24Float: return GalImageFormat.D32_S8 | Sfloat;
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Format.ToString());
|
||||
}
|
||||
|
||||
public static TextureReaderDelegate GetReader(GalImageFormat Format)
|
||||
public static byte[] ReadTexture(IAMemory Memory, GalImage Image, long Position)
|
||||
{
|
||||
return GetImageDescriptor(Format).Reader;
|
||||
AMemory CpuMemory;
|
||||
|
||||
if (Memory is NvGpuVmm Vmm)
|
||||
{
|
||||
CpuMemory = Vmm.Memory;
|
||||
}
|
||||
else
|
||||
{
|
||||
CpuMemory = (AMemory)Memory;
|
||||
}
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Image);
|
||||
|
||||
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
||||
|
||||
(int Width, int Height) = GetImageSizeInBlocks(Image);
|
||||
|
||||
int BytesPerPixel = Desc.BytesPerPixel;
|
||||
|
||||
int OutOffs = 0;
|
||||
|
||||
byte[] Data = new byte[Width * Height * BytesPerPixel];
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
CpuMemory.ReadBytes(Position + Offset, Data, OutOffs, BytesPerPixel);
|
||||
|
||||
OutOffs += BytesPerPixel;
|
||||
}
|
||||
|
||||
return Data;
|
||||
}
|
||||
|
||||
public static void WriteTexture(NvGpuVmm Vmm, GalImage Image, long Position, byte[] Data)
|
||||
{
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Image);
|
||||
|
||||
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
||||
|
||||
(int Width, int Height) = ImageUtils.GetImageSizeInBlocks(Image);
|
||||
|
||||
int BytesPerPixel = Desc.BytesPerPixel;
|
||||
|
||||
int InOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
Vmm.Memory.WriteBytes(Position + Offset, Data, InOffs, BytesPerPixel);
|
||||
|
||||
InOffs += BytesPerPixel;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetSize(GalImage Image)
|
||||
{
|
||||
switch (Image.Format & GalImageFormat.FormatMask)
|
||||
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
||||
|
||||
int Width = DivRoundUp(Image.Width, Desc.BlockWidth);
|
||||
int Height = DivRoundUp(Image.Height, Desc.BlockHeight);
|
||||
|
||||
return Desc.BytesPerPixel * Width * Height;
|
||||
}
|
||||
|
||||
public static int GetPitch(GalImageFormat Format, int Width)
|
||||
{
|
||||
ImageDescriptor Desc = GetImageDescriptor(Format);
|
||||
|
||||
return Desc.BytesPerPixel * DivRoundUp(Width, Desc.BlockWidth);
|
||||
}
|
||||
|
||||
public static int GetBlockWidth(GalImageFormat Format)
|
||||
{
|
||||
return GetImageDescriptor(Format).BlockWidth;
|
||||
}
|
||||
|
||||
public static int GetBlockHeight(GalImageFormat Format)
|
||||
{
|
||||
return GetImageDescriptor(Format).BlockHeight;
|
||||
}
|
||||
|
||||
public static int GetAlignedWidth(GalImage Image)
|
||||
{
|
||||
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
||||
|
||||
int AlignMask;
|
||||
|
||||
if (Image.Layout == GalMemoryLayout.BlockLinear)
|
||||
{
|
||||
case GalImageFormat.R32G32B32A32:
|
||||
return Image.Width * Image.Height * 16;
|
||||
|
||||
case GalImageFormat.R16G16B16A16:
|
||||
case GalImageFormat.D32_S8:
|
||||
case GalImageFormat.R32G32:
|
||||
return Image.Width * Image.Height * 8;
|
||||
|
||||
case GalImageFormat.A8B8G8R8:
|
||||
case GalImageFormat.A8B8G8R8_SRGB:
|
||||
case GalImageFormat.A2B10G10R10:
|
||||
case GalImageFormat.R16G16:
|
||||
case GalImageFormat.R32:
|
||||
case GalImageFormat.D32:
|
||||
case GalImageFormat.B10G11R11:
|
||||
case GalImageFormat.D24_S8:
|
||||
return Image.Width * Image.Height * 4;
|
||||
|
||||
case GalImageFormat.B4G4R4A4:
|
||||
case GalImageFormat.A1R5G5B5:
|
||||
case GalImageFormat.B5G6R5:
|
||||
case GalImageFormat.R8G8:
|
||||
case GalImageFormat.G8R8:
|
||||
case GalImageFormat.R16:
|
||||
case GalImageFormat.D16:
|
||||
return Image.Width * Image.Height * 2;
|
||||
|
||||
case GalImageFormat.R8:
|
||||
return Image.Width * Image.Height;
|
||||
|
||||
case GalImageFormat.BC1_RGBA:
|
||||
case GalImageFormat.BC4:
|
||||
{
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 4, 4, 8);
|
||||
}
|
||||
|
||||
case GalImageFormat.BC6H_SF16:
|
||||
case GalImageFormat.BC6H_UF16:
|
||||
case GalImageFormat.BC7:
|
||||
case GalImageFormat.BC2:
|
||||
case GalImageFormat.BC3:
|
||||
case GalImageFormat.BC5:
|
||||
case GalImageFormat.ASTC_4x4:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 4, 4, 16);
|
||||
|
||||
case GalImageFormat.ASTC_5x5:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 5, 5, 16);
|
||||
|
||||
case GalImageFormat.ASTC_6x6:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 6, 6, 16);
|
||||
|
||||
case GalImageFormat.ASTC_8x8:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 8, 8, 16);
|
||||
|
||||
case GalImageFormat.ASTC_10x10:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 10, 10, 16);
|
||||
|
||||
case GalImageFormat.ASTC_12x12:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 12, 12, 16);
|
||||
|
||||
case GalImageFormat.ASTC_5x4:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 5, 4, 16);
|
||||
|
||||
case GalImageFormat.ASTC_6x5:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 6, 5, 16);
|
||||
|
||||
case GalImageFormat.ASTC_8x6:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 8, 6, 16);
|
||||
|
||||
case GalImageFormat.ASTC_10x8:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 10, 8, 16);
|
||||
|
||||
case GalImageFormat.ASTC_12x10:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 12, 10, 16);
|
||||
|
||||
case GalImageFormat.ASTC_8x5:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 8, 5, 16);
|
||||
|
||||
case GalImageFormat.ASTC_10x5:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 10, 5, 16);
|
||||
|
||||
case GalImageFormat.ASTC_10x6:
|
||||
return CompressedTextureSize(Image.Width, Image.Height, 10, 6, 16);
|
||||
AlignMask = Image.TileWidth * (64 / Desc.BytesPerPixel) - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
AlignMask = (32 / Desc.BytesPerPixel) - 1;
|
||||
}
|
||||
|
||||
throw new NotImplementedException((Image.Format & GalImageFormat.FormatMask).ToString());
|
||||
return (Image.Width + AlignMask) & ~AlignMask;
|
||||
}
|
||||
|
||||
public static (int Width, int Height) GetImageSizeInBlocks(GalImage Image)
|
||||
{
|
||||
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
||||
|
||||
return (DivRoundUp(Image.Width, Desc.BlockWidth),
|
||||
DivRoundUp(Image.Height, Desc.BlockHeight));
|
||||
}
|
||||
|
||||
public static int GetBytesPerPixel(GalImageFormat Format)
|
||||
{
|
||||
return GetImageDescriptor(Format).BytesPerPixel;
|
||||
}
|
||||
|
||||
private static int DivRoundUp(int LHS, int RHS)
|
||||
{
|
||||
return (LHS + (RHS - 1)) / RHS;
|
||||
}
|
||||
|
||||
public static bool HasColor(GalImageFormat Format)
|
||||
{
|
||||
return GetImageDescriptor(Format).HasColor;
|
||||
return (GetImageDescriptor(Format).Target & TargetBuffer.Color) != 0;
|
||||
}
|
||||
|
||||
public static bool HasDepth(GalImageFormat Format)
|
||||
{
|
||||
return GetImageDescriptor(Format).HasDepth;
|
||||
return (GetImageDescriptor(Format).Target & TargetBuffer.Depth) != 0;
|
||||
}
|
||||
|
||||
public static bool HasStencil(GalImageFormat Format)
|
||||
{
|
||||
return GetImageDescriptor(Format).HasStencil;
|
||||
return (GetImageDescriptor(Format).Target & TargetBuffer.Stencil) != 0;
|
||||
}
|
||||
|
||||
public static bool IsCompressed(GalImageFormat Format)
|
||||
{
|
||||
return GetImageDescriptor(Format).Compressed;
|
||||
ImageDescriptor Desc = GetImageDescriptor(Format);
|
||||
|
||||
return (Desc.BlockWidth | Desc.BlockHeight) != 1;
|
||||
}
|
||||
|
||||
private static ImageDescriptor GetImageDescriptor(GalImageFormat Format)
|
||||
|
@ -348,13 +385,5 @@ namespace Ryujinx.Graphics.Texture
|
|||
default: throw new NotImplementedException(((int)Type).ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static int CompressedTextureSize(int TextureWidth, int TextureHeight, int BlockWidth, int BlockHeight, int Bpb)
|
||||
{
|
||||
int W = (TextureWidth + (BlockWidth - 1)) / BlockWidth;
|
||||
int H = (TextureHeight + (BlockHeight - 1)) / BlockHeight;
|
||||
|
||||
return W * H * Bpb;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,44 +17,20 @@ namespace Ryujinx.Graphics.Texture
|
|||
GalTextureSource ZSource = (GalTextureSource)((Tic[0] >> 25) & 7);
|
||||
GalTextureSource WSource = (GalTextureSource)((Tic[0] >> 28) & 7);
|
||||
|
||||
int Width = (Tic[4] & 0xffff) + 1;
|
||||
int Height = (Tic[5] & 0xffff) + 1;
|
||||
|
||||
return new GalImage(
|
||||
Width,
|
||||
Height,
|
||||
Format,
|
||||
XSource,
|
||||
YSource,
|
||||
ZSource,
|
||||
WSource);
|
||||
}
|
||||
|
||||
public static byte[] GetTextureData(NvGpuVmm Vmm, long TicPosition)
|
||||
{
|
||||
int[] Tic = ReadWords(Vmm, TicPosition, 8);
|
||||
|
||||
GalImageFormat Format = GetImageFormat(Tic);
|
||||
|
||||
long TextureAddress = (uint)Tic[1];
|
||||
|
||||
TextureAddress |= (long)((ushort)Tic[2]) << 32;
|
||||
|
||||
TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7);
|
||||
|
||||
GalMemoryLayout Layout;
|
||||
|
||||
if (Swizzle == TextureSwizzle.BlockLinear ||
|
||||
Swizzle == TextureSwizzle.BlockLinearColorKey)
|
||||
{
|
||||
TextureAddress &= ~0x1ffL;
|
||||
Layout = GalMemoryLayout.BlockLinear;
|
||||
}
|
||||
else if (Swizzle == TextureSwizzle.Pitch ||
|
||||
Swizzle == TextureSwizzle.PitchColorKey)
|
||||
else
|
||||
{
|
||||
TextureAddress &= ~0x1fL;
|
||||
Layout = GalMemoryLayout.Pitch;
|
||||
}
|
||||
|
||||
int Pitch = (Tic[3] & 0xffff) << 5;
|
||||
|
||||
int BlockHeightLog2 = (Tic[3] >> 3) & 7;
|
||||
int TileWidthLog2 = (Tic[3] >> 10) & 7;
|
||||
|
||||
|
@ -64,17 +40,17 @@ namespace Ryujinx.Graphics.Texture
|
|||
int Width = (Tic[4] & 0xffff) + 1;
|
||||
int Height = (Tic[5] & 0xffff) + 1;
|
||||
|
||||
TextureInfo Texture = new TextureInfo(
|
||||
TextureAddress,
|
||||
return new GalImage(
|
||||
Width,
|
||||
Height,
|
||||
Pitch,
|
||||
BlockHeight,
|
||||
TileWidth,
|
||||
Swizzle,
|
||||
Format);
|
||||
|
||||
return TextureReader.Read(Vmm, Texture);
|
||||
BlockHeight,
|
||||
Layout,
|
||||
Format,
|
||||
XSource,
|
||||
YSource,
|
||||
ZSource,
|
||||
WSource);
|
||||
}
|
||||
|
||||
public static GalTextureSampler MakeSampler(NvGpu Gpu, NvGpuVmm Vmm, long TscPosition)
|
||||
|
@ -107,7 +83,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
|
||||
private static GalImageFormat GetImageFormat(int[] Tic)
|
||||
{
|
||||
GalTextureType RType = (GalTextureType)((Tic[0] >> 7) & 7);
|
||||
GalTextureType RType = (GalTextureType)((Tic[0] >> 7) & 7);
|
||||
GalTextureType GType = (GalTextureType)((Tic[0] >> 10) & 7);
|
||||
GalTextureType BType = (GalTextureType)((Tic[0] >> 13) & 7);
|
||||
GalTextureType AType = (GalTextureType)((Tic[0] >> 16) & 7);
|
||||
|
|
|
@ -1,33 +1,30 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Graphics.Gal;
|
||||
using Ryujinx.Graphics.Memory;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
static class TextureHelper
|
||||
{
|
||||
public static ISwizzle GetSwizzle(TextureInfo Texture, int BlockWidth, int Bpp)
|
||||
public static ISwizzle GetSwizzle(GalImage Image)
|
||||
{
|
||||
int Width = (Texture.Width + (BlockWidth - 1)) / BlockWidth;
|
||||
int BlockWidth = ImageUtils.GetBlockWidth (Image.Format);
|
||||
int BytesPerPixel = ImageUtils.GetBytesPerPixel(Image.Format);
|
||||
|
||||
int AlignMask = Texture.TileWidth * (64 / Bpp) - 1;
|
||||
int Width = (Image.Width + (BlockWidth - 1)) / BlockWidth;
|
||||
|
||||
Width = (Width + AlignMask) & ~AlignMask;
|
||||
|
||||
switch (Texture.Swizzle)
|
||||
if (Image.Layout == GalMemoryLayout.BlockLinear)
|
||||
{
|
||||
case TextureSwizzle._1dBuffer:
|
||||
case TextureSwizzle.Pitch:
|
||||
case TextureSwizzle.PitchColorKey:
|
||||
return new LinearSwizzle(Texture.Pitch, Bpp);
|
||||
int AlignMask = Image.TileWidth * (64 / BytesPerPixel) - 1;
|
||||
|
||||
case TextureSwizzle.BlockLinear:
|
||||
case TextureSwizzle.BlockLinearColorKey:
|
||||
return new BlockLinearSwizzle(Width, Bpp, Texture.BlockHeight);
|
||||
Width = (Width + AlignMask) & ~AlignMask;
|
||||
|
||||
return new BlockLinearSwizzle(Width, BytesPerPixel, Image.GobBlockHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new LinearSwizzle(Image.Pitch, BytesPerPixel);
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Texture.Swizzle.ToString());
|
||||
}
|
||||
|
||||
public static (AMemory Memory, long Position) GetMemoryAndPosition(
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
using Ryujinx.Graphics.Gal;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
public struct TextureInfo
|
||||
{
|
||||
public long Position { get; private set; }
|
||||
|
||||
public int Width { get; private set; }
|
||||
public int Height { get; private set; }
|
||||
public int Pitch { get; private set; }
|
||||
|
||||
public int BlockHeight { get; private set; }
|
||||
public int TileWidth { get; private set; }
|
||||
|
||||
public TextureSwizzle Swizzle { get; private set; }
|
||||
|
||||
public GalImageFormat Format { get; private set; }
|
||||
|
||||
public TextureInfo(
|
||||
long Position,
|
||||
int Width,
|
||||
int Height)
|
||||
{
|
||||
this.Position = Position;
|
||||
this.Width = Width;
|
||||
this.Height = Height;
|
||||
|
||||
Pitch = 0;
|
||||
|
||||
BlockHeight = 16;
|
||||
|
||||
TileWidth = 1;
|
||||
|
||||
Swizzle = TextureSwizzle.BlockLinear;
|
||||
|
||||
Format = GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm;
|
||||
}
|
||||
|
||||
public TextureInfo(
|
||||
long Position,
|
||||
int Width,
|
||||
int Height,
|
||||
int Pitch,
|
||||
int BlockHeight,
|
||||
int TileWidth,
|
||||
TextureSwizzle Swizzle,
|
||||
GalImageFormat Format)
|
||||
{
|
||||
this.Position = Position;
|
||||
this.Width = Width;
|
||||
this.Height = Height;
|
||||
this.Pitch = Pitch;
|
||||
this.BlockHeight = BlockHeight;
|
||||
this.TileWidth = TileWidth;
|
||||
this.Swizzle = Swizzle;
|
||||
this.Format = Format;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,398 +0,0 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Graphics.Gal;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
delegate byte[] TextureReaderDelegate(IAMemory Memory, TextureInfo Texture);
|
||||
|
||||
public static class TextureReader
|
||||
{
|
||||
public static byte[] Read(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
TextureReaderDelegate Reader = ImageUtils.GetReader(Texture.Format);
|
||||
|
||||
return Reader(Memory, Texture);
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read1Bpp(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = Texture.Width;
|
||||
int Height = Texture.Height;
|
||||
|
||||
byte[] Output = new byte[Width * Height];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 1);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
byte Pixel = CpuMem.ReadByte(Position + Offset);
|
||||
|
||||
*(BuffPtr + OutOffs) = Pixel;
|
||||
|
||||
OutOffs++;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read5551(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = Texture.Width;
|
||||
int Height = Texture.Height;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 2];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 2);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
uint Pixel = (uint)CpuMem.ReadInt16(Position + Offset);
|
||||
|
||||
Pixel = (Pixel & 0x001f) << 11 |
|
||||
(Pixel & 0x03e0) << 1 |
|
||||
(Pixel & 0x7c00) >> 9 |
|
||||
(Pixel & 0x8000) >> 15;
|
||||
|
||||
*(short*)(BuffPtr + OutOffs) = (short)Pixel;
|
||||
|
||||
OutOffs += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read565(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = Texture.Width;
|
||||
int Height = Texture.Height;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 2];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 2);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
uint Pixel = (uint)CpuMem.ReadInt16(Position + Offset);
|
||||
|
||||
Pixel = (Pixel & 0x001f) << 11 |
|
||||
(Pixel & 0x07e0) |
|
||||
(Pixel & 0xf800) >> 11;
|
||||
|
||||
*(short*)(BuffPtr + OutOffs) = (short)Pixel;
|
||||
|
||||
OutOffs += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read2Bpp(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = Texture.Width;
|
||||
int Height = Texture.Height;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 2];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 2);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
short Pixel = CpuMem.ReadInt16(Position + Offset);
|
||||
|
||||
*(short*)(BuffPtr + OutOffs) = Pixel;
|
||||
|
||||
OutOffs += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read4Bpp(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = Texture.Width;
|
||||
int Height = Texture.Height;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 4];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 4);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
int Pixel = CpuMem.ReadInt32(Position + Offset);
|
||||
|
||||
*(int*)(BuffPtr + OutOffs) = Pixel;
|
||||
|
||||
OutOffs += 4;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read8Bpp(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = Texture.Width;
|
||||
int Height = Texture.Height;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 8];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 8);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
long Pixel = CpuMem.ReadInt64(Position + Offset);
|
||||
|
||||
*(long*)(BuffPtr + OutOffs) = Pixel;
|
||||
|
||||
OutOffs += 8;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read16Bpp(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = Texture.Width;
|
||||
int Height = Texture.Height;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 16];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 16);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
long PxLow = CpuMem.ReadInt64(Position + Offset + 0);
|
||||
long PxHigh = CpuMem.ReadInt64(Position + Offset + 8);
|
||||
|
||||
*(long*)(BuffPtr + OutOffs + 0) = PxLow;
|
||||
*(long*)(BuffPtr + OutOffs + 8) = PxHigh;
|
||||
|
||||
OutOffs += 16;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read8Bpt4x4(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
int Width = (Texture.Width + 3) / 4;
|
||||
int Height = (Texture.Height + 3) / 4;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 8];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 4, 8);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
long Tile = CpuMem.ReadInt64(Position + Offset);
|
||||
|
||||
*(long*)(BuffPtr + OutOffs) = Tile;
|
||||
|
||||
OutOffs += 8;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal unsafe static byte[] Read16BptCompressedTexture(IAMemory Memory, TextureInfo Texture, int BlockWidth, int BlockHeight)
|
||||
{
|
||||
int Width = (Texture.Width + (BlockWidth - 1)) / BlockWidth;
|
||||
int Height = (Texture.Height + (BlockHeight - 1)) / BlockHeight;
|
||||
|
||||
byte[] Output = new byte[Width * Height * 16];
|
||||
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, BlockWidth, 16);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Output)
|
||||
{
|
||||
long OutOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
long Tile0 = CpuMem.ReadInt64(Position + Offset + 0);
|
||||
long Tile1 = CpuMem.ReadInt64(Position + Offset + 8);
|
||||
|
||||
*(long*)(BuffPtr + OutOffs + 0) = Tile0;
|
||||
*(long*)(BuffPtr + OutOffs + 8) = Tile1;
|
||||
|
||||
OutOffs += 16;
|
||||
}
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture4x4(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 4, 4);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture5x5(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 5, 5);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture6x6(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 6, 6);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture8x8(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 8, 8);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture10x10(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 10, 10);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture12x12(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 12, 12);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture5x4(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 5, 4);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture6x5(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 6, 5);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture8x6(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 8, 6);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture10x8(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 10, 8);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture12x10(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 12, 10);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture8x5(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 5, 5);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture10x5(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 10, 5);
|
||||
}
|
||||
|
||||
internal static byte[] Read16BptCompressedTexture10x6(IAMemory Memory, TextureInfo Texture)
|
||||
{
|
||||
return Read16BptCompressedTexture(Memory, Texture, 10, 6);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Graphics.Gal;
|
||||
using Ryujinx.Graphics.Memory;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
static class TextureWriter
|
||||
{
|
||||
public unsafe static void Write(IAMemory Memory, TextureInfo Texture, byte[] Data)
|
||||
{
|
||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 4);
|
||||
|
||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
||||
Memory,
|
||||
Texture.Position);
|
||||
|
||||
fixed (byte* BuffPtr = Data)
|
||||
{
|
||||
long InOffs = 0;
|
||||
|
||||
for (int Y = 0; Y < Texture.Height; Y++)
|
||||
for (int X = 0; X < Texture.Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
int Pixel = *(int*)(BuffPtr + InOffs);
|
||||
|
||||
CpuMem.WriteInt32(Position + Offset, Pixel);
|
||||
|
||||
InOffs += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
Ryujinx.Graphics/ValueRange.cs
Normal file
17
Ryujinx.Graphics/ValueRange.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
namespace Ryujinx.Graphics
|
||||
{
|
||||
struct ValueRange<T>
|
||||
{
|
||||
public long Start { get; private set; }
|
||||
public long End { get; private set; }
|
||||
|
||||
public T Value { get; set; }
|
||||
|
||||
public ValueRange(long Start, long End, T Value = default(T))
|
||||
{
|
||||
this.Start = Start;
|
||||
this.End = End;
|
||||
this.Value = Value;
|
||||
}
|
||||
}
|
||||
}
|
234
Ryujinx.Graphics/ValueRangeSet.cs
Normal file
234
Ryujinx.Graphics/ValueRangeSet.cs
Normal file
|
@ -0,0 +1,234 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics
|
||||
{
|
||||
class ValueRangeSet<T>
|
||||
{
|
||||
private List<ValueRange<T>> Ranges;
|
||||
|
||||
public ValueRangeSet()
|
||||
{
|
||||
Ranges = new List<ValueRange<T>>();
|
||||
}
|
||||
|
||||
public void Add(ValueRange<T> Range)
|
||||
{
|
||||
if (Range.End <= Range.Start)
|
||||
{
|
||||
//Empty or invalid range, do nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
int First = BinarySearchFirstIntersection(Range);
|
||||
|
||||
if (First == -1)
|
||||
{
|
||||
//No intersections case.
|
||||
//Find first greater than range (after the current one).
|
||||
//If found, add before, otherwise add to the end of the list.
|
||||
int GtIndex = BinarySearchGt(Range);
|
||||
|
||||
if (GtIndex != -1)
|
||||
{
|
||||
Ranges.Insert(GtIndex, Range);
|
||||
}
|
||||
else
|
||||
{
|
||||
Ranges.Add(Range);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
(int Start, int End) = GetAllIntersectionRanges(Range, First);
|
||||
|
||||
ValueRange<T> Prev = Ranges[Start];
|
||||
ValueRange<T> Next = Ranges[End];
|
||||
|
||||
Ranges.RemoveRange(Start, (End - Start) + 1);
|
||||
|
||||
InsertNextNeighbour(Start, Range, Next);
|
||||
|
||||
int NewIndex = Start;
|
||||
|
||||
Ranges.Insert(Start, Range);
|
||||
|
||||
InsertPrevNeighbour(Start, Range, Prev);
|
||||
|
||||
//Try merging neighbours if the value is equal.
|
||||
if (NewIndex > 0)
|
||||
{
|
||||
Prev = Ranges[NewIndex - 1];
|
||||
|
||||
if (Prev.End == Range.Start && CompareValues(Prev, Range))
|
||||
{
|
||||
Ranges.RemoveAt(--NewIndex);
|
||||
|
||||
Ranges[NewIndex] = new ValueRange<T>(Prev.Start, Range.End, Range.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (NewIndex < Ranges.Count - 1)
|
||||
{
|
||||
Next = Ranges[NewIndex + 1];
|
||||
|
||||
if (Next.Start == Range.End && CompareValues(Next, Range))
|
||||
{
|
||||
Ranges.RemoveAt(NewIndex + 1);
|
||||
|
||||
Ranges[NewIndex] = new ValueRange<T>(Range.Start, Next.End, Range.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool CompareValues(ValueRange<T> LHS, ValueRange<T> RHS)
|
||||
{
|
||||
return LHS.Value?.Equals(RHS.Value) ?? RHS.Value == null;
|
||||
}
|
||||
|
||||
public void Remove(ValueRange<T> Range)
|
||||
{
|
||||
int First = BinarySearchFirstIntersection(Range);
|
||||
|
||||
if (First == -1)
|
||||
{
|
||||
//Nothing to remove.
|
||||
return;
|
||||
}
|
||||
|
||||
(int Start, int End) = GetAllIntersectionRanges(Range, First);
|
||||
|
||||
ValueRange<T> Prev = Ranges[Start];
|
||||
ValueRange<T> Next = Ranges[End];
|
||||
|
||||
Ranges.RemoveRange(Start, (End - Start) + 1);
|
||||
|
||||
InsertNextNeighbour(Start, Range, Next);
|
||||
InsertPrevNeighbour(Start, Range, Prev);
|
||||
}
|
||||
|
||||
private void InsertNextNeighbour(int Index, ValueRange<T> Range, ValueRange<T> Next)
|
||||
{
|
||||
//Split last intersection (ordered by Start) if necessary.
|
||||
if (Range.End < Next.End)
|
||||
{
|
||||
InsertNewRange(Index, Range.End, Next.End, Next.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void InsertPrevNeighbour(int Index, ValueRange<T> Range, ValueRange<T> Prev)
|
||||
{
|
||||
//Split first intersection (ordered by Start) if necessary.
|
||||
if (Range.Start > Prev.Start)
|
||||
{
|
||||
InsertNewRange(Index, Prev.Start, Range.Start, Prev.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void InsertNewRange(int Index, long Start, long End, T Value)
|
||||
{
|
||||
Ranges.Insert(Index, new ValueRange<T>(Start, End, Value));
|
||||
}
|
||||
|
||||
public ValueRange<T>[] GetAllIntersections(ValueRange<T> Range)
|
||||
{
|
||||
int First = BinarySearchFirstIntersection(Range);
|
||||
|
||||
if (First == -1)
|
||||
{
|
||||
return new ValueRange<T>[0];
|
||||
}
|
||||
|
||||
(int Start, int End) = GetAllIntersectionRanges(Range, First);
|
||||
|
||||
return Ranges.GetRange(Start, (End - Start) + 1).ToArray();
|
||||
}
|
||||
|
||||
private (int Start, int End) GetAllIntersectionRanges(ValueRange<T> Range, int BaseIndex)
|
||||
{
|
||||
int Start = BaseIndex;
|
||||
int End = BaseIndex;
|
||||
|
||||
while (Start > 0 && Intersects(Range, Ranges[Start - 1]))
|
||||
{
|
||||
Start--;
|
||||
}
|
||||
|
||||
while (End < Ranges.Count - 1 && Intersects(Range, Ranges[End + 1]))
|
||||
{
|
||||
End++;
|
||||
}
|
||||
|
||||
return (Start, End);
|
||||
}
|
||||
|
||||
private int BinarySearchFirstIntersection(ValueRange<T> Range)
|
||||
{
|
||||
int Left = 0;
|
||||
int Right = Ranges.Count - 1;
|
||||
|
||||
while (Left <= Right)
|
||||
{
|
||||
int Size = Right - Left;
|
||||
|
||||
int Middle = Left + (Size >> 1);
|
||||
|
||||
ValueRange<T> Current = Ranges[Middle];
|
||||
|
||||
if (Intersects(Range, Current))
|
||||
{
|
||||
return Middle;
|
||||
}
|
||||
|
||||
if (Range.Start < Current.Start)
|
||||
{
|
||||
Right = Middle - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Left = Middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int BinarySearchGt(ValueRange<T> Range)
|
||||
{
|
||||
int GtIndex = -1;
|
||||
|
||||
int Left = 0;
|
||||
int Right = Ranges.Count - 1;
|
||||
|
||||
while (Left <= Right)
|
||||
{
|
||||
int Size = Right - Left;
|
||||
|
||||
int Middle = Left + (Size >> 1);
|
||||
|
||||
ValueRange<T> Current = Ranges[Middle];
|
||||
|
||||
if (Range.Start < Current.Start)
|
||||
{
|
||||
Right = Middle - 1;
|
||||
|
||||
if (GtIndex == -1 || Current.Start < Ranges[GtIndex].Start)
|
||||
{
|
||||
GtIndex = Middle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Left = Middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return GtIndex;
|
||||
}
|
||||
|
||||
private bool Intersects(ValueRange<T> LHS, ValueRange<T> RHS)
|
||||
{
|
||||
return LHS.Start < RHS.End && RHS.Start < LHS.End;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,416 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics
|
||||
{
|
||||
static class Demangler
|
||||
{
|
||||
private static readonly Dictionary<string, string> BuiltinTypes = new Dictionary<string, string>
|
||||
{
|
||||
{ "v", "void" },
|
||||
{ "w", "wchar_t" },
|
||||
{ "b", "bool" },
|
||||
{ "c", "char" },
|
||||
{ "a", "signed char" },
|
||||
{ "h", "unsigned char" },
|
||||
{ "s", "short" },
|
||||
{ "t", "unsigned short" },
|
||||
{ "i", "int" },
|
||||
{ "j", "unsigned int" },
|
||||
{ "l", "long" },
|
||||
{ "m", "unsigned long" },
|
||||
{ "x", "long long" },
|
||||
{ "y", "unsigned long long" },
|
||||
{ "n", "__int128" },
|
||||
{ "o", "unsigned __int128" },
|
||||
{ "f", "float" },
|
||||
{ "d", "double" },
|
||||
{ "e", "long double" },
|
||||
{ "g", "__float128" },
|
||||
{ "z", "..." },
|
||||
{ "Dd", "__iec559_double" },
|
||||
{ "De", "__iec559_float128" },
|
||||
{ "Df", "__iec559_float" },
|
||||
{ "Dh", "__iec559_float16" },
|
||||
{ "Di", "char32_t" },
|
||||
{ "Ds", "char16_t" },
|
||||
{ "Da", "decltype(auto)" },
|
||||
{ "Dn", "std::nullptr_t" },
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, string> SubstitutionExtra = new Dictionary<string, string>
|
||||
{
|
||||
{"Sa", "std::allocator"},
|
||||
{"Sb", "std::basic_string"},
|
||||
{"Ss", "std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>>"},
|
||||
{"Si", "std::basic_istream<char, ::std::char_traits<char>>"},
|
||||
{"So", "std::basic_ostream<char, ::std::char_traits<char>>"},
|
||||
{"Sd", "std::basic_iostream<char, ::std::char_traits<char>>"}
|
||||
};
|
||||
|
||||
private static int FromBase36(string encoded)
|
||||
{
|
||||
string base36 = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
char[] reversedEncoded = encoded.ToLower().ToCharArray().Reverse().ToArray();
|
||||
int result = 0;
|
||||
for (int i = 0; i < reversedEncoded.Length; i++)
|
||||
{
|
||||
char c = reversedEncoded[i];
|
||||
int value = base36.IndexOf(c);
|
||||
if (value == -1)
|
||||
return -1;
|
||||
result += value * (int)Math.Pow(36, i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string GetCompressedValue(string compression, List<string> compressionData, out int pos)
|
||||
{
|
||||
string res = null;
|
||||
bool canHaveUnqualifiedName = false;
|
||||
pos = -1;
|
||||
if (compressionData.Count == 0 || !compression.StartsWith("S"))
|
||||
return null;
|
||||
|
||||
if (compression.Length >= 2 && SubstitutionExtra.TryGetValue(compression.Substring(0, 2), out string substitutionValue))
|
||||
{
|
||||
pos = 1;
|
||||
res = substitutionValue;
|
||||
compression = compression.Substring(2);
|
||||
}
|
||||
else if (compression.StartsWith("St"))
|
||||
{
|
||||
pos = 1;
|
||||
canHaveUnqualifiedName = true;
|
||||
res = "std";
|
||||
compression = compression.Substring(2);
|
||||
}
|
||||
else if (compression.StartsWith("S_"))
|
||||
{
|
||||
pos = 1;
|
||||
res = compressionData[0];
|
||||
canHaveUnqualifiedName = true;
|
||||
compression = compression.Substring(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
int id = -1;
|
||||
int underscorePos = compression.IndexOf('_');
|
||||
if (underscorePos == -1)
|
||||
return null;
|
||||
string partialId = compression.Substring(1, underscorePos - 1);
|
||||
|
||||
id = FromBase36(partialId);
|
||||
if (id == -1 || compressionData.Count <= (id + 1))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
res = compressionData[id + 1];
|
||||
pos = partialId.Length + 1;
|
||||
canHaveUnqualifiedName= true;
|
||||
compression = compression.Substring(pos);
|
||||
}
|
||||
if (res != null)
|
||||
{
|
||||
if (canHaveUnqualifiedName)
|
||||
{
|
||||
List<string> type = ReadName(compression, compressionData, out int endOfNameType);
|
||||
if (endOfNameType != -1 && type != null)
|
||||
{
|
||||
pos += endOfNameType;
|
||||
res = res + "::" + type[type.Count - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private static List<string> ReadName(string mangled, List<string> compressionData, out int pos, bool isNested = true)
|
||||
{
|
||||
List<string> res = new List<string>();
|
||||
string charCountString = null;
|
||||
int charCount = 0;
|
||||
int i;
|
||||
|
||||
pos = -1;
|
||||
for (i = 0; i < mangled.Length; i++)
|
||||
{
|
||||
char chr = mangled[i];
|
||||
if (charCountString == null)
|
||||
{
|
||||
if (ReadCVQualifiers(chr) != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (chr == 'S')
|
||||
{
|
||||
string data = GetCompressedValue(mangled.Substring(i), compressionData, out pos);
|
||||
if (pos == -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (res.Count == 0)
|
||||
res.Add(data);
|
||||
else
|
||||
res.Add(res[res.Count - 1] + "::" + data);
|
||||
i += pos;
|
||||
if (i < mangled.Length && mangled[i] == 'E')
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (chr == 'E')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Char.IsDigit(chr))
|
||||
{
|
||||
charCountString += chr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!int.TryParse(charCountString, out charCount))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
string demangledPart = mangled.Substring(i, charCount);
|
||||
if (res.Count == 0)
|
||||
res.Add(demangledPart);
|
||||
else
|
||||
res.Add(res[res.Count - 1] + "::" + demangledPart);
|
||||
i = i + charCount - 1;
|
||||
charCount = 0;
|
||||
charCountString = null;
|
||||
if (!isNested)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
pos = i;
|
||||
return res;
|
||||
}
|
||||
|
||||
private static string ReadBuiltinType(string mangledType, out int pos)
|
||||
{
|
||||
string res = null;
|
||||
string possibleBuiltinType;
|
||||
pos = -1;
|
||||
possibleBuiltinType = mangledType[0].ToString();
|
||||
if (!BuiltinTypes.TryGetValue(possibleBuiltinType, out res))
|
||||
{
|
||||
if (mangledType.Length >= 2)
|
||||
{
|
||||
// Try to match the first 2 chars if the first call failed
|
||||
possibleBuiltinType = mangledType.Substring(0, 2);
|
||||
BuiltinTypes.TryGetValue(possibleBuiltinType, out res);
|
||||
}
|
||||
}
|
||||
if (res != null)
|
||||
pos = possibleBuiltinType.Length;
|
||||
return res;
|
||||
}
|
||||
|
||||
private static string ReadCVQualifiers(char qualifier)
|
||||
{
|
||||
if (qualifier == 'r')
|
||||
return "restricted";
|
||||
else if (qualifier == 'V')
|
||||
return "volatile";
|
||||
else if (qualifier == 'K')
|
||||
return "const";
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string ReadRefQualifiers(char qualifier)
|
||||
{
|
||||
if (qualifier == 'R')
|
||||
return "&";
|
||||
else if (qualifier == 'O')
|
||||
return "&&";
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string ReadSpecialQualifiers(char qualifier)
|
||||
{
|
||||
if (qualifier == 'P')
|
||||
return "*";
|
||||
else if (qualifier == 'C')
|
||||
return "complex";
|
||||
else if (qualifier == 'G')
|
||||
return "imaginary";
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<string> ReadParameters(string mangledParams, List<string> compressionData, out int pos)
|
||||
{
|
||||
List<string> res = new List<string>();
|
||||
List<string> refQualifiers = new List<string>();
|
||||
string parsedTypePart = null;
|
||||
string currentRefQualifiers = null;
|
||||
string currentBuiltinType = null;
|
||||
string currentSpecialQualifiers = null;
|
||||
string currentCompressedValue = null;
|
||||
int i = 0;
|
||||
pos = -1;
|
||||
|
||||
for (i = 0; i < mangledParams.Length; i++)
|
||||
{
|
||||
if (currentBuiltinType != null)
|
||||
{
|
||||
string currentCVQualifier = String.Join(" ", refQualifiers);
|
||||
// Try to mimic the compression indexing
|
||||
if (currentRefQualifiers != null)
|
||||
{
|
||||
compressionData.Add(currentBuiltinType + currentRefQualifiers);
|
||||
}
|
||||
if (refQualifiers.Count != 0)
|
||||
{
|
||||
compressionData.Add(currentBuiltinType + " " + currentCVQualifier + currentRefQualifiers);
|
||||
}
|
||||
if (currentSpecialQualifiers != null)
|
||||
{
|
||||
compressionData.Add(currentBuiltinType + " " + currentCVQualifier + currentRefQualifiers + currentSpecialQualifiers);
|
||||
}
|
||||
if (currentRefQualifiers == null && currentCVQualifier == null && currentSpecialQualifiers == null)
|
||||
{
|
||||
compressionData.Add(currentBuiltinType);
|
||||
}
|
||||
currentBuiltinType = null;
|
||||
currentCompressedValue = null;
|
||||
currentCVQualifier = null;
|
||||
currentRefQualifiers = null;
|
||||
refQualifiers.Clear();
|
||||
currentSpecialQualifiers = null;
|
||||
}
|
||||
char chr = mangledParams[i];
|
||||
string part = mangledParams.Substring(i);
|
||||
|
||||
// Try to read qualifiers
|
||||
parsedTypePart = ReadCVQualifiers(chr);
|
||||
if (parsedTypePart != null)
|
||||
{
|
||||
refQualifiers.Add(parsedTypePart);
|
||||
|
||||
// need more data
|
||||
continue;
|
||||
}
|
||||
|
||||
parsedTypePart = ReadRefQualifiers(chr);
|
||||
if (parsedTypePart != null)
|
||||
{
|
||||
currentRefQualifiers = parsedTypePart;
|
||||
|
||||
// need more data
|
||||
continue;
|
||||
}
|
||||
|
||||
parsedTypePart = ReadSpecialQualifiers(chr);
|
||||
if (parsedTypePart != null)
|
||||
{
|
||||
currentSpecialQualifiers = parsedTypePart;
|
||||
|
||||
// need more data
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: extended-qualifier?
|
||||
|
||||
if (part.StartsWith("S"))
|
||||
{
|
||||
parsedTypePart = GetCompressedValue(part, compressionData, out pos);
|
||||
if (pos != -1 && parsedTypePart != null)
|
||||
{
|
||||
currentCompressedValue = parsedTypePart;
|
||||
i += pos;
|
||||
res.Add(currentCompressedValue + " " + String.Join(" ", refQualifiers) + currentRefQualifiers + currentSpecialQualifiers);
|
||||
currentBuiltinType = null;
|
||||
currentCompressedValue = null;
|
||||
currentRefQualifiers = null;
|
||||
refQualifiers.Clear();
|
||||
currentSpecialQualifiers = null;
|
||||
continue;
|
||||
}
|
||||
pos = -1;
|
||||
return null;
|
||||
}
|
||||
else if (part.StartsWith("N"))
|
||||
{
|
||||
part = part.Substring(1);
|
||||
List<string> name = ReadName(part, compressionData, out pos);
|
||||
if (pos != -1 && name != null)
|
||||
{
|
||||
i += pos + 1;
|
||||
res.Add(name[name.Count - 1] + " " + String.Join(" ", refQualifiers) + currentRefQualifiers + currentSpecialQualifiers);
|
||||
currentBuiltinType = null;
|
||||
currentCompressedValue = null;
|
||||
currentRefQualifiers = null;
|
||||
refQualifiers.Clear();
|
||||
currentSpecialQualifiers = null;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Try builting
|
||||
parsedTypePart = ReadBuiltinType(part, out pos);
|
||||
if (pos == -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
currentBuiltinType = parsedTypePart;
|
||||
res.Add(currentBuiltinType + " " + String.Join(" ", refQualifiers) + currentRefQualifiers + currentSpecialQualifiers);
|
||||
i = i + pos -1;
|
||||
}
|
||||
pos = i;
|
||||
return res;
|
||||
}
|
||||
|
||||
private static string ParseFunctionName(string mangled)
|
||||
{
|
||||
List<string> compressionData = new List<string>();
|
||||
int pos = 0;
|
||||
string res;
|
||||
bool isNested = mangled.StartsWith("N");
|
||||
|
||||
// If it's start with "N" it must be a nested function name
|
||||
if (isNested)
|
||||
mangled = mangled.Substring(1);
|
||||
compressionData = ReadName(mangled, compressionData, out pos, isNested);
|
||||
if (pos == -1)
|
||||
return null;
|
||||
res = compressionData[compressionData.Count - 1];
|
||||
compressionData.Remove(res);
|
||||
mangled = mangled.Substring(pos + 1);
|
||||
|
||||
// more data? maybe not a data name so...
|
||||
if (mangled != String.Empty)
|
||||
{
|
||||
List<string> parameters = ReadParameters(mangled, compressionData, out pos);
|
||||
// parameters parsing error, we return the original data to avoid information loss.
|
||||
if (pos == -1)
|
||||
return null;
|
||||
parameters = parameters.Select(outer => outer.Trim()).ToList();
|
||||
res += "(" + String.Join(", ", parameters) + ")";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static string Parse(string originalMangled)
|
||||
{
|
||||
if (originalMangled.StartsWith("_Z"))
|
||||
{
|
||||
// We assume that we have a name (TOOD: support special names)
|
||||
string res = ParseFunctionName(originalMangled.Substring(2));
|
||||
if (res == null)
|
||||
return originalMangled;
|
||||
return res;
|
||||
}
|
||||
return originalMangled;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class ArraySubscriptingExpression : BaseNode
|
||||
{
|
||||
private BaseNode LeftNode;
|
||||
private BaseNode Subscript;
|
||||
|
||||
public ArraySubscriptingExpression(BaseNode LeftNode, BaseNode Subscript) : base(NodeType.ArraySubscriptingExpression)
|
||||
{
|
||||
this.LeftNode = LeftNode;
|
||||
this.Subscript = Subscript;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write("(");
|
||||
LeftNode.Print(Writer);
|
||||
Writer.Write(")[");
|
||||
Subscript.Print(Writer);
|
||||
Writer.Write("]");
|
||||
}
|
||||
}
|
||||
}
|
59
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/ArrayType.cs
Normal file
59
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/ArrayType.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class ArrayType : BaseNode
|
||||
{
|
||||
private BaseNode Base;
|
||||
private BaseNode DimensionExpression;
|
||||
private string DimensionString;
|
||||
|
||||
public ArrayType(BaseNode Base, BaseNode DimensionExpression = null) : base(NodeType.ArrayType)
|
||||
{
|
||||
this.Base = Base;
|
||||
this.DimensionExpression = DimensionExpression;
|
||||
}
|
||||
|
||||
public ArrayType(BaseNode Base, string DimensionString) : base(NodeType.ArrayType)
|
||||
{
|
||||
this.Base = Base;
|
||||
this.DimensionString = DimensionString;
|
||||
}
|
||||
|
||||
public override bool HasRightPart()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool IsArray()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Base.PrintLeft(Writer);
|
||||
}
|
||||
|
||||
public override void PrintRight(TextWriter Writer)
|
||||
{
|
||||
// FIXME: detect if previous char was a ].
|
||||
Writer.Write(" ");
|
||||
|
||||
Writer.Write("[");
|
||||
|
||||
if (DimensionString != null)
|
||||
{
|
||||
Writer.Write(DimensionString);
|
||||
}
|
||||
else if (DimensionExpression != null)
|
||||
{
|
||||
DimensionExpression.Print(Writer);
|
||||
}
|
||||
|
||||
Writer.Write("]");
|
||||
|
||||
Base.PrintRight(Writer);
|
||||
}
|
||||
}
|
||||
}
|
113
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/BaseNode.cs
Normal file
113
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/BaseNode.cs
Normal file
|
@ -0,0 +1,113 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public enum NodeType
|
||||
{
|
||||
CVQualifierType,
|
||||
SimpleReferenceType,
|
||||
NameType,
|
||||
EncodedFunction,
|
||||
NestedName,
|
||||
SpecialName,
|
||||
LiteralOperator,
|
||||
NodeArray,
|
||||
ElaboratedType,
|
||||
PostfixQualifiedType,
|
||||
SpecialSubstitution,
|
||||
ExpandedSpecialSubstitution,
|
||||
CtorDtorNameType,
|
||||
EnclosedExpression,
|
||||
ForwardTemplateReference,
|
||||
NameTypeWithTemplateArguments,
|
||||
PackedTemplateArgument,
|
||||
TemplateArguments,
|
||||
BooleanExpression,
|
||||
CastExpression,
|
||||
CallExpression,
|
||||
IntegerCastExpression,
|
||||
PackedTemplateParameter,
|
||||
PackedTemplateParameterExpansion,
|
||||
IntegerLiteral,
|
||||
DeleteExpression,
|
||||
MemberExpression,
|
||||
ArraySubscriptingExpression,
|
||||
InitListExpression,
|
||||
PostfixExpression,
|
||||
ConditionalExpression,
|
||||
ThrowExpression,
|
||||
FunctionParameter,
|
||||
ConversionExpression,
|
||||
BinaryExpression,
|
||||
PrefixExpression,
|
||||
BracedExpression,
|
||||
BracedRangeExpression,
|
||||
NewExpression,
|
||||
QualifiedName,
|
||||
StdQualifiedName,
|
||||
DtOrName,
|
||||
GlobalQualifiedName,
|
||||
NoexceptSpec,
|
||||
DynamicExceptionSpec,
|
||||
FunctionType,
|
||||
PointerType,
|
||||
ReferenceType,
|
||||
ConversionOperatorType,
|
||||
LocalName,
|
||||
CtorVtableSpecialName,
|
||||
ArrayType
|
||||
}
|
||||
|
||||
public abstract class BaseNode
|
||||
{
|
||||
public NodeType Type { get; protected set; }
|
||||
|
||||
public BaseNode(NodeType Type)
|
||||
{
|
||||
this.Type = Type;
|
||||
}
|
||||
|
||||
public virtual void Print(TextWriter Writer)
|
||||
{
|
||||
PrintLeft(Writer);
|
||||
|
||||
if (HasRightPart())
|
||||
{
|
||||
PrintRight(Writer);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void PrintLeft(TextWriter Writer);
|
||||
|
||||
public virtual bool HasRightPart()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual bool IsArray()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual bool HasFunctions()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual string GetName()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual void PrintRight(TextWriter Writer) {}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringWriter Writer = new StringWriter();
|
||||
|
||||
Print(Writer);
|
||||
|
||||
return Writer.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class BinaryExpression : BaseNode
|
||||
{
|
||||
private BaseNode LeftPart;
|
||||
private string Name;
|
||||
private BaseNode RightPart;
|
||||
|
||||
public BinaryExpression(BaseNode LeftPart, string Name, BaseNode RightPart) : base(NodeType.BinaryExpression)
|
||||
{
|
||||
this.LeftPart = LeftPart;
|
||||
this.Name = Name;
|
||||
this.RightPart = RightPart;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (Name.Equals(">"))
|
||||
{
|
||||
Writer.Write("(");
|
||||
}
|
||||
|
||||
Writer.Write("(");
|
||||
LeftPart.Print(Writer);
|
||||
Writer.Write(") ");
|
||||
|
||||
Writer.Write(Name);
|
||||
|
||||
Writer.Write(" (");
|
||||
RightPart.Print(Writer);
|
||||
Writer.Write(")");
|
||||
|
||||
if (Name.Equals(">"))
|
||||
{
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class BracedExpression : BaseNode
|
||||
{
|
||||
private BaseNode Element;
|
||||
private BaseNode Expression;
|
||||
private bool IsArrayExpression;
|
||||
|
||||
public BracedExpression(BaseNode Element, BaseNode Expression, bool IsArrayExpression) : base(NodeType.BracedExpression)
|
||||
{
|
||||
this.Element = Element;
|
||||
this.Expression = Expression;
|
||||
this.IsArrayExpression = IsArrayExpression;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (IsArrayExpression)
|
||||
{
|
||||
Writer.Write("[");
|
||||
Element.Print(Writer);
|
||||
Writer.Write("]");
|
||||
}
|
||||
else
|
||||
{
|
||||
Writer.Write(".");
|
||||
Element.Print(Writer);
|
||||
}
|
||||
|
||||
if (!Expression.GetType().Equals(NodeType.BracedExpression) || !Expression.GetType().Equals(NodeType.BracedRangeExpression))
|
||||
{
|
||||
Writer.Write(" = ");
|
||||
}
|
||||
|
||||
Expression.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class BracedRangeExpression : BaseNode
|
||||
{
|
||||
private BaseNode FirstNode;
|
||||
private BaseNode LastNode;
|
||||
private BaseNode Expression;
|
||||
|
||||
public BracedRangeExpression(BaseNode FirstNode, BaseNode LastNode, BaseNode Expression) : base(NodeType.BracedRangeExpression)
|
||||
{
|
||||
this.FirstNode = FirstNode;
|
||||
this.LastNode = LastNode;
|
||||
this.Expression = Expression;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write("[");
|
||||
FirstNode.Print(Writer);
|
||||
Writer.Write(" ... ");
|
||||
LastNode.Print(Writer);
|
||||
Writer.Write("]");
|
||||
|
||||
if (!Expression.GetType().Equals(NodeType.BracedExpression) || !Expression.GetType().Equals(NodeType.BracedRangeExpression))
|
||||
{
|
||||
Writer.Write(" = ");
|
||||
}
|
||||
|
||||
Expression.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
25
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/CallExpression.cs
Normal file
25
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/CallExpression.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class CallExpression : NodeArray
|
||||
{
|
||||
private BaseNode Callee;
|
||||
|
||||
public CallExpression(BaseNode Callee, List<BaseNode> Nodes) : base(Nodes, NodeType.CallExpression)
|
||||
{
|
||||
this.Callee = Callee;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Callee.Print(Writer);
|
||||
|
||||
Writer.Write("(");
|
||||
Writer.Write(string.Join<BaseNode>(", ", Nodes.ToArray()));
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
30
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/CasExpression.cs
Normal file
30
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/CasExpression.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class CastExpression : BaseNode
|
||||
{
|
||||
private string Kind;
|
||||
private BaseNode To;
|
||||
private BaseNode From;
|
||||
|
||||
public CastExpression(string Kind, BaseNode To, BaseNode From) : base(NodeType.CastExpression)
|
||||
{
|
||||
this.Kind = Kind;
|
||||
this.To = To;
|
||||
this.From = From;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write(Kind);
|
||||
Writer.Write("<");
|
||||
To.PrintLeft(Writer);
|
||||
Writer.Write(">(");
|
||||
From.PrintLeft(Writer);
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class ConditionalExpression : BaseNode
|
||||
{
|
||||
private BaseNode ThenNode;
|
||||
private BaseNode ElseNode;
|
||||
private BaseNode ConditionNode;
|
||||
|
||||
public ConditionalExpression(BaseNode ConditionNode, BaseNode ThenNode, BaseNode ElseNode) : base(NodeType.ConditionalExpression)
|
||||
{
|
||||
this.ThenNode = ThenNode;
|
||||
this.ConditionNode = ConditionNode;
|
||||
this.ElseNode = ElseNode;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write("(");
|
||||
ConditionNode.Print(Writer);
|
||||
Writer.Write(") ? (");
|
||||
ThenNode.Print(Writer);
|
||||
Writer.Write(") : (");
|
||||
ElseNode.Print(Writer);
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class ConversionExpression : BaseNode
|
||||
{
|
||||
private BaseNode TypeNode;
|
||||
private BaseNode Expressions;
|
||||
|
||||
public ConversionExpression(BaseNode TypeNode, BaseNode Expressions) : base(NodeType.ConversionExpression)
|
||||
{
|
||||
this.TypeNode = TypeNode;
|
||||
this.Expressions = Expressions;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write("(");
|
||||
TypeNode.Print(Writer);
|
||||
Writer.Write(")(");
|
||||
Expressions.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class ConversionOperatorType : ParentNode
|
||||
{
|
||||
public ConversionOperatorType(BaseNode Child) : base(NodeType.ConversionOperatorType, Child) { }
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write("operator ");
|
||||
Child.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class CtorDtorNameType : ParentNode
|
||||
{
|
||||
private bool IsDestructor;
|
||||
|
||||
public CtorDtorNameType(BaseNode Name, bool IsDestructor) : base(NodeType.CtorDtorNameType, Name)
|
||||
{
|
||||
this.IsDestructor = IsDestructor;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (IsDestructor)
|
||||
{
|
||||
Writer.Write("~");
|
||||
}
|
||||
|
||||
Writer.Write(Child.GetName());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class CtorVtableSpecialName : BaseNode
|
||||
{
|
||||
private BaseNode FirstType;
|
||||
private BaseNode SecondType;
|
||||
|
||||
public CtorVtableSpecialName(BaseNode FirstType, BaseNode SecondType) : base(NodeType.CtorVtableSpecialName)
|
||||
{
|
||||
this.FirstType = FirstType;
|
||||
this.SecondType = SecondType;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write("construction vtable for ");
|
||||
FirstType.Print(Writer);
|
||||
Writer.Write("-in-");
|
||||
SecondType.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class DeleteExpression : ParentNode
|
||||
{
|
||||
private bool IsGlobal;
|
||||
private bool IsArrayExpression;
|
||||
|
||||
public DeleteExpression(BaseNode Child, bool IsGlobal, bool IsArrayExpression) : base(NodeType.DeleteExpression, Child)
|
||||
{
|
||||
this.IsGlobal = IsGlobal;
|
||||
this.IsArrayExpression = IsArrayExpression;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (IsGlobal)
|
||||
{
|
||||
Writer.Write("::");
|
||||
}
|
||||
|
||||
Writer.Write("delete");
|
||||
|
||||
if (IsArrayExpression)
|
||||
{
|
||||
Writer.Write("[] ");
|
||||
}
|
||||
|
||||
Child.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
15
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/DtorName.cs
Normal file
15
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/DtorName.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class DtorName : ParentNode
|
||||
{
|
||||
public DtorName(BaseNode Name) : base(NodeType.DtOrName, Name) { }
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write("~");
|
||||
Child.PrintLeft(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class DynamicExceptionSpec : ParentNode
|
||||
{
|
||||
public DynamicExceptionSpec(BaseNode Child) : base(NodeType.DynamicExceptionSpec, Child) { }
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write("throw(");
|
||||
Child.Print(Writer);
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
21
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/ElaboratedType.cs
Normal file
21
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/ElaboratedType.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class ElaboratedType : ParentNode
|
||||
{
|
||||
private string Elaborated;
|
||||
|
||||
public ElaboratedType(string Elaborated, BaseNode Type) : base(NodeType.ElaboratedType, Type)
|
||||
{
|
||||
this.Elaborated = Elaborated;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write(Elaborated);
|
||||
Writer.Write(" ");
|
||||
Child.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class EnclosedExpression : BaseNode
|
||||
{
|
||||
private string Prefix;
|
||||
private BaseNode Expression;
|
||||
private string Postfix;
|
||||
|
||||
public EnclosedExpression(string Prefix, BaseNode Expression, string Postfix) : base(NodeType.EnclosedExpression)
|
||||
{
|
||||
this.Prefix = Prefix;
|
||||
this.Expression = Expression;
|
||||
this.Postfix = Postfix;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write(Prefix);
|
||||
Expression.Print(Writer);
|
||||
Writer.Write(Postfix);
|
||||
}
|
||||
}
|
||||
}
|
77
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/EncodedFunction.cs
Normal file
77
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/EncodedFunction.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class EncodedFunction : BaseNode
|
||||
{
|
||||
private BaseNode Name;
|
||||
private BaseNode Params;
|
||||
private BaseNode CV;
|
||||
private BaseNode Ref;
|
||||
private BaseNode Attrs;
|
||||
private BaseNode Ret;
|
||||
|
||||
public EncodedFunction(BaseNode Name, BaseNode Params, BaseNode CV, BaseNode Ref, BaseNode Attrs, BaseNode Ret) : base(NodeType.NameType)
|
||||
{
|
||||
this.Name = Name;
|
||||
this.Params = Params;
|
||||
this.CV = CV;
|
||||
this.Ref = Ref;
|
||||
this.Attrs = Attrs;
|
||||
this.Ret = Ret;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (Ret != null)
|
||||
{
|
||||
Ret.PrintLeft(Writer);
|
||||
|
||||
if (!Ret.HasRightPart())
|
||||
{
|
||||
Writer.Write(" ");
|
||||
}
|
||||
}
|
||||
|
||||
Name.Print(Writer);
|
||||
|
||||
}
|
||||
|
||||
public override bool HasRightPart()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void PrintRight(TextWriter Writer)
|
||||
{
|
||||
Writer.Write("(");
|
||||
|
||||
if (Params != null)
|
||||
{
|
||||
Params.Print(Writer);
|
||||
}
|
||||
|
||||
Writer.Write(")");
|
||||
|
||||
if (Ret != null)
|
||||
{
|
||||
Ret.PrintRight(Writer);
|
||||
}
|
||||
|
||||
if (CV != null)
|
||||
{
|
||||
CV.Print(Writer);
|
||||
}
|
||||
|
||||
if (Ref != null)
|
||||
{
|
||||
Ref.Print(Writer);
|
||||
}
|
||||
|
||||
if (Attrs != null)
|
||||
{
|
||||
Attrs.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
48
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/FoldExpression.cs
Normal file
48
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/FoldExpression.cs
Normal file
|
@ -0,0 +1,48 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class FoldExpression : BaseNode
|
||||
{
|
||||
private bool IsLeftFold;
|
||||
private string OperatorName;
|
||||
private BaseNode Expression;
|
||||
private BaseNode Initializer;
|
||||
|
||||
public FoldExpression(bool IsLeftFold, string OperatorName, BaseNode Expression, BaseNode Initializer) : base(NodeType.FunctionParameter)
|
||||
{
|
||||
this.IsLeftFold = IsLeftFold;
|
||||
this.OperatorName = OperatorName;
|
||||
this.Expression = Expression;
|
||||
this.Initializer = Initializer;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write("(");
|
||||
|
||||
if (IsLeftFold && Initializer != null)
|
||||
{
|
||||
Initializer.Print(Writer);
|
||||
Writer.Write(" ");
|
||||
Writer.Write(OperatorName);
|
||||
Writer.Write(" ");
|
||||
}
|
||||
|
||||
Writer.Write(IsLeftFold ? "... " : " ");
|
||||
Writer.Write(OperatorName);
|
||||
Writer.Write(!IsLeftFold ? " ..." : " ");
|
||||
Expression.Print(Writer);
|
||||
|
||||
if (!IsLeftFold && Initializer != null)
|
||||
{
|
||||
Initializer.Print(Writer);
|
||||
Writer.Write(" ");
|
||||
Writer.Write(OperatorName);
|
||||
Writer.Write(" ");
|
||||
}
|
||||
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class ForwardTemplateReference : BaseNode
|
||||
{
|
||||
// TODO: Compute inside the Demangler
|
||||
public BaseNode Reference;
|
||||
private int Index;
|
||||
|
||||
public ForwardTemplateReference(int Index) : base(NodeType.ForwardTemplateReference)
|
||||
{
|
||||
this.Index = Index;
|
||||
}
|
||||
|
||||
public override string GetName()
|
||||
{
|
||||
return Reference.GetName();
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Reference.PrintLeft(Writer);
|
||||
}
|
||||
|
||||
public override void PrintRight(TextWriter Writer)
|
||||
{
|
||||
Reference.PrintRight(Writer);
|
||||
}
|
||||
|
||||
public override bool HasRightPart()
|
||||
{
|
||||
return Reference.HasRightPart();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class FunctionParameter : BaseNode
|
||||
{
|
||||
private string Number;
|
||||
|
||||
public FunctionParameter(string Number) : base(NodeType.FunctionParameter)
|
||||
{
|
||||
this.Number = Number;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write("fp ");
|
||||
|
||||
if (Number != null)
|
||||
{
|
||||
Writer.Write(Number);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
61
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/FunctionType.cs
Normal file
61
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/FunctionType.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class FunctionType : BaseNode
|
||||
{
|
||||
private BaseNode ReturnType;
|
||||
private BaseNode Params;
|
||||
private BaseNode CVQualifier;
|
||||
private SimpleReferenceType ReferenceQualifier;
|
||||
private BaseNode ExceptionSpec;
|
||||
|
||||
public FunctionType(BaseNode ReturnType, BaseNode Params, BaseNode CVQualifier, SimpleReferenceType ReferenceQualifier, BaseNode ExceptionSpec) : base(NodeType.FunctionType)
|
||||
{
|
||||
this.ReturnType = ReturnType;
|
||||
this.Params = Params;
|
||||
this.CVQualifier = CVQualifier;
|
||||
this.ReferenceQualifier = ReferenceQualifier;
|
||||
this.ExceptionSpec = ExceptionSpec;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
ReturnType.PrintLeft(Writer);
|
||||
Writer.Write(" ");
|
||||
}
|
||||
|
||||
public override void PrintRight(TextWriter Writer)
|
||||
{
|
||||
Writer.Write("(");
|
||||
Params.Print(Writer);
|
||||
Writer.Write(")");
|
||||
|
||||
ReturnType.PrintRight(Writer);
|
||||
|
||||
CVQualifier.Print(Writer);
|
||||
|
||||
if (ReferenceQualifier.Qualifier != Reference.None)
|
||||
{
|
||||
Writer.Write(" ");
|
||||
ReferenceQualifier.PrintQualifier(Writer);
|
||||
}
|
||||
|
||||
if (ExceptionSpec != null)
|
||||
{
|
||||
Writer.Write(" ");
|
||||
ExceptionSpec.Print(Writer);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool HasRightPart()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool HasFunctions()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class GlobalQualifiedName : ParentNode
|
||||
{
|
||||
public GlobalQualifiedName(BaseNode Child) : base(NodeType.GlobalQualifiedName, Child) { }
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write("::");
|
||||
Child.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class InitListExpression : BaseNode
|
||||
{
|
||||
private BaseNode TypeNode;
|
||||
private List<BaseNode> Nodes;
|
||||
|
||||
public InitListExpression(BaseNode TypeNode, List<BaseNode> Nodes) : base(NodeType.InitListExpression)
|
||||
{
|
||||
this.TypeNode = TypeNode;
|
||||
this.Nodes = Nodes;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (TypeNode != null)
|
||||
{
|
||||
TypeNode.Print(Writer);
|
||||
}
|
||||
|
||||
Writer.Write("{");
|
||||
Writer.Write(string.Join<BaseNode>(", ", Nodes.ToArray()));
|
||||
Writer.Write("}");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class IntegerCastExpression : ParentNode
|
||||
{
|
||||
private string Number;
|
||||
|
||||
public IntegerCastExpression(BaseNode Type, string Number) : base(NodeType.IntegerCastExpression, Type)
|
||||
{
|
||||
this.Number = Number;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write("(");
|
||||
Child.Print(Writer);
|
||||
Writer.Write(")");
|
||||
Writer.Write(Number);
|
||||
}
|
||||
}
|
||||
}
|
41
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/IntegerLiteral.cs
Normal file
41
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/IntegerLiteral.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class IntegerLiteral : BaseNode
|
||||
{
|
||||
private string LitteralName;
|
||||
private string LitteralValue;
|
||||
|
||||
public IntegerLiteral(string LitteralName, string LitteralValue) : base(NodeType.IntegerLiteral)
|
||||
{
|
||||
this.LitteralValue = LitteralValue;
|
||||
this.LitteralName = LitteralName;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (LitteralName.Length > 3)
|
||||
{
|
||||
Writer.Write("(");
|
||||
Writer.Write(LitteralName);
|
||||
Writer.Write(")");
|
||||
}
|
||||
|
||||
if (LitteralValue[0] == 'n')
|
||||
{
|
||||
Writer.Write("-");
|
||||
Writer.Write(LitteralValue.Substring(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
Writer.Write(LitteralValue);
|
||||
}
|
||||
|
||||
if (LitteralName.Length <= 3)
|
||||
{
|
||||
Writer.Write(LitteralName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
16
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/LiteralOperator.cs
Normal file
16
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/LiteralOperator.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class LiteralOperator : ParentNode
|
||||
{
|
||||
public LiteralOperator(BaseNode Child) : base(NodeType.LiteralOperator, Child) { }
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write("operator \"");
|
||||
Child.PrintLeft(Writer);
|
||||
Writer.Write("\"");
|
||||
}
|
||||
}
|
||||
}
|
23
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/LocalName.cs
Normal file
23
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/LocalName.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class LocalName : BaseNode
|
||||
{
|
||||
private BaseNode Encoding;
|
||||
private BaseNode Entity;
|
||||
|
||||
public LocalName(BaseNode Encoding, BaseNode Entity) : base(NodeType.LocalName)
|
||||
{
|
||||
this.Encoding = Encoding;
|
||||
this.Entity = Entity;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Encoding.Print(Writer);
|
||||
Writer.Write("::");
|
||||
Entity.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class MemberExpression : BaseNode
|
||||
{
|
||||
private BaseNode LeftNode;
|
||||
private string Kind;
|
||||
private BaseNode RightNode;
|
||||
|
||||
public MemberExpression(BaseNode LeftNode, string Kind, BaseNode RightNode) : base(NodeType.MemberExpression)
|
||||
{
|
||||
this.LeftNode = LeftNode;
|
||||
this.Kind = Kind;
|
||||
this.RightNode = RightNode;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
LeftNode.Print(Writer);
|
||||
Writer.Write(Kind);
|
||||
RightNode.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
29
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NameType.cs
Normal file
29
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NameType.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class NameType : BaseNode
|
||||
{
|
||||
private string NameValue;
|
||||
|
||||
public NameType(string NameValue, NodeType Type) : base(Type)
|
||||
{
|
||||
this.NameValue = NameValue;
|
||||
}
|
||||
|
||||
public NameType(string NameValue) : base(NodeType.NameType)
|
||||
{
|
||||
this.NameValue = NameValue;
|
||||
}
|
||||
|
||||
public override string GetName()
|
||||
{
|
||||
return NameValue;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Writer.Write(NameValue);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class NameTypeWithTemplateArguments : BaseNode
|
||||
{
|
||||
private BaseNode Prev;
|
||||
private BaseNode TemplateArgument;
|
||||
|
||||
public NameTypeWithTemplateArguments(BaseNode Prev, BaseNode TemplateArgument) : base(NodeType.NameTypeWithTemplateArguments)
|
||||
{
|
||||
this.Prev = Prev;
|
||||
this.TemplateArgument = TemplateArgument;
|
||||
}
|
||||
|
||||
public override string GetName()
|
||||
{
|
||||
return Prev.GetName();
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Prev.Print(Writer);
|
||||
TemplateArgument.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
26
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NestedName.cs
Normal file
26
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NestedName.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class NestedName : ParentNode
|
||||
{
|
||||
private BaseNode Name;
|
||||
|
||||
public NestedName(BaseNode Name, BaseNode Type) : base(NodeType.NestedName, Type)
|
||||
{
|
||||
this.Name = Name;
|
||||
}
|
||||
|
||||
public override string GetName()
|
||||
{
|
||||
return Name.GetName();
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
Child.Print(Writer);
|
||||
Writer.Write("::");
|
||||
Name.Print(Writer);
|
||||
}
|
||||
}
|
||||
}
|
55
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NewExpression.cs
Normal file
55
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NewExpression.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class NewExpression : BaseNode
|
||||
{
|
||||
private NodeArray Expressions;
|
||||
private BaseNode TypeNode;
|
||||
private NodeArray Initializers;
|
||||
|
||||
private bool IsGlobal;
|
||||
private bool IsArrayExpression;
|
||||
|
||||
public NewExpression(NodeArray Expressions, BaseNode TypeNode, NodeArray Initializers, bool IsGlobal, bool IsArrayExpression) : base(NodeType.NewExpression)
|
||||
{
|
||||
this.Expressions = Expressions;
|
||||
this.TypeNode = TypeNode;
|
||||
this.Initializers = Initializers;
|
||||
|
||||
this.IsGlobal = IsGlobal;
|
||||
this.IsArrayExpression = IsArrayExpression;
|
||||
}
|
||||
|
||||
public override void PrintLeft(TextWriter Writer)
|
||||
{
|
||||
if (IsGlobal)
|
||||
{
|
||||
Writer.Write("::operator ");
|
||||
}
|
||||
|
||||
Writer.Write("new ");
|
||||
|
||||
if (IsArrayExpression)
|
||||
{
|
||||
Writer.Write("[] ");
|
||||
}
|
||||
|
||||
if (Expressions.Nodes.Count != 0)
|
||||
{
|
||||
Writer.Write("(");
|
||||
Expressions.Print(Writer);
|
||||
Writer.Write(")");
|
||||
}
|
||||
|
||||
TypeNode.Print(Writer);
|
||||
|
||||
if (Initializers.Nodes.Count != 0)
|
||||
{
|
||||
Writer.Write("(");
|
||||
Initializers.Print(Writer);
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue