mirror of
https://github.com/ryujinx-mirror/ryujinx.git
synced 2024-11-25 03:25:13 +00:00
Do naming refactoring on Ryujinx.Graphics (#611)
* Renaming part 1 * Renaming part 2 * Renaming part 3 * Renaming part 4 * Renaming part 5 * Renaming part 6 * Renaming part 7 * Renaming part 8 * Renaming part 9 * Renaming part 10 * General cleanup * Thought I got all of these * Apply #595 * Additional renaming * Tweaks from feedback * Rename files
This commit is contained in:
parent
8e71ea0812
commit
1f554c1093
125 changed files with 9121 additions and 9120 deletions
|
@ -8,41 +8,41 @@ namespace Ryujinx.Graphics
|
||||||
private const int MethSetMethod = 0x10;
|
private const int MethSetMethod = 0x10;
|
||||||
private const int MethSetData = 0x11;
|
private const int MethSetData = 0x11;
|
||||||
|
|
||||||
private NvGpu Gpu;
|
private NvGpu _gpu;
|
||||||
|
|
||||||
public CdmaProcessor(NvGpu Gpu)
|
public CdmaProcessor(NvGpu gpu)
|
||||||
{
|
{
|
||||||
this.Gpu = Gpu;
|
_gpu = gpu;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PushCommands(NvGpuVmm Vmm, int[] CmdBuffer)
|
public void PushCommands(NvGpuVmm vmm, int[] cmdBuffer)
|
||||||
{
|
{
|
||||||
List<ChCommand> Commands = new List<ChCommand>();
|
List<ChCommand> commands = new List<ChCommand>();
|
||||||
|
|
||||||
ChClassId CurrentClass = 0;
|
ChClassId currentClass = 0;
|
||||||
|
|
||||||
for (int Index = 0; Index < CmdBuffer.Length; Index++)
|
for (int index = 0; index < cmdBuffer.Length; index++)
|
||||||
{
|
{
|
||||||
int Cmd = CmdBuffer[Index];
|
int cmd = cmdBuffer[index];
|
||||||
|
|
||||||
int Value = (Cmd >> 0) & 0xffff;
|
int value = (cmd >> 0) & 0xffff;
|
||||||
int MethodOffset = (Cmd >> 16) & 0xfff;
|
int methodOffset = (cmd >> 16) & 0xfff;
|
||||||
|
|
||||||
ChSubmissionMode SubmissionMode = (ChSubmissionMode)((Cmd >> 28) & 0xf);
|
ChSubmissionMode submissionMode = (ChSubmissionMode)((cmd >> 28) & 0xf);
|
||||||
|
|
||||||
switch (SubmissionMode)
|
switch (submissionMode)
|
||||||
{
|
{
|
||||||
case ChSubmissionMode.SetClass: CurrentClass = (ChClassId)(Value >> 6); break;
|
case ChSubmissionMode.SetClass: currentClass = (ChClassId)(value >> 6); break;
|
||||||
|
|
||||||
case ChSubmissionMode.Incrementing:
|
case ChSubmissionMode.Incrementing:
|
||||||
{
|
{
|
||||||
int Count = Value;
|
int count = value;
|
||||||
|
|
||||||
for (int ArgIdx = 0; ArgIdx < Count; ArgIdx++)
|
for (int argIdx = 0; argIdx < count; argIdx++)
|
||||||
{
|
{
|
||||||
int Argument = CmdBuffer[++Index];
|
int argument = cmdBuffer[++index];
|
||||||
|
|
||||||
Commands.Add(new ChCommand(CurrentClass, MethodOffset + ArgIdx, Argument));
|
commands.Add(new ChCommand(currentClass, methodOffset + argIdx, argument));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -50,44 +50,44 @@ namespace Ryujinx.Graphics
|
||||||
|
|
||||||
case ChSubmissionMode.NonIncrementing:
|
case ChSubmissionMode.NonIncrementing:
|
||||||
{
|
{
|
||||||
int Count = Value;
|
int count = value;
|
||||||
|
|
||||||
int[] Arguments = new int[Count];
|
int[] arguments = new int[count];
|
||||||
|
|
||||||
for (int ArgIdx = 0; ArgIdx < Count; ArgIdx++)
|
for (int argIdx = 0; argIdx < count; argIdx++)
|
||||||
{
|
{
|
||||||
Arguments[ArgIdx] = CmdBuffer[++Index];
|
arguments[argIdx] = cmdBuffer[++index];
|
||||||
}
|
}
|
||||||
|
|
||||||
Commands.Add(new ChCommand(CurrentClass, MethodOffset, Arguments));
|
commands.Add(new ChCommand(currentClass, methodOffset, arguments));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessCommands(Vmm, Commands.ToArray());
|
ProcessCommands(vmm, commands.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessCommands(NvGpuVmm Vmm, ChCommand[] Commands)
|
private void ProcessCommands(NvGpuVmm vmm, ChCommand[] commands)
|
||||||
{
|
{
|
||||||
int MethodOffset = 0;
|
int methodOffset = 0;
|
||||||
|
|
||||||
foreach (ChCommand Command in Commands)
|
foreach (ChCommand command in commands)
|
||||||
{
|
{
|
||||||
switch (Command.MethodOffset)
|
switch (command.MethodOffset)
|
||||||
{
|
{
|
||||||
case MethSetMethod: MethodOffset = Command.Arguments[0]; break;
|
case MethSetMethod: methodOffset = command.Arguments[0]; break;
|
||||||
|
|
||||||
case MethSetData:
|
case MethSetData:
|
||||||
{
|
{
|
||||||
if (Command.ClassId == ChClassId.NvDec)
|
if (command.ClassId == ChClassId.NvDec)
|
||||||
{
|
{
|
||||||
Gpu.VideoDecoder.Process(Vmm, MethodOffset, Command.Arguments);
|
_gpu.VideoDecoder.Process(vmm, methodOffset, command.Arguments);
|
||||||
}
|
}
|
||||||
else if (Command.ClassId == ChClassId.GraphicsVic)
|
else if (command.ClassId == ChClassId.GraphicsVic)
|
||||||
{
|
{
|
||||||
Gpu.VideoImageComposer.Process(Vmm, MethodOffset, Command.Arguments);
|
_gpu.VideoImageComposer.Process(vmm, methodOffset, command.Arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -2,7 +2,7 @@ namespace Ryujinx.Graphics
|
||||||
{
|
{
|
||||||
enum ChClassId
|
enum ChClassId
|
||||||
{
|
{
|
||||||
Host1x = 0x1,
|
Host1X = 0x1,
|
||||||
VideoEncodeMpeg = 0x20,
|
VideoEncodeMpeg = 0x20,
|
||||||
VideoEncodeNvEnc = 0x21,
|
VideoEncodeNvEnc = 0x21,
|
||||||
VideoStreamingVi = 0x30,
|
VideoStreamingVi = 0x30,
|
||||||
|
@ -10,7 +10,7 @@ namespace Ryujinx.Graphics
|
||||||
VideoStreamingIspB = 0x34,
|
VideoStreamingIspB = 0x34,
|
||||||
VideoStreamingViI2c = 0x36,
|
VideoStreamingViI2c = 0x36,
|
||||||
GraphicsVic = 0x5d,
|
GraphicsVic = 0x5d,
|
||||||
Graphics3d = 0x60,
|
Graphics3D = 0x60,
|
||||||
GraphicsGpu = 0x61,
|
GraphicsGpu = 0x61,
|
||||||
Tsec = 0xe0,
|
Tsec = 0xe0,
|
||||||
TsecB = 0xe1,
|
TsecB = 0xe1,
|
||||||
|
|
|
@ -8,11 +8,11 @@ namespace Ryujinx.Graphics
|
||||||
|
|
||||||
public int[] Arguments { get; private set; }
|
public int[] Arguments { get; private set; }
|
||||||
|
|
||||||
public ChCommand(ChClassId ClassId, int MethodOffset, params int[] Arguments)
|
public ChCommand(ChClassId classId, int methodOffset, params int[] arguments)
|
||||||
{
|
{
|
||||||
this.ClassId = ClassId;
|
ClassId = classId;
|
||||||
this.MethodOffset = MethodOffset;
|
MethodOffset = methodOffset;
|
||||||
this.Arguments = Arguments;
|
Arguments = arguments;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,10 +6,10 @@ namespace Ryujinx.Graphics
|
||||||
{
|
{
|
||||||
public class DmaPusher
|
public class DmaPusher
|
||||||
{
|
{
|
||||||
private ConcurrentQueue<(NvGpuVmm, long)> IbBuffer;
|
private ConcurrentQueue<(NvGpuVmm, long)> _ibBuffer;
|
||||||
|
|
||||||
private long DmaPut;
|
private long _dmaPut;
|
||||||
private long DmaGet;
|
private long _dmaGet;
|
||||||
|
|
||||||
private struct DmaState
|
private struct DmaState
|
||||||
{
|
{
|
||||||
|
@ -21,43 +21,43 @@ namespace Ryujinx.Graphics
|
||||||
public int LengthPending;
|
public int LengthPending;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DmaState State;
|
private DmaState _state;
|
||||||
|
|
||||||
private bool SliEnable;
|
private bool _sliEnable;
|
||||||
private bool SliActive;
|
private bool _sliActive;
|
||||||
|
|
||||||
private bool IbEnable;
|
private bool _ibEnable;
|
||||||
private bool NonMain;
|
private bool _nonMain;
|
||||||
|
|
||||||
private long DmaMGet;
|
private long _dmaMGet;
|
||||||
|
|
||||||
private NvGpuVmm Vmm;
|
private NvGpuVmm _vmm;
|
||||||
|
|
||||||
private NvGpu Gpu;
|
private NvGpu _gpu;
|
||||||
|
|
||||||
private AutoResetEvent Event;
|
private AutoResetEvent _event;
|
||||||
|
|
||||||
public DmaPusher(NvGpu Gpu)
|
public DmaPusher(NvGpu gpu)
|
||||||
{
|
{
|
||||||
this.Gpu = Gpu;
|
_gpu = gpu;
|
||||||
|
|
||||||
IbBuffer = new ConcurrentQueue<(NvGpuVmm, long)>();
|
_ibBuffer = new ConcurrentQueue<(NvGpuVmm, long)>();
|
||||||
|
|
||||||
IbEnable = true;
|
_ibEnable = true;
|
||||||
|
|
||||||
Event = new AutoResetEvent(false);
|
_event = new AutoResetEvent(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Push(NvGpuVmm Vmm, long Entry)
|
public void Push(NvGpuVmm vmm, long entry)
|
||||||
{
|
{
|
||||||
IbBuffer.Enqueue((Vmm, Entry));
|
_ibBuffer.Enqueue((vmm, entry));
|
||||||
|
|
||||||
Event.Set();
|
_event.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool WaitForCommands()
|
public bool WaitForCommands()
|
||||||
{
|
{
|
||||||
return Event.WaitOne(8);
|
return _event.WaitOne(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DispatchCalls()
|
public void DispatchCalls()
|
||||||
|
@ -67,101 +67,101 @@ namespace Ryujinx.Graphics
|
||||||
|
|
||||||
private bool Step()
|
private bool Step()
|
||||||
{
|
{
|
||||||
if (DmaGet != DmaPut)
|
if (_dmaGet != _dmaPut)
|
||||||
{
|
{
|
||||||
int Word = Vmm.ReadInt32(DmaGet);
|
int word = _vmm.ReadInt32(_dmaGet);
|
||||||
|
|
||||||
DmaGet += 4;
|
_dmaGet += 4;
|
||||||
|
|
||||||
if (!NonMain)
|
if (!_nonMain)
|
||||||
{
|
{
|
||||||
DmaMGet = DmaGet;
|
_dmaMGet = _dmaGet;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (State.LengthPending != 0)
|
if (_state.LengthPending != 0)
|
||||||
{
|
{
|
||||||
State.LengthPending = 0;
|
_state.LengthPending = 0;
|
||||||
State.MethodCount = Word & 0xffffff;
|
_state.MethodCount = word & 0xffffff;
|
||||||
}
|
}
|
||||||
else if (State.MethodCount != 0)
|
else if (_state.MethodCount != 0)
|
||||||
{
|
{
|
||||||
if (!SliEnable || SliActive)
|
if (!_sliEnable || _sliActive)
|
||||||
{
|
{
|
||||||
CallMethod(Word);
|
CallMethod(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!State.NonIncrementing)
|
if (!_state.NonIncrementing)
|
||||||
{
|
{
|
||||||
State.Method++;
|
_state.Method++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (State.IncrementOnce)
|
if (_state.IncrementOnce)
|
||||||
{
|
{
|
||||||
State.NonIncrementing = true;
|
_state.NonIncrementing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
State.MethodCount--;
|
_state.MethodCount--;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int SumissionMode = (Word >> 29) & 7;
|
int sumissionMode = (word >> 29) & 7;
|
||||||
|
|
||||||
switch (SumissionMode)
|
switch (sumissionMode)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
//Incrementing.
|
//Incrementing.
|
||||||
SetNonImmediateState(Word);
|
SetNonImmediateState(word);
|
||||||
|
|
||||||
State.NonIncrementing = false;
|
_state.NonIncrementing = false;
|
||||||
State.IncrementOnce = false;
|
_state.IncrementOnce = false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
//Non-incrementing.
|
//Non-incrementing.
|
||||||
SetNonImmediateState(Word);
|
SetNonImmediateState(word);
|
||||||
|
|
||||||
State.NonIncrementing = true;
|
_state.NonIncrementing = true;
|
||||||
State.IncrementOnce = false;
|
_state.IncrementOnce = false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
//Immediate.
|
//Immediate.
|
||||||
State.Method = (Word >> 0) & 0x1fff;
|
_state.Method = (word >> 0) & 0x1fff;
|
||||||
State.SubChannel = (Word >> 13) & 7;
|
_state.SubChannel = (word >> 13) & 7;
|
||||||
State.NonIncrementing = true;
|
_state.NonIncrementing = true;
|
||||||
State.IncrementOnce = false;
|
_state.IncrementOnce = false;
|
||||||
|
|
||||||
CallMethod((Word >> 16) & 0x1fff);
|
CallMethod((word >> 16) & 0x1fff);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
//Increment-once.
|
//Increment-once.
|
||||||
SetNonImmediateState(Word);
|
SetNonImmediateState(word);
|
||||||
|
|
||||||
State.NonIncrementing = false;
|
_state.NonIncrementing = false;
|
||||||
State.IncrementOnce = true;
|
_state.IncrementOnce = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IbEnable && IbBuffer.TryDequeue(out (NvGpuVmm Vmm, long Entry) Tuple))
|
else if (_ibEnable && _ibBuffer.TryDequeue(out (NvGpuVmm Vmm, long Entry) tuple))
|
||||||
{
|
{
|
||||||
this.Vmm = Tuple.Vmm;
|
_vmm = tuple.Vmm;
|
||||||
|
|
||||||
long Entry = Tuple.Entry;
|
long entry = tuple.Entry;
|
||||||
|
|
||||||
int Length = (int)(Entry >> 42) & 0x1fffff;
|
int length = (int)(entry >> 42) & 0x1fffff;
|
||||||
|
|
||||||
DmaGet = Entry & 0xfffffffffc;
|
_dmaGet = entry & 0xfffffffffc;
|
||||||
DmaPut = DmaGet + Length * 4;
|
_dmaPut = _dmaGet + length * 4;
|
||||||
|
|
||||||
NonMain = (Entry & (1L << 41)) != 0;
|
_nonMain = (entry & (1L << 41)) != 0;
|
||||||
|
|
||||||
Gpu.ResourceManager.ClearPbCache();
|
_gpu.ResourceManager.ClearPbCache();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -171,20 +171,20 @@ namespace Ryujinx.Graphics
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetNonImmediateState(int Word)
|
private void SetNonImmediateState(int word)
|
||||||
{
|
{
|
||||||
State.Method = (Word >> 0) & 0x1fff;
|
_state.Method = (word >> 0) & 0x1fff;
|
||||||
State.SubChannel = (Word >> 13) & 7;
|
_state.SubChannel = (word >> 13) & 7;
|
||||||
State.MethodCount = (Word >> 16) & 0x1fff;
|
_state.MethodCount = (word >> 16) & 0x1fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CallMethod(int Argument)
|
private void CallMethod(int argument)
|
||||||
{
|
{
|
||||||
Gpu.Fifo.CallMethod(Vmm, new GpuMethodCall(
|
_gpu.Fifo.CallMethod(_vmm, new GpuMethodCall(
|
||||||
State.Method,
|
_state.Method,
|
||||||
Argument,
|
argument,
|
||||||
State.SubChannel,
|
_state.SubChannel,
|
||||||
State.MethodCount));
|
_state.MethodCount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,15 +5,15 @@ namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
static class EmbeddedResource
|
static class EmbeddedResource
|
||||||
{
|
{
|
||||||
public static string GetString(string Name)
|
public static string GetString(string name)
|
||||||
{
|
{
|
||||||
Assembly Asm = typeof(EmbeddedResource).Assembly;
|
Assembly asm = typeof(EmbeddedResource).Assembly;
|
||||||
|
|
||||||
using (Stream ResStream = Asm.GetManifestResourceStream(Name))
|
using (Stream resStream = asm.GetManifestResourceStream(name))
|
||||||
{
|
{
|
||||||
StreamReader Reader = new StreamReader(ResStream);
|
StreamReader reader = new StreamReader(resStream);
|
||||||
|
|
||||||
return Reader.ReadToEnd();
|
return reader.ReadToEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,15 +8,15 @@ namespace Ryujinx.Graphics.Gal
|
||||||
public float Alpha { get; private set; }
|
public float Alpha { get; private set; }
|
||||||
|
|
||||||
public GalColorF(
|
public GalColorF(
|
||||||
float Red,
|
float red,
|
||||||
float Green,
|
float green,
|
||||||
float Blue,
|
float blue,
|
||||||
float Alpha)
|
float alpha)
|
||||||
{
|
{
|
||||||
this.Red = Red;
|
Red = red;
|
||||||
this.Green = Green;
|
Green = green;
|
||||||
this.Blue = Blue;
|
Blue = blue;
|
||||||
this.Alpha = Alpha;
|
Alpha = alpha;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
{
|
{
|
||||||
public enum GalFrontFace
|
public enum GalFrontFace
|
||||||
{
|
{
|
||||||
CW = 0x900,
|
Cw = 0x900,
|
||||||
CCW = 0x901
|
Ccw = 0x901
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,63 +25,63 @@ namespace Ryujinx.Graphics.Gal
|
||||||
public GalTextureTarget TextureTarget;
|
public GalTextureTarget TextureTarget;
|
||||||
|
|
||||||
public GalImage(
|
public GalImage(
|
||||||
int Width,
|
int width,
|
||||||
int Height,
|
int height,
|
||||||
int Depth,
|
int depth,
|
||||||
int LayerCount,
|
int layerCount,
|
||||||
int TileWidth,
|
int tileWidth,
|
||||||
int GobBlockHeight,
|
int gobBlockHeight,
|
||||||
int GobBlockDepth,
|
int gobBlockDepth,
|
||||||
GalMemoryLayout Layout,
|
GalMemoryLayout layout,
|
||||||
GalImageFormat Format,
|
GalImageFormat format,
|
||||||
GalTextureTarget TextureTarget,
|
GalTextureTarget textureTarget,
|
||||||
int MaxMipmapLevel = 1,
|
int maxMipmapLevel = 1,
|
||||||
GalTextureSource XSource = GalTextureSource.Red,
|
GalTextureSource xSource = GalTextureSource.Red,
|
||||||
GalTextureSource YSource = GalTextureSource.Green,
|
GalTextureSource ySource = GalTextureSource.Green,
|
||||||
GalTextureSource ZSource = GalTextureSource.Blue,
|
GalTextureSource zSource = GalTextureSource.Blue,
|
||||||
GalTextureSource WSource = GalTextureSource.Alpha)
|
GalTextureSource wSource = GalTextureSource.Alpha)
|
||||||
{
|
{
|
||||||
this.Width = Width;
|
Width = width;
|
||||||
this.Height = Height;
|
Height = height;
|
||||||
this.LayerCount = LayerCount;
|
LayerCount = layerCount;
|
||||||
this.Depth = Depth;
|
Depth = depth;
|
||||||
this.TileWidth = TileWidth;
|
TileWidth = tileWidth;
|
||||||
this.GobBlockHeight = GobBlockHeight;
|
GobBlockHeight = gobBlockHeight;
|
||||||
this.GobBlockDepth = GobBlockDepth;
|
GobBlockDepth = gobBlockDepth;
|
||||||
this.Layout = Layout;
|
Layout = layout;
|
||||||
this.Format = Format;
|
Format = format;
|
||||||
this.MaxMipmapLevel = MaxMipmapLevel;
|
MaxMipmapLevel = maxMipmapLevel;
|
||||||
this.XSource = XSource;
|
XSource = xSource;
|
||||||
this.YSource = YSource;
|
YSource = ySource;
|
||||||
this.ZSource = ZSource;
|
ZSource = zSource;
|
||||||
this.WSource = WSource;
|
WSource = wSource;
|
||||||
this.TextureTarget = TextureTarget;
|
TextureTarget = textureTarget;
|
||||||
|
|
||||||
Pitch = ImageUtils.GetPitch(Format, Width);
|
Pitch = ImageUtils.GetPitch(format, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SizeMatches(GalImage Image, bool IgnoreLayer = false)
|
public bool SizeMatches(GalImage image, bool ignoreLayer = false)
|
||||||
{
|
{
|
||||||
if (ImageUtils.GetBytesPerPixel(Format) !=
|
if (ImageUtils.GetBytesPerPixel(Format) !=
|
||||||
ImageUtils.GetBytesPerPixel(Image.Format))
|
ImageUtils.GetBytesPerPixel(image.Format))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImageUtils.GetAlignedWidth(this) !=
|
if (ImageUtils.GetAlignedWidth(this) !=
|
||||||
ImageUtils.GetAlignedWidth(Image))
|
ImageUtils.GetAlignedWidth(image))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Result = Height == Image.Height && Depth == Image.Depth;
|
bool result = Height == image.Height && Depth == image.Depth;
|
||||||
|
|
||||||
if (!IgnoreLayer)
|
if (!ignoreLayer)
|
||||||
{
|
{
|
||||||
Result = Result && LayerCount == Image.LayerCount;
|
result = result && LayerCount == image.LayerCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -22,23 +22,23 @@ namespace Ryujinx.Graphics.Gal
|
||||||
Astc2D12x12,
|
Astc2D12x12,
|
||||||
Astc2DEnd,
|
Astc2DEnd,
|
||||||
|
|
||||||
RGBA4,
|
Rgba4,
|
||||||
RGB565,
|
Rgb565,
|
||||||
BGR565,
|
Bgr565,
|
||||||
BGR5A1,
|
Bgr5A1,
|
||||||
RGB5A1,
|
Rgb5A1,
|
||||||
R8,
|
R8,
|
||||||
RG8,
|
Rg8,
|
||||||
RGBX8,
|
Rgbx8,
|
||||||
RGBA8,
|
Rgba8,
|
||||||
BGRA8,
|
Bgra8,
|
||||||
RGB10A2,
|
Rgb10A2,
|
||||||
R16,
|
R16,
|
||||||
RG16,
|
Rg16,
|
||||||
RGBA16,
|
Rgba16,
|
||||||
R32,
|
R32,
|
||||||
RG32,
|
Rg32,
|
||||||
RGBA32,
|
Rgba32,
|
||||||
R11G11B10,
|
R11G11B10,
|
||||||
D16,
|
D16,
|
||||||
D24,
|
D24,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{
|
{
|
||||||
public struct ColorMaskState
|
public struct ColorMaskState
|
||||||
{
|
{
|
||||||
private static readonly ColorMaskState _Default = new ColorMaskState()
|
private static readonly ColorMaskState DefaultBackingField = new ColorMaskState()
|
||||||
{
|
{
|
||||||
Red = true,
|
Red = true,
|
||||||
Green = true,
|
Green = true,
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
Alpha = true
|
Alpha = true
|
||||||
};
|
};
|
||||||
|
|
||||||
public static ColorMaskState Default => _Default;
|
public static ColorMaskState Default => DefaultBackingField;
|
||||||
|
|
||||||
public bool Red;
|
public bool Red;
|
||||||
public bool Green;
|
public bool Green;
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
public struct BlendState
|
public struct BlendState
|
||||||
{
|
{
|
||||||
private static readonly BlendState _Default = new BlendState()
|
private static readonly BlendState DefaultBackingField = new BlendState()
|
||||||
{
|
{
|
||||||
Enabled = false,
|
Enabled = false,
|
||||||
SeparateAlpha = false,
|
SeparateAlpha = false,
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
FuncDstAlpha = GalBlendFactor.Zero
|
FuncDstAlpha = GalBlendFactor.Zero
|
||||||
};
|
};
|
||||||
|
|
||||||
public static BlendState Default => _Default;
|
public static BlendState Default => DefaultBackingField;
|
||||||
|
|
||||||
public bool Enabled;
|
public bool Enabled;
|
||||||
public bool SeparateAlpha;
|
public bool SeparateAlpha;
|
||||||
|
@ -111,9 +111,9 @@
|
||||||
{
|
{
|
||||||
ConstBufferKeys = new long[Stages][];
|
ConstBufferKeys = new long[Stages][];
|
||||||
|
|
||||||
for (int Stage = 0; Stage < Stages; Stage++)
|
for (int stage = 0; stage < Stages; stage++)
|
||||||
{
|
{
|
||||||
ConstBufferKeys[Stage] = new long[ConstBuffersPerStage];
|
ConstBufferKeys[stage] = new long[ConstBuffersPerStage];
|
||||||
}
|
}
|
||||||
|
|
||||||
Blends = new BlendState[RenderTargetsCount];
|
Blends = new BlendState[RenderTargetsCount];
|
||||||
|
|
|
@ -4,48 +4,48 @@
|
||||||
{
|
{
|
||||||
Bitmap = 0x1c,
|
Bitmap = 0x1c,
|
||||||
Unknown1D = 0x1d,
|
Unknown1D = 0x1d,
|
||||||
RGBA32Float = 0xc0,
|
Rgba32Float = 0xc0,
|
||||||
RGBA32Sint = 0xc1,
|
Rgba32Sint = 0xc1,
|
||||||
RGBA32Uint = 0xc2,
|
Rgba32Uint = 0xc2,
|
||||||
RGBX32Float = 0xc3,
|
Rgbx32Float = 0xc3,
|
||||||
RGBX32Sint = 0xc4,
|
Rgbx32Sint = 0xc4,
|
||||||
RGBX32Uint = 0xc5,
|
Rgbx32Uint = 0xc5,
|
||||||
RGBA16Unorm = 0xc6,
|
Rgba16Unorm = 0xc6,
|
||||||
RGBA16Snorm = 0xc7,
|
Rgba16Snorm = 0xc7,
|
||||||
RGBA16Sint = 0xc8,
|
Rgba16Sint = 0xc8,
|
||||||
RGBA16Uint = 0xc9,
|
Rgba16Uint = 0xc9,
|
||||||
RGBA16Float = 0xca,
|
Rgba16Float = 0xca,
|
||||||
RG32Float = 0xcb,
|
Rg32Float = 0xcb,
|
||||||
RG32Sint = 0xcc,
|
Rg32Sint = 0xcc,
|
||||||
RG32Uint = 0xcd,
|
Rg32Uint = 0xcd,
|
||||||
RGBX16Float = 0xce,
|
Rgbx16Float = 0xce,
|
||||||
BGRA8Unorm = 0xcf,
|
Bgra8Unorm = 0xcf,
|
||||||
BGRA8Srgb = 0xd0,
|
Bgra8Srgb = 0xd0,
|
||||||
RGB10A2Unorm = 0xd1,
|
Rgb10A2Unorm = 0xd1,
|
||||||
RGB10A2Uint = 0xd2,
|
Rgb10A2Uint = 0xd2,
|
||||||
RGBA8Unorm = 0xd5,
|
Rgba8Unorm = 0xd5,
|
||||||
RGBA8Srgb = 0xd6,
|
Rgba8Srgb = 0xd6,
|
||||||
RGBA8Snorm = 0xd7,
|
Rgba8Snorm = 0xd7,
|
||||||
RGBA8Sint = 0xd8,
|
Rgba8Sint = 0xd8,
|
||||||
RGBA8Uint = 0xd9,
|
Rgba8Uint = 0xd9,
|
||||||
RG16Unorm = 0xda,
|
Rg16Unorm = 0xda,
|
||||||
RG16Snorm = 0xdb,
|
Rg16Snorm = 0xdb,
|
||||||
RG16Sint = 0xdc,
|
Rg16Sint = 0xdc,
|
||||||
RG16Uint = 0xdd,
|
Rg16Uint = 0xdd,
|
||||||
RG16Float = 0xde,
|
Rg16Float = 0xde,
|
||||||
BGR10A2Unorm = 0xdf,
|
Bgr10A2Unorm = 0xdf,
|
||||||
R11G11B10Float = 0xe0,
|
R11G11B10Float = 0xe0,
|
||||||
R32Sint = 0xe3,
|
R32Sint = 0xe3,
|
||||||
R32Uint = 0xe4,
|
R32Uint = 0xe4,
|
||||||
R32Float = 0xe5,
|
R32Float = 0xe5,
|
||||||
BGRX8Unorm = 0xe6,
|
Bgrx8Unorm = 0xe6,
|
||||||
BGRX8Srgb = 0xe7,
|
Bgrx8Srgb = 0xe7,
|
||||||
B5G6R5Unorm = 0xe8,
|
B5G6R5Unorm = 0xe8,
|
||||||
BGR5A1Unorm = 0xe9,
|
Bgr5A1Unorm = 0xe9,
|
||||||
RG8Unorm = 0xea,
|
Rg8Unorm = 0xea,
|
||||||
RG8Snorm = 0xeb,
|
Rg8Snorm = 0xeb,
|
||||||
RG8Sint = 0xec,
|
Rg8Sint = 0xec,
|
||||||
RG8Uint = 0xed,
|
Rg8Uint = 0xed,
|
||||||
R16Unorm = 0xee,
|
R16Unorm = 0xee,
|
||||||
R16Snorm = 0xef,
|
R16Snorm = 0xef,
|
||||||
R16Sint = 0xf0,
|
R16Sint = 0xf0,
|
||||||
|
@ -56,13 +56,13 @@
|
||||||
R8Sint = 0xf5,
|
R8Sint = 0xf5,
|
||||||
R8Uint = 0xf6,
|
R8Uint = 0xf6,
|
||||||
A8Unorm = 0xf7,
|
A8Unorm = 0xf7,
|
||||||
BGR5X1Unorm = 0xf8,
|
Bgr5x1Unorm = 0xf8,
|
||||||
RGBX8Unorm = 0xf9,
|
Rgbx8Unorm = 0xf9,
|
||||||
RGBX8Srgb = 0xfa,
|
Rgbx8Srgb = 0xfa,
|
||||||
BGR5X1UnormUnknownFB = 0xfb,
|
Bgr5x1UnormUnknownFB = 0xfb,
|
||||||
BGR5X1UnormUnknownFC = 0xfc,
|
Bgr5x1UnormUnknownFC = 0xfc,
|
||||||
BGRX8UnormUnknownFD = 0xfd,
|
Bgrx8UnormUnknownFD = 0xfd,
|
||||||
BGRX8UnormUnknownFE = 0xfe,
|
Bgrx8UnormUnknownFE = 0xfe,
|
||||||
Y32UintUnknownFF = 0xff
|
Y32UintUnknownFF = 0xff
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,20 +2,20 @@ namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
public enum GalTextureFormat
|
public enum GalTextureFormat
|
||||||
{
|
{
|
||||||
RGBA32 = 0x1,
|
Rgba32 = 0x1,
|
||||||
RGBA16 = 0x3,
|
Rgba16 = 0x3,
|
||||||
RG32 = 0x4,
|
Rg32 = 0x4,
|
||||||
RGBA8 = 0x8,
|
Rgba8 = 0x8,
|
||||||
RGB10A2 = 0x9,
|
Rgb10A2 = 0x9,
|
||||||
RG16 = 0xc,
|
Rg16 = 0xc,
|
||||||
R32 = 0xf,
|
R32 = 0xf,
|
||||||
BptcSfloat = 0x10,
|
BptcSfloat = 0x10,
|
||||||
BptcUfloat = 0x11,
|
BptcUfloat = 0x11,
|
||||||
RGBA4 = 0x12,
|
Rgba4 = 0x12,
|
||||||
RGB5A1 = 0x14,
|
Rgb5A1 = 0x14,
|
||||||
RGB565 = 0x15,
|
Rgb565 = 0x15,
|
||||||
BptcUnorm = 0x17,
|
BptcUnorm = 0x17,
|
||||||
RG8 = 0x18,
|
Rg8 = 0x18,
|
||||||
R16 = 0x1b,
|
R16 = 0x1b,
|
||||||
R8 = 0x1d,
|
R8 = 0x1d,
|
||||||
R11G11B10F = 0x21,
|
R11G11B10F = 0x21,
|
||||||
|
@ -26,7 +26,7 @@ namespace Ryujinx.Graphics.Gal
|
||||||
BC5 = 0x28,
|
BC5 = 0x28,
|
||||||
D24S8 = 0x29,
|
D24S8 = 0x29,
|
||||||
D32F = 0x2f,
|
D32F = 0x2f,
|
||||||
D32FX24S8 = 0x30,
|
D32Fx24S8 = 0x30,
|
||||||
D16 = 0x3a,
|
D16 = 0x3a,
|
||||||
Astc2D4x4 = 0x40,
|
Astc2D4x4 = 0x40,
|
||||||
Astc2D5x5 = 0x41,
|
Astc2D5x5 = 0x41,
|
||||||
|
|
|
@ -16,26 +16,26 @@ namespace Ryujinx.Graphics.Gal
|
||||||
public DepthCompareFunc DepthCompareFunc { get; private set; }
|
public DepthCompareFunc DepthCompareFunc { get; private set; }
|
||||||
|
|
||||||
public GalTextureSampler(
|
public GalTextureSampler(
|
||||||
GalTextureWrap AddressU,
|
GalTextureWrap addressU,
|
||||||
GalTextureWrap AddressV,
|
GalTextureWrap addressV,
|
||||||
GalTextureWrap AddressP,
|
GalTextureWrap addressP,
|
||||||
GalTextureFilter MinFilter,
|
GalTextureFilter minFilter,
|
||||||
GalTextureFilter MagFilter,
|
GalTextureFilter magFilter,
|
||||||
GalTextureMipFilter MipFilter,
|
GalTextureMipFilter mipFilter,
|
||||||
GalColorF BorderColor,
|
GalColorF borderColor,
|
||||||
bool DepthCompare,
|
bool depthCompare,
|
||||||
DepthCompareFunc DepthCompareFunc)
|
DepthCompareFunc depthCompareFunc)
|
||||||
{
|
{
|
||||||
this.AddressU = AddressU;
|
AddressU = addressU;
|
||||||
this.AddressV = AddressV;
|
AddressV = addressV;
|
||||||
this.AddressP = AddressP;
|
AddressP = addressP;
|
||||||
this.MinFilter = MinFilter;
|
MinFilter = minFilter;
|
||||||
this.MagFilter = MagFilter;
|
MagFilter = magFilter;
|
||||||
this.MipFilter = MipFilter;
|
MipFilter = mipFilter;
|
||||||
this.BorderColor = BorderColor;
|
BorderColor = borderColor;
|
||||||
|
|
||||||
this.DepthCompare = DepthCompare;
|
DepthCompare = depthCompare;
|
||||||
this.DepthCompareFunc = DepthCompareFunc;
|
DepthCompareFunc = depthCompareFunc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,8 +6,8 @@
|
||||||
Unorm = 2,
|
Unorm = 2,
|
||||||
Sint = 3,
|
Sint = 3,
|
||||||
Uint = 4,
|
Uint = 4,
|
||||||
Snorm_Force_Fp16 = 5,
|
SnormForceFp16 = 5,
|
||||||
Unorm_Force_Fp16 = 6,
|
UnormForceFp16 = 6,
|
||||||
Float = 7
|
Float = 7
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,21 +13,21 @@ namespace Ryujinx.Graphics.Gal
|
||||||
public bool IsBgra { get; private set; }
|
public bool IsBgra { get; private set; }
|
||||||
|
|
||||||
public GalVertexAttrib(
|
public GalVertexAttrib(
|
||||||
int Index,
|
int index,
|
||||||
bool IsConst,
|
bool isConst,
|
||||||
int Offset,
|
int offset,
|
||||||
byte[] Data,
|
byte[] data,
|
||||||
GalVertexAttribSize Size,
|
GalVertexAttribSize size,
|
||||||
GalVertexAttribType Type,
|
GalVertexAttribType type,
|
||||||
bool IsBgra)
|
bool isBgra)
|
||||||
{
|
{
|
||||||
this.Index = Index;
|
Index = index;
|
||||||
this.IsConst = IsConst;
|
IsConst = isConst;
|
||||||
this.Data = Data;
|
Data = data;
|
||||||
this.Offset = Offset;
|
Offset = offset;
|
||||||
this.Size = Size;
|
Size = size;
|
||||||
this.Type = Type;
|
Type = type;
|
||||||
this.IsBgra = IsBgra;
|
IsBgra = isBgra;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,11 +7,11 @@ namespace Ryujinx.Graphics.Gal
|
||||||
void LockCache();
|
void LockCache();
|
||||||
void UnlockCache();
|
void UnlockCache();
|
||||||
|
|
||||||
void Create(long Key, long Size);
|
void Create(long key, long size);
|
||||||
|
|
||||||
bool IsCached(long Key, long Size);
|
bool IsCached(long key, long size);
|
||||||
|
|
||||||
void SetData(long Key, long Size, IntPtr HostAddress);
|
void SetData(long key, long size, IntPtr hostAddress);
|
||||||
void SetData(long Key, byte[] Data);
|
void SetData(long key, byte[] data);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
namespace Ryujinx.Graphics.Gal
|
namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
public unsafe interface IGalMemory
|
public interface IGalMemory
|
||||||
{
|
{
|
||||||
int ReadInt32(long Position);
|
int ReadInt32(long position);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,10 +2,10 @@
|
||||||
{
|
{
|
||||||
public interface IGalPipeline
|
public interface IGalPipeline
|
||||||
{
|
{
|
||||||
void Bind(GalPipelineState State);
|
void Bind(GalPipelineState state);
|
||||||
void Unbind(GalPipelineState State);
|
void Unbind(GalPipelineState state);
|
||||||
|
|
||||||
void ResetDepthMask();
|
void ResetDepthMask();
|
||||||
void ResetColorMask(int Index);
|
void ResetColorMask(int index);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,29 +8,29 @@ namespace Ryujinx.Graphics.Gal
|
||||||
void UnlockCaches();
|
void UnlockCaches();
|
||||||
|
|
||||||
void ClearBuffers(
|
void ClearBuffers(
|
||||||
GalClearBufferFlags Flags,
|
GalClearBufferFlags flags,
|
||||||
int Attachment,
|
int attachment,
|
||||||
float Red,
|
float red,
|
||||||
float Green,
|
float green,
|
||||||
float Blue,
|
float blue,
|
||||||
float Alpha,
|
float alpha,
|
||||||
float Depth,
|
float depth,
|
||||||
int Stencil);
|
int stencil);
|
||||||
|
|
||||||
bool IsVboCached(long Key, long DataSize);
|
bool IsVboCached(long key, long dataSize);
|
||||||
|
|
||||||
bool IsIboCached(long Key, long DataSize);
|
bool IsIboCached(long key, long dataSize);
|
||||||
|
|
||||||
void CreateVbo(long Key, int DataSize, IntPtr HostAddress);
|
void CreateVbo(long key, int dataSize, IntPtr hostAddress);
|
||||||
void CreateVbo(long Key, byte[] Data);
|
void CreateVbo(long key, byte[] data);
|
||||||
|
|
||||||
void CreateIbo(long Key, int DataSize, IntPtr HostAddress);
|
void CreateIbo(long key, int dataSize, IntPtr hostAddress);
|
||||||
void CreateIbo(long Key, int DataSize, byte[] Buffer);
|
void CreateIbo(long key, int dataSize, byte[] buffer);
|
||||||
|
|
||||||
void SetIndexArray(int Size, GalIndexFormat Format);
|
void SetIndexArray(int size, GalIndexFormat format);
|
||||||
|
|
||||||
void DrawArrays(int First, int Count, GalPrimitiveType PrimType);
|
void DrawArrays(int first, int count, GalPrimitiveType primType);
|
||||||
|
|
||||||
void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType);
|
void DrawElements(long iboKey, int first, int vertexBase, GalPrimitiveType primType);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,42 +4,42 @@ namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
void Bind();
|
void Bind();
|
||||||
|
|
||||||
void BindColor(long Key, int Attachment);
|
void BindColor(long key, int attachment);
|
||||||
|
|
||||||
void UnbindColor(int Attachment);
|
void UnbindColor(int attachment);
|
||||||
|
|
||||||
void BindZeta(long Key);
|
void BindZeta(long key);
|
||||||
|
|
||||||
void UnbindZeta();
|
void UnbindZeta();
|
||||||
|
|
||||||
void Present(long Key);
|
void Present(long key);
|
||||||
|
|
||||||
void SetMap(int[] Map);
|
void SetMap(int[] map);
|
||||||
|
|
||||||
void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom);
|
void SetTransform(bool flipX, bool flipY, int top, int left, int right, int bottom);
|
||||||
|
|
||||||
void SetWindowSize(int Width, int Height);
|
void SetWindowSize(int width, int height);
|
||||||
|
|
||||||
void SetViewport(int Attachment, int X, int Y, int Width, int Height);
|
void SetViewport(int attachment, int x, int y, int width, int height);
|
||||||
|
|
||||||
void Render();
|
void Render();
|
||||||
|
|
||||||
void Copy(
|
void Copy(
|
||||||
GalImage SrcImage,
|
GalImage srcImage,
|
||||||
GalImage DstImage,
|
GalImage dstImage,
|
||||||
long SrcKey,
|
long srcKey,
|
||||||
long DstKey,
|
long dstKey,
|
||||||
int SrcLayer,
|
int srcLayer,
|
||||||
int DstLayer,
|
int dstLayer,
|
||||||
int SrcX0,
|
int srcX0,
|
||||||
int SrcY0,
|
int srcY0,
|
||||||
int SrcX1,
|
int srcX1,
|
||||||
int SrcY1,
|
int srcY1,
|
||||||
int DstX0,
|
int dstX0,
|
||||||
int DstY0,
|
int dstY0,
|
||||||
int DstX1,
|
int dstX1,
|
||||||
int DstY1);
|
int dstY1);
|
||||||
|
|
||||||
void Reinterpret(long Key, GalImage NewImage);
|
void Reinterpret(long key, GalImage newImage);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
public interface IGalRenderer
|
public interface IGalRenderer
|
||||||
{
|
{
|
||||||
void QueueAction(Action ActionMthd);
|
void QueueAction(Action actionMthd);
|
||||||
|
|
||||||
void RunActions();
|
void RunActions();
|
||||||
|
|
||||||
|
|
|
@ -4,16 +4,16 @@ namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
public interface IGalShader
|
public interface IGalShader
|
||||||
{
|
{
|
||||||
void Create(IGalMemory Memory, long Key, GalShaderType Type);
|
void Create(IGalMemory memory, long key, GalShaderType type);
|
||||||
|
|
||||||
void Create(IGalMemory Memory, long VpAPos, long Key, GalShaderType Type);
|
void Create(IGalMemory memory, long vpAPos, long key, GalShaderType type);
|
||||||
|
|
||||||
IEnumerable<ShaderDeclInfo> GetConstBufferUsage(long Key);
|
IEnumerable<ShaderDeclInfo> GetConstBufferUsage(long key);
|
||||||
IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key);
|
IEnumerable<ShaderDeclInfo> GetTextureUsage(long key);
|
||||||
|
|
||||||
void Bind(long Key);
|
void Bind(long key);
|
||||||
|
|
||||||
void Unbind(GalShaderType Type);
|
void Unbind(GalShaderType type);
|
||||||
|
|
||||||
void BindProgram();
|
void BindProgram();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,14 @@ namespace Ryujinx.Graphics.Gal
|
||||||
void LockCache();
|
void LockCache();
|
||||||
void UnlockCache();
|
void UnlockCache();
|
||||||
|
|
||||||
void Create(long Key, int Size, GalImage Image);
|
void Create(long key, int size, GalImage image);
|
||||||
|
|
||||||
void Create(long Key, byte[] Data, GalImage Image);
|
void Create(long key, byte[] data, GalImage image);
|
||||||
|
|
||||||
bool TryGetImage(long Key, out GalImage Image);
|
bool TryGetImage(long key, out GalImage image);
|
||||||
|
|
||||||
void Bind(long Key, int Index, GalImage Image);
|
void Bind(long key, int index, GalImage image);
|
||||||
|
|
||||||
void SetSampler(GalImage Image, GalTextureSampler Sampler);
|
void SetSampler(GalImage image, GalTextureSampler sampler);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
delegate void DeleteValue<T>(T Value);
|
delegate void DeleteValue<T>(T value);
|
||||||
}
|
}
|
|
@ -18,10 +18,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
public bool HasDepth => ImageUtils.HasDepth(Image.Format);
|
public bool HasDepth => ImageUtils.HasDepth(Image.Format);
|
||||||
public bool HasStencil => ImageUtils.HasStencil(Image.Format);
|
public bool HasStencil => ImageUtils.HasStencil(Image.Format);
|
||||||
|
|
||||||
public ImageHandler(int Handle, GalImage Image)
|
public ImageHandler(int handle, GalImage image)
|
||||||
{
|
{
|
||||||
this.Handle = Handle;
|
Handle = handle;
|
||||||
this.Image = Image;
|
Image = image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,191 +0,0 @@
|
||||||
using Ryujinx.Common;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
|
||||||
{
|
|
||||||
class OGLCachedResource<T>
|
|
||||||
{
|
|
||||||
public delegate void DeleteValue(T Value);
|
|
||||||
|
|
||||||
private const int MinTimeDelta = 5 * 60000;
|
|
||||||
private const int MaxRemovalsPerRun = 10;
|
|
||||||
|
|
||||||
private struct CacheBucket
|
|
||||||
{
|
|
||||||
public T Value { get; private set; }
|
|
||||||
|
|
||||||
public LinkedListNode<long> Node { get; private set; }
|
|
||||||
|
|
||||||
public long DataSize { get; private set; }
|
|
||||||
|
|
||||||
public long Timestamp { get; private set; }
|
|
||||||
|
|
||||||
public CacheBucket(T Value, long DataSize, LinkedListNode<long> Node)
|
|
||||||
{
|
|
||||||
this.Value = Value;
|
|
||||||
this.DataSize = DataSize;
|
|
||||||
this.Node = Node;
|
|
||||||
|
|
||||||
Timestamp = PerformanceCounter.ElapsedMilliseconds;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<long, CacheBucket> Cache;
|
|
||||||
|
|
||||||
private LinkedList<long> SortedCache;
|
|
||||||
|
|
||||||
private DeleteValue DeleteValueCallback;
|
|
||||||
|
|
||||||
private Queue<T> DeletePending;
|
|
||||||
|
|
||||||
private bool Locked;
|
|
||||||
|
|
||||||
private long MaxSize;
|
|
||||||
private long TotalSize;
|
|
||||||
|
|
||||||
public OGLCachedResource(DeleteValue DeleteValueCallback, long MaxSize)
|
|
||||||
{
|
|
||||||
this.MaxSize = MaxSize;
|
|
||||||
|
|
||||||
if (DeleteValueCallback == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(DeleteValueCallback));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.DeleteValueCallback = DeleteValueCallback;
|
|
||||||
|
|
||||||
Cache = new Dictionary<long, CacheBucket>();
|
|
||||||
|
|
||||||
SortedCache = new LinkedList<long>();
|
|
||||||
|
|
||||||
DeletePending = new Queue<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Lock()
|
|
||||||
{
|
|
||||||
Locked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Unlock()
|
|
||||||
{
|
|
||||||
Locked = false;
|
|
||||||
|
|
||||||
while (DeletePending.TryDequeue(out T Value))
|
|
||||||
{
|
|
||||||
DeleteValueCallback(Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
ClearCacheIfNeeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddOrUpdate(long Key, T Value, long Size)
|
|
||||||
{
|
|
||||||
if (!Locked)
|
|
||||||
{
|
|
||||||
ClearCacheIfNeeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
LinkedListNode<long> Node = SortedCache.AddLast(Key);
|
|
||||||
|
|
||||||
CacheBucket NewBucket = new CacheBucket(Value, Size, Node);
|
|
||||||
|
|
||||||
if (Cache.TryGetValue(Key, out CacheBucket Bucket))
|
|
||||||
{
|
|
||||||
if (Locked)
|
|
||||||
{
|
|
||||||
DeletePending.Enqueue(Bucket.Value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DeleteValueCallback(Bucket.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
SortedCache.Remove(Bucket.Node);
|
|
||||||
|
|
||||||
TotalSize -= Bucket.DataSize;
|
|
||||||
|
|
||||||
Cache[Key] = NewBucket;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Cache.Add(Key, NewBucket);
|
|
||||||
}
|
|
||||||
|
|
||||||
TotalSize += Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetValue(long Key, out T Value)
|
|
||||||
{
|
|
||||||
if (Cache.TryGetValue(Key, out CacheBucket Bucket))
|
|
||||||
{
|
|
||||||
Value = Bucket.Value;
|
|
||||||
|
|
||||||
SortedCache.Remove(Bucket.Node);
|
|
||||||
|
|
||||||
LinkedListNode<long> Node = SortedCache.AddLast(Key);
|
|
||||||
|
|
||||||
Cache[Key] = new CacheBucket(Value, Bucket.DataSize, Node);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value = default(T);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetSize(long Key, out long Size)
|
|
||||||
{
|
|
||||||
if (Cache.TryGetValue(Key, out CacheBucket Bucket))
|
|
||||||
{
|
|
||||||
Size = Bucket.DataSize;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Size = 0;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ClearCacheIfNeeded()
|
|
||||||
{
|
|
||||||
long Timestamp = PerformanceCounter.ElapsedMilliseconds;
|
|
||||||
|
|
||||||
int Count = 0;
|
|
||||||
|
|
||||||
while (Count++ < MaxRemovalsPerRun)
|
|
||||||
{
|
|
||||||
LinkedListNode<long> Node = SortedCache.First;
|
|
||||||
|
|
||||||
if (Node == null)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CacheBucket Bucket = Cache[Node.Value];
|
|
||||||
|
|
||||||
long TimeDelta = Timestamp - Bucket.Timestamp;
|
|
||||||
|
|
||||||
if (TimeDelta <= MinTimeDelta && !UnderMemoryPressure())
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SortedCache.Remove(Node);
|
|
||||||
|
|
||||||
Cache.Remove(Node.Value);
|
|
||||||
|
|
||||||
DeleteValueCallback(Bucket.Value);
|
|
||||||
|
|
||||||
TotalSize -= Bucket.DataSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool UnderMemoryPressure()
|
|
||||||
{
|
|
||||||
return TotalSize >= MaxSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
|
||||||
{
|
|
||||||
class OGLConstBuffer : IGalConstBuffer
|
|
||||||
{
|
|
||||||
private const long MaxConstBufferCacheSize = 64 * 1024 * 1024;
|
|
||||||
|
|
||||||
private OGLCachedResource<OGLStreamBuffer> Cache;
|
|
||||||
|
|
||||||
public OGLConstBuffer()
|
|
||||||
{
|
|
||||||
Cache = new OGLCachedResource<OGLStreamBuffer>(DeleteBuffer, MaxConstBufferCacheSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LockCache()
|
|
||||||
{
|
|
||||||
Cache.Lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UnlockCache()
|
|
||||||
{
|
|
||||||
Cache.Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Create(long Key, long Size)
|
|
||||||
{
|
|
||||||
OGLStreamBuffer Buffer = new OGLStreamBuffer(BufferTarget.UniformBuffer, Size);
|
|
||||||
|
|
||||||
Cache.AddOrUpdate(Key, Buffer, Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsCached(long Key, long Size)
|
|
||||||
{
|
|
||||||
return Cache.TryGetSize(Key, out long CachedSize) && CachedSize == Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetData(long Key, long Size, IntPtr HostAddress)
|
|
||||||
{
|
|
||||||
if (Cache.TryGetValue(Key, out OGLStreamBuffer Buffer))
|
|
||||||
{
|
|
||||||
Buffer.SetData(Size, HostAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetData(long Key, byte[] Data)
|
|
||||||
{
|
|
||||||
if (Cache.TryGetValue(Key, out OGLStreamBuffer Buffer))
|
|
||||||
{
|
|
||||||
Buffer.SetData(Data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetUbo(long Key, out int UboHandle)
|
|
||||||
{
|
|
||||||
if (Cache.TryGetValue(Key, out OGLStreamBuffer Buffer))
|
|
||||||
{
|
|
||||||
UboHandle = Buffer.Handle;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
UboHandle = 0;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void DeleteBuffer(OGLStreamBuffer Buffer)
|
|
||||||
{
|
|
||||||
Buffer.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
|
||||||
using Ryujinx.Common.Logging;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
|
||||||
{
|
|
||||||
static class OGLExtension
|
|
||||||
{
|
|
||||||
// Private lazy backing variables
|
|
||||||
private static Lazy<bool> s_EnhancedLayouts = new Lazy<bool>(() => HasExtension("GL_ARB_enhanced_layouts"));
|
|
||||||
private static Lazy<bool> s_TextureMirrorClamp = new Lazy<bool>(() => HasExtension("GL_EXT_texture_mirror_clamp"));
|
|
||||||
private static Lazy<bool> s_ViewportArray = new Lazy<bool>(() => HasExtension("GL_ARB_viewport_array"));
|
|
||||||
|
|
||||||
private static Lazy<bool> s_NvidiaDriver = new Lazy<bool>(() => IsNvidiaDriver());
|
|
||||||
|
|
||||||
// Public accessors
|
|
||||||
public static bool EnhancedLayouts => s_EnhancedLayouts.Value;
|
|
||||||
public static bool TextureMirrorClamp => s_TextureMirrorClamp.Value;
|
|
||||||
public static bool ViewportArray => s_ViewportArray.Value;
|
|
||||||
|
|
||||||
public static bool NvidiaDrvier => s_NvidiaDriver.Value;
|
|
||||||
|
|
||||||
private static bool HasExtension(string Name)
|
|
||||||
{
|
|
||||||
int NumExtensions = GL.GetInteger(GetPName.NumExtensions);
|
|
||||||
|
|
||||||
for (int Extension = 0; Extension < NumExtensions; Extension++)
|
|
||||||
{
|
|
||||||
if (GL.GetString(StringNameIndexed.Extensions, Extension) == Name)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.PrintInfo(LogClass.Gpu, $"OpenGL extension {Name} unavailable. You may experience some performance degredation");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsNvidiaDriver()
|
|
||||||
{
|
|
||||||
return GL.GetString(StringName.Vendor).Equals("NVIDIA Corporation");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Required
|
|
||||||
{
|
|
||||||
// Public accessors
|
|
||||||
public static bool EnhancedLayouts => s_EnhancedLayoutsRequired.Value;
|
|
||||||
public static bool TextureMirrorClamp => s_TextureMirrorClampRequired.Value;
|
|
||||||
public static bool ViewportArray => s_ViewportArrayRequired.Value;
|
|
||||||
|
|
||||||
// Private lazy backing variables
|
|
||||||
private static Lazy<bool> s_EnhancedLayoutsRequired = new Lazy<bool>(() => HasExtensionRequired(OGLExtension.EnhancedLayouts, "GL_ARB_enhanced_layouts"));
|
|
||||||
private static Lazy<bool> s_TextureMirrorClampRequired = new Lazy<bool>(() => HasExtensionRequired(OGLExtension.TextureMirrorClamp, "GL_EXT_texture_mirror_clamp"));
|
|
||||||
private static Lazy<bool> s_ViewportArrayRequired = new Lazy<bool>(() => HasExtensionRequired(OGLExtension.ViewportArray, "GL_ARB_viewport_array"));
|
|
||||||
|
|
||||||
private static bool HasExtensionRequired(bool Value, string Name)
|
|
||||||
{
|
|
||||||
if (Value)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.PrintWarning(LogClass.Gpu, $"Required OpenGL extension {Name} unavailable. You may experience some rendering issues");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
|
||||||
{
|
|
||||||
static class OGLLimit
|
|
||||||
{
|
|
||||||
private static Lazy<int> s_MaxUboSize = new Lazy<int>(() => GL.GetInteger(GetPName.MaxUniformBlockSize));
|
|
||||||
|
|
||||||
public static int MaxUboSize => s_MaxUboSize.Value;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,207 +0,0 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
|
||||||
{
|
|
||||||
class OGLRasterizer : IGalRasterizer
|
|
||||||
{
|
|
||||||
private const long MaxVertexBufferCacheSize = 128 * 1024 * 1024;
|
|
||||||
private const long MaxIndexBufferCacheSize = 64 * 1024 * 1024;
|
|
||||||
|
|
||||||
private int[] VertexBuffers;
|
|
||||||
|
|
||||||
private OGLCachedResource<int> VboCache;
|
|
||||||
private OGLCachedResource<int> IboCache;
|
|
||||||
|
|
||||||
private struct IbInfo
|
|
||||||
{
|
|
||||||
public int Count;
|
|
||||||
public int ElemSizeLog2;
|
|
||||||
|
|
||||||
public DrawElementsType Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IbInfo IndexBuffer;
|
|
||||||
|
|
||||||
public OGLRasterizer()
|
|
||||||
{
|
|
||||||
VertexBuffers = new int[32];
|
|
||||||
|
|
||||||
VboCache = new OGLCachedResource<int>(GL.DeleteBuffer, MaxVertexBufferCacheSize);
|
|
||||||
IboCache = new OGLCachedResource<int>(GL.DeleteBuffer, MaxIndexBufferCacheSize);
|
|
||||||
|
|
||||||
IndexBuffer = new IbInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LockCaches()
|
|
||||||
{
|
|
||||||
VboCache.Lock();
|
|
||||||
IboCache.Lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UnlockCaches()
|
|
||||||
{
|
|
||||||
VboCache.Unlock();
|
|
||||||
IboCache.Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearBuffers(
|
|
||||||
GalClearBufferFlags Flags,
|
|
||||||
int Attachment,
|
|
||||||
float Red,
|
|
||||||
float Green,
|
|
||||||
float Blue,
|
|
||||||
float Alpha,
|
|
||||||
float Depth,
|
|
||||||
int Stencil)
|
|
||||||
{
|
|
||||||
GL.ColorMask(
|
|
||||||
Attachment,
|
|
||||||
Flags.HasFlag(GalClearBufferFlags.ColorRed),
|
|
||||||
Flags.HasFlag(GalClearBufferFlags.ColorGreen),
|
|
||||||
Flags.HasFlag(GalClearBufferFlags.ColorBlue),
|
|
||||||
Flags.HasFlag(GalClearBufferFlags.ColorAlpha));
|
|
||||||
|
|
||||||
GL.ClearBuffer(ClearBuffer.Color, Attachment, new float[] { Red, Green, Blue, Alpha });
|
|
||||||
|
|
||||||
GL.ColorMask(Attachment, true, true, true, true);
|
|
||||||
GL.DepthMask(true);
|
|
||||||
|
|
||||||
if (Flags.HasFlag(GalClearBufferFlags.Depth))
|
|
||||||
{
|
|
||||||
GL.ClearBuffer(ClearBuffer.Depth, 0, ref Depth);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Flags.HasFlag(GalClearBufferFlags.Stencil))
|
|
||||||
{
|
|
||||||
GL.ClearBuffer(ClearBuffer.Stencil, 0, ref Stencil);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsVboCached(long Key, long DataSize)
|
|
||||||
{
|
|
||||||
return VboCache.TryGetSize(Key, out long Size) && Size == DataSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsIboCached(long Key, long DataSize)
|
|
||||||
{
|
|
||||||
return IboCache.TryGetSize(Key, out long Size) && Size == DataSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CreateVbo(long Key, int DataSize, IntPtr HostAddress)
|
|
||||||
{
|
|
||||||
int Handle = GL.GenBuffer();
|
|
||||||
|
|
||||||
VboCache.AddOrUpdate(Key, Handle, DataSize);
|
|
||||||
|
|
||||||
IntPtr Length = new IntPtr(DataSize);
|
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
|
|
||||||
GL.BufferData(BufferTarget.ArrayBuffer, Length, HostAddress, BufferUsageHint.StreamDraw);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CreateVbo(long Key, byte[] Data)
|
|
||||||
{
|
|
||||||
int Handle = GL.GenBuffer();
|
|
||||||
|
|
||||||
VboCache.AddOrUpdate(Key, Handle, Data.Length);
|
|
||||||
|
|
||||||
IntPtr Length = new IntPtr(Data.Length);
|
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
|
|
||||||
GL.BufferData(BufferTarget.ArrayBuffer, Length, Data, BufferUsageHint.StreamDraw);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CreateIbo(long Key, int DataSize, IntPtr HostAddress)
|
|
||||||
{
|
|
||||||
int Handle = GL.GenBuffer();
|
|
||||||
|
|
||||||
IboCache.AddOrUpdate(Key, Handle, (uint)DataSize);
|
|
||||||
|
|
||||||
IntPtr Length = new IntPtr(DataSize);
|
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle);
|
|
||||||
GL.BufferData(BufferTarget.ElementArrayBuffer, Length, HostAddress, BufferUsageHint.StreamDraw);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CreateIbo(long Key, int DataSize, byte[] Buffer)
|
|
||||||
{
|
|
||||||
int Handle = GL.GenBuffer();
|
|
||||||
|
|
||||||
IboCache.AddOrUpdate(Key, Handle, DataSize);
|
|
||||||
|
|
||||||
IntPtr Length = new IntPtr(Buffer.Length);
|
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle);
|
|
||||||
GL.BufferData(BufferTarget.ElementArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetIndexArray(int Size, GalIndexFormat Format)
|
|
||||||
{
|
|
||||||
IndexBuffer.Type = OGLEnumConverter.GetDrawElementsType(Format);
|
|
||||||
|
|
||||||
IndexBuffer.Count = Size >> (int)Format;
|
|
||||||
|
|
||||||
IndexBuffer.ElemSizeLog2 = (int)Format;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DrawArrays(int First, int Count, GalPrimitiveType PrimType)
|
|
||||||
{
|
|
||||||
if (Count == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PrimType == GalPrimitiveType.Quads)
|
|
||||||
{
|
|
||||||
for (int Offset = 0; Offset < Count; Offset += 4)
|
|
||||||
{
|
|
||||||
GL.DrawArrays(PrimitiveType.TriangleFan, First + Offset, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (PrimType == GalPrimitiveType.QuadStrip)
|
|
||||||
{
|
|
||||||
GL.DrawArrays(PrimitiveType.TriangleFan, First, 4);
|
|
||||||
|
|
||||||
for (int Offset = 2; Offset < Count; Offset += 2)
|
|
||||||
{
|
|
||||||
GL.DrawArrays(PrimitiveType.TriangleFan, First + Offset, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, Count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType)
|
|
||||||
{
|
|
||||||
if (!IboCache.TryGetValue(IboKey, out int IboHandle))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrimitiveType Mode = OGLEnumConverter.GetPrimitiveType(PrimType);
|
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, IboHandle);
|
|
||||||
|
|
||||||
First <<= IndexBuffer.ElemSizeLog2;
|
|
||||||
|
|
||||||
if (VertexBase != 0)
|
|
||||||
{
|
|
||||||
IntPtr Indices = new IntPtr(First);
|
|
||||||
|
|
||||||
GL.DrawElementsBaseVertex(Mode, IndexBuffer.Count, IndexBuffer.Type, Indices, VertexBase);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GL.DrawElements(Mode, IndexBuffer.Count, IndexBuffer.Type, First);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetVbo(long VboKey, out int VboHandle)
|
|
||||||
{
|
|
||||||
return VboCache.TryGetValue(VboKey, out VboHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,549 +0,0 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
|
||||||
using Ryujinx.Graphics.Texture;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
|
||||||
{
|
|
||||||
class OGLRenderTarget : IGalRenderTarget
|
|
||||||
{
|
|
||||||
private const int NativeWidth = 1280;
|
|
||||||
private const int NativeHeight = 720;
|
|
||||||
|
|
||||||
private const int RenderTargetsCount = GalPipelineState.RenderTargetsCount;
|
|
||||||
|
|
||||||
private struct Rect
|
|
||||||
{
|
|
||||||
public int X { get; private set; }
|
|
||||||
public int Y { get; private set; }
|
|
||||||
public int Width { get; private set; }
|
|
||||||
public int Height { get; private set; }
|
|
||||||
|
|
||||||
public Rect(int X, int Y, int Width, int Height)
|
|
||||||
{
|
|
||||||
this.X = X;
|
|
||||||
this.Y = Y;
|
|
||||||
this.Width = Width;
|
|
||||||
this.Height = Height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class FrameBufferAttachments
|
|
||||||
{
|
|
||||||
public int MapCount { get; set; }
|
|
||||||
|
|
||||||
public DrawBuffersEnum[] Map { get; private set; }
|
|
||||||
|
|
||||||
public long[] Colors { get; private set; }
|
|
||||||
|
|
||||||
public long Zeta { get; set; }
|
|
||||||
|
|
||||||
public FrameBufferAttachments()
|
|
||||||
{
|
|
||||||
Colors = new long[RenderTargetsCount];
|
|
||||||
|
|
||||||
Map = new DrawBuffersEnum[RenderTargetsCount];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update(FrameBufferAttachments Source)
|
|
||||||
{
|
|
||||||
for (int Index = 0; Index < RenderTargetsCount; Index++)
|
|
||||||
{
|
|
||||||
Map[Index] = Source.Map[Index];
|
|
||||||
|
|
||||||
Colors[Index] = Source.Colors[Index];
|
|
||||||
}
|
|
||||||
|
|
||||||
MapCount = Source.MapCount;
|
|
||||||
Zeta = Source.Zeta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int[] ColorHandles;
|
|
||||||
private int ZetaHandle;
|
|
||||||
|
|
||||||
private OGLTexture Texture;
|
|
||||||
|
|
||||||
private ImageHandler ReadTex;
|
|
||||||
|
|
||||||
private Rect Window;
|
|
||||||
|
|
||||||
private float[] Viewports;
|
|
||||||
|
|
||||||
private bool FlipX;
|
|
||||||
private bool FlipY;
|
|
||||||
|
|
||||||
private int CropTop;
|
|
||||||
private int CropLeft;
|
|
||||||
private int CropRight;
|
|
||||||
private int CropBottom;
|
|
||||||
|
|
||||||
//This framebuffer is used to attach guest rendertargets,
|
|
||||||
//think of it as a dummy OpenGL VAO
|
|
||||||
private int DummyFrameBuffer;
|
|
||||||
|
|
||||||
//These framebuffers are used to blit images
|
|
||||||
private int SrcFb;
|
|
||||||
private int DstFb;
|
|
||||||
|
|
||||||
private FrameBufferAttachments Attachments;
|
|
||||||
private FrameBufferAttachments OldAttachments;
|
|
||||||
|
|
||||||
private int CopyPBO;
|
|
||||||
|
|
||||||
public bool FramebufferSrgb { get; set; }
|
|
||||||
|
|
||||||
public OGLRenderTarget(OGLTexture Texture)
|
|
||||||
{
|
|
||||||
Attachments = new FrameBufferAttachments();
|
|
||||||
|
|
||||||
OldAttachments = new FrameBufferAttachments();
|
|
||||||
|
|
||||||
ColorHandles = new int[RenderTargetsCount];
|
|
||||||
|
|
||||||
Viewports = new float[RenderTargetsCount * 4];
|
|
||||||
|
|
||||||
this.Texture = Texture;
|
|
||||||
|
|
||||||
Texture.TextureDeleted += TextureDeletionHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TextureDeletionHandler(object Sender, int Handle)
|
|
||||||
{
|
|
||||||
//Texture was deleted, the handle is no longer valid, so
|
|
||||||
//reset all uses of this handle on a render target.
|
|
||||||
for (int Attachment = 0; Attachment < RenderTargetsCount; Attachment++)
|
|
||||||
{
|
|
||||||
if (ColorHandles[Attachment] == Handle)
|
|
||||||
{
|
|
||||||
ColorHandles[Attachment] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ZetaHandle == Handle)
|
|
||||||
{
|
|
||||||
ZetaHandle = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Bind()
|
|
||||||
{
|
|
||||||
if (DummyFrameBuffer == 0)
|
|
||||||
{
|
|
||||||
DummyFrameBuffer = GL.GenFramebuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
|
|
||||||
|
|
||||||
ImageHandler CachedImage;
|
|
||||||
|
|
||||||
for (int Attachment = 0; Attachment < RenderTargetsCount; Attachment++)
|
|
||||||
{
|
|
||||||
long Key = Attachments.Colors[Attachment];
|
|
||||||
|
|
||||||
int Handle = 0;
|
|
||||||
|
|
||||||
if (Key != 0 && Texture.TryGetImageHandler(Key, out CachedImage))
|
|
||||||
{
|
|
||||||
Handle = CachedImage.Handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Handle == ColorHandles[Attachment])
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.FramebufferTexture(
|
|
||||||
FramebufferTarget.DrawFramebuffer,
|
|
||||||
FramebufferAttachment.ColorAttachment0 + Attachment,
|
|
||||||
Handle,
|
|
||||||
0);
|
|
||||||
|
|
||||||
ColorHandles[Attachment] = Handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Attachments.Zeta != 0 && Texture.TryGetImageHandler(Attachments.Zeta, out CachedImage))
|
|
||||||
{
|
|
||||||
if (CachedImage.Handle != ZetaHandle)
|
|
||||||
{
|
|
||||||
if (CachedImage.HasDepth && CachedImage.HasStencil)
|
|
||||||
{
|
|
||||||
GL.FramebufferTexture(
|
|
||||||
FramebufferTarget.DrawFramebuffer,
|
|
||||||
FramebufferAttachment.DepthStencilAttachment,
|
|
||||||
CachedImage.Handle,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
else if (CachedImage.HasDepth)
|
|
||||||
{
|
|
||||||
GL.FramebufferTexture(
|
|
||||||
FramebufferTarget.DrawFramebuffer,
|
|
||||||
FramebufferAttachment.DepthAttachment,
|
|
||||||
CachedImage.Handle,
|
|
||||||
0);
|
|
||||||
|
|
||||||
GL.FramebufferTexture(
|
|
||||||
FramebufferTarget.DrawFramebuffer,
|
|
||||||
FramebufferAttachment.StencilAttachment,
|
|
||||||
0,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Invalid image format \"" + CachedImage.Format + "\" used as Zeta!");
|
|
||||||
}
|
|
||||||
|
|
||||||
ZetaHandle = CachedImage.Handle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ZetaHandle != 0)
|
|
||||||
{
|
|
||||||
GL.FramebufferTexture(
|
|
||||||
FramebufferTarget.DrawFramebuffer,
|
|
||||||
FramebufferAttachment.DepthStencilAttachment,
|
|
||||||
0,
|
|
||||||
0);
|
|
||||||
|
|
||||||
ZetaHandle = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OGLExtension.ViewportArray)
|
|
||||||
{
|
|
||||||
GL.ViewportArray(0, RenderTargetsCount, Viewports);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GL.Viewport(
|
|
||||||
(int)Viewports[0],
|
|
||||||
(int)Viewports[1],
|
|
||||||
(int)Viewports[2],
|
|
||||||
(int)Viewports[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Attachments.MapCount > 1)
|
|
||||||
{
|
|
||||||
GL.DrawBuffers(Attachments.MapCount, Attachments.Map);
|
|
||||||
}
|
|
||||||
else if (Attachments.MapCount == 1)
|
|
||||||
{
|
|
||||||
GL.DrawBuffer((DrawBufferMode)Attachments.Map[0]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GL.DrawBuffer(DrawBufferMode.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
OldAttachments.Update(Attachments);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BindColor(long Key, int Attachment)
|
|
||||||
{
|
|
||||||
Attachments.Colors[Attachment] = Key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UnbindColor(int Attachment)
|
|
||||||
{
|
|
||||||
Attachments.Colors[Attachment] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BindZeta(long Key)
|
|
||||||
{
|
|
||||||
Attachments.Zeta = Key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UnbindZeta()
|
|
||||||
{
|
|
||||||
Attachments.Zeta = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Present(long Key)
|
|
||||||
{
|
|
||||||
Texture.TryGetImageHandler(Key, out ReadTex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetMap(int[] Map)
|
|
||||||
{
|
|
||||||
if (Map != null)
|
|
||||||
{
|
|
||||||
Attachments.MapCount = Map.Length;
|
|
||||||
|
|
||||||
for (int Attachment = 0; Attachment < Attachments.MapCount; Attachment++)
|
|
||||||
{
|
|
||||||
Attachments.Map[Attachment] = DrawBuffersEnum.ColorAttachment0 + Map[Attachment];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Attachments.MapCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom)
|
|
||||||
{
|
|
||||||
this.FlipX = FlipX;
|
|
||||||
this.FlipY = FlipY;
|
|
||||||
|
|
||||||
CropTop = Top;
|
|
||||||
CropLeft = Left;
|
|
||||||
CropRight = Right;
|
|
||||||
CropBottom = Bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetWindowSize(int Width, int Height)
|
|
||||||
{
|
|
||||||
Window = new Rect(0, 0, Width, Height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetViewport(int Attachment, int X, int Y, int Width, int Height)
|
|
||||||
{
|
|
||||||
int Offset = Attachment * 4;
|
|
||||||
|
|
||||||
Viewports[Offset + 0] = X;
|
|
||||||
Viewports[Offset + 1] = Y;
|
|
||||||
Viewports[Offset + 2] = Width;
|
|
||||||
Viewports[Offset + 3] = Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Render()
|
|
||||||
{
|
|
||||||
if (ReadTex == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SrcX0, SrcX1, SrcY0, SrcY1;
|
|
||||||
|
|
||||||
if (CropLeft == 0 && CropRight == 0)
|
|
||||||
{
|
|
||||||
SrcX0 = 0;
|
|
||||||
SrcX1 = ReadTex.Width;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SrcX0 = CropLeft;
|
|
||||||
SrcX1 = CropRight;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CropTop == 0 && CropBottom == 0)
|
|
||||||
{
|
|
||||||
SrcY0 = 0;
|
|
||||||
SrcY1 = ReadTex.Height;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SrcY0 = CropTop;
|
|
||||||
SrcY1 = CropBottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
float RatioX = MathF.Min(1f, (Window.Height * (float)NativeWidth) / ((float)NativeHeight * Window.Width));
|
|
||||||
float RatioY = MathF.Min(1f, (Window.Width * (float)NativeHeight) / ((float)NativeWidth * Window.Height));
|
|
||||||
|
|
||||||
int DstWidth = (int)(Window.Width * RatioX);
|
|
||||||
int DstHeight = (int)(Window.Height * RatioY);
|
|
||||||
|
|
||||||
int DstPaddingX = (Window.Width - DstWidth) / 2;
|
|
||||||
int DstPaddingY = (Window.Height - DstHeight) / 2;
|
|
||||||
|
|
||||||
int DstX0 = FlipX ? Window.Width - DstPaddingX : DstPaddingX;
|
|
||||||
int DstX1 = FlipX ? DstPaddingX : Window.Width - DstPaddingX;
|
|
||||||
|
|
||||||
int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
|
|
||||||
int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
|
|
||||||
|
|
||||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
|
||||||
|
|
||||||
GL.Disable(EnableCap.FramebufferSrgb);
|
|
||||||
|
|
||||||
GL.BlitFramebuffer(
|
|
||||||
SrcX0,
|
|
||||||
SrcY0,
|
|
||||||
SrcX1,
|
|
||||||
SrcY1,
|
|
||||||
DstX0,
|
|
||||||
DstY0,
|
|
||||||
DstX1,
|
|
||||||
DstY1,
|
|
||||||
ClearBufferMask.ColorBufferBit,
|
|
||||||
BlitFramebufferFilter.Linear);
|
|
||||||
|
|
||||||
if (FramebufferSrgb)
|
|
||||||
{
|
|
||||||
GL.Enable(EnableCap.FramebufferSrgb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Copy(
|
|
||||||
GalImage SrcImage,
|
|
||||||
GalImage DstImage,
|
|
||||||
long SrcKey,
|
|
||||||
long DstKey,
|
|
||||||
int SrcLayer,
|
|
||||||
int DstLayer,
|
|
||||||
int SrcX0,
|
|
||||||
int SrcY0,
|
|
||||||
int SrcX1,
|
|
||||||
int SrcY1,
|
|
||||||
int DstX0,
|
|
||||||
int DstY0,
|
|
||||||
int DstX1,
|
|
||||||
int DstY1)
|
|
||||||
{
|
|
||||||
if (Texture.TryGetImageHandler(SrcKey, out ImageHandler SrcTex) &&
|
|
||||||
Texture.TryGetImageHandler(DstKey, out ImageHandler DstTex))
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (ImageUtils.IsArray(SrcImage.TextureTarget) && SrcLayer > 0)
|
|
||||||
{
|
|
||||||
GL.FramebufferTextureLayer(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0, SrcLayer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImageUtils.IsArray(DstImage.TextureTarget) && DstLayer > 0)
|
|
||||||
{
|
|
||||||
GL.FramebufferTextureLayer(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0, DstLayer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BlitFramebufferFilter Filter = BlitFramebufferFilter.Nearest;
|
|
||||||
|
|
||||||
if (SrcTex.HasColor)
|
|
||||||
{
|
|
||||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
|
||||||
|
|
||||||
Filter = BlitFramebufferFilter.Linear;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClearBufferMask Mask = GetClearMask(SrcTex);
|
|
||||||
|
|
||||||
GL.BlitFramebuffer(SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, Mask, Filter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Reinterpret(long Key, GalImage NewImage)
|
|
||||||
{
|
|
||||||
if (!Texture.TryGetImage(Key, out GalImage OldImage))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NewImage.Format == OldImage.Format &&
|
|
||||||
NewImage.Width == OldImage.Width &&
|
|
||||||
NewImage.Height == OldImage.Height &&
|
|
||||||
NewImage.Depth == OldImage.Depth &&
|
|
||||||
NewImage.LayerCount == OldImage.LayerCount &&
|
|
||||||
NewImage.TextureTarget == OldImage.TextureTarget)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CopyPBO == 0)
|
|
||||||
{
|
|
||||||
CopyPBO = GL.GenBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyPBO);
|
|
||||||
|
|
||||||
//The buffer should be large enough to hold the largest texture.
|
|
||||||
int BufferSize = Math.Max(ImageUtils.GetSize(OldImage),
|
|
||||||
ImageUtils.GetSize(NewImage));
|
|
||||||
|
|
||||||
GL.BufferData(BufferTarget.PixelPackBuffer, BufferSize, IntPtr.Zero, BufferUsageHint.StreamCopy);
|
|
||||||
|
|
||||||
if (!Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
(_, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(CachedImage.Format);
|
|
||||||
|
|
||||||
TextureTarget Target = ImageUtils.GetTextureTarget(NewImage.TextureTarget);
|
|
||||||
|
|
||||||
GL.BindTexture(Target, CachedImage.Handle);
|
|
||||||
|
|
||||||
GL.GetTexImage(Target, 0, Format, Type, IntPtr.Zero);
|
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
|
|
||||||
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyPBO);
|
|
||||||
|
|
||||||
GL.PixelStore(PixelStoreParameter.UnpackRowLength, OldImage.Width);
|
|
||||||
|
|
||||||
Texture.Create(Key, ImageUtils.GetSize(NewImage), NewImage);
|
|
||||||
|
|
||||||
GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0);
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ClearBufferMask GetClearMask(ImageHandler CachedImage)
|
|
||||||
{
|
|
||||||
return (CachedImage.HasColor ? ClearBufferMask.ColorBufferBit : 0) |
|
|
||||||
(CachedImage.HasDepth ? ClearBufferMask.DepthBufferBit : 0) |
|
|
||||||
(CachedImage.HasStencil ? ClearBufferMask.StencilBufferBit : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
|
||||||
{
|
|
||||||
public class OGLRenderer : IGalRenderer
|
|
||||||
{
|
|
||||||
public IGalConstBuffer Buffer { get; private set; }
|
|
||||||
|
|
||||||
public IGalRenderTarget RenderTarget { get; private set; }
|
|
||||||
|
|
||||||
public IGalRasterizer Rasterizer { get; private set; }
|
|
||||||
|
|
||||||
public IGalShader Shader { get; private set; }
|
|
||||||
|
|
||||||
public IGalPipeline Pipeline { get; private set; }
|
|
||||||
|
|
||||||
public IGalTexture Texture { get; private set; }
|
|
||||||
|
|
||||||
private ConcurrentQueue<Action> ActionsQueue;
|
|
||||||
|
|
||||||
public OGLRenderer()
|
|
||||||
{
|
|
||||||
Buffer = new OGLConstBuffer();
|
|
||||||
|
|
||||||
Texture = new OGLTexture();
|
|
||||||
|
|
||||||
RenderTarget = new OGLRenderTarget(Texture as OGLTexture);
|
|
||||||
|
|
||||||
Rasterizer = new OGLRasterizer();
|
|
||||||
|
|
||||||
Shader = new OGLShader(Buffer as OGLConstBuffer);
|
|
||||||
|
|
||||||
Pipeline = new OGLPipeline(
|
|
||||||
Buffer as OGLConstBuffer,
|
|
||||||
RenderTarget as OGLRenderTarget,
|
|
||||||
Rasterizer as OGLRasterizer,
|
|
||||||
Shader as OGLShader);
|
|
||||||
|
|
||||||
ActionsQueue = new ConcurrentQueue<Action>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void QueueAction(Action ActionMthd)
|
|
||||||
{
|
|
||||||
ActionsQueue.Enqueue(ActionMthd);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RunActions()
|
|
||||||
{
|
|
||||||
int Count = ActionsQueue.Count;
|
|
||||||
|
|
||||||
while (Count-- > 0 && ActionsQueue.TryDequeue(out Action RenderAction))
|
|
||||||
{
|
|
||||||
RenderAction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,298 +0,0 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
|
||||||
using Ryujinx.Graphics.Gal.Shader;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
|
||||||
{
|
|
||||||
class OGLShader : IGalShader
|
|
||||||
{
|
|
||||||
public const int ReservedCbufCount = 1;
|
|
||||||
|
|
||||||
private const int ExtraDataSize = 4;
|
|
||||||
|
|
||||||
public OGLShaderProgram Current;
|
|
||||||
|
|
||||||
private ConcurrentDictionary<long, OGLShaderStage> Stages;
|
|
||||||
|
|
||||||
private Dictionary<OGLShaderProgram, int> Programs;
|
|
||||||
|
|
||||||
public int CurrentProgramHandle { get; private set; }
|
|
||||||
|
|
||||||
private OGLConstBuffer Buffer;
|
|
||||||
|
|
||||||
private int ExtraUboHandle;
|
|
||||||
|
|
||||||
public OGLShader(OGLConstBuffer Buffer)
|
|
||||||
{
|
|
||||||
this.Buffer = Buffer;
|
|
||||||
|
|
||||||
Stages = new ConcurrentDictionary<long, OGLShaderStage>();
|
|
||||||
|
|
||||||
Programs = new Dictionary<OGLShaderProgram, int>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Create(IGalMemory Memory, long Key, GalShaderType Type)
|
|
||||||
{
|
|
||||||
Stages.GetOrAdd(Key, (Stage) => ShaderStageFactory(Memory, Key, 0, false, Type));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Create(IGalMemory Memory, long VpAPos, long Key, GalShaderType Type)
|
|
||||||
{
|
|
||||||
Stages.GetOrAdd(Key, (Stage) => ShaderStageFactory(Memory, VpAPos, Key, true, Type));
|
|
||||||
}
|
|
||||||
|
|
||||||
private OGLShaderStage ShaderStageFactory(
|
|
||||||
IGalMemory Memory,
|
|
||||||
long Position,
|
|
||||||
long PositionB,
|
|
||||||
bool IsDualVp,
|
|
||||||
GalShaderType Type)
|
|
||||||
{
|
|
||||||
GlslProgram Program;
|
|
||||||
|
|
||||||
GlslDecompiler Decompiler = new GlslDecompiler(OGLLimit.MaxUboSize, OGLExtension.NvidiaDrvier);
|
|
||||||
|
|
||||||
int ShaderDumpIndex = ShaderDumper.DumpIndex;
|
|
||||||
|
|
||||||
if (IsDualVp)
|
|
||||||
{
|
|
||||||
ShaderDumper.Dump(Memory, Position, Type, "a");
|
|
||||||
ShaderDumper.Dump(Memory, PositionB, Type, "b");
|
|
||||||
|
|
||||||
Program = Decompiler.Decompile(Memory, Position, PositionB, Type);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ShaderDumper.Dump(Memory, Position, Type);
|
|
||||||
|
|
||||||
Program = Decompiler.Decompile(Memory, Position, Type);
|
|
||||||
}
|
|
||||||
|
|
||||||
string Code = Program.Code;
|
|
||||||
|
|
||||||
if (ShaderDumper.IsDumpEnabled())
|
|
||||||
{
|
|
||||||
Code = "//Shader " + ShaderDumpIndex + Environment.NewLine + Code;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new OGLShaderStage(Type, Code, Program.Uniforms, Program.Textures);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<ShaderDeclInfo> GetConstBufferUsage(long Key)
|
|
||||||
{
|
|
||||||
if (Stages.TryGetValue(Key, out OGLShaderStage Stage))
|
|
||||||
{
|
|
||||||
return Stage.ConstBufferUsage;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Enumerable.Empty<ShaderDeclInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key)
|
|
||||||
{
|
|
||||||
if (Stages.TryGetValue(Key, out OGLShaderStage Stage))
|
|
||||||
{
|
|
||||||
return Stage.TextureUsage;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Enumerable.Empty<ShaderDeclInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe void SetExtraData(float FlipX, float FlipY, int Instance)
|
|
||||||
{
|
|
||||||
BindProgram();
|
|
||||||
|
|
||||||
EnsureExtraBlock();
|
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.UniformBuffer, ExtraUboHandle);
|
|
||||||
|
|
||||||
float* Data = stackalloc float[ExtraDataSize];
|
|
||||||
Data[0] = FlipX;
|
|
||||||
Data[1] = FlipY;
|
|
||||||
Data[2] = BitConverter.Int32BitsToSingle(Instance);
|
|
||||||
|
|
||||||
//Invalidate buffer
|
|
||||||
GL.BufferData(BufferTarget.UniformBuffer, ExtraDataSize * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw);
|
|
||||||
|
|
||||||
GL.BufferSubData(BufferTarget.UniformBuffer, IntPtr.Zero, ExtraDataSize * sizeof(float), (IntPtr)Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Bind(long Key)
|
|
||||||
{
|
|
||||||
if (Stages.TryGetValue(Key, out OGLShaderStage Stage))
|
|
||||||
{
|
|
||||||
Bind(Stage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Bind(OGLShaderStage Stage)
|
|
||||||
{
|
|
||||||
if (Stage.Type == GalShaderType.Geometry)
|
|
||||||
{
|
|
||||||
//Enhanced layouts are required for Geometry shaders
|
|
||||||
//skip this stage if current driver has no ARB_enhanced_layouts
|
|
||||||
if (!OGLExtension.EnhancedLayouts)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (Stage.Type)
|
|
||||||
{
|
|
||||||
case GalShaderType.Vertex: Current.Vertex = Stage; break;
|
|
||||||
case GalShaderType.TessControl: Current.TessControl = Stage; break;
|
|
||||||
case GalShaderType.TessEvaluation: Current.TessEvaluation = Stage; break;
|
|
||||||
case GalShaderType.Geometry: Current.Geometry = Stage; break;
|
|
||||||
case GalShaderType.Fragment: Current.Fragment = Stage; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Unbind(GalShaderType Type)
|
|
||||||
{
|
|
||||||
switch (Type)
|
|
||||||
{
|
|
||||||
case GalShaderType.Vertex: Current.Vertex = null; break;
|
|
||||||
case GalShaderType.TessControl: Current.TessControl = null; break;
|
|
||||||
case GalShaderType.TessEvaluation: Current.TessEvaluation = null; break;
|
|
||||||
case GalShaderType.Geometry: Current.Geometry = null; break;
|
|
||||||
case GalShaderType.Fragment: Current.Fragment = null; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BindProgram()
|
|
||||||
{
|
|
||||||
if (Current.Vertex == null ||
|
|
||||||
Current.Fragment == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Programs.TryGetValue(Current, out int Handle))
|
|
||||||
{
|
|
||||||
Handle = GL.CreateProgram();
|
|
||||||
|
|
||||||
AttachIfNotNull(Handle, Current.Vertex);
|
|
||||||
AttachIfNotNull(Handle, Current.TessControl);
|
|
||||||
AttachIfNotNull(Handle, Current.TessEvaluation);
|
|
||||||
AttachIfNotNull(Handle, Current.Geometry);
|
|
||||||
AttachIfNotNull(Handle, Current.Fragment);
|
|
||||||
|
|
||||||
GL.LinkProgram(Handle);
|
|
||||||
|
|
||||||
CheckProgramLink(Handle);
|
|
||||||
|
|
||||||
BindUniformBlocks(Handle);
|
|
||||||
BindTextureLocations(Handle);
|
|
||||||
|
|
||||||
Programs.Add(Current, Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.UseProgram(Handle);
|
|
||||||
|
|
||||||
CurrentProgramHandle = Handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EnsureExtraBlock()
|
|
||||||
{
|
|
||||||
if (ExtraUboHandle == 0)
|
|
||||||
{
|
|
||||||
ExtraUboHandle = GL.GenBuffer();
|
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.UniformBuffer, ExtraUboHandle);
|
|
||||||
|
|
||||||
GL.BufferData(BufferTarget.UniformBuffer, ExtraDataSize * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw);
|
|
||||||
|
|
||||||
GL.BindBufferBase(BufferRangeTarget.UniformBuffer, 0, ExtraUboHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AttachIfNotNull(int ProgramHandle, OGLShaderStage Stage)
|
|
||||||
{
|
|
||||||
if (Stage != null)
|
|
||||||
{
|
|
||||||
Stage.Compile();
|
|
||||||
|
|
||||||
GL.AttachShader(ProgramHandle, Stage.Handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BindUniformBlocks(int ProgramHandle)
|
|
||||||
{
|
|
||||||
int ExtraBlockindex = GL.GetUniformBlockIndex(ProgramHandle, GlslDecl.ExtraUniformBlockName);
|
|
||||||
|
|
||||||
GL.UniformBlockBinding(ProgramHandle, ExtraBlockindex, 0);
|
|
||||||
|
|
||||||
int FreeBinding = ReservedCbufCount;
|
|
||||||
|
|
||||||
void BindUniformBlocksIfNotNull(OGLShaderStage Stage)
|
|
||||||
{
|
|
||||||
if (Stage != null)
|
|
||||||
{
|
|
||||||
foreach (ShaderDeclInfo DeclInfo in Stage.ConstBufferUsage)
|
|
||||||
{
|
|
||||||
int BlockIndex = GL.GetUniformBlockIndex(ProgramHandle, DeclInfo.Name);
|
|
||||||
|
|
||||||
if (BlockIndex < 0)
|
|
||||||
{
|
|
||||||
//It is expected that its found, if it's not then driver might be in a malfunction
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.UniformBlockBinding(ProgramHandle, BlockIndex, FreeBinding);
|
|
||||||
|
|
||||||
FreeBinding++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BindUniformBlocksIfNotNull(Current.Vertex);
|
|
||||||
BindUniformBlocksIfNotNull(Current.TessControl);
|
|
||||||
BindUniformBlocksIfNotNull(Current.TessEvaluation);
|
|
||||||
BindUniformBlocksIfNotNull(Current.Geometry);
|
|
||||||
BindUniformBlocksIfNotNull(Current.Fragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BindTextureLocations(int ProgramHandle)
|
|
||||||
{
|
|
||||||
int Index = 0;
|
|
||||||
|
|
||||||
void BindTexturesIfNotNull(OGLShaderStage Stage)
|
|
||||||
{
|
|
||||||
if (Stage != null)
|
|
||||||
{
|
|
||||||
foreach (ShaderDeclInfo Decl in Stage.TextureUsage)
|
|
||||||
{
|
|
||||||
int Location = GL.GetUniformLocation(ProgramHandle, Decl.Name);
|
|
||||||
|
|
||||||
GL.Uniform1(Location, Index);
|
|
||||||
|
|
||||||
Index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.UseProgram(ProgramHandle);
|
|
||||||
|
|
||||||
BindTexturesIfNotNull(Current.Vertex);
|
|
||||||
BindTexturesIfNotNull(Current.TessControl);
|
|
||||||
BindTexturesIfNotNull(Current.TessEvaluation);
|
|
||||||
BindTexturesIfNotNull(Current.Geometry);
|
|
||||||
BindTexturesIfNotNull(Current.Fragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CheckProgramLink(int Handle)
|
|
||||||
{
|
|
||||||
int Status = 0;
|
|
||||||
|
|
||||||
GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out Status);
|
|
||||||
|
|
||||||
if (Status == 0)
|
|
||||||
{
|
|
||||||
throw new ShaderException(GL.GetProgramInfoLog(Handle));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,86 +0,0 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
|
||||||
{
|
|
||||||
struct OGLShaderProgram
|
|
||||||
{
|
|
||||||
public OGLShaderStage Vertex;
|
|
||||||
public OGLShaderStage TessControl;
|
|
||||||
public OGLShaderStage TessEvaluation;
|
|
||||||
public OGLShaderStage Geometry;
|
|
||||||
public OGLShaderStage Fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
class OGLShaderStage : IDisposable
|
|
||||||
{
|
|
||||||
public int Handle { get; private set; }
|
|
||||||
|
|
||||||
public bool IsCompiled { get; private set; }
|
|
||||||
|
|
||||||
public GalShaderType Type { get; private set; }
|
|
||||||
|
|
||||||
public string Code { get; private set; }
|
|
||||||
|
|
||||||
public IEnumerable<ShaderDeclInfo> ConstBufferUsage { get; private set; }
|
|
||||||
public IEnumerable<ShaderDeclInfo> TextureUsage { get; private set; }
|
|
||||||
|
|
||||||
public OGLShaderStage(
|
|
||||||
GalShaderType Type,
|
|
||||||
string Code,
|
|
||||||
IEnumerable<ShaderDeclInfo> ConstBufferUsage,
|
|
||||||
IEnumerable<ShaderDeclInfo> TextureUsage)
|
|
||||||
{
|
|
||||||
this.Type = Type;
|
|
||||||
this.Code = Code;
|
|
||||||
this.ConstBufferUsage = ConstBufferUsage;
|
|
||||||
this.TextureUsage = TextureUsage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Compile()
|
|
||||||
{
|
|
||||||
if (Handle == 0)
|
|
||||||
{
|
|
||||||
Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type));
|
|
||||||
|
|
||||||
CompileAndCheck(Handle, Code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool Disposing)
|
|
||||||
{
|
|
||||||
if (Disposing && Handle != 0)
|
|
||||||
{
|
|
||||||
GL.DeleteShader(Handle);
|
|
||||||
|
|
||||||
Handle = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void CompileAndCheck(int Handle, string Code)
|
|
||||||
{
|
|
||||||
GL.ShaderSource(Handle, Code);
|
|
||||||
GL.CompileShader(Handle);
|
|
||||||
|
|
||||||
CheckCompilation(Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CheckCompilation(int Handle)
|
|
||||||
{
|
|
||||||
int Status = 0;
|
|
||||||
|
|
||||||
GL.GetShader(Handle, ShaderParameter.CompileStatus, out Status);
|
|
||||||
|
|
||||||
if (Status == 0)
|
|
||||||
{
|
|
||||||
throw new ShaderException(GL.GetShaderInfoLog(Handle));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,381 +0,0 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
|
||||||
using Ryujinx.Graphics.Texture;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
|
||||||
{
|
|
||||||
class OGLTexture : IGalTexture
|
|
||||||
{
|
|
||||||
private const long MaxTextureCacheSize = 768 * 1024 * 1024;
|
|
||||||
|
|
||||||
private OGLCachedResource<ImageHandler> TextureCache;
|
|
||||||
|
|
||||||
public EventHandler<int> TextureDeleted { get; set; }
|
|
||||||
|
|
||||||
public OGLTexture()
|
|
||||||
{
|
|
||||||
TextureCache = new OGLCachedResource<ImageHandler>(DeleteTexture, MaxTextureCacheSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LockCache()
|
|
||||||
{
|
|
||||||
TextureCache.Lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UnlockCache()
|
|
||||||
{
|
|
||||||
TextureCache.Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DeleteTexture(ImageHandler CachedImage)
|
|
||||||
{
|
|
||||||
TextureDeleted?.Invoke(this, CachedImage.Handle);
|
|
||||||
|
|
||||||
GL.DeleteTexture(CachedImage.Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Create(long Key, int Size, GalImage Image)
|
|
||||||
{
|
|
||||||
int Handle = GL.GenTexture();
|
|
||||||
|
|
||||||
TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget);
|
|
||||||
|
|
||||||
GL.BindTexture(Target, Handle);
|
|
||||||
|
|
||||||
const int Level = 0; //TODO: Support mipmap textures.
|
|
||||||
const int Border = 0;
|
|
||||||
|
|
||||||
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Size);
|
|
||||||
|
|
||||||
if (ImageUtils.IsCompressed(Image.Format))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Surfaces with compressed formats are not supported!");
|
|
||||||
}
|
|
||||||
|
|
||||||
(PixelInternalFormat InternalFmt,
|
|
||||||
PixelFormat Format,
|
|
||||||
PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
|
|
||||||
|
|
||||||
switch (Target)
|
|
||||||
{
|
|
||||||
case TextureTarget.Texture1D:
|
|
||||||
GL.TexImage1D(
|
|
||||||
Target,
|
|
||||||
Level,
|
|
||||||
InternalFmt,
|
|
||||||
Image.Width,
|
|
||||||
Border,
|
|
||||||
Format,
|
|
||||||
Type,
|
|
||||||
IntPtr.Zero);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TextureTarget.Texture2D:
|
|
||||||
GL.TexImage2D(
|
|
||||||
Target,
|
|
||||||
Level,
|
|
||||||
InternalFmt,
|
|
||||||
Image.Width,
|
|
||||||
Image.Height,
|
|
||||||
Border,
|
|
||||||
Format,
|
|
||||||
Type,
|
|
||||||
IntPtr.Zero);
|
|
||||||
break;
|
|
||||||
case TextureTarget.Texture3D:
|
|
||||||
GL.TexImage3D(
|
|
||||||
Target,
|
|
||||||
Level,
|
|
||||||
InternalFmt,
|
|
||||||
Image.Width,
|
|
||||||
Image.Height,
|
|
||||||
Image.Depth,
|
|
||||||
Border,
|
|
||||||
Format,
|
|
||||||
Type,
|
|
||||||
IntPtr.Zero);
|
|
||||||
break;
|
|
||||||
case TextureTarget.Texture2DArray:
|
|
||||||
GL.TexImage3D(
|
|
||||||
Target,
|
|
||||||
Level,
|
|
||||||
InternalFmt,
|
|
||||||
Image.Width,
|
|
||||||
Image.Height,
|
|
||||||
Image.LayerCount,
|
|
||||||
Border,
|
|
||||||
Format,
|
|
||||||
Type,
|
|
||||||
IntPtr.Zero);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException($"Unsupported texture target type: {Target}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Create(long Key, byte[] Data, GalImage Image)
|
|
||||||
{
|
|
||||||
int Handle = GL.GenTexture();
|
|
||||||
|
|
||||||
TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget);
|
|
||||||
|
|
||||||
GL.BindTexture(Target, Handle);
|
|
||||||
|
|
||||||
const int Level = 0; //TODO: Support mipmap textures.
|
|
||||||
const int Border = 0;
|
|
||||||
|
|
||||||
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length);
|
|
||||||
|
|
||||||
if (ImageUtils.IsCompressed(Image.Format) && !IsAstc(Image.Format))
|
|
||||||
{
|
|
||||||
InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format);
|
|
||||||
|
|
||||||
switch (Target)
|
|
||||||
{
|
|
||||||
case TextureTarget.Texture1D:
|
|
||||||
GL.CompressedTexImage1D(
|
|
||||||
Target,
|
|
||||||
Level,
|
|
||||||
InternalFmt,
|
|
||||||
Image.Width,
|
|
||||||
Border,
|
|
||||||
Data.Length,
|
|
||||||
Data);
|
|
||||||
break;
|
|
||||||
case TextureTarget.Texture2D:
|
|
||||||
GL.CompressedTexImage2D(
|
|
||||||
Target,
|
|
||||||
Level,
|
|
||||||
InternalFmt,
|
|
||||||
Image.Width,
|
|
||||||
Image.Height,
|
|
||||||
Border,
|
|
||||||
Data.Length,
|
|
||||||
Data);
|
|
||||||
break;
|
|
||||||
case TextureTarget.Texture3D:
|
|
||||||
GL.CompressedTexImage3D(
|
|
||||||
Target,
|
|
||||||
Level,
|
|
||||||
InternalFmt,
|
|
||||||
Image.Width,
|
|
||||||
Image.Height,
|
|
||||||
Image.Depth,
|
|
||||||
Border,
|
|
||||||
Data.Length,
|
|
||||||
Data);
|
|
||||||
break;
|
|
||||||
case TextureTarget.Texture2DArray:
|
|
||||||
GL.CompressedTexImage3D(
|
|
||||||
Target,
|
|
||||||
Level,
|
|
||||||
InternalFmt,
|
|
||||||
Image.Width,
|
|
||||||
Image.Height,
|
|
||||||
Image.LayerCount,
|
|
||||||
Border,
|
|
||||||
Data.Length,
|
|
||||||
Data);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException($"Unsupported texture target type: {Target}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//TODO: Use KHR_texture_compression_astc_hdr when available
|
|
||||||
if (IsAstc(Image.Format))
|
|
||||||
{
|
|
||||||
int TextureBlockWidth = ImageUtils.GetBlockWidth(Image.Format);
|
|
||||||
int TextureBlockHeight = ImageUtils.GetBlockHeight(Image.Format);
|
|
||||||
int TextureBlockDepth = ImageUtils.GetBlockDepth(Image.Format);
|
|
||||||
|
|
||||||
Data = ASTCDecoder.DecodeToRGBA8888(
|
|
||||||
Data,
|
|
||||||
TextureBlockWidth,
|
|
||||||
TextureBlockHeight,
|
|
||||||
TextureBlockDepth,
|
|
||||||
Image.Width,
|
|
||||||
Image.Height,
|
|
||||||
Image.Depth);
|
|
||||||
|
|
||||||
Image.Format = GalImageFormat.RGBA8 | (Image.Format & GalImageFormat.TypeMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
(PixelInternalFormat InternalFmt,
|
|
||||||
PixelFormat Format,
|
|
||||||
PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
|
|
||||||
|
|
||||||
|
|
||||||
switch (Target)
|
|
||||||
{
|
|
||||||
case TextureTarget.Texture1D:
|
|
||||||
GL.TexImage1D(
|
|
||||||
Target,
|
|
||||||
Level,
|
|
||||||
InternalFmt,
|
|
||||||
Image.Width,
|
|
||||||
Border,
|
|
||||||
Format,
|
|
||||||
Type,
|
|
||||||
Data);
|
|
||||||
break;
|
|
||||||
case TextureTarget.Texture2D:
|
|
||||||
GL.TexImage2D(
|
|
||||||
Target,
|
|
||||||
Level,
|
|
||||||
InternalFmt,
|
|
||||||
Image.Width,
|
|
||||||
Image.Height,
|
|
||||||
Border,
|
|
||||||
Format,
|
|
||||||
Type,
|
|
||||||
Data);
|
|
||||||
break;
|
|
||||||
case TextureTarget.Texture3D:
|
|
||||||
GL.TexImage3D(
|
|
||||||
Target,
|
|
||||||
Level,
|
|
||||||
InternalFmt,
|
|
||||||
Image.Width,
|
|
||||||
Image.Height,
|
|
||||||
Image.Depth,
|
|
||||||
Border,
|
|
||||||
Format,
|
|
||||||
Type,
|
|
||||||
Data);
|
|
||||||
break;
|
|
||||||
case TextureTarget.Texture2DArray:
|
|
||||||
GL.TexImage3D(
|
|
||||||
Target,
|
|
||||||
Level,
|
|
||||||
InternalFmt,
|
|
||||||
Image.Width,
|
|
||||||
Image.Height,
|
|
||||||
Image.LayerCount,
|
|
||||||
Border,
|
|
||||||
Format,
|
|
||||||
Type,
|
|
||||||
Data);
|
|
||||||
break;
|
|
||||||
case TextureTarget.TextureCubeMap:
|
|
||||||
Span<byte> Array = new Span<byte>(Data);
|
|
||||||
|
|
||||||
int FaceSize = ImageUtils.GetSize(Image) / 6;
|
|
||||||
|
|
||||||
for (int Face = 0; Face < 6; Face++)
|
|
||||||
{
|
|
||||||
GL.TexImage2D(
|
|
||||||
TextureTarget.TextureCubeMapPositiveX + Face,
|
|
||||||
Level,
|
|
||||||
InternalFmt,
|
|
||||||
Image.Width,
|
|
||||||
Image.Height,
|
|
||||||
Border,
|
|
||||||
Format,
|
|
||||||
Type,
|
|
||||||
Array.Slice(Face * FaceSize, FaceSize).ToArray());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException($"Unsupported texture target type: {Target}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsAstc(GalImageFormat Format)
|
|
||||||
{
|
|
||||||
Format &= GalImageFormat.FormatMask;
|
|
||||||
|
|
||||||
return Format > GalImageFormat.Astc2DStart && Format < GalImageFormat.Astc2DEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetImage(long Key, out GalImage Image)
|
|
||||||
{
|
|
||||||
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
|
|
||||||
{
|
|
||||||
Image = CachedImage.Image;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Image = default(GalImage);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetImageHandler(long Key, out ImageHandler CachedImage)
|
|
||||||
{
|
|
||||||
if (TextureCache.TryGetValue(Key, out CachedImage))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
CachedImage = null;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Bind(long Key, int Index, GalImage Image)
|
|
||||||
{
|
|
||||||
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
|
|
||||||
{
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
|
||||||
|
|
||||||
TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget);
|
|
||||||
|
|
||||||
GL.BindTexture(Target, 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(Target, TextureParameterName.TextureSwizzleRgba, SwizzleRgba);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetSampler(GalImage Image, GalTextureSampler Sampler)
|
|
||||||
{
|
|
||||||
int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU);
|
|
||||||
int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV);
|
|
||||||
int WrapR = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressP);
|
|
||||||
|
|
||||||
int MinFilter = (int)OGLEnumConverter.GetTextureMinFilter(Sampler.MinFilter, Sampler.MipFilter);
|
|
||||||
int MagFilter = (int)OGLEnumConverter.GetTextureMagFilter(Sampler.MagFilter);
|
|
||||||
|
|
||||||
TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget);
|
|
||||||
|
|
||||||
GL.TexParameter(Target, TextureParameterName.TextureWrapS, WrapS);
|
|
||||||
GL.TexParameter(Target, TextureParameterName.TextureWrapT, WrapT);
|
|
||||||
GL.TexParameter(Target, TextureParameterName.TextureWrapR, WrapR);
|
|
||||||
|
|
||||||
GL.TexParameter(Target, TextureParameterName.TextureMinFilter, MinFilter);
|
|
||||||
GL.TexParameter(Target, TextureParameterName.TextureMagFilter, MagFilter);
|
|
||||||
|
|
||||||
float[] Color = new float[]
|
|
||||||
{
|
|
||||||
Sampler.BorderColor.Red,
|
|
||||||
Sampler.BorderColor.Green,
|
|
||||||
Sampler.BorderColor.Blue,
|
|
||||||
Sampler.BorderColor.Alpha
|
|
||||||
};
|
|
||||||
|
|
||||||
GL.TexParameter(Target, TextureParameterName.TextureBorderColor, Color);
|
|
||||||
|
|
||||||
if (Sampler.DepthCompare)
|
|
||||||
{
|
|
||||||
GL.TexParameter(Target, TextureParameterName.TextureCompareMode, (int)All.CompareRToTexture);
|
|
||||||
GL.TexParameter(Target, TextureParameterName.TextureCompareFunc, (int)OGLEnumConverter.GetDepthCompareFunc(Sampler.DepthCompareFunc));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GL.TexParameter(Target, TextureParameterName.TextureCompareMode, (int)All.None);
|
|
||||||
GL.TexParameter(Target, TextureParameterName.TextureCompareFunc, (int)All.Never);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
191
Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs
Normal file
191
Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
using Ryujinx.Common;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
{
|
||||||
|
class OglCachedResource<T>
|
||||||
|
{
|
||||||
|
public delegate void DeleteValue(T value);
|
||||||
|
|
||||||
|
private const int MinTimeDelta = 5 * 60000;
|
||||||
|
private const int MaxRemovalsPerRun = 10;
|
||||||
|
|
||||||
|
private struct CacheBucket
|
||||||
|
{
|
||||||
|
public T Value { get; private set; }
|
||||||
|
|
||||||
|
public LinkedListNode<long> Node { get; private set; }
|
||||||
|
|
||||||
|
public long DataSize { get; private set; }
|
||||||
|
|
||||||
|
public long Timestamp { get; private set; }
|
||||||
|
|
||||||
|
public CacheBucket(T value, long dataSize, LinkedListNode<long> node)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
DataSize = dataSize;
|
||||||
|
Node = node;
|
||||||
|
|
||||||
|
Timestamp = PerformanceCounter.ElapsedMilliseconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<long, CacheBucket> _cache;
|
||||||
|
|
||||||
|
private LinkedList<long> _sortedCache;
|
||||||
|
|
||||||
|
private DeleteValue _deleteValueCallback;
|
||||||
|
|
||||||
|
private Queue<T> _deletePending;
|
||||||
|
|
||||||
|
private bool _locked;
|
||||||
|
|
||||||
|
private long _maxSize;
|
||||||
|
private long _totalSize;
|
||||||
|
|
||||||
|
public OglCachedResource(DeleteValue deleteValueCallback, long maxSize)
|
||||||
|
{
|
||||||
|
_maxSize = maxSize;
|
||||||
|
|
||||||
|
if (deleteValueCallback == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(deleteValueCallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
_deleteValueCallback = deleteValueCallback;
|
||||||
|
|
||||||
|
_cache = new Dictionary<long, CacheBucket>();
|
||||||
|
|
||||||
|
_sortedCache = new LinkedList<long>();
|
||||||
|
|
||||||
|
_deletePending = new Queue<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Lock()
|
||||||
|
{
|
||||||
|
_locked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unlock()
|
||||||
|
{
|
||||||
|
_locked = false;
|
||||||
|
|
||||||
|
while (_deletePending.TryDequeue(out T value))
|
||||||
|
{
|
||||||
|
_deleteValueCallback(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearCacheIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddOrUpdate(long key, T value, long size)
|
||||||
|
{
|
||||||
|
if (!_locked)
|
||||||
|
{
|
||||||
|
ClearCacheIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedListNode<long> node = _sortedCache.AddLast(key);
|
||||||
|
|
||||||
|
CacheBucket newBucket = new CacheBucket(value, size, node);
|
||||||
|
|
||||||
|
if (_cache.TryGetValue(key, out CacheBucket bucket))
|
||||||
|
{
|
||||||
|
if (_locked)
|
||||||
|
{
|
||||||
|
_deletePending.Enqueue(bucket.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_deleteValueCallback(bucket.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
_sortedCache.Remove(bucket.Node);
|
||||||
|
|
||||||
|
_totalSize -= bucket.DataSize;
|
||||||
|
|
||||||
|
_cache[key] = newBucket;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_cache.Add(key, newBucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
_totalSize += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(long key, out T value)
|
||||||
|
{
|
||||||
|
if (_cache.TryGetValue(key, out CacheBucket bucket))
|
||||||
|
{
|
||||||
|
value = bucket.Value;
|
||||||
|
|
||||||
|
_sortedCache.Remove(bucket.Node);
|
||||||
|
|
||||||
|
LinkedListNode<long> node = _sortedCache.AddLast(key);
|
||||||
|
|
||||||
|
_cache[key] = new CacheBucket(value, bucket.DataSize, node);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = default(T);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetSize(long key, out long size)
|
||||||
|
{
|
||||||
|
if (_cache.TryGetValue(key, out CacheBucket bucket))
|
||||||
|
{
|
||||||
|
size = bucket.DataSize;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = 0;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearCacheIfNeeded()
|
||||||
|
{
|
||||||
|
long timestamp = PerformanceCounter.ElapsedMilliseconds;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
while (count++ < MaxRemovalsPerRun)
|
||||||
|
{
|
||||||
|
LinkedListNode<long> node = _sortedCache.First;
|
||||||
|
|
||||||
|
if (node == null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CacheBucket bucket = _cache[node.Value];
|
||||||
|
|
||||||
|
long timeDelta = timestamp - bucket.Timestamp;
|
||||||
|
|
||||||
|
if (timeDelta <= MinTimeDelta && !UnderMemoryPressure())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_sortedCache.Remove(node);
|
||||||
|
|
||||||
|
_cache.Remove(node.Value);
|
||||||
|
|
||||||
|
_deleteValueCallback(bucket.Value);
|
||||||
|
|
||||||
|
_totalSize -= bucket.DataSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool UnderMemoryPressure()
|
||||||
|
{
|
||||||
|
return _totalSize >= _maxSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
Ryujinx.Graphics/Gal/OpenGL/OglConstBuffer.cs
Normal file
74
Ryujinx.Graphics/Gal/OpenGL/OglConstBuffer.cs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
{
|
||||||
|
class OglConstBuffer : IGalConstBuffer
|
||||||
|
{
|
||||||
|
private const long MaxConstBufferCacheSize = 64 * 1024 * 1024;
|
||||||
|
|
||||||
|
private OglCachedResource<OglStreamBuffer> _cache;
|
||||||
|
|
||||||
|
public OglConstBuffer()
|
||||||
|
{
|
||||||
|
_cache = new OglCachedResource<OglStreamBuffer>(DeleteBuffer, MaxConstBufferCacheSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LockCache()
|
||||||
|
{
|
||||||
|
_cache.Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnlockCache()
|
||||||
|
{
|
||||||
|
_cache.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Create(long key, long size)
|
||||||
|
{
|
||||||
|
OglStreamBuffer buffer = new OglStreamBuffer(BufferTarget.UniformBuffer, size);
|
||||||
|
|
||||||
|
_cache.AddOrUpdate(key, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCached(long key, long size)
|
||||||
|
{
|
||||||
|
return _cache.TryGetSize(key, out long cachedSize) && cachedSize == size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetData(long key, long size, IntPtr hostAddress)
|
||||||
|
{
|
||||||
|
if (_cache.TryGetValue(key, out OglStreamBuffer buffer))
|
||||||
|
{
|
||||||
|
buffer.SetData(size, hostAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetData(long key, byte[] data)
|
||||||
|
{
|
||||||
|
if (_cache.TryGetValue(key, out OglStreamBuffer buffer))
|
||||||
|
{
|
||||||
|
buffer.SetData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetUbo(long key, out int uboHandle)
|
||||||
|
{
|
||||||
|
if (_cache.TryGetValue(key, out OglStreamBuffer buffer))
|
||||||
|
{
|
||||||
|
uboHandle = buffer.Handle;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uboHandle = 0;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DeleteBuffer(OglStreamBuffer buffer)
|
||||||
|
{
|
||||||
|
buffer.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,34 +3,34 @@ using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
static class OGLEnumConverter
|
static class OglEnumConverter
|
||||||
{
|
{
|
||||||
public static FrontFaceDirection GetFrontFace(GalFrontFace FrontFace)
|
public static FrontFaceDirection GetFrontFace(GalFrontFace frontFace)
|
||||||
{
|
{
|
||||||
switch (FrontFace)
|
switch (frontFace)
|
||||||
{
|
{
|
||||||
case GalFrontFace.CW: return FrontFaceDirection.Cw;
|
case GalFrontFace.Cw: return FrontFaceDirection.Cw;
|
||||||
case GalFrontFace.CCW: return FrontFaceDirection.Ccw;
|
case GalFrontFace.Ccw: return FrontFaceDirection.Ccw;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(FrontFace) + " \"" + FrontFace + "\" is not valid!");
|
throw new ArgumentException(nameof(frontFace) + " \"" + frontFace + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CullFaceMode GetCullFace(GalCullFace CullFace)
|
public static CullFaceMode GetCullFace(GalCullFace cullFace)
|
||||||
{
|
{
|
||||||
switch (CullFace)
|
switch (cullFace)
|
||||||
{
|
{
|
||||||
case GalCullFace.Front: return CullFaceMode.Front;
|
case GalCullFace.Front: return CullFaceMode.Front;
|
||||||
case GalCullFace.Back: return CullFaceMode.Back;
|
case GalCullFace.Back: return CullFaceMode.Back;
|
||||||
case GalCullFace.FrontAndBack: return CullFaceMode.FrontAndBack;
|
case GalCullFace.FrontAndBack: return CullFaceMode.FrontAndBack;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(CullFace) + " \"" + CullFace + "\" is not valid!");
|
throw new ArgumentException(nameof(cullFace) + " \"" + cullFace + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StencilOp GetStencilOp(GalStencilOp Op)
|
public static StencilOp GetStencilOp(GalStencilOp op)
|
||||||
{
|
{
|
||||||
switch (Op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case GalStencilOp.Keep: return StencilOp.Keep;
|
case GalStencilOp.Keep: return StencilOp.Keep;
|
||||||
case GalStencilOp.Zero: return StencilOp.Zero;
|
case GalStencilOp.Zero: return StencilOp.Zero;
|
||||||
|
@ -42,28 +42,28 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalStencilOp.DecrWrap: return StencilOp.DecrWrap;
|
case GalStencilOp.DecrWrap: return StencilOp.DecrWrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Op) + " \"" + Op + "\" is not valid!");
|
throw new ArgumentException(nameof(op) + " \"" + op + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DepthFunction GetDepthFunc(GalComparisonOp Func)
|
public static DepthFunction GetDepthFunc(GalComparisonOp func)
|
||||||
{
|
{
|
||||||
return (DepthFunction)GetFunc(Func);
|
return (DepthFunction)GetFunc(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StencilFunction GetStencilFunc(GalComparisonOp Func)
|
public static StencilFunction GetStencilFunc(GalComparisonOp func)
|
||||||
{
|
{
|
||||||
return (StencilFunction)GetFunc(Func);
|
return (StencilFunction)GetFunc(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static All GetFunc(GalComparisonOp Func)
|
private static All GetFunc(GalComparisonOp func)
|
||||||
{
|
{
|
||||||
if ((int)Func >= (int)All.Never &&
|
if ((int)func >= (int)All.Never &&
|
||||||
(int)Func <= (int)All.Always)
|
(int)func <= (int)All.Always)
|
||||||
{
|
{
|
||||||
return (All)Func;
|
return (All)func;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (Func)
|
switch (func)
|
||||||
{
|
{
|
||||||
case GalComparisonOp.Never: return All.Never;
|
case GalComparisonOp.Never: return All.Never;
|
||||||
case GalComparisonOp.Less: return All.Less;
|
case GalComparisonOp.Less: return All.Less;
|
||||||
|
@ -75,24 +75,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalComparisonOp.Always: return All.Always;
|
case GalComparisonOp.Always: return All.Always;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Func) + " \"" + Func + "\" is not valid!");
|
throw new ArgumentException(nameof(func) + " \"" + func + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DrawElementsType GetDrawElementsType(GalIndexFormat Format)
|
public static DrawElementsType GetDrawElementsType(GalIndexFormat format)
|
||||||
{
|
{
|
||||||
switch (Format)
|
switch (format)
|
||||||
{
|
{
|
||||||
case GalIndexFormat.Byte: return DrawElementsType.UnsignedByte;
|
case GalIndexFormat.Byte: return DrawElementsType.UnsignedByte;
|
||||||
case GalIndexFormat.Int16: return DrawElementsType.UnsignedShort;
|
case GalIndexFormat.Int16: return DrawElementsType.UnsignedShort;
|
||||||
case GalIndexFormat.Int32: return DrawElementsType.UnsignedInt;
|
case GalIndexFormat.Int32: return DrawElementsType.UnsignedInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Format) + " \"" + Format + "\" is not valid!");
|
throw new ArgumentException(nameof(format) + " \"" + format + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PrimitiveType GetPrimitiveType(GalPrimitiveType Type)
|
public static PrimitiveType GetPrimitiveType(GalPrimitiveType type)
|
||||||
{
|
{
|
||||||
switch (Type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case GalPrimitiveType.Points: return PrimitiveType.Points;
|
case GalPrimitiveType.Points: return PrimitiveType.Points;
|
||||||
case GalPrimitiveType.Lines: return PrimitiveType.Lines;
|
case GalPrimitiveType.Lines: return PrimitiveType.Lines;
|
||||||
|
@ -109,12 +109,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalPrimitiveType.Patches: return PrimitiveType.Patches;
|
case GalPrimitiveType.Patches: return PrimitiveType.Patches;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Type) + " \"" + Type + "\" is not valid!");
|
throw new ArgumentException(nameof(type) + " \"" + type + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderType GetShaderType(GalShaderType Type)
|
public static ShaderType GetShaderType(GalShaderType type)
|
||||||
{
|
{
|
||||||
switch (Type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case GalShaderType.Vertex: return ShaderType.VertexShader;
|
case GalShaderType.Vertex: return ShaderType.VertexShader;
|
||||||
case GalShaderType.TessControl: return ShaderType.TessControlShader;
|
case GalShaderType.TessControl: return ShaderType.TessControlShader;
|
||||||
|
@ -123,50 +123,50 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalShaderType.Fragment: return ShaderType.FragmentShader;
|
case GalShaderType.Fragment: return ShaderType.FragmentShader;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Type) + " \"" + Type + "\" is not valid!");
|
throw new ArgumentException(nameof(type) + " \"" + type + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (PixelInternalFormat, PixelFormat, PixelType) GetImageFormat(GalImageFormat Format)
|
public static (PixelInternalFormat, PixelFormat, PixelType) GetImageFormat(GalImageFormat format)
|
||||||
{
|
{
|
||||||
switch (Format)
|
switch (format)
|
||||||
{
|
{
|
||||||
case GalImageFormat.RGBA32 | GalImageFormat.Float: return (PixelInternalFormat.Rgba32f, PixelFormat.Rgba, PixelType.Float);
|
case GalImageFormat.Rgba32 | GalImageFormat.Float: return (PixelInternalFormat.Rgba32f, PixelFormat.Rgba, PixelType.Float);
|
||||||
case GalImageFormat.RGBA32 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba32i, PixelFormat.RgbaInteger, PixelType.Int);
|
case GalImageFormat.Rgba32 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba32i, PixelFormat.RgbaInteger, PixelType.Int);
|
||||||
case GalImageFormat.RGBA32 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba32ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt);
|
case GalImageFormat.Rgba32 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba32ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt);
|
||||||
case GalImageFormat.RGBA16 | GalImageFormat.Float: return (PixelInternalFormat.Rgba16f, PixelFormat.Rgba, PixelType.HalfFloat);
|
case GalImageFormat.Rgba16 | GalImageFormat.Float: return (PixelInternalFormat.Rgba16f, PixelFormat.Rgba, PixelType.HalfFloat);
|
||||||
case GalImageFormat.RGBA16 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba16i, PixelFormat.RgbaInteger, PixelType.Short);
|
case GalImageFormat.Rgba16 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba16i, PixelFormat.RgbaInteger, PixelType.Short);
|
||||||
case GalImageFormat.RGBA16 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba16ui, PixelFormat.RgbaInteger, PixelType.UnsignedShort);
|
case GalImageFormat.Rgba16 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba16ui, PixelFormat.RgbaInteger, PixelType.UnsignedShort);
|
||||||
case GalImageFormat.RGBA16 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba16, PixelFormat.Rgba, PixelType.UnsignedShort);
|
case GalImageFormat.Rgba16 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba16, PixelFormat.Rgba, PixelType.UnsignedShort);
|
||||||
case GalImageFormat.RG32 | GalImageFormat.Float: return (PixelInternalFormat.Rg32f, PixelFormat.Rg, PixelType.Float);
|
case GalImageFormat.Rg32 | GalImageFormat.Float: return (PixelInternalFormat.Rg32f, PixelFormat.Rg, PixelType.Float);
|
||||||
case GalImageFormat.RG32 | GalImageFormat.Sint: return (PixelInternalFormat.Rg32i, PixelFormat.RgInteger, PixelType.Int);
|
case GalImageFormat.Rg32 | GalImageFormat.Sint: return (PixelInternalFormat.Rg32i, PixelFormat.RgInteger, PixelType.Int);
|
||||||
case GalImageFormat.RG32 | GalImageFormat.Uint: return (PixelInternalFormat.Rg32ui, PixelFormat.RgInteger, PixelType.UnsignedInt);
|
case GalImageFormat.Rg32 | GalImageFormat.Uint: return (PixelInternalFormat.Rg32ui, PixelFormat.RgInteger, PixelType.UnsignedInt);
|
||||||
case GalImageFormat.RGBX8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb8, PixelFormat.Rgba, PixelType.UnsignedByte);
|
case GalImageFormat.Rgbx8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb8, PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||||
case GalImageFormat.RGBA8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rgba8Snorm, PixelFormat.Rgba, PixelType.Byte);
|
case GalImageFormat.Rgba8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rgba8Snorm, PixelFormat.Rgba, PixelType.Byte);
|
||||||
case GalImageFormat.RGBA8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte);
|
case GalImageFormat.Rgba8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||||
case GalImageFormat.RGBA8 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba8i, PixelFormat.RgbaInteger, PixelType.Byte);
|
case GalImageFormat.Rgba8 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba8i, PixelFormat.RgbaInteger, PixelType.Byte);
|
||||||
case GalImageFormat.RGBA8 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba8ui, PixelFormat.RgbaInteger, PixelType.UnsignedByte);
|
case GalImageFormat.Rgba8 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba8ui, PixelFormat.RgbaInteger, PixelType.UnsignedByte);
|
||||||
case GalImageFormat.RGBA8 | GalImageFormat.Srgb: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte);
|
case GalImageFormat.Rgba8 | GalImageFormat.Srgb: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||||
case GalImageFormat.BGRA8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Bgra, PixelType.UnsignedByte);
|
case GalImageFormat.Bgra8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Bgra, PixelType.UnsignedByte);
|
||||||
case GalImageFormat.BGRA8 | GalImageFormat.Srgb: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Bgra, PixelType.UnsignedByte);
|
case GalImageFormat.Bgra8 | GalImageFormat.Srgb: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Bgra, PixelType.UnsignedByte);
|
||||||
case GalImageFormat.RGBA4 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba4, PixelFormat.Rgba, PixelType.UnsignedShort4444Reversed);
|
case GalImageFormat.Rgba4 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba4, PixelFormat.Rgba, PixelType.UnsignedShort4444Reversed);
|
||||||
case GalImageFormat.RGB10A2 | GalImageFormat.Uint: return (PixelInternalFormat.Rgb10A2ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt2101010Reversed);
|
case GalImageFormat.Rgb10A2 | GalImageFormat.Uint: return (PixelInternalFormat.Rgb10A2ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt2101010Reversed);
|
||||||
case GalImageFormat.RGB10A2 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed);
|
case GalImageFormat.Rgb10A2 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed);
|
||||||
case GalImageFormat.R32 | GalImageFormat.Float: return (PixelInternalFormat.R32f, PixelFormat.Red, PixelType.Float);
|
case GalImageFormat.R32 | GalImageFormat.Float: return (PixelInternalFormat.R32f, PixelFormat.Red, PixelType.Float);
|
||||||
case GalImageFormat.R32 | GalImageFormat.Sint: return (PixelInternalFormat.R32i, PixelFormat.Red, PixelType.Int);
|
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.R32 | GalImageFormat.Uint: return (PixelInternalFormat.R32ui, PixelFormat.Red, PixelType.UnsignedInt);
|
||||||
case GalImageFormat.BGR5A1 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551);
|
case GalImageFormat.Bgr5A1 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551);
|
||||||
case GalImageFormat.RGB5A1 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed);
|
case GalImageFormat.Rgb5A1 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed);
|
||||||
case GalImageFormat.RGB565 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565Reversed);
|
case GalImageFormat.Rgb565 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565Reversed);
|
||||||
case GalImageFormat.BGR565 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565);
|
case GalImageFormat.Bgr565 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565);
|
||||||
case GalImageFormat.RG16 | GalImageFormat.Float: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat);
|
case GalImageFormat.Rg16 | GalImageFormat.Float: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat);
|
||||||
case GalImageFormat.RG16 | GalImageFormat.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short);
|
case GalImageFormat.Rg16 | GalImageFormat.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short);
|
||||||
case GalImageFormat.RG16 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Short);
|
case GalImageFormat.Rg16 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Short);
|
||||||
case GalImageFormat.RG16 | GalImageFormat.Uint: return (PixelInternalFormat.Rg16ui, PixelFormat.RgInteger, PixelType.UnsignedShort);
|
case GalImageFormat.Rg16 | GalImageFormat.Uint: return (PixelInternalFormat.Rg16ui, PixelFormat.RgInteger, PixelType.UnsignedShort);
|
||||||
case GalImageFormat.RG16 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg16, PixelFormat.Rg, PixelType.UnsignedShort);
|
case GalImageFormat.Rg16 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg16, PixelFormat.Rg, PixelType.UnsignedShort);
|
||||||
case GalImageFormat.RG8 | GalImageFormat.Sint: return (PixelInternalFormat.Rg8i, PixelFormat.RgInteger, PixelType.Byte);
|
case GalImageFormat.Rg8 | GalImageFormat.Sint: return (PixelInternalFormat.Rg8i, PixelFormat.RgInteger, PixelType.Byte);
|
||||||
case GalImageFormat.RG8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg8Snorm, PixelFormat.Rg, PixelType.Byte);
|
case GalImageFormat.Rg8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg8Snorm, PixelFormat.Rg, PixelType.Byte);
|
||||||
case GalImageFormat.RG8 | GalImageFormat.Uint: return (PixelInternalFormat.Rg8ui, PixelFormat.RgInteger, PixelType.UnsignedByte);
|
case GalImageFormat.Rg8 | GalImageFormat.Uint: return (PixelInternalFormat.Rg8ui, PixelFormat.RgInteger, PixelType.UnsignedByte);
|
||||||
case GalImageFormat.RG8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg8, PixelFormat.Rg, PixelType.UnsignedByte);
|
case GalImageFormat.Rg8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg8, PixelFormat.Rg, PixelType.UnsignedByte);
|
||||||
case GalImageFormat.R16 | GalImageFormat.Float: return (PixelInternalFormat.R16f, PixelFormat.Red, PixelType.HalfFloat);
|
case GalImageFormat.R16 | GalImageFormat.Float: return (PixelInternalFormat.R16f, PixelFormat.Red, PixelType.HalfFloat);
|
||||||
case GalImageFormat.R16 | GalImageFormat.Sint: return (PixelInternalFormat.R16i, PixelFormat.RedInteger, PixelType.Short);
|
case GalImageFormat.R16 | GalImageFormat.Sint: return (PixelInternalFormat.R16i, PixelFormat.RedInteger, PixelType.Short);
|
||||||
case GalImageFormat.R16 | GalImageFormat.Snorm: return (PixelInternalFormat.R16Snorm, PixelFormat.Red, PixelType.Short);
|
case GalImageFormat.R16 | GalImageFormat.Snorm: return (PixelInternalFormat.R16Snorm, PixelFormat.Red, PixelType.Short);
|
||||||
|
@ -186,12 +186,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalImageFormat.D32S8 | GalImageFormat.Float: return (PixelInternalFormat.Depth32fStencil8, PixelFormat.DepthStencil, PixelType.Float32UnsignedInt248Rev);
|
case GalImageFormat.D32S8 | GalImageFormat.Float: return (PixelInternalFormat.Depth32fStencil8, PixelFormat.DepthStencil, PixelType.Float32UnsignedInt248Rev);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException($"{Format & GalImageFormat.FormatMask} {Format & GalImageFormat.TypeMask}");
|
throw new NotImplementedException($"{format & GalImageFormat.FormatMask} {format & GalImageFormat.TypeMask}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static All GetDepthCompareFunc(DepthCompareFunc DepthCompareFunc)
|
public static All GetDepthCompareFunc(DepthCompareFunc depthCompareFunc)
|
||||||
{
|
{
|
||||||
switch (DepthCompareFunc)
|
switch (depthCompareFunc)
|
||||||
{
|
{
|
||||||
case DepthCompareFunc.LEqual:
|
case DepthCompareFunc.LEqual:
|
||||||
return All.Lequal;
|
return All.Lequal;
|
||||||
|
@ -210,13 +210,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case DepthCompareFunc.Never:
|
case DepthCompareFunc.Never:
|
||||||
return All.Never;
|
return All.Never;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentException(nameof(DepthCompareFunc) + " \"" + DepthCompareFunc + "\" is not valid!");
|
throw new ArgumentException(nameof(depthCompareFunc) + " \"" + depthCompareFunc + "\" is not valid!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InternalFormat GetCompressedImageFormat(GalImageFormat Format)
|
public static InternalFormat GetCompressedImageFormat(GalImageFormat format)
|
||||||
{
|
{
|
||||||
switch (Format)
|
switch (format)
|
||||||
{
|
{
|
||||||
case GalImageFormat.BptcSfloat | GalImageFormat.Float: return InternalFormat.CompressedRgbBptcSignedFloat;
|
case GalImageFormat.BptcSfloat | GalImageFormat.Float: return InternalFormat.CompressedRgbBptcSignedFloat;
|
||||||
case GalImageFormat.BptcUfloat | GalImageFormat.Float: return InternalFormat.CompressedRgbBptcUnsignedFloat;
|
case GalImageFormat.BptcUfloat | GalImageFormat.Float: return InternalFormat.CompressedRgbBptcUnsignedFloat;
|
||||||
|
@ -234,12 +234,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalImageFormat.BC5 | GalImageFormat.Unorm: return InternalFormat.CompressedRgRgtc2;
|
case GalImageFormat.BC5 | GalImageFormat.Unorm: return InternalFormat.CompressedRgRgtc2;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException($"{Format & GalImageFormat.FormatMask} {Format & GalImageFormat.TypeMask}");
|
throw new NotImplementedException($"{format & GalImageFormat.FormatMask} {format & GalImageFormat.TypeMask}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static All GetTextureSwizzle(GalTextureSource Source)
|
public static All GetTextureSwizzle(GalTextureSource source)
|
||||||
{
|
{
|
||||||
switch (Source)
|
switch (source)
|
||||||
{
|
{
|
||||||
case GalTextureSource.Zero: return All.Zero;
|
case GalTextureSource.Zero: return All.Zero;
|
||||||
case GalTextureSource.Red: return All.Red;
|
case GalTextureSource.Red: return All.Red;
|
||||||
|
@ -250,12 +250,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalTextureSource.OneFloat: return All.One;
|
case GalTextureSource.OneFloat: return All.One;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Source) + " \"" + Source + "\" is not valid!");
|
throw new ArgumentException(nameof(source) + " \"" + source + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextureWrapMode GetTextureWrapMode(GalTextureWrap Wrap)
|
public static TextureWrapMode GetTextureWrapMode(GalTextureWrap wrap)
|
||||||
{
|
{
|
||||||
switch (Wrap)
|
switch (wrap)
|
||||||
{
|
{
|
||||||
case GalTextureWrap.Repeat: return TextureWrapMode.Repeat;
|
case GalTextureWrap.Repeat: return TextureWrapMode.Repeat;
|
||||||
case GalTextureWrap.MirroredRepeat: return TextureWrapMode.MirroredRepeat;
|
case GalTextureWrap.MirroredRepeat: return TextureWrapMode.MirroredRepeat;
|
||||||
|
@ -264,9 +264,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalTextureWrap.Clamp: return TextureWrapMode.Clamp;
|
case GalTextureWrap.Clamp: return TextureWrapMode.Clamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OGLExtension.TextureMirrorClamp)
|
if (OglExtension.TextureMirrorClamp)
|
||||||
{
|
{
|
||||||
switch (Wrap)
|
switch (wrap)
|
||||||
{
|
{
|
||||||
case GalTextureWrap.MirrorClampToEdge: return (TextureWrapMode)ExtTextureMirrorClamp.MirrorClampToEdgeExt;
|
case GalTextureWrap.MirrorClampToEdge: return (TextureWrapMode)ExtTextureMirrorClamp.MirrorClampToEdgeExt;
|
||||||
case GalTextureWrap.MirrorClampToBorder: return (TextureWrapMode)ExtTextureMirrorClamp.MirrorClampToBorderExt;
|
case GalTextureWrap.MirrorClampToBorder: return (TextureWrapMode)ExtTextureMirrorClamp.MirrorClampToBorderExt;
|
||||||
|
@ -276,7 +276,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Fallback to non-mirrored clamps
|
//Fallback to non-mirrored clamps
|
||||||
switch (Wrap)
|
switch (wrap)
|
||||||
{
|
{
|
||||||
case GalTextureWrap.MirrorClampToEdge: return TextureWrapMode.ClampToEdge;
|
case GalTextureWrap.MirrorClampToEdge: return TextureWrapMode.ClampToEdge;
|
||||||
case GalTextureWrap.MirrorClampToBorder: return TextureWrapMode.ClampToBorder;
|
case GalTextureWrap.MirrorClampToBorder: return TextureWrapMode.ClampToBorder;
|
||||||
|
@ -284,37 +284,37 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Wrap) + " \"" + Wrap + "\" is not valid!");
|
throw new ArgumentException(nameof(wrap) + " \"" + wrap + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextureMinFilter GetTextureMinFilter(
|
public static TextureMinFilter GetTextureMinFilter(
|
||||||
GalTextureFilter MinFilter,
|
GalTextureFilter minFilter,
|
||||||
GalTextureMipFilter MipFilter)
|
GalTextureMipFilter mipFilter)
|
||||||
{
|
{
|
||||||
//TODO: Mip (needs mipmap support first).
|
//TODO: Mip (needs mipmap support first).
|
||||||
switch (MinFilter)
|
switch (minFilter)
|
||||||
{
|
{
|
||||||
case GalTextureFilter.Nearest: return TextureMinFilter.Nearest;
|
case GalTextureFilter.Nearest: return TextureMinFilter.Nearest;
|
||||||
case GalTextureFilter.Linear: return TextureMinFilter.Linear;
|
case GalTextureFilter.Linear: return TextureMinFilter.Linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(MinFilter) + " \"" + MinFilter + "\" is not valid!");
|
throw new ArgumentException(nameof(minFilter) + " \"" + minFilter + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextureMagFilter GetTextureMagFilter(GalTextureFilter Filter)
|
public static TextureMagFilter GetTextureMagFilter(GalTextureFilter filter)
|
||||||
{
|
{
|
||||||
switch (Filter)
|
switch (filter)
|
||||||
{
|
{
|
||||||
case GalTextureFilter.Nearest: return TextureMagFilter.Nearest;
|
case GalTextureFilter.Nearest: return TextureMagFilter.Nearest;
|
||||||
case GalTextureFilter.Linear: return TextureMagFilter.Linear;
|
case GalTextureFilter.Linear: return TextureMagFilter.Linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Filter) + " \"" + Filter + "\" is not valid!");
|
throw new ArgumentException(nameof(filter) + " \"" + filter + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlendEquationMode GetBlendEquation(GalBlendEquation BlendEquation)
|
public static BlendEquationMode GetBlendEquation(GalBlendEquation blendEquation)
|
||||||
{
|
{
|
||||||
switch (BlendEquation)
|
switch (blendEquation)
|
||||||
{
|
{
|
||||||
case GalBlendEquation.FuncAdd:
|
case GalBlendEquation.FuncAdd:
|
||||||
case GalBlendEquation.FuncAddGl:
|
case GalBlendEquation.FuncAddGl:
|
||||||
|
@ -337,12 +337,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
return BlendEquationMode.Max;
|
return BlendEquationMode.Max;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(BlendEquation) + " \"" + BlendEquation + "\" is not valid!");
|
throw new ArgumentException(nameof(blendEquation) + " \"" + blendEquation + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlendingFactor GetBlendFactor(GalBlendFactor BlendFactor)
|
public static BlendingFactor GetBlendFactor(GalBlendFactor blendFactor)
|
||||||
{
|
{
|
||||||
switch (BlendFactor)
|
switch (blendFactor)
|
||||||
{
|
{
|
||||||
case GalBlendFactor.Zero:
|
case GalBlendFactor.Zero:
|
||||||
case GalBlendFactor.ZeroGl:
|
case GalBlendFactor.ZeroGl:
|
||||||
|
@ -421,7 +421,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
return BlendingFactor.ConstantColor;
|
return BlendingFactor.ConstantColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(BlendFactor) + " \"" + BlendFactor + "\" is not valid!");
|
throw new ArgumentException(nameof(blendFactor) + " \"" + blendFactor + "\" is not valid!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
70
Ryujinx.Graphics/Gal/OpenGL/OglExtension.cs
Normal file
70
Ryujinx.Graphics/Gal/OpenGL/OglExtension.cs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
{
|
||||||
|
static class OglExtension
|
||||||
|
{
|
||||||
|
// Private lazy backing variables
|
||||||
|
private static Lazy<bool> _enhancedLayouts = new Lazy<bool>(() => HasExtension("GL_ARB_enhanced_layouts"));
|
||||||
|
private static Lazy<bool> _textureMirrorClamp = new Lazy<bool>(() => HasExtension("GL_EXT_texture_mirror_clamp"));
|
||||||
|
private static Lazy<bool> _viewportArray = new Lazy<bool>(() => HasExtension("GL_ARB_viewport_array"));
|
||||||
|
|
||||||
|
private static Lazy<bool> _nvidiaDriver = new Lazy<bool>(() => IsNvidiaDriver());
|
||||||
|
|
||||||
|
// Public accessors
|
||||||
|
public static bool EnhancedLayouts => _enhancedLayouts.Value;
|
||||||
|
public static bool TextureMirrorClamp => _textureMirrorClamp.Value;
|
||||||
|
public static bool ViewportArray => _viewportArray.Value;
|
||||||
|
|
||||||
|
public static bool NvidiaDriver => _nvidiaDriver.Value;
|
||||||
|
|
||||||
|
private static bool HasExtension(string name)
|
||||||
|
{
|
||||||
|
int numExtensions = GL.GetInteger(GetPName.NumExtensions);
|
||||||
|
|
||||||
|
for (int extension = 0; extension < numExtensions; extension++)
|
||||||
|
{
|
||||||
|
if (GL.GetString(StringNameIndexed.Extensions, extension) == name)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.PrintInfo(LogClass.Gpu, $"OpenGL extension {name} unavailable. You may experience some performance degradation");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsNvidiaDriver()
|
||||||
|
{
|
||||||
|
return GL.GetString(StringName.Vendor).Equals("NVIDIA Corporation");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Required
|
||||||
|
{
|
||||||
|
// Public accessors
|
||||||
|
public static bool EnhancedLayouts => _enhancedLayoutsRequired.Value;
|
||||||
|
public static bool TextureMirrorClamp => _textureMirrorClampRequired.Value;
|
||||||
|
public static bool ViewportArray => _viewportArrayRequired.Value;
|
||||||
|
|
||||||
|
// Private lazy backing variables
|
||||||
|
private static Lazy<bool> _enhancedLayoutsRequired = new Lazy<bool>(() => HasExtensionRequired(OglExtension.EnhancedLayouts, "GL_ARB_enhanced_layouts"));
|
||||||
|
private static Lazy<bool> _textureMirrorClampRequired = new Lazy<bool>(() => HasExtensionRequired(OglExtension.TextureMirrorClamp, "GL_EXT_texture_mirror_clamp"));
|
||||||
|
private static Lazy<bool> _viewportArrayRequired = new Lazy<bool>(() => HasExtensionRequired(OglExtension.ViewportArray, "GL_ARB_viewport_array"));
|
||||||
|
|
||||||
|
private static bool HasExtensionRequired(bool value, string name)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.PrintWarning(LogClass.Gpu, $"Required OpenGL extension {name} unavailable. You may experience some rendering issues");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
Ryujinx.Graphics/Gal/OpenGL/OglLimit.cs
Normal file
12
Ryujinx.Graphics/Gal/OpenGL/OglLimit.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
{
|
||||||
|
static class OglLimit
|
||||||
|
{
|
||||||
|
private static Lazy<int> _sMaxUboSize = new Lazy<int>(() => GL.GetInteger(GetPName.MaxUniformBlockSize));
|
||||||
|
|
||||||
|
public static int MaxUboSize => _sMaxUboSize.Value;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,9 +4,9 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
class OGLPipeline : IGalPipeline
|
class OglPipeline : IGalPipeline
|
||||||
{
|
{
|
||||||
private static Dictionary<GalVertexAttribSize, int> AttribElements =
|
private static Dictionary<GalVertexAttribSize, int> _attribElements =
|
||||||
new Dictionary<GalVertexAttribSize, int>()
|
new Dictionary<GalVertexAttribSize, int>()
|
||||||
{
|
{
|
||||||
{ GalVertexAttribSize._32_32_32_32, 4 },
|
{ GalVertexAttribSize._32_32_32_32, 4 },
|
||||||
|
@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{ GalVertexAttribSize._11_11_10, 3 }
|
{ GalVertexAttribSize._11_11_10, 3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> FloatAttribTypes =
|
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> _floatAttribTypes =
|
||||||
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
||||||
{
|
{
|
||||||
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Float },
|
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Float },
|
||||||
|
@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{ GalVertexAttribSize._16, VertexAttribPointerType.HalfFloat }
|
{ GalVertexAttribSize._16, VertexAttribPointerType.HalfFloat }
|
||||||
};
|
};
|
||||||
|
|
||||||
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> SignedAttribTypes =
|
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> _signedAttribTypes =
|
||||||
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
||||||
{
|
{
|
||||||
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Int },
|
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Int },
|
||||||
|
@ -56,7 +56,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{ GalVertexAttribSize._10_10_10_2, VertexAttribPointerType.Int2101010Rev }
|
{ GalVertexAttribSize._10_10_10_2, VertexAttribPointerType.Int2101010Rev }
|
||||||
};
|
};
|
||||||
|
|
||||||
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> UnsignedAttribTypes =
|
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> _unsignedAttribTypes =
|
||||||
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
||||||
{
|
{
|
||||||
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.UnsignedInt },
|
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.UnsignedInt },
|
||||||
|
@ -75,30 +75,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{ GalVertexAttribSize._11_11_10, VertexAttribPointerType.UnsignedInt10F11F11FRev }
|
{ GalVertexAttribSize._11_11_10, VertexAttribPointerType.UnsignedInt10F11F11FRev }
|
||||||
};
|
};
|
||||||
|
|
||||||
private GalPipelineState Old;
|
private GalPipelineState _old;
|
||||||
|
|
||||||
private OGLConstBuffer Buffer;
|
private OglConstBuffer _buffer;
|
||||||
private OGLRenderTarget RenderTarget;
|
private OglRenderTarget _renderTarget;
|
||||||
private OGLRasterizer Rasterizer;
|
private OglRasterizer _rasterizer;
|
||||||
private OGLShader Shader;
|
private OglShader _shader;
|
||||||
|
|
||||||
private int VaoHandle;
|
private int _vaoHandle;
|
||||||
|
|
||||||
public OGLPipeline(
|
public OglPipeline(
|
||||||
OGLConstBuffer Buffer,
|
OglConstBuffer buffer,
|
||||||
OGLRenderTarget RenderTarget,
|
OglRenderTarget renderTarget,
|
||||||
OGLRasterizer Rasterizer,
|
OglRasterizer rasterizer,
|
||||||
OGLShader Shader)
|
OglShader shader)
|
||||||
{
|
{
|
||||||
this.Buffer = Buffer;
|
_buffer = buffer;
|
||||||
this.RenderTarget = RenderTarget;
|
_renderTarget = renderTarget;
|
||||||
this.Rasterizer = Rasterizer;
|
_rasterizer = rasterizer;
|
||||||
this.Shader = Shader;
|
_shader = shader;
|
||||||
|
|
||||||
//These values match OpenGL's defaults
|
//These values match OpenGL's defaults
|
||||||
Old = new GalPipelineState
|
_old = new GalPipelineState
|
||||||
{
|
{
|
||||||
FrontFace = GalFrontFace.CCW,
|
FrontFace = GalFrontFace.Ccw,
|
||||||
|
|
||||||
CullFaceEnabled = false,
|
CullFaceEnabled = false,
|
||||||
CullFace = GalCullFace.Back,
|
CullFace = GalCullFace.Back,
|
||||||
|
@ -133,11 +133,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
PrimitiveRestartIndex = 0
|
PrimitiveRestartIndex = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
|
for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++)
|
||||||
{
|
{
|
||||||
Old.Blends[Index] = BlendState.Default;
|
_old.Blends[index] = BlendState.Default;
|
||||||
|
|
||||||
Old.ColorMasks[Index] = ColorMaskState.Default;
|
_old.ColorMasks[index] = ColorMaskState.Default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,122 +147,122 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
BindVertexLayout(New);
|
BindVertexLayout(New);
|
||||||
|
|
||||||
if (New.FramebufferSrgb != Old.FramebufferSrgb)
|
if (New.FramebufferSrgb != _old.FramebufferSrgb)
|
||||||
{
|
{
|
||||||
Enable(EnableCap.FramebufferSrgb, New.FramebufferSrgb);
|
Enable(EnableCap.FramebufferSrgb, New.FramebufferSrgb);
|
||||||
|
|
||||||
RenderTarget.FramebufferSrgb = New.FramebufferSrgb;
|
_renderTarget.FramebufferSrgb = New.FramebufferSrgb;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.FlipX != Old.FlipX || New.FlipY != Old.FlipY || New.Instance != Old.Instance)
|
if (New.FlipX != _old.FlipX || New.FlipY != _old.FlipY || New.Instance != _old.Instance)
|
||||||
{
|
{
|
||||||
Shader.SetExtraData(New.FlipX, New.FlipY, New.Instance);
|
_shader.SetExtraData(New.FlipX, New.FlipY, New.Instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.FrontFace != Old.FrontFace)
|
if (New.FrontFace != _old.FrontFace)
|
||||||
{
|
{
|
||||||
GL.FrontFace(OGLEnumConverter.GetFrontFace(New.FrontFace));
|
GL.FrontFace(OglEnumConverter.GetFrontFace(New.FrontFace));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.CullFaceEnabled != Old.CullFaceEnabled)
|
if (New.CullFaceEnabled != _old.CullFaceEnabled)
|
||||||
{
|
{
|
||||||
Enable(EnableCap.CullFace, New.CullFaceEnabled);
|
Enable(EnableCap.CullFace, New.CullFaceEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.CullFaceEnabled)
|
if (New.CullFaceEnabled)
|
||||||
{
|
{
|
||||||
if (New.CullFace != Old.CullFace)
|
if (New.CullFace != _old.CullFace)
|
||||||
{
|
{
|
||||||
GL.CullFace(OGLEnumConverter.GetCullFace(New.CullFace));
|
GL.CullFace(OglEnumConverter.GetCullFace(New.CullFace));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.DepthTestEnabled != Old.DepthTestEnabled)
|
if (New.DepthTestEnabled != _old.DepthTestEnabled)
|
||||||
{
|
{
|
||||||
Enable(EnableCap.DepthTest, New.DepthTestEnabled);
|
Enable(EnableCap.DepthTest, New.DepthTestEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.DepthWriteEnabled != Old.DepthWriteEnabled)
|
if (New.DepthWriteEnabled != _old.DepthWriteEnabled)
|
||||||
{
|
{
|
||||||
GL.DepthMask(New.DepthWriteEnabled);
|
GL.DepthMask(New.DepthWriteEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.DepthTestEnabled)
|
if (New.DepthTestEnabled)
|
||||||
{
|
{
|
||||||
if (New.DepthFunc != Old.DepthFunc)
|
if (New.DepthFunc != _old.DepthFunc)
|
||||||
{
|
{
|
||||||
GL.DepthFunc(OGLEnumConverter.GetDepthFunc(New.DepthFunc));
|
GL.DepthFunc(OglEnumConverter.GetDepthFunc(New.DepthFunc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.DepthRangeNear != Old.DepthRangeNear ||
|
if (New.DepthRangeNear != _old.DepthRangeNear ||
|
||||||
New.DepthRangeFar != Old.DepthRangeFar)
|
New.DepthRangeFar != _old.DepthRangeFar)
|
||||||
{
|
{
|
||||||
GL.DepthRange(New.DepthRangeNear, New.DepthRangeFar);
|
GL.DepthRange(New.DepthRangeNear, New.DepthRangeFar);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.StencilTestEnabled != Old.StencilTestEnabled)
|
if (New.StencilTestEnabled != _old.StencilTestEnabled)
|
||||||
{
|
{
|
||||||
Enable(EnableCap.StencilTest, New.StencilTestEnabled);
|
Enable(EnableCap.StencilTest, New.StencilTestEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.StencilTwoSideEnabled != Old.StencilTwoSideEnabled)
|
if (New.StencilTwoSideEnabled != _old.StencilTwoSideEnabled)
|
||||||
{
|
{
|
||||||
Enable((EnableCap)All.StencilTestTwoSideExt, New.StencilTwoSideEnabled);
|
Enable((EnableCap)All.StencilTestTwoSideExt, New.StencilTwoSideEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.StencilTestEnabled)
|
if (New.StencilTestEnabled)
|
||||||
{
|
{
|
||||||
if (New.StencilBackFuncFunc != Old.StencilBackFuncFunc ||
|
if (New.StencilBackFuncFunc != _old.StencilBackFuncFunc ||
|
||||||
New.StencilBackFuncRef != Old.StencilBackFuncRef ||
|
New.StencilBackFuncRef != _old.StencilBackFuncRef ||
|
||||||
New.StencilBackFuncMask != Old.StencilBackFuncMask)
|
New.StencilBackFuncMask != _old.StencilBackFuncMask)
|
||||||
{
|
{
|
||||||
GL.StencilFuncSeparate(
|
GL.StencilFuncSeparate(
|
||||||
StencilFace.Back,
|
StencilFace.Back,
|
||||||
OGLEnumConverter.GetStencilFunc(New.StencilBackFuncFunc),
|
OglEnumConverter.GetStencilFunc(New.StencilBackFuncFunc),
|
||||||
New.StencilBackFuncRef,
|
New.StencilBackFuncRef,
|
||||||
New.StencilBackFuncMask);
|
New.StencilBackFuncMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.StencilBackOpFail != Old.StencilBackOpFail ||
|
if (New.StencilBackOpFail != _old.StencilBackOpFail ||
|
||||||
New.StencilBackOpZFail != Old.StencilBackOpZFail ||
|
New.StencilBackOpZFail != _old.StencilBackOpZFail ||
|
||||||
New.StencilBackOpZPass != Old.StencilBackOpZPass)
|
New.StencilBackOpZPass != _old.StencilBackOpZPass)
|
||||||
{
|
{
|
||||||
GL.StencilOpSeparate(
|
GL.StencilOpSeparate(
|
||||||
StencilFace.Back,
|
StencilFace.Back,
|
||||||
OGLEnumConverter.GetStencilOp(New.StencilBackOpFail),
|
OglEnumConverter.GetStencilOp(New.StencilBackOpFail),
|
||||||
OGLEnumConverter.GetStencilOp(New.StencilBackOpZFail),
|
OglEnumConverter.GetStencilOp(New.StencilBackOpZFail),
|
||||||
OGLEnumConverter.GetStencilOp(New.StencilBackOpZPass));
|
OglEnumConverter.GetStencilOp(New.StencilBackOpZPass));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.StencilBackMask != Old.StencilBackMask)
|
if (New.StencilBackMask != _old.StencilBackMask)
|
||||||
{
|
{
|
||||||
GL.StencilMaskSeparate(StencilFace.Back, New.StencilBackMask);
|
GL.StencilMaskSeparate(StencilFace.Back, New.StencilBackMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.StencilFrontFuncFunc != Old.StencilFrontFuncFunc ||
|
if (New.StencilFrontFuncFunc != _old.StencilFrontFuncFunc ||
|
||||||
New.StencilFrontFuncRef != Old.StencilFrontFuncRef ||
|
New.StencilFrontFuncRef != _old.StencilFrontFuncRef ||
|
||||||
New.StencilFrontFuncMask != Old.StencilFrontFuncMask)
|
New.StencilFrontFuncMask != _old.StencilFrontFuncMask)
|
||||||
{
|
{
|
||||||
GL.StencilFuncSeparate(
|
GL.StencilFuncSeparate(
|
||||||
StencilFace.Front,
|
StencilFace.Front,
|
||||||
OGLEnumConverter.GetStencilFunc(New.StencilFrontFuncFunc),
|
OglEnumConverter.GetStencilFunc(New.StencilFrontFuncFunc),
|
||||||
New.StencilFrontFuncRef,
|
New.StencilFrontFuncRef,
|
||||||
New.StencilFrontFuncMask);
|
New.StencilFrontFuncMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.StencilFrontOpFail != Old.StencilFrontOpFail ||
|
if (New.StencilFrontOpFail != _old.StencilFrontOpFail ||
|
||||||
New.StencilFrontOpZFail != Old.StencilFrontOpZFail ||
|
New.StencilFrontOpZFail != _old.StencilFrontOpZFail ||
|
||||||
New.StencilFrontOpZPass != Old.StencilFrontOpZPass)
|
New.StencilFrontOpZPass != _old.StencilFrontOpZPass)
|
||||||
{
|
{
|
||||||
GL.StencilOpSeparate(
|
GL.StencilOpSeparate(
|
||||||
StencilFace.Front,
|
StencilFace.Front,
|
||||||
OGLEnumConverter.GetStencilOp(New.StencilFrontOpFail),
|
OglEnumConverter.GetStencilOp(New.StencilFrontOpFail),
|
||||||
OGLEnumConverter.GetStencilOp(New.StencilFrontOpZFail),
|
OglEnumConverter.GetStencilOp(New.StencilFrontOpZFail),
|
||||||
OGLEnumConverter.GetStencilOp(New.StencilFrontOpZPass));
|
OglEnumConverter.GetStencilOp(New.StencilFrontOpZPass));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.StencilFrontMask != Old.StencilFrontMask)
|
if (New.StencilFrontMask != _old.StencilFrontMask)
|
||||||
{
|
{
|
||||||
GL.StencilMaskSeparate(StencilFace.Front, New.StencilFrontMask);
|
GL.StencilMaskSeparate(StencilFace.Front, New.StencilFrontMask);
|
||||||
}
|
}
|
||||||
|
@ -277,42 +277,42 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
int scissorsApplied = 0;
|
int scissorsApplied = 0;
|
||||||
bool applyToAll = false;
|
bool applyToAll = false;
|
||||||
|
|
||||||
for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
|
for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++)
|
||||||
{
|
{
|
||||||
if (New.ScissorTestEnabled[Index])
|
if (New.ScissorTestEnabled[index])
|
||||||
{
|
{
|
||||||
// If viewport arrays are unavailable apply first scissor test to all or
|
// If viewport arrays are unavailable apply first scissor test to all or
|
||||||
// there is only 1 scissor test and it's the first, the scissor test applies to all viewports
|
// there is only 1 scissor test and it's the first, the scissor test applies to all viewports
|
||||||
if (!OGLExtension.Required.ViewportArray || (Index == 0 && New.ScissorTestCount == 1))
|
if (!OglExtension.Required.ViewportArray || (index == 0 && New.ScissorTestCount == 1))
|
||||||
{
|
{
|
||||||
GL.Enable(EnableCap.ScissorTest);
|
GL.Enable(EnableCap.ScissorTest);
|
||||||
applyToAll = true;
|
applyToAll = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GL.Enable(IndexedEnableCap.ScissorTest, Index);
|
GL.Enable(IndexedEnableCap.ScissorTest, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.ScissorTestEnabled[Index] != Old.ScissorTestEnabled[Index] ||
|
if (New.ScissorTestEnabled[index] != _old.ScissorTestEnabled[index] ||
|
||||||
New.ScissorTestX[Index] != Old.ScissorTestX[Index] ||
|
New.ScissorTestX[index] != _old.ScissorTestX[index] ||
|
||||||
New.ScissorTestY[Index] != Old.ScissorTestY[Index] ||
|
New.ScissorTestY[index] != _old.ScissorTestY[index] ||
|
||||||
New.ScissorTestWidth[Index] != Old.ScissorTestWidth[Index] ||
|
New.ScissorTestWidth[index] != _old.ScissorTestWidth[index] ||
|
||||||
New.ScissorTestHeight[Index] != Old.ScissorTestHeight[Index])
|
New.ScissorTestHeight[index] != _old.ScissorTestHeight[index])
|
||||||
{
|
{
|
||||||
if (applyToAll)
|
if (applyToAll)
|
||||||
{
|
{
|
||||||
GL.Scissor(New.ScissorTestX[Index], New.ScissorTestY[Index],
|
GL.Scissor(New.ScissorTestX[index], New.ScissorTestY[index],
|
||||||
New.ScissorTestWidth[Index], New.ScissorTestHeight[Index]);
|
New.ScissorTestWidth[index], New.ScissorTestHeight[index]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GL.ScissorIndexed(Index, New.ScissorTestX[Index], New.ScissorTestY[Index],
|
GL.ScissorIndexed(index, New.ScissorTestX[index], New.ScissorTestY[index],
|
||||||
New.ScissorTestWidth[Index], New.ScissorTestHeight[Index]);
|
New.ScissorTestWidth[index], New.ScissorTestHeight[index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If all scissor tests have been applied, or viewport arrays are unavailable we can skip remaining itterations
|
// If all scissor tests have been applied, or viewport arrays are unavailable we can skip remaining iterations
|
||||||
if (!OGLExtension.Required.ViewportArray || ++scissorsApplied == New.ScissorTestCount)
|
if (!OglExtension.Required.ViewportArray || ++scissorsApplied == New.ScissorTestCount)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -323,26 +323,26 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
if (New.BlendIndependent)
|
if (New.BlendIndependent)
|
||||||
{
|
{
|
||||||
for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
|
for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++)
|
||||||
{
|
{
|
||||||
SetBlendState(Index, New.Blends[Index], Old.Blends[Index]);
|
SetBlendState(index, New.Blends[index], _old.Blends[index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (New.BlendIndependent != Old.BlendIndependent)
|
if (New.BlendIndependent != _old.BlendIndependent)
|
||||||
{
|
{
|
||||||
SetAllBlendState(New.Blends[0]);
|
SetAllBlendState(New.Blends[0]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SetBlendState(New.Blends[0], Old.Blends[0]);
|
SetBlendState(New.Blends[0], _old.Blends[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.ColorMaskCommon)
|
if (New.ColorMaskCommon)
|
||||||
{
|
{
|
||||||
if (New.ColorMaskCommon != Old.ColorMaskCommon || !New.ColorMasks[0].Equals(Old.ColorMasks[0]))
|
if (New.ColorMaskCommon != _old.ColorMaskCommon || !New.ColorMasks[0].Equals(_old.ColorMasks[0]))
|
||||||
{
|
{
|
||||||
GL.ColorMask(
|
GL.ColorMask(
|
||||||
New.ColorMasks[0].Red,
|
New.ColorMasks[0].Red,
|
||||||
|
@ -353,39 +353,39 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
|
for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++)
|
||||||
{
|
{
|
||||||
if (!New.ColorMasks[Index].Equals(Old.ColorMasks[Index]))
|
if (!New.ColorMasks[index].Equals(_old.ColorMasks[index]))
|
||||||
{
|
{
|
||||||
GL.ColorMask(
|
GL.ColorMask(
|
||||||
Index,
|
index,
|
||||||
New.ColorMasks[Index].Red,
|
New.ColorMasks[index].Red,
|
||||||
New.ColorMasks[Index].Green,
|
New.ColorMasks[index].Green,
|
||||||
New.ColorMasks[Index].Blue,
|
New.ColorMasks[index].Blue,
|
||||||
New.ColorMasks[Index].Alpha);
|
New.ColorMasks[index].Alpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.PrimitiveRestartEnabled != Old.PrimitiveRestartEnabled)
|
if (New.PrimitiveRestartEnabled != _old.PrimitiveRestartEnabled)
|
||||||
{
|
{
|
||||||
Enable(EnableCap.PrimitiveRestart, New.PrimitiveRestartEnabled);
|
Enable(EnableCap.PrimitiveRestart, New.PrimitiveRestartEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.PrimitiveRestartEnabled)
|
if (New.PrimitiveRestartEnabled)
|
||||||
{
|
{
|
||||||
if (New.PrimitiveRestartIndex != Old.PrimitiveRestartIndex)
|
if (New.PrimitiveRestartIndex != _old.PrimitiveRestartIndex)
|
||||||
{
|
{
|
||||||
GL.PrimitiveRestartIndex(New.PrimitiveRestartIndex);
|
GL.PrimitiveRestartIndex(New.PrimitiveRestartIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Old = New;
|
_old = New;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Unbind(GalPipelineState State)
|
public void Unbind(GalPipelineState state)
|
||||||
{
|
{
|
||||||
if (State.ScissorTestCount > 0)
|
if (state.ScissorTestCount > 0)
|
||||||
{
|
{
|
||||||
GL.Disable(EnableCap.ScissorTest);
|
GL.Disable(EnableCap.ScissorTest);
|
||||||
}
|
}
|
||||||
|
@ -400,29 +400,29 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
if (New.SeparateAlpha)
|
if (New.SeparateAlpha)
|
||||||
{
|
{
|
||||||
GL.BlendEquationSeparate(
|
GL.BlendEquationSeparate(
|
||||||
OGLEnumConverter.GetBlendEquation(New.EquationRgb),
|
OglEnumConverter.GetBlendEquation(New.EquationRgb),
|
||||||
OGLEnumConverter.GetBlendEquation(New.EquationAlpha));
|
OglEnumConverter.GetBlendEquation(New.EquationAlpha));
|
||||||
|
|
||||||
GL.BlendFuncSeparate(
|
GL.BlendFuncSeparate(
|
||||||
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
|
(BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
|
||||||
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb),
|
(BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb),
|
||||||
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
|
(BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
|
||||||
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstAlpha));
|
(BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstAlpha));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GL.BlendEquation(OGLEnumConverter.GetBlendEquation(New.EquationRgb));
|
GL.BlendEquation(OglEnumConverter.GetBlendEquation(New.EquationRgb));
|
||||||
|
|
||||||
GL.BlendFunc(
|
GL.BlendFunc(
|
||||||
OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
|
OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
|
||||||
OGLEnumConverter.GetBlendFactor(New.FuncDstRgb));
|
OglEnumConverter.GetBlendFactor(New.FuncDstRgb));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetBlendState(BlendState New, BlendState Old)
|
private void SetBlendState(BlendState New, BlendState old)
|
||||||
{
|
{
|
||||||
if (New.Enabled != Old.Enabled)
|
if (New.Enabled != old.Enabled)
|
||||||
{
|
{
|
||||||
Enable(EnableCap.Blend, New.Enabled);
|
Enable(EnableCap.Blend, New.Enabled);
|
||||||
}
|
}
|
||||||
|
@ -431,91 +431,91 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
if (New.SeparateAlpha)
|
if (New.SeparateAlpha)
|
||||||
{
|
{
|
||||||
if (New.EquationRgb != Old.EquationRgb ||
|
if (New.EquationRgb != old.EquationRgb ||
|
||||||
New.EquationAlpha != Old.EquationAlpha)
|
New.EquationAlpha != old.EquationAlpha)
|
||||||
{
|
{
|
||||||
GL.BlendEquationSeparate(
|
GL.BlendEquationSeparate(
|
||||||
OGLEnumConverter.GetBlendEquation(New.EquationRgb),
|
OglEnumConverter.GetBlendEquation(New.EquationRgb),
|
||||||
OGLEnumConverter.GetBlendEquation(New.EquationAlpha));
|
OglEnumConverter.GetBlendEquation(New.EquationAlpha));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.FuncSrcRgb != Old.FuncSrcRgb ||
|
if (New.FuncSrcRgb != old.FuncSrcRgb ||
|
||||||
New.FuncDstRgb != Old.FuncDstRgb ||
|
New.FuncDstRgb != old.FuncDstRgb ||
|
||||||
New.FuncSrcAlpha != Old.FuncSrcAlpha ||
|
New.FuncSrcAlpha != old.FuncSrcAlpha ||
|
||||||
New.FuncDstAlpha != Old.FuncDstAlpha)
|
New.FuncDstAlpha != old.FuncDstAlpha)
|
||||||
{
|
{
|
||||||
GL.BlendFuncSeparate(
|
GL.BlendFuncSeparate(
|
||||||
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
|
(BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
|
||||||
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb),
|
(BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb),
|
||||||
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
|
(BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
|
||||||
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstAlpha));
|
(BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstAlpha));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (New.EquationRgb != Old.EquationRgb)
|
if (New.EquationRgb != old.EquationRgb)
|
||||||
{
|
{
|
||||||
GL.BlendEquation(OGLEnumConverter.GetBlendEquation(New.EquationRgb));
|
GL.BlendEquation(OglEnumConverter.GetBlendEquation(New.EquationRgb));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.FuncSrcRgb != Old.FuncSrcRgb ||
|
if (New.FuncSrcRgb != old.FuncSrcRgb ||
|
||||||
New.FuncDstRgb != Old.FuncDstRgb)
|
New.FuncDstRgb != old.FuncDstRgb)
|
||||||
{
|
{
|
||||||
GL.BlendFunc(
|
GL.BlendFunc(
|
||||||
OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
|
OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
|
||||||
OGLEnumConverter.GetBlendFactor(New.FuncDstRgb));
|
OglEnumConverter.GetBlendFactor(New.FuncDstRgb));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetBlendState(int Index, BlendState New, BlendState Old)
|
private void SetBlendState(int index, BlendState New, BlendState old)
|
||||||
{
|
{
|
||||||
if (New.Enabled != Old.Enabled)
|
if (New.Enabled != old.Enabled)
|
||||||
{
|
{
|
||||||
Enable(IndexedEnableCap.Blend, Index, New.Enabled);
|
Enable(IndexedEnableCap.Blend, index, New.Enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.Enabled)
|
if (New.Enabled)
|
||||||
{
|
{
|
||||||
if (New.SeparateAlpha)
|
if (New.SeparateAlpha)
|
||||||
{
|
{
|
||||||
if (New.EquationRgb != Old.EquationRgb ||
|
if (New.EquationRgb != old.EquationRgb ||
|
||||||
New.EquationAlpha != Old.EquationAlpha)
|
New.EquationAlpha != old.EquationAlpha)
|
||||||
{
|
{
|
||||||
GL.BlendEquationSeparate(
|
GL.BlendEquationSeparate(
|
||||||
Index,
|
index,
|
||||||
OGLEnumConverter.GetBlendEquation(New.EquationRgb),
|
OglEnumConverter.GetBlendEquation(New.EquationRgb),
|
||||||
OGLEnumConverter.GetBlendEquation(New.EquationAlpha));
|
OglEnumConverter.GetBlendEquation(New.EquationAlpha));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.FuncSrcRgb != Old.FuncSrcRgb ||
|
if (New.FuncSrcRgb != old.FuncSrcRgb ||
|
||||||
New.FuncDstRgb != Old.FuncDstRgb ||
|
New.FuncDstRgb != old.FuncDstRgb ||
|
||||||
New.FuncSrcAlpha != Old.FuncSrcAlpha ||
|
New.FuncSrcAlpha != old.FuncSrcAlpha ||
|
||||||
New.FuncDstAlpha != Old.FuncDstAlpha)
|
New.FuncDstAlpha != old.FuncDstAlpha)
|
||||||
{
|
{
|
||||||
GL.BlendFuncSeparate(
|
GL.BlendFuncSeparate(
|
||||||
Index,
|
index,
|
||||||
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
|
(BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
|
||||||
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb),
|
(BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb),
|
||||||
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
|
(BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
|
||||||
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstAlpha));
|
(BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstAlpha));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (New.EquationRgb != Old.EquationRgb)
|
if (New.EquationRgb != old.EquationRgb)
|
||||||
{
|
{
|
||||||
GL.BlendEquation(Index, OGLEnumConverter.GetBlendEquation(New.EquationRgb));
|
GL.BlendEquation(index, OglEnumConverter.GetBlendEquation(New.EquationRgb));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New.FuncSrcRgb != Old.FuncSrcRgb ||
|
if (New.FuncSrcRgb != old.FuncSrcRgb ||
|
||||||
New.FuncDstRgb != Old.FuncDstRgb)
|
New.FuncDstRgb != old.FuncDstRgb)
|
||||||
{
|
{
|
||||||
GL.BlendFunc(
|
GL.BlendFunc(
|
||||||
Index,
|
index,
|
||||||
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
|
(BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
|
||||||
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb));
|
(BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -523,310 +523,310 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
private void BindConstBuffers(GalPipelineState New)
|
private void BindConstBuffers(GalPipelineState New)
|
||||||
{
|
{
|
||||||
int FreeBinding = OGLShader.ReservedCbufCount;
|
int freeBinding = OglShader.ReservedCbufCount;
|
||||||
|
|
||||||
void BindIfNotNull(OGLShaderStage Stage)
|
void BindIfNotNull(OglShaderStage stage)
|
||||||
{
|
{
|
||||||
if (Stage != null)
|
if (stage != null)
|
||||||
{
|
{
|
||||||
foreach (ShaderDeclInfo DeclInfo in Stage.ConstBufferUsage)
|
foreach (ShaderDeclInfo declInfo in stage.ConstBufferUsage)
|
||||||
{
|
{
|
||||||
long Key = New.ConstBufferKeys[(int)Stage.Type][DeclInfo.Cbuf];
|
long key = New.ConstBufferKeys[(int)stage.Type][declInfo.Cbuf];
|
||||||
|
|
||||||
if (Key != 0 && Buffer.TryGetUbo(Key, out int UboHandle))
|
if (key != 0 && _buffer.TryGetUbo(key, out int uboHandle))
|
||||||
{
|
{
|
||||||
GL.BindBufferBase(BufferRangeTarget.UniformBuffer, FreeBinding, UboHandle);
|
GL.BindBufferBase(BufferRangeTarget.UniformBuffer, freeBinding, uboHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeBinding++;
|
freeBinding++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BindIfNotNull(Shader.Current.Vertex);
|
BindIfNotNull(_shader.Current.Vertex);
|
||||||
BindIfNotNull(Shader.Current.TessControl);
|
BindIfNotNull(_shader.Current.TessControl);
|
||||||
BindIfNotNull(Shader.Current.TessEvaluation);
|
BindIfNotNull(_shader.Current.TessEvaluation);
|
||||||
BindIfNotNull(Shader.Current.Geometry);
|
BindIfNotNull(_shader.Current.Geometry);
|
||||||
BindIfNotNull(Shader.Current.Fragment);
|
BindIfNotNull(_shader.Current.Fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BindVertexLayout(GalPipelineState New)
|
private void BindVertexLayout(GalPipelineState New)
|
||||||
{
|
{
|
||||||
foreach (GalVertexBinding Binding in New.VertexBindings)
|
foreach (GalVertexBinding binding in New.VertexBindings)
|
||||||
{
|
{
|
||||||
if (!Binding.Enabled || !Rasterizer.TryGetVbo(Binding.VboKey, out int VboHandle))
|
if (!binding.Enabled || !_rasterizer.TryGetVbo(binding.VboKey, out int vboHandle))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VaoHandle == 0)
|
if (_vaoHandle == 0)
|
||||||
{
|
{
|
||||||
VaoHandle = GL.GenVertexArray();
|
_vaoHandle = GL.GenVertexArray();
|
||||||
|
|
||||||
//Vertex arrays shouldn't be used anywhere else in OpenGL's backend
|
//Vertex arrays shouldn't be used anywhere else in OpenGL's backend
|
||||||
//if you want to use it, move this line out of the if
|
//if you want to use it, move this line out of the if
|
||||||
GL.BindVertexArray(VaoHandle);
|
GL.BindVertexArray(_vaoHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (GalVertexAttrib Attrib in Binding.Attribs)
|
foreach (GalVertexAttrib attrib in binding.Attribs)
|
||||||
{
|
{
|
||||||
//Skip uninitialized attributes.
|
//Skip uninitialized attributes.
|
||||||
if (Attrib.Size == 0)
|
if (attrib.Size == 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
GL.BindBuffer(BufferTarget.ArrayBuffer, vboHandle);
|
||||||
|
|
||||||
bool Unsigned =
|
bool unsigned =
|
||||||
Attrib.Type == GalVertexAttribType.Unorm ||
|
attrib.Type == GalVertexAttribType.Unorm ||
|
||||||
Attrib.Type == GalVertexAttribType.Uint ||
|
attrib.Type == GalVertexAttribType.Uint ||
|
||||||
Attrib.Type == GalVertexAttribType.Uscaled;
|
attrib.Type == GalVertexAttribType.Uscaled;
|
||||||
|
|
||||||
bool Normalize =
|
bool normalize =
|
||||||
Attrib.Type == GalVertexAttribType.Snorm ||
|
attrib.Type == GalVertexAttribType.Snorm ||
|
||||||
Attrib.Type == GalVertexAttribType.Unorm;
|
attrib.Type == GalVertexAttribType.Unorm;
|
||||||
|
|
||||||
VertexAttribPointerType Type = 0;
|
VertexAttribPointerType type = 0;
|
||||||
|
|
||||||
if (Attrib.Type == GalVertexAttribType.Float)
|
if (attrib.Type == GalVertexAttribType.Float)
|
||||||
{
|
{
|
||||||
Type = GetType(FloatAttribTypes, Attrib);
|
type = GetType(_floatAttribTypes, attrib);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Unsigned)
|
if (unsigned)
|
||||||
{
|
{
|
||||||
Type = GetType(UnsignedAttribTypes, Attrib);
|
type = GetType(_unsignedAttribTypes, attrib);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Type = GetType(SignedAttribTypes, Attrib);
|
type = GetType(_signedAttribTypes, attrib);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!AttribElements.TryGetValue(Attrib.Size, out int Size))
|
if (!_attribElements.TryGetValue(attrib.Size, out int size))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Invalid attribute size \"" + Attrib.Size + "\"!");
|
throw new InvalidOperationException("Invalid attribute size \"" + attrib.Size + "\"!");
|
||||||
}
|
}
|
||||||
|
|
||||||
int Offset = Attrib.Offset;
|
int offset = attrib.Offset;
|
||||||
|
|
||||||
if (Binding.Stride != 0)
|
if (binding.Stride != 0)
|
||||||
{
|
{
|
||||||
GL.EnableVertexAttribArray(Attrib.Index);
|
GL.EnableVertexAttribArray(attrib.Index);
|
||||||
|
|
||||||
if (Attrib.Type == GalVertexAttribType.Sint ||
|
if (attrib.Type == GalVertexAttribType.Sint ||
|
||||||
Attrib.Type == GalVertexAttribType.Uint)
|
attrib.Type == GalVertexAttribType.Uint)
|
||||||
{
|
{
|
||||||
IntPtr Pointer = new IntPtr(Offset);
|
IntPtr pointer = new IntPtr(offset);
|
||||||
|
|
||||||
VertexAttribIntegerType IType = (VertexAttribIntegerType)Type;
|
VertexAttribIntegerType iType = (VertexAttribIntegerType)type;
|
||||||
|
|
||||||
GL.VertexAttribIPointer(Attrib.Index, Size, IType, Binding.Stride, Pointer);
|
GL.VertexAttribIPointer(attrib.Index, size, iType, binding.Stride, pointer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Binding.Stride, Offset);
|
GL.VertexAttribPointer(attrib.Index, size, type, normalize, binding.Stride, offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GL.DisableVertexAttribArray(Attrib.Index);
|
GL.DisableVertexAttribArray(attrib.Index);
|
||||||
|
|
||||||
SetConstAttrib(Attrib);
|
SetConstAttrib(attrib);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Binding.Instanced && Binding.Divisor != 0)
|
if (binding.Instanced && binding.Divisor != 0)
|
||||||
{
|
{
|
||||||
GL.VertexAttribDivisor(Attrib.Index, 1);
|
GL.VertexAttribDivisor(attrib.Index, 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GL.VertexAttribDivisor(Attrib.Index, 0);
|
GL.VertexAttribDivisor(attrib.Index, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static VertexAttribPointerType GetType(Dictionary<GalVertexAttribSize, VertexAttribPointerType> Dict, GalVertexAttrib Attrib)
|
private static VertexAttribPointerType GetType(Dictionary<GalVertexAttribSize, VertexAttribPointerType> dict, GalVertexAttrib attrib)
|
||||||
{
|
{
|
||||||
if (!Dict.TryGetValue(Attrib.Size, out VertexAttribPointerType Type))
|
if (!dict.TryGetValue(attrib.Size, out VertexAttribPointerType type))
|
||||||
{
|
{
|
||||||
ThrowUnsupportedAttrib(Attrib);
|
ThrowUnsupportedAttrib(attrib);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe static void SetConstAttrib(GalVertexAttrib Attrib)
|
private static unsafe void SetConstAttrib(GalVertexAttrib attrib)
|
||||||
{
|
{
|
||||||
if (Attrib.Size == GalVertexAttribSize._10_10_10_2 ||
|
if (attrib.Size == GalVertexAttribSize._10_10_10_2 ||
|
||||||
Attrib.Size == GalVertexAttribSize._11_11_10)
|
attrib.Size == GalVertexAttribSize._11_11_10)
|
||||||
{
|
{
|
||||||
ThrowUnsupportedAttrib(Attrib);
|
ThrowUnsupportedAttrib(attrib);
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (byte* Ptr = Attrib.Data)
|
fixed (byte* ptr = attrib.Data)
|
||||||
{
|
{
|
||||||
if (Attrib.Type == GalVertexAttribType.Unorm)
|
if (attrib.Type == GalVertexAttribType.Unorm)
|
||||||
{
|
{
|
||||||
switch (Attrib.Size)
|
switch (attrib.Size)
|
||||||
{
|
{
|
||||||
case GalVertexAttribSize._8:
|
case GalVertexAttribSize._8:
|
||||||
case GalVertexAttribSize._8_8:
|
case GalVertexAttribSize._8_8:
|
||||||
case GalVertexAttribSize._8_8_8:
|
case GalVertexAttribSize._8_8_8:
|
||||||
case GalVertexAttribSize._8_8_8_8:
|
case GalVertexAttribSize._8_8_8_8:
|
||||||
GL.VertexAttrib4N((uint)Attrib.Index, Ptr);
|
GL.VertexAttrib4N((uint)attrib.Index, ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GalVertexAttribSize._16:
|
case GalVertexAttribSize._16:
|
||||||
case GalVertexAttribSize._16_16:
|
case GalVertexAttribSize._16_16:
|
||||||
case GalVertexAttribSize._16_16_16:
|
case GalVertexAttribSize._16_16_16:
|
||||||
case GalVertexAttribSize._16_16_16_16:
|
case GalVertexAttribSize._16_16_16_16:
|
||||||
GL.VertexAttrib4N((uint)Attrib.Index, (ushort*)Ptr);
|
GL.VertexAttrib4N((uint)attrib.Index, (ushort*)ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GalVertexAttribSize._32:
|
case GalVertexAttribSize._32:
|
||||||
case GalVertexAttribSize._32_32:
|
case GalVertexAttribSize._32_32:
|
||||||
case GalVertexAttribSize._32_32_32:
|
case GalVertexAttribSize._32_32_32:
|
||||||
case GalVertexAttribSize._32_32_32_32:
|
case GalVertexAttribSize._32_32_32_32:
|
||||||
GL.VertexAttrib4N((uint)Attrib.Index, (uint*)Ptr);
|
GL.VertexAttrib4N((uint)attrib.Index, (uint*)ptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Attrib.Type == GalVertexAttribType.Snorm)
|
else if (attrib.Type == GalVertexAttribType.Snorm)
|
||||||
{
|
{
|
||||||
switch (Attrib.Size)
|
switch (attrib.Size)
|
||||||
{
|
{
|
||||||
case GalVertexAttribSize._8:
|
case GalVertexAttribSize._8:
|
||||||
case GalVertexAttribSize._8_8:
|
case GalVertexAttribSize._8_8:
|
||||||
case GalVertexAttribSize._8_8_8:
|
case GalVertexAttribSize._8_8_8:
|
||||||
case GalVertexAttribSize._8_8_8_8:
|
case GalVertexAttribSize._8_8_8_8:
|
||||||
GL.VertexAttrib4N((uint)Attrib.Index, (sbyte*)Ptr);
|
GL.VertexAttrib4N((uint)attrib.Index, (sbyte*)ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GalVertexAttribSize._16:
|
case GalVertexAttribSize._16:
|
||||||
case GalVertexAttribSize._16_16:
|
case GalVertexAttribSize._16_16:
|
||||||
case GalVertexAttribSize._16_16_16:
|
case GalVertexAttribSize._16_16_16:
|
||||||
case GalVertexAttribSize._16_16_16_16:
|
case GalVertexAttribSize._16_16_16_16:
|
||||||
GL.VertexAttrib4N((uint)Attrib.Index, (short*)Ptr);
|
GL.VertexAttrib4N((uint)attrib.Index, (short*)ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GalVertexAttribSize._32:
|
case GalVertexAttribSize._32:
|
||||||
case GalVertexAttribSize._32_32:
|
case GalVertexAttribSize._32_32:
|
||||||
case GalVertexAttribSize._32_32_32:
|
case GalVertexAttribSize._32_32_32:
|
||||||
case GalVertexAttribSize._32_32_32_32:
|
case GalVertexAttribSize._32_32_32_32:
|
||||||
GL.VertexAttrib4N((uint)Attrib.Index, (int*)Ptr);
|
GL.VertexAttrib4N((uint)attrib.Index, (int*)ptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Attrib.Type == GalVertexAttribType.Uint)
|
else if (attrib.Type == GalVertexAttribType.Uint)
|
||||||
{
|
{
|
||||||
switch (Attrib.Size)
|
switch (attrib.Size)
|
||||||
{
|
{
|
||||||
case GalVertexAttribSize._8:
|
case GalVertexAttribSize._8:
|
||||||
case GalVertexAttribSize._8_8:
|
case GalVertexAttribSize._8_8:
|
||||||
case GalVertexAttribSize._8_8_8:
|
case GalVertexAttribSize._8_8_8:
|
||||||
case GalVertexAttribSize._8_8_8_8:
|
case GalVertexAttribSize._8_8_8_8:
|
||||||
GL.VertexAttribI4((uint)Attrib.Index, Ptr);
|
GL.VertexAttribI4((uint)attrib.Index, ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GalVertexAttribSize._16:
|
case GalVertexAttribSize._16:
|
||||||
case GalVertexAttribSize._16_16:
|
case GalVertexAttribSize._16_16:
|
||||||
case GalVertexAttribSize._16_16_16:
|
case GalVertexAttribSize._16_16_16:
|
||||||
case GalVertexAttribSize._16_16_16_16:
|
case GalVertexAttribSize._16_16_16_16:
|
||||||
GL.VertexAttribI4((uint)Attrib.Index, (ushort*)Ptr);
|
GL.VertexAttribI4((uint)attrib.Index, (ushort*)ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GalVertexAttribSize._32:
|
case GalVertexAttribSize._32:
|
||||||
case GalVertexAttribSize._32_32:
|
case GalVertexAttribSize._32_32:
|
||||||
case GalVertexAttribSize._32_32_32:
|
case GalVertexAttribSize._32_32_32:
|
||||||
case GalVertexAttribSize._32_32_32_32:
|
case GalVertexAttribSize._32_32_32_32:
|
||||||
GL.VertexAttribI4((uint)Attrib.Index, (uint*)Ptr);
|
GL.VertexAttribI4((uint)attrib.Index, (uint*)ptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Attrib.Type == GalVertexAttribType.Sint)
|
else if (attrib.Type == GalVertexAttribType.Sint)
|
||||||
{
|
{
|
||||||
switch (Attrib.Size)
|
switch (attrib.Size)
|
||||||
{
|
{
|
||||||
case GalVertexAttribSize._8:
|
case GalVertexAttribSize._8:
|
||||||
case GalVertexAttribSize._8_8:
|
case GalVertexAttribSize._8_8:
|
||||||
case GalVertexAttribSize._8_8_8:
|
case GalVertexAttribSize._8_8_8:
|
||||||
case GalVertexAttribSize._8_8_8_8:
|
case GalVertexAttribSize._8_8_8_8:
|
||||||
GL.VertexAttribI4((uint)Attrib.Index, (sbyte*)Ptr);
|
GL.VertexAttribI4((uint)attrib.Index, (sbyte*)ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GalVertexAttribSize._16:
|
case GalVertexAttribSize._16:
|
||||||
case GalVertexAttribSize._16_16:
|
case GalVertexAttribSize._16_16:
|
||||||
case GalVertexAttribSize._16_16_16:
|
case GalVertexAttribSize._16_16_16:
|
||||||
case GalVertexAttribSize._16_16_16_16:
|
case GalVertexAttribSize._16_16_16_16:
|
||||||
GL.VertexAttribI4((uint)Attrib.Index, (short*)Ptr);
|
GL.VertexAttribI4((uint)attrib.Index, (short*)ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GalVertexAttribSize._32:
|
case GalVertexAttribSize._32:
|
||||||
case GalVertexAttribSize._32_32:
|
case GalVertexAttribSize._32_32:
|
||||||
case GalVertexAttribSize._32_32_32:
|
case GalVertexAttribSize._32_32_32:
|
||||||
case GalVertexAttribSize._32_32_32_32:
|
case GalVertexAttribSize._32_32_32_32:
|
||||||
GL.VertexAttribI4((uint)Attrib.Index, (int*)Ptr);
|
GL.VertexAttribI4((uint)attrib.Index, (int*)ptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Attrib.Type == GalVertexAttribType.Float)
|
else if (attrib.Type == GalVertexAttribType.Float)
|
||||||
{
|
{
|
||||||
switch (Attrib.Size)
|
switch (attrib.Size)
|
||||||
{
|
{
|
||||||
case GalVertexAttribSize._32:
|
case GalVertexAttribSize._32:
|
||||||
case GalVertexAttribSize._32_32:
|
case GalVertexAttribSize._32_32:
|
||||||
case GalVertexAttribSize._32_32_32:
|
case GalVertexAttribSize._32_32_32:
|
||||||
case GalVertexAttribSize._32_32_32_32:
|
case GalVertexAttribSize._32_32_32_32:
|
||||||
GL.VertexAttrib4(Attrib.Index, (float*)Ptr);
|
GL.VertexAttrib4(attrib.Index, (float*)ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: ThrowUnsupportedAttrib(Attrib); break;
|
default: ThrowUnsupportedAttrib(attrib); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ThrowUnsupportedAttrib(GalVertexAttrib Attrib)
|
private static void ThrowUnsupportedAttrib(GalVertexAttrib attrib)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException("Unsupported size \"" + Attrib.Size + "\" on type \"" + Attrib.Type + "\"!");
|
throw new NotImplementedException("Unsupported size \"" + attrib.Size + "\" on type \"" + attrib.Type + "\"!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Enable(EnableCap Cap, bool Enabled)
|
private void Enable(EnableCap cap, bool enabled)
|
||||||
{
|
{
|
||||||
if (Enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
GL.Enable(Cap);
|
GL.Enable(cap);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GL.Disable(Cap);
|
GL.Disable(cap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Enable(IndexedEnableCap Cap, int Index, bool Enabled)
|
private void Enable(IndexedEnableCap cap, int index, bool enabled)
|
||||||
{
|
{
|
||||||
if (Enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
GL.Enable(Cap, Index);
|
GL.Enable(cap, index);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GL.Disable(Cap, Index);
|
GL.Disable(cap, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetDepthMask()
|
public void ResetDepthMask()
|
||||||
{
|
{
|
||||||
Old.DepthWriteEnabled = true;
|
_old.DepthWriteEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetColorMask(int Index)
|
public void ResetColorMask(int index)
|
||||||
{
|
{
|
||||||
Old.ColorMasks[Index] = ColorMaskState.Default;
|
_old.ColorMasks[index] = ColorMaskState.Default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
207
Ryujinx.Graphics/Gal/OpenGL/OglRasterizer.cs
Normal file
207
Ryujinx.Graphics/Gal/OpenGL/OglRasterizer.cs
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
{
|
||||||
|
class OglRasterizer : IGalRasterizer
|
||||||
|
{
|
||||||
|
private const long MaxVertexBufferCacheSize = 128 * 1024 * 1024;
|
||||||
|
private const long MaxIndexBufferCacheSize = 64 * 1024 * 1024;
|
||||||
|
|
||||||
|
private int[] _vertexBuffers;
|
||||||
|
|
||||||
|
private OglCachedResource<int> _vboCache;
|
||||||
|
private OglCachedResource<int> _iboCache;
|
||||||
|
|
||||||
|
private struct IbInfo
|
||||||
|
{
|
||||||
|
public int Count;
|
||||||
|
public int ElemSizeLog2;
|
||||||
|
|
||||||
|
public DrawElementsType Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IbInfo _indexBuffer;
|
||||||
|
|
||||||
|
public OglRasterizer()
|
||||||
|
{
|
||||||
|
_vertexBuffers = new int[32];
|
||||||
|
|
||||||
|
_vboCache = new OglCachedResource<int>(GL.DeleteBuffer, MaxVertexBufferCacheSize);
|
||||||
|
_iboCache = new OglCachedResource<int>(GL.DeleteBuffer, MaxIndexBufferCacheSize);
|
||||||
|
|
||||||
|
_indexBuffer = new IbInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LockCaches()
|
||||||
|
{
|
||||||
|
_vboCache.Lock();
|
||||||
|
_iboCache.Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnlockCaches()
|
||||||
|
{
|
||||||
|
_vboCache.Unlock();
|
||||||
|
_iboCache.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearBuffers(
|
||||||
|
GalClearBufferFlags flags,
|
||||||
|
int attachment,
|
||||||
|
float red,
|
||||||
|
float green,
|
||||||
|
float blue,
|
||||||
|
float alpha,
|
||||||
|
float depth,
|
||||||
|
int stencil)
|
||||||
|
{
|
||||||
|
GL.ColorMask(
|
||||||
|
attachment,
|
||||||
|
flags.HasFlag(GalClearBufferFlags.ColorRed),
|
||||||
|
flags.HasFlag(GalClearBufferFlags.ColorGreen),
|
||||||
|
flags.HasFlag(GalClearBufferFlags.ColorBlue),
|
||||||
|
flags.HasFlag(GalClearBufferFlags.ColorAlpha));
|
||||||
|
|
||||||
|
GL.ClearBuffer(ClearBuffer.Color, attachment, new float[] { red, green, blue, alpha });
|
||||||
|
|
||||||
|
GL.ColorMask(attachment, true, true, true, true);
|
||||||
|
GL.DepthMask(true);
|
||||||
|
|
||||||
|
if (flags.HasFlag(GalClearBufferFlags.Depth))
|
||||||
|
{
|
||||||
|
GL.ClearBuffer(ClearBuffer.Depth, 0, ref depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags.HasFlag(GalClearBufferFlags.Stencil))
|
||||||
|
{
|
||||||
|
GL.ClearBuffer(ClearBuffer.Stencil, 0, ref stencil);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsVboCached(long key, long dataSize)
|
||||||
|
{
|
||||||
|
return _vboCache.TryGetSize(key, out long size) && size == dataSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsIboCached(long key, long dataSize)
|
||||||
|
{
|
||||||
|
return _iboCache.TryGetSize(key, out long size) && size == dataSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateVbo(long key, int dataSize, IntPtr hostAddress)
|
||||||
|
{
|
||||||
|
int handle = GL.GenBuffer();
|
||||||
|
|
||||||
|
_vboCache.AddOrUpdate(key, handle, dataSize);
|
||||||
|
|
||||||
|
IntPtr length = new IntPtr(dataSize);
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.ArrayBuffer, handle);
|
||||||
|
GL.BufferData(BufferTarget.ArrayBuffer, length, hostAddress, BufferUsageHint.StreamDraw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateVbo(long key, byte[] data)
|
||||||
|
{
|
||||||
|
int handle = GL.GenBuffer();
|
||||||
|
|
||||||
|
_vboCache.AddOrUpdate(key, handle, data.Length);
|
||||||
|
|
||||||
|
IntPtr length = new IntPtr(data.Length);
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.ArrayBuffer, handle);
|
||||||
|
GL.BufferData(BufferTarget.ArrayBuffer, length, data, BufferUsageHint.StreamDraw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateIbo(long key, int dataSize, IntPtr hostAddress)
|
||||||
|
{
|
||||||
|
int handle = GL.GenBuffer();
|
||||||
|
|
||||||
|
_iboCache.AddOrUpdate(key, handle, (uint)dataSize);
|
||||||
|
|
||||||
|
IntPtr length = new IntPtr(dataSize);
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, handle);
|
||||||
|
GL.BufferData(BufferTarget.ElementArrayBuffer, length, hostAddress, BufferUsageHint.StreamDraw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateIbo(long key, int dataSize, byte[] buffer)
|
||||||
|
{
|
||||||
|
int handle = GL.GenBuffer();
|
||||||
|
|
||||||
|
_iboCache.AddOrUpdate(key, handle, dataSize);
|
||||||
|
|
||||||
|
IntPtr length = new IntPtr(buffer.Length);
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, handle);
|
||||||
|
GL.BufferData(BufferTarget.ElementArrayBuffer, length, buffer, BufferUsageHint.StreamDraw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetIndexArray(int size, GalIndexFormat format)
|
||||||
|
{
|
||||||
|
_indexBuffer.Type = OglEnumConverter.GetDrawElementsType(format);
|
||||||
|
|
||||||
|
_indexBuffer.Count = size >> (int)format;
|
||||||
|
|
||||||
|
_indexBuffer.ElemSizeLog2 = (int)format;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawArrays(int first, int count, GalPrimitiveType primType)
|
||||||
|
{
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (primType == GalPrimitiveType.Quads)
|
||||||
|
{
|
||||||
|
for (int offset = 0; offset < count; offset += 4)
|
||||||
|
{
|
||||||
|
GL.DrawArrays(PrimitiveType.TriangleFan, first + offset, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (primType == GalPrimitiveType.QuadStrip)
|
||||||
|
{
|
||||||
|
GL.DrawArrays(PrimitiveType.TriangleFan, first, 4);
|
||||||
|
|
||||||
|
for (int offset = 2; offset < count; offset += 2)
|
||||||
|
{
|
||||||
|
GL.DrawArrays(PrimitiveType.TriangleFan, first + offset, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL.DrawArrays(OglEnumConverter.GetPrimitiveType(primType), first, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawElements(long iboKey, int first, int vertexBase, GalPrimitiveType primType)
|
||||||
|
{
|
||||||
|
if (!_iboCache.TryGetValue(iboKey, out int iboHandle))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrimitiveType mode = OglEnumConverter.GetPrimitiveType(primType);
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, iboHandle);
|
||||||
|
|
||||||
|
first <<= _indexBuffer.ElemSizeLog2;
|
||||||
|
|
||||||
|
if (vertexBase != 0)
|
||||||
|
{
|
||||||
|
IntPtr indices = new IntPtr(first);
|
||||||
|
|
||||||
|
GL.DrawElementsBaseVertex(mode, _indexBuffer.Count, _indexBuffer.Type, indices, vertexBase);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL.DrawElements(mode, _indexBuffer.Count, _indexBuffer.Type, first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetVbo(long vboKey, out int vboHandle)
|
||||||
|
{
|
||||||
|
return _vboCache.TryGetValue(vboKey, out vboHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
549
Ryujinx.Graphics/Gal/OpenGL/OglRenderTarget.cs
Normal file
549
Ryujinx.Graphics/Gal/OpenGL/OglRenderTarget.cs
Normal file
|
@ -0,0 +1,549 @@
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using Ryujinx.Graphics.Texture;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
{
|
||||||
|
class OglRenderTarget : IGalRenderTarget
|
||||||
|
{
|
||||||
|
private const int NativeWidth = 1280;
|
||||||
|
private const int NativeHeight = 720;
|
||||||
|
|
||||||
|
private const int RenderTargetsCount = GalPipelineState.RenderTargetsCount;
|
||||||
|
|
||||||
|
private struct Rect
|
||||||
|
{
|
||||||
|
public int X { get; private set; }
|
||||||
|
public int Y { get; private set; }
|
||||||
|
public int Width { get; private set; }
|
||||||
|
public int Height { get; private set; }
|
||||||
|
|
||||||
|
public Rect(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Width = width;
|
||||||
|
Height = height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FrameBufferAttachments
|
||||||
|
{
|
||||||
|
public int MapCount { get; set; }
|
||||||
|
|
||||||
|
public DrawBuffersEnum[] Map { get; private set; }
|
||||||
|
|
||||||
|
public long[] Colors { get; private set; }
|
||||||
|
|
||||||
|
public long Zeta { get; set; }
|
||||||
|
|
||||||
|
public FrameBufferAttachments()
|
||||||
|
{
|
||||||
|
Colors = new long[RenderTargetsCount];
|
||||||
|
|
||||||
|
Map = new DrawBuffersEnum[RenderTargetsCount];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(FrameBufferAttachments source)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < RenderTargetsCount; index++)
|
||||||
|
{
|
||||||
|
Map[index] = source.Map[index];
|
||||||
|
|
||||||
|
Colors[index] = source.Colors[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
MapCount = source.MapCount;
|
||||||
|
Zeta = source.Zeta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] _colorHandles;
|
||||||
|
private int _zetaHandle;
|
||||||
|
|
||||||
|
private OglTexture _texture;
|
||||||
|
|
||||||
|
private ImageHandler _readTex;
|
||||||
|
|
||||||
|
private Rect _window;
|
||||||
|
|
||||||
|
private float[] _viewports;
|
||||||
|
|
||||||
|
private bool _flipX;
|
||||||
|
private bool _flipY;
|
||||||
|
|
||||||
|
private int _cropTop;
|
||||||
|
private int _cropLeft;
|
||||||
|
private int _cropRight;
|
||||||
|
private int _cropBottom;
|
||||||
|
|
||||||
|
//This framebuffer is used to attach guest rendertargets,
|
||||||
|
//think of it as a dummy OpenGL VAO
|
||||||
|
private int _dummyFrameBuffer;
|
||||||
|
|
||||||
|
//These framebuffers are used to blit images
|
||||||
|
private int _srcFb;
|
||||||
|
private int _dstFb;
|
||||||
|
|
||||||
|
private FrameBufferAttachments _attachments;
|
||||||
|
private FrameBufferAttachments _oldAttachments;
|
||||||
|
|
||||||
|
private int _copyPbo;
|
||||||
|
|
||||||
|
public bool FramebufferSrgb { get; set; }
|
||||||
|
|
||||||
|
public OglRenderTarget(OglTexture texture)
|
||||||
|
{
|
||||||
|
_attachments = new FrameBufferAttachments();
|
||||||
|
|
||||||
|
_oldAttachments = new FrameBufferAttachments();
|
||||||
|
|
||||||
|
_colorHandles = new int[RenderTargetsCount];
|
||||||
|
|
||||||
|
_viewports = new float[RenderTargetsCount * 4];
|
||||||
|
|
||||||
|
_texture = texture;
|
||||||
|
|
||||||
|
texture.TextureDeleted += TextureDeletionHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TextureDeletionHandler(object sender, int handle)
|
||||||
|
{
|
||||||
|
//Texture was deleted, the handle is no longer valid, so
|
||||||
|
//reset all uses of this handle on a render target.
|
||||||
|
for (int attachment = 0; attachment < RenderTargetsCount; attachment++)
|
||||||
|
{
|
||||||
|
if (_colorHandles[attachment] == handle)
|
||||||
|
{
|
||||||
|
_colorHandles[attachment] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_zetaHandle == handle)
|
||||||
|
{
|
||||||
|
_zetaHandle = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Bind()
|
||||||
|
{
|
||||||
|
if (_dummyFrameBuffer == 0)
|
||||||
|
{
|
||||||
|
_dummyFrameBuffer = GL.GenFramebuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, _dummyFrameBuffer);
|
||||||
|
|
||||||
|
ImageHandler cachedImage;
|
||||||
|
|
||||||
|
for (int attachment = 0; attachment < RenderTargetsCount; attachment++)
|
||||||
|
{
|
||||||
|
long key = _attachments.Colors[attachment];
|
||||||
|
|
||||||
|
int handle = 0;
|
||||||
|
|
||||||
|
if (key != 0 && _texture.TryGetImageHandler(key, out cachedImage))
|
||||||
|
{
|
||||||
|
handle = cachedImage.Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle == _colorHandles[attachment])
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.FramebufferTexture(
|
||||||
|
FramebufferTarget.DrawFramebuffer,
|
||||||
|
FramebufferAttachment.ColorAttachment0 + attachment,
|
||||||
|
handle,
|
||||||
|
0);
|
||||||
|
|
||||||
|
_colorHandles[attachment] = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_attachments.Zeta != 0 && _texture.TryGetImageHandler(_attachments.Zeta, out cachedImage))
|
||||||
|
{
|
||||||
|
if (cachedImage.Handle != _zetaHandle)
|
||||||
|
{
|
||||||
|
if (cachedImage.HasDepth && cachedImage.HasStencil)
|
||||||
|
{
|
||||||
|
GL.FramebufferTexture(
|
||||||
|
FramebufferTarget.DrawFramebuffer,
|
||||||
|
FramebufferAttachment.DepthStencilAttachment,
|
||||||
|
cachedImage.Handle,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
else if (cachedImage.HasDepth)
|
||||||
|
{
|
||||||
|
GL.FramebufferTexture(
|
||||||
|
FramebufferTarget.DrawFramebuffer,
|
||||||
|
FramebufferAttachment.DepthAttachment,
|
||||||
|
cachedImage.Handle,
|
||||||
|
0);
|
||||||
|
|
||||||
|
GL.FramebufferTexture(
|
||||||
|
FramebufferTarget.DrawFramebuffer,
|
||||||
|
FramebufferAttachment.StencilAttachment,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Invalid image format \"" + cachedImage.Format + "\" used as Zeta!");
|
||||||
|
}
|
||||||
|
|
||||||
|
_zetaHandle = cachedImage.Handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_zetaHandle != 0)
|
||||||
|
{
|
||||||
|
GL.FramebufferTexture(
|
||||||
|
FramebufferTarget.DrawFramebuffer,
|
||||||
|
FramebufferAttachment.DepthStencilAttachment,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
|
||||||
|
_zetaHandle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OglExtension.ViewportArray)
|
||||||
|
{
|
||||||
|
GL.ViewportArray(0, RenderTargetsCount, _viewports);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL.Viewport(
|
||||||
|
(int)_viewports[0],
|
||||||
|
(int)_viewports[1],
|
||||||
|
(int)_viewports[2],
|
||||||
|
(int)_viewports[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_attachments.MapCount > 1)
|
||||||
|
{
|
||||||
|
GL.DrawBuffers(_attachments.MapCount, _attachments.Map);
|
||||||
|
}
|
||||||
|
else if (_attachments.MapCount == 1)
|
||||||
|
{
|
||||||
|
GL.DrawBuffer((DrawBufferMode)_attachments.Map[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL.DrawBuffer(DrawBufferMode.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
_oldAttachments.Update(_attachments);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BindColor(long key, int attachment)
|
||||||
|
{
|
||||||
|
_attachments.Colors[attachment] = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnbindColor(int attachment)
|
||||||
|
{
|
||||||
|
_attachments.Colors[attachment] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BindZeta(long key)
|
||||||
|
{
|
||||||
|
_attachments.Zeta = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnbindZeta()
|
||||||
|
{
|
||||||
|
_attachments.Zeta = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Present(long key)
|
||||||
|
{
|
||||||
|
_texture.TryGetImageHandler(key, out _readTex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetMap(int[] map)
|
||||||
|
{
|
||||||
|
if (map != null)
|
||||||
|
{
|
||||||
|
_attachments.MapCount = map.Length;
|
||||||
|
|
||||||
|
for (int attachment = 0; attachment < _attachments.MapCount; attachment++)
|
||||||
|
{
|
||||||
|
_attachments.Map[attachment] = DrawBuffersEnum.ColorAttachment0 + map[attachment];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_attachments.MapCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTransform(bool flipX, bool flipY, int top, int left, int right, int bottom)
|
||||||
|
{
|
||||||
|
_flipX = flipX;
|
||||||
|
_flipY = flipY;
|
||||||
|
|
||||||
|
_cropTop = top;
|
||||||
|
_cropLeft = left;
|
||||||
|
_cropRight = right;
|
||||||
|
_cropBottom = bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetWindowSize(int width, int height)
|
||||||
|
{
|
||||||
|
_window = new Rect(0, 0, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetViewport(int attachment, int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
int offset = attachment * 4;
|
||||||
|
|
||||||
|
_viewports[offset + 0] = x;
|
||||||
|
_viewports[offset + 1] = y;
|
||||||
|
_viewports[offset + 2] = width;
|
||||||
|
_viewports[offset + 3] = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render()
|
||||||
|
{
|
||||||
|
if (_readTex == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int srcX0, srcX1, srcY0, srcY1;
|
||||||
|
|
||||||
|
if (_cropLeft == 0 && _cropRight == 0)
|
||||||
|
{
|
||||||
|
srcX0 = 0;
|
||||||
|
srcX1 = _readTex.Width;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
srcX0 = _cropLeft;
|
||||||
|
srcX1 = _cropRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cropTop == 0 && _cropBottom == 0)
|
||||||
|
{
|
||||||
|
srcY0 = 0;
|
||||||
|
srcY1 = _readTex.Height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
srcY0 = _cropTop;
|
||||||
|
srcY1 = _cropBottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ratioX = MathF.Min(1f, (_window.Height * (float)NativeWidth) / ((float)NativeHeight * _window.Width));
|
||||||
|
float ratioY = MathF.Min(1f, (_window.Width * (float)NativeHeight) / ((float)NativeWidth * _window.Height));
|
||||||
|
|
||||||
|
int dstWidth = (int)(_window.Width * ratioX);
|
||||||
|
int dstHeight = (int)(_window.Height * ratioY);
|
||||||
|
|
||||||
|
int dstPaddingX = (_window.Width - dstWidth) / 2;
|
||||||
|
int dstPaddingY = (_window.Height - dstHeight) / 2;
|
||||||
|
|
||||||
|
int dstX0 = _flipX ? _window.Width - dstPaddingX : dstPaddingX;
|
||||||
|
int dstX1 = _flipX ? dstPaddingX : _window.Width - dstPaddingX;
|
||||||
|
|
||||||
|
int dstY0 = _flipY ? dstPaddingY : _window.Height - dstPaddingY;
|
||||||
|
int dstY1 = _flipY ? _window.Height - dstPaddingY : dstPaddingY;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
|
||||||
|
|
||||||
|
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||||
|
|
||||||
|
GL.Disable(EnableCap.FramebufferSrgb);
|
||||||
|
|
||||||
|
GL.BlitFramebuffer(
|
||||||
|
srcX0,
|
||||||
|
srcY0,
|
||||||
|
srcX1,
|
||||||
|
srcY1,
|
||||||
|
dstX0,
|
||||||
|
dstY0,
|
||||||
|
dstX1,
|
||||||
|
dstY1,
|
||||||
|
ClearBufferMask.ColorBufferBit,
|
||||||
|
BlitFramebufferFilter.Linear);
|
||||||
|
|
||||||
|
if (FramebufferSrgb)
|
||||||
|
{
|
||||||
|
GL.Enable(EnableCap.FramebufferSrgb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Copy(
|
||||||
|
GalImage srcImage,
|
||||||
|
GalImage dstImage,
|
||||||
|
long srcKey,
|
||||||
|
long dstKey,
|
||||||
|
int srcLayer,
|
||||||
|
int dstLayer,
|
||||||
|
int srcX0,
|
||||||
|
int srcY0,
|
||||||
|
int srcX1,
|
||||||
|
int srcY1,
|
||||||
|
int dstX0,
|
||||||
|
int dstY0,
|
||||||
|
int dstX1,
|
||||||
|
int dstY1)
|
||||||
|
{
|
||||||
|
if (_texture.TryGetImageHandler(srcKey, out ImageHandler srcTex) &&
|
||||||
|
_texture.TryGetImageHandler(dstKey, out ImageHandler dstTex))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (ImageUtils.IsArray(srcImage.TextureTarget) && srcLayer > 0)
|
||||||
|
{
|
||||||
|
GL.FramebufferTextureLayer(FramebufferTarget.ReadFramebuffer, attachment, srcTex.Handle, 0, srcLayer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, attachment, srcTex.Handle, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImageUtils.IsArray(dstImage.TextureTarget) && dstLayer > 0)
|
||||||
|
{
|
||||||
|
GL.FramebufferTextureLayer(FramebufferTarget.DrawFramebuffer, attachment, dstTex.Handle, 0, dstLayer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, attachment, dstTex.Handle, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BlitFramebufferFilter filter = BlitFramebufferFilter.Nearest;
|
||||||
|
|
||||||
|
if (srcTex.HasColor)
|
||||||
|
{
|
||||||
|
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||||
|
|
||||||
|
filter = BlitFramebufferFilter.Linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearBufferMask mask = GetClearMask(srcTex);
|
||||||
|
|
||||||
|
GL.BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reinterpret(long key, GalImage newImage)
|
||||||
|
{
|
||||||
|
if (!_texture.TryGetImage(key, out GalImage oldImage))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newImage.Format == oldImage.Format &&
|
||||||
|
newImage.Width == oldImage.Width &&
|
||||||
|
newImage.Height == oldImage.Height &&
|
||||||
|
newImage.Depth == oldImage.Depth &&
|
||||||
|
newImage.LayerCount == oldImage.LayerCount &&
|
||||||
|
newImage.TextureTarget == oldImage.TextureTarget)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_copyPbo == 0)
|
||||||
|
{
|
||||||
|
_copyPbo = GL.GenBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.PixelPackBuffer, _copyPbo);
|
||||||
|
|
||||||
|
//The buffer should be large enough to hold the largest texture.
|
||||||
|
int bufferSize = Math.Max(ImageUtils.GetSize(oldImage),
|
||||||
|
ImageUtils.GetSize(newImage));
|
||||||
|
|
||||||
|
GL.BufferData(BufferTarget.PixelPackBuffer, bufferSize, IntPtr.Zero, BufferUsageHint.StreamCopy);
|
||||||
|
|
||||||
|
if (!_texture.TryGetImageHandler(key, out ImageHandler cachedImage))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
(_, PixelFormat format, PixelType type) = OglEnumConverter.GetImageFormat(cachedImage.Format);
|
||||||
|
|
||||||
|
TextureTarget target = ImageUtils.GetTextureTarget(newImage.TextureTarget);
|
||||||
|
|
||||||
|
GL.BindTexture(target, cachedImage.Handle);
|
||||||
|
|
||||||
|
GL.GetTexImage(target, 0, format, type, IntPtr.Zero);
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
|
||||||
|
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, _copyPbo);
|
||||||
|
|
||||||
|
GL.PixelStore(PixelStoreParameter.UnpackRowLength, oldImage.Width);
|
||||||
|
|
||||||
|
_texture.Create(key, ImageUtils.GetSize(newImage), newImage);
|
||||||
|
|
||||||
|
GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0);
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ClearBufferMask GetClearMask(ImageHandler cachedImage)
|
||||||
|
{
|
||||||
|
return (cachedImage.HasColor ? ClearBufferMask.ColorBufferBit : 0) |
|
||||||
|
(cachedImage.HasDepth ? ClearBufferMask.DepthBufferBit : 0) |
|
||||||
|
(cachedImage.HasStencil ? ClearBufferMask.StencilBufferBit : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
Ryujinx.Graphics/Gal/OpenGL/OglRenderer.cs
Normal file
58
Ryujinx.Graphics/Gal/OpenGL/OglRenderer.cs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
{
|
||||||
|
public class OglRenderer : IGalRenderer
|
||||||
|
{
|
||||||
|
public IGalConstBuffer Buffer { get; private set; }
|
||||||
|
|
||||||
|
public IGalRenderTarget RenderTarget { get; private set; }
|
||||||
|
|
||||||
|
public IGalRasterizer Rasterizer { get; private set; }
|
||||||
|
|
||||||
|
public IGalShader Shader { get; private set; }
|
||||||
|
|
||||||
|
public IGalPipeline Pipeline { get; private set; }
|
||||||
|
|
||||||
|
public IGalTexture Texture { get; private set; }
|
||||||
|
|
||||||
|
private ConcurrentQueue<Action> _actionsQueue;
|
||||||
|
|
||||||
|
public OglRenderer()
|
||||||
|
{
|
||||||
|
Buffer = new OglConstBuffer();
|
||||||
|
|
||||||
|
Texture = new OglTexture();
|
||||||
|
|
||||||
|
RenderTarget = new OglRenderTarget(Texture as OglTexture);
|
||||||
|
|
||||||
|
Rasterizer = new OglRasterizer();
|
||||||
|
|
||||||
|
Shader = new OglShader(Buffer as OglConstBuffer);
|
||||||
|
|
||||||
|
Pipeline = new OglPipeline(
|
||||||
|
Buffer as OglConstBuffer,
|
||||||
|
RenderTarget as OglRenderTarget,
|
||||||
|
Rasterizer as OglRasterizer,
|
||||||
|
Shader as OglShader);
|
||||||
|
|
||||||
|
_actionsQueue = new ConcurrentQueue<Action>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void QueueAction(Action actionMthd)
|
||||||
|
{
|
||||||
|
_actionsQueue.Enqueue(actionMthd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RunActions()
|
||||||
|
{
|
||||||
|
int count = _actionsQueue.Count;
|
||||||
|
|
||||||
|
while (count-- > 0 && _actionsQueue.TryDequeue(out Action renderAction))
|
||||||
|
{
|
||||||
|
renderAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
298
Ryujinx.Graphics/Gal/OpenGL/OglShader.cs
Normal file
298
Ryujinx.Graphics/Gal/OpenGL/OglShader.cs
Normal file
|
@ -0,0 +1,298 @@
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using Ryujinx.Graphics.Gal.Shader;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
{
|
||||||
|
class OglShader : IGalShader
|
||||||
|
{
|
||||||
|
public const int ReservedCbufCount = 1;
|
||||||
|
|
||||||
|
private const int ExtraDataSize = 4;
|
||||||
|
|
||||||
|
public OglShaderProgram Current;
|
||||||
|
|
||||||
|
private ConcurrentDictionary<long, OglShaderStage> _stages;
|
||||||
|
|
||||||
|
private Dictionary<OglShaderProgram, int> _programs;
|
||||||
|
|
||||||
|
public int CurrentProgramHandle { get; private set; }
|
||||||
|
|
||||||
|
private OglConstBuffer _buffer;
|
||||||
|
|
||||||
|
private int _extraUboHandle;
|
||||||
|
|
||||||
|
public OglShader(OglConstBuffer buffer)
|
||||||
|
{
|
||||||
|
_buffer = buffer;
|
||||||
|
|
||||||
|
_stages = new ConcurrentDictionary<long, OglShaderStage>();
|
||||||
|
|
||||||
|
_programs = new Dictionary<OglShaderProgram, int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Create(IGalMemory memory, long key, GalShaderType type)
|
||||||
|
{
|
||||||
|
_stages.GetOrAdd(key, (stage) => ShaderStageFactory(memory, key, 0, false, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Create(IGalMemory memory, long vpAPos, long key, GalShaderType type)
|
||||||
|
{
|
||||||
|
_stages.GetOrAdd(key, (stage) => ShaderStageFactory(memory, vpAPos, key, true, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
private OglShaderStage ShaderStageFactory(
|
||||||
|
IGalMemory memory,
|
||||||
|
long position,
|
||||||
|
long positionB,
|
||||||
|
bool isDualVp,
|
||||||
|
GalShaderType type)
|
||||||
|
{
|
||||||
|
GlslProgram program;
|
||||||
|
|
||||||
|
GlslDecompiler decompiler = new GlslDecompiler(OglLimit.MaxUboSize, OglExtension.NvidiaDriver);
|
||||||
|
|
||||||
|
int shaderDumpIndex = ShaderDumper.DumpIndex;
|
||||||
|
|
||||||
|
if (isDualVp)
|
||||||
|
{
|
||||||
|
ShaderDumper.Dump(memory, position, type, "a");
|
||||||
|
ShaderDumper.Dump(memory, positionB, type, "b");
|
||||||
|
|
||||||
|
program = decompiler.Decompile(memory, position, positionB, type);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ShaderDumper.Dump(memory, position, type);
|
||||||
|
|
||||||
|
program = decompiler.Decompile(memory, position, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
string code = program.Code;
|
||||||
|
|
||||||
|
if (ShaderDumper.IsDumpEnabled())
|
||||||
|
{
|
||||||
|
code = "//Shader " + shaderDumpIndex + Environment.NewLine + code;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new OglShaderStage(type, code, program.Uniforms, program.Textures);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ShaderDeclInfo> GetConstBufferUsage(long key)
|
||||||
|
{
|
||||||
|
if (_stages.TryGetValue(key, out OglShaderStage stage))
|
||||||
|
{
|
||||||
|
return stage.ConstBufferUsage;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Enumerable.Empty<ShaderDeclInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ShaderDeclInfo> GetTextureUsage(long key)
|
||||||
|
{
|
||||||
|
if (_stages.TryGetValue(key, out OglShaderStage stage))
|
||||||
|
{
|
||||||
|
return stage.TextureUsage;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Enumerable.Empty<ShaderDeclInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe void SetExtraData(float flipX, float flipY, int instance)
|
||||||
|
{
|
||||||
|
BindProgram();
|
||||||
|
|
||||||
|
EnsureExtraBlock();
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.UniformBuffer, _extraUboHandle);
|
||||||
|
|
||||||
|
float* data = stackalloc float[ExtraDataSize];
|
||||||
|
data[0] = flipX;
|
||||||
|
data[1] = flipY;
|
||||||
|
data[2] = BitConverter.Int32BitsToSingle(instance);
|
||||||
|
|
||||||
|
//Invalidate buffer
|
||||||
|
GL.BufferData(BufferTarget.UniformBuffer, ExtraDataSize * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw);
|
||||||
|
|
||||||
|
GL.BufferSubData(BufferTarget.UniformBuffer, IntPtr.Zero, ExtraDataSize * sizeof(float), (IntPtr)data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Bind(long key)
|
||||||
|
{
|
||||||
|
if (_stages.TryGetValue(key, out OglShaderStage stage))
|
||||||
|
{
|
||||||
|
Bind(stage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Bind(OglShaderStage stage)
|
||||||
|
{
|
||||||
|
if (stage.Type == GalShaderType.Geometry)
|
||||||
|
{
|
||||||
|
//Enhanced layouts are required for Geometry shaders
|
||||||
|
//skip this stage if current driver has no ARB_enhanced_layouts
|
||||||
|
if (!OglExtension.EnhancedLayouts)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (stage.Type)
|
||||||
|
{
|
||||||
|
case GalShaderType.Vertex: Current.Vertex = stage; break;
|
||||||
|
case GalShaderType.TessControl: Current.TessControl = stage; break;
|
||||||
|
case GalShaderType.TessEvaluation: Current.TessEvaluation = stage; break;
|
||||||
|
case GalShaderType.Geometry: Current.Geometry = stage; break;
|
||||||
|
case GalShaderType.Fragment: Current.Fragment = stage; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unbind(GalShaderType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case GalShaderType.Vertex: Current.Vertex = null; break;
|
||||||
|
case GalShaderType.TessControl: Current.TessControl = null; break;
|
||||||
|
case GalShaderType.TessEvaluation: Current.TessEvaluation = null; break;
|
||||||
|
case GalShaderType.Geometry: Current.Geometry = null; break;
|
||||||
|
case GalShaderType.Fragment: Current.Fragment = null; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BindProgram()
|
||||||
|
{
|
||||||
|
if (Current.Vertex == null ||
|
||||||
|
Current.Fragment == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_programs.TryGetValue(Current, out int handle))
|
||||||
|
{
|
||||||
|
handle = GL.CreateProgram();
|
||||||
|
|
||||||
|
AttachIfNotNull(handle, Current.Vertex);
|
||||||
|
AttachIfNotNull(handle, Current.TessControl);
|
||||||
|
AttachIfNotNull(handle, Current.TessEvaluation);
|
||||||
|
AttachIfNotNull(handle, Current.Geometry);
|
||||||
|
AttachIfNotNull(handle, Current.Fragment);
|
||||||
|
|
||||||
|
GL.LinkProgram(handle);
|
||||||
|
|
||||||
|
CheckProgramLink(handle);
|
||||||
|
|
||||||
|
BindUniformBlocks(handle);
|
||||||
|
BindTextureLocations(handle);
|
||||||
|
|
||||||
|
_programs.Add(Current, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.UseProgram(handle);
|
||||||
|
|
||||||
|
CurrentProgramHandle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsureExtraBlock()
|
||||||
|
{
|
||||||
|
if (_extraUboHandle == 0)
|
||||||
|
{
|
||||||
|
_extraUboHandle = GL.GenBuffer();
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.UniformBuffer, _extraUboHandle);
|
||||||
|
|
||||||
|
GL.BufferData(BufferTarget.UniformBuffer, ExtraDataSize * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw);
|
||||||
|
|
||||||
|
GL.BindBufferBase(BufferRangeTarget.UniformBuffer, 0, _extraUboHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AttachIfNotNull(int programHandle, OglShaderStage stage)
|
||||||
|
{
|
||||||
|
if (stage != null)
|
||||||
|
{
|
||||||
|
stage.Compile();
|
||||||
|
|
||||||
|
GL.AttachShader(programHandle, stage.Handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BindUniformBlocks(int programHandle)
|
||||||
|
{
|
||||||
|
int extraBlockindex = GL.GetUniformBlockIndex(programHandle, GlslDecl.ExtraUniformBlockName);
|
||||||
|
|
||||||
|
GL.UniformBlockBinding(programHandle, extraBlockindex, 0);
|
||||||
|
|
||||||
|
int freeBinding = ReservedCbufCount;
|
||||||
|
|
||||||
|
void BindUniformBlocksIfNotNull(OglShaderStage stage)
|
||||||
|
{
|
||||||
|
if (stage != null)
|
||||||
|
{
|
||||||
|
foreach (ShaderDeclInfo declInfo in stage.ConstBufferUsage)
|
||||||
|
{
|
||||||
|
int blockIndex = GL.GetUniformBlockIndex(programHandle, declInfo.Name);
|
||||||
|
|
||||||
|
if (blockIndex < 0)
|
||||||
|
{
|
||||||
|
//It is expected that its found, if it's not then driver might be in a malfunction
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.UniformBlockBinding(programHandle, blockIndex, freeBinding);
|
||||||
|
|
||||||
|
freeBinding++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BindUniformBlocksIfNotNull(Current.Vertex);
|
||||||
|
BindUniformBlocksIfNotNull(Current.TessControl);
|
||||||
|
BindUniformBlocksIfNotNull(Current.TessEvaluation);
|
||||||
|
BindUniformBlocksIfNotNull(Current.Geometry);
|
||||||
|
BindUniformBlocksIfNotNull(Current.Fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BindTextureLocations(int programHandle)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
void BindTexturesIfNotNull(OglShaderStage stage)
|
||||||
|
{
|
||||||
|
if (stage != null)
|
||||||
|
{
|
||||||
|
foreach (ShaderDeclInfo decl in stage.TextureUsage)
|
||||||
|
{
|
||||||
|
int location = GL.GetUniformLocation(programHandle, decl.Name);
|
||||||
|
|
||||||
|
GL.Uniform1(location, index);
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.UseProgram(programHandle);
|
||||||
|
|
||||||
|
BindTexturesIfNotNull(Current.Vertex);
|
||||||
|
BindTexturesIfNotNull(Current.TessControl);
|
||||||
|
BindTexturesIfNotNull(Current.TessEvaluation);
|
||||||
|
BindTexturesIfNotNull(Current.Geometry);
|
||||||
|
BindTexturesIfNotNull(Current.Fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CheckProgramLink(int handle)
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
GL.GetProgram(handle, GetProgramParameterName.LinkStatus, out status);
|
||||||
|
|
||||||
|
if (status == 0)
|
||||||
|
{
|
||||||
|
throw new ShaderException(GL.GetProgramInfoLog(handle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
86
Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs
Normal file
86
Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
{
|
||||||
|
struct OglShaderProgram
|
||||||
|
{
|
||||||
|
public OglShaderStage Vertex;
|
||||||
|
public OglShaderStage TessControl;
|
||||||
|
public OglShaderStage TessEvaluation;
|
||||||
|
public OglShaderStage Geometry;
|
||||||
|
public OglShaderStage Fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
class OglShaderStage : IDisposable
|
||||||
|
{
|
||||||
|
public int Handle { get; private set; }
|
||||||
|
|
||||||
|
public bool IsCompiled { get; private set; }
|
||||||
|
|
||||||
|
public GalShaderType Type { get; private set; }
|
||||||
|
|
||||||
|
public string Code { get; private set; }
|
||||||
|
|
||||||
|
public IEnumerable<ShaderDeclInfo> ConstBufferUsage { get; private set; }
|
||||||
|
public IEnumerable<ShaderDeclInfo> TextureUsage { get; private set; }
|
||||||
|
|
||||||
|
public OglShaderStage(
|
||||||
|
GalShaderType type,
|
||||||
|
string code,
|
||||||
|
IEnumerable<ShaderDeclInfo> constBufferUsage,
|
||||||
|
IEnumerable<ShaderDeclInfo> textureUsage)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
Code = code;
|
||||||
|
ConstBufferUsage = constBufferUsage;
|
||||||
|
TextureUsage = textureUsage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Compile()
|
||||||
|
{
|
||||||
|
if (Handle == 0)
|
||||||
|
{
|
||||||
|
Handle = GL.CreateShader(OglEnumConverter.GetShaderType(Type));
|
||||||
|
|
||||||
|
CompileAndCheck(Handle, Code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && Handle != 0)
|
||||||
|
{
|
||||||
|
GL.DeleteShader(Handle);
|
||||||
|
|
||||||
|
Handle = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CompileAndCheck(int handle, string code)
|
||||||
|
{
|
||||||
|
GL.ShaderSource(handle, code);
|
||||||
|
GL.CompileShader(handle);
|
||||||
|
|
||||||
|
CheckCompilation(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CheckCompilation(int handle)
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
GL.GetShader(handle, ShaderParameter.CompileStatus, out status);
|
||||||
|
|
||||||
|
if (status == 0)
|
||||||
|
{
|
||||||
|
throw new ShaderException(GL.GetShaderInfoLog(handle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
class OGLStreamBuffer : IDisposable
|
class OglStreamBuffer : IDisposable
|
||||||
{
|
{
|
||||||
public int Handle { get; protected set; }
|
public int Handle { get; protected set; }
|
||||||
|
|
||||||
|
@ -11,30 +11,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
protected BufferTarget Target { get; private set; }
|
protected BufferTarget Target { get; private set; }
|
||||||
|
|
||||||
public OGLStreamBuffer(BufferTarget Target, long Size)
|
public OglStreamBuffer(BufferTarget target, long size)
|
||||||
{
|
{
|
||||||
this.Target = Target;
|
Target = target;
|
||||||
this.Size = Size;
|
Size = size;
|
||||||
|
|
||||||
Handle = GL.GenBuffer();
|
Handle = GL.GenBuffer();
|
||||||
|
|
||||||
GL.BindBuffer(Target, Handle);
|
GL.BindBuffer(target, Handle);
|
||||||
|
|
||||||
GL.BufferData(Target, (IntPtr)Size, IntPtr.Zero, BufferUsageHint.StreamDraw);
|
GL.BufferData(target, (IntPtr)size, IntPtr.Zero, BufferUsageHint.StreamDraw);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(long Size, IntPtr HostAddress)
|
public void SetData(long size, IntPtr hostAddress)
|
||||||
{
|
{
|
||||||
GL.BindBuffer(Target, Handle);
|
GL.BindBuffer(Target, Handle);
|
||||||
|
|
||||||
GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)Size, HostAddress);
|
GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)size, hostAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(byte[] Data)
|
public void SetData(byte[] data)
|
||||||
{
|
{
|
||||||
GL.BindBuffer(Target, Handle);
|
GL.BindBuffer(Target, Handle);
|
||||||
|
|
||||||
GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)Data.Length, Data);
|
GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)data.Length, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -42,9 +42,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Dispose(bool Disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (Disposing && Handle != 0)
|
if (disposing && Handle != 0)
|
||||||
{
|
{
|
||||||
GL.DeleteBuffer(Handle);
|
GL.DeleteBuffer(Handle);
|
||||||
|
|
381
Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs
Normal file
381
Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs
Normal file
|
@ -0,0 +1,381 @@
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using Ryujinx.Graphics.Texture;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
{
|
||||||
|
class OglTexture : IGalTexture
|
||||||
|
{
|
||||||
|
private const long MaxTextureCacheSize = 768 * 1024 * 1024;
|
||||||
|
|
||||||
|
private OglCachedResource<ImageHandler> _textureCache;
|
||||||
|
|
||||||
|
public EventHandler<int> TextureDeleted { get; set; }
|
||||||
|
|
||||||
|
public OglTexture()
|
||||||
|
{
|
||||||
|
_textureCache = new OglCachedResource<ImageHandler>(DeleteTexture, MaxTextureCacheSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LockCache()
|
||||||
|
{
|
||||||
|
_textureCache.Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnlockCache()
|
||||||
|
{
|
||||||
|
_textureCache.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeleteTexture(ImageHandler cachedImage)
|
||||||
|
{
|
||||||
|
TextureDeleted?.Invoke(this, cachedImage.Handle);
|
||||||
|
|
||||||
|
GL.DeleteTexture(cachedImage.Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Create(long key, int size, GalImage image)
|
||||||
|
{
|
||||||
|
int handle = GL.GenTexture();
|
||||||
|
|
||||||
|
TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
|
||||||
|
|
||||||
|
GL.BindTexture(target, handle);
|
||||||
|
|
||||||
|
const int level = 0; //TODO: Support mipmap textures.
|
||||||
|
const int border = 0;
|
||||||
|
|
||||||
|
_textureCache.AddOrUpdate(key, new ImageHandler(handle, image), (uint)size);
|
||||||
|
|
||||||
|
if (ImageUtils.IsCompressed(image.Format))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Surfaces with compressed formats are not supported!");
|
||||||
|
}
|
||||||
|
|
||||||
|
(PixelInternalFormat internalFmt,
|
||||||
|
PixelFormat format,
|
||||||
|
PixelType type) = OglEnumConverter.GetImageFormat(image.Format);
|
||||||
|
|
||||||
|
switch (target)
|
||||||
|
{
|
||||||
|
case TextureTarget.Texture1D:
|
||||||
|
GL.TexImage1D(
|
||||||
|
target,
|
||||||
|
level,
|
||||||
|
internalFmt,
|
||||||
|
image.Width,
|
||||||
|
border,
|
||||||
|
format,
|
||||||
|
type,
|
||||||
|
IntPtr.Zero);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TextureTarget.Texture2D:
|
||||||
|
GL.TexImage2D(
|
||||||
|
target,
|
||||||
|
level,
|
||||||
|
internalFmt,
|
||||||
|
image.Width,
|
||||||
|
image.Height,
|
||||||
|
border,
|
||||||
|
format,
|
||||||
|
type,
|
||||||
|
IntPtr.Zero);
|
||||||
|
break;
|
||||||
|
case TextureTarget.Texture3D:
|
||||||
|
GL.TexImage3D(
|
||||||
|
target,
|
||||||
|
level,
|
||||||
|
internalFmt,
|
||||||
|
image.Width,
|
||||||
|
image.Height,
|
||||||
|
image.Depth,
|
||||||
|
border,
|
||||||
|
format,
|
||||||
|
type,
|
||||||
|
IntPtr.Zero);
|
||||||
|
break;
|
||||||
|
case TextureTarget.Texture2DArray:
|
||||||
|
GL.TexImage3D(
|
||||||
|
target,
|
||||||
|
level,
|
||||||
|
internalFmt,
|
||||||
|
image.Width,
|
||||||
|
image.Height,
|
||||||
|
image.LayerCount,
|
||||||
|
border,
|
||||||
|
format,
|
||||||
|
type,
|
||||||
|
IntPtr.Zero);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"Unsupported texture target type: {target}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Create(long key, byte[] data, GalImage image)
|
||||||
|
{
|
||||||
|
int handle = GL.GenTexture();
|
||||||
|
|
||||||
|
TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
|
||||||
|
|
||||||
|
GL.BindTexture(target, handle);
|
||||||
|
|
||||||
|
const int level = 0; //TODO: Support mipmap textures.
|
||||||
|
const int border = 0;
|
||||||
|
|
||||||
|
_textureCache.AddOrUpdate(key, new ImageHandler(handle, image), (uint)data.Length);
|
||||||
|
|
||||||
|
if (ImageUtils.IsCompressed(image.Format) && !IsAstc(image.Format))
|
||||||
|
{
|
||||||
|
InternalFormat internalFmt = OglEnumConverter.GetCompressedImageFormat(image.Format);
|
||||||
|
|
||||||
|
switch (target)
|
||||||
|
{
|
||||||
|
case TextureTarget.Texture1D:
|
||||||
|
GL.CompressedTexImage1D(
|
||||||
|
target,
|
||||||
|
level,
|
||||||
|
internalFmt,
|
||||||
|
image.Width,
|
||||||
|
border,
|
||||||
|
data.Length,
|
||||||
|
data);
|
||||||
|
break;
|
||||||
|
case TextureTarget.Texture2D:
|
||||||
|
GL.CompressedTexImage2D(
|
||||||
|
target,
|
||||||
|
level,
|
||||||
|
internalFmt,
|
||||||
|
image.Width,
|
||||||
|
image.Height,
|
||||||
|
border,
|
||||||
|
data.Length,
|
||||||
|
data);
|
||||||
|
break;
|
||||||
|
case TextureTarget.Texture3D:
|
||||||
|
GL.CompressedTexImage3D(
|
||||||
|
target,
|
||||||
|
level,
|
||||||
|
internalFmt,
|
||||||
|
image.Width,
|
||||||
|
image.Height,
|
||||||
|
image.Depth,
|
||||||
|
border,
|
||||||
|
data.Length,
|
||||||
|
data);
|
||||||
|
break;
|
||||||
|
case TextureTarget.Texture2DArray:
|
||||||
|
GL.CompressedTexImage3D(
|
||||||
|
target,
|
||||||
|
level,
|
||||||
|
internalFmt,
|
||||||
|
image.Width,
|
||||||
|
image.Height,
|
||||||
|
image.LayerCount,
|
||||||
|
border,
|
||||||
|
data.Length,
|
||||||
|
data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"Unsupported texture target type: {target}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//TODO: Use KHR_texture_compression_astc_hdr when available
|
||||||
|
if (IsAstc(image.Format))
|
||||||
|
{
|
||||||
|
int textureBlockWidth = ImageUtils.GetBlockWidth(image.Format);
|
||||||
|
int textureBlockHeight = ImageUtils.GetBlockHeight(image.Format);
|
||||||
|
int textureBlockDepth = ImageUtils.GetBlockDepth(image.Format);
|
||||||
|
|
||||||
|
data = AstcDecoder.DecodeToRgba8888(
|
||||||
|
data,
|
||||||
|
textureBlockWidth,
|
||||||
|
textureBlockHeight,
|
||||||
|
textureBlockDepth,
|
||||||
|
image.Width,
|
||||||
|
image.Height,
|
||||||
|
image.Depth);
|
||||||
|
|
||||||
|
image.Format = GalImageFormat.Rgba8 | (image.Format & GalImageFormat.TypeMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
(PixelInternalFormat internalFmt,
|
||||||
|
PixelFormat format,
|
||||||
|
PixelType type) = OglEnumConverter.GetImageFormat(image.Format);
|
||||||
|
|
||||||
|
|
||||||
|
switch (target)
|
||||||
|
{
|
||||||
|
case TextureTarget.Texture1D:
|
||||||
|
GL.TexImage1D(
|
||||||
|
target,
|
||||||
|
level,
|
||||||
|
internalFmt,
|
||||||
|
image.Width,
|
||||||
|
border,
|
||||||
|
format,
|
||||||
|
type,
|
||||||
|
data);
|
||||||
|
break;
|
||||||
|
case TextureTarget.Texture2D:
|
||||||
|
GL.TexImage2D(
|
||||||
|
target,
|
||||||
|
level,
|
||||||
|
internalFmt,
|
||||||
|
image.Width,
|
||||||
|
image.Height,
|
||||||
|
border,
|
||||||
|
format,
|
||||||
|
type,
|
||||||
|
data);
|
||||||
|
break;
|
||||||
|
case TextureTarget.Texture3D:
|
||||||
|
GL.TexImage3D(
|
||||||
|
target,
|
||||||
|
level,
|
||||||
|
internalFmt,
|
||||||
|
image.Width,
|
||||||
|
image.Height,
|
||||||
|
image.Depth,
|
||||||
|
border,
|
||||||
|
format,
|
||||||
|
type,
|
||||||
|
data);
|
||||||
|
break;
|
||||||
|
case TextureTarget.Texture2DArray:
|
||||||
|
GL.TexImage3D(
|
||||||
|
target,
|
||||||
|
level,
|
||||||
|
internalFmt,
|
||||||
|
image.Width,
|
||||||
|
image.Height,
|
||||||
|
image.LayerCount,
|
||||||
|
border,
|
||||||
|
format,
|
||||||
|
type,
|
||||||
|
data);
|
||||||
|
break;
|
||||||
|
case TextureTarget.TextureCubeMap:
|
||||||
|
Span<byte> array = new Span<byte>(data);
|
||||||
|
|
||||||
|
int faceSize = ImageUtils.GetSize(image) / 6;
|
||||||
|
|
||||||
|
for (int face = 0; face < 6; face++)
|
||||||
|
{
|
||||||
|
GL.TexImage2D(
|
||||||
|
TextureTarget.TextureCubeMapPositiveX + face,
|
||||||
|
level,
|
||||||
|
internalFmt,
|
||||||
|
image.Width,
|
||||||
|
image.Height,
|
||||||
|
border,
|
||||||
|
format,
|
||||||
|
type,
|
||||||
|
array.Slice(face * faceSize, faceSize).ToArray());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"Unsupported texture target type: {target}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsAstc(GalImageFormat format)
|
||||||
|
{
|
||||||
|
format &= GalImageFormat.FormatMask;
|
||||||
|
|
||||||
|
return format > GalImageFormat.Astc2DStart && format < GalImageFormat.Astc2DEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetImage(long key, out GalImage image)
|
||||||
|
{
|
||||||
|
if (_textureCache.TryGetValue(key, out ImageHandler cachedImage))
|
||||||
|
{
|
||||||
|
image = cachedImage.Image;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
image = default(GalImage);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetImageHandler(long key, out ImageHandler cachedImage)
|
||||||
|
{
|
||||||
|
if (_textureCache.TryGetValue(key, out cachedImage))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedImage = null;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Bind(long key, int index, GalImage image)
|
||||||
|
{
|
||||||
|
if (_textureCache.TryGetValue(key, out ImageHandler cachedImage))
|
||||||
|
{
|
||||||
|
GL.ActiveTexture(TextureUnit.Texture0 + index);
|
||||||
|
|
||||||
|
TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
|
||||||
|
|
||||||
|
GL.BindTexture(target, 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(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetSampler(GalImage image, GalTextureSampler sampler)
|
||||||
|
{
|
||||||
|
int wrapS = (int)OglEnumConverter.GetTextureWrapMode(sampler.AddressU);
|
||||||
|
int wrapT = (int)OglEnumConverter.GetTextureWrapMode(sampler.AddressV);
|
||||||
|
int wrapR = (int)OglEnumConverter.GetTextureWrapMode(sampler.AddressP);
|
||||||
|
|
||||||
|
int minFilter = (int)OglEnumConverter.GetTextureMinFilter(sampler.MinFilter, sampler.MipFilter);
|
||||||
|
int magFilter = (int)OglEnumConverter.GetTextureMagFilter(sampler.MagFilter);
|
||||||
|
|
||||||
|
TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
|
||||||
|
|
||||||
|
GL.TexParameter(target, TextureParameterName.TextureWrapS, wrapS);
|
||||||
|
GL.TexParameter(target, TextureParameterName.TextureWrapT, wrapT);
|
||||||
|
GL.TexParameter(target, TextureParameterName.TextureWrapR, wrapR);
|
||||||
|
|
||||||
|
GL.TexParameter(target, TextureParameterName.TextureMinFilter, minFilter);
|
||||||
|
GL.TexParameter(target, TextureParameterName.TextureMagFilter, magFilter);
|
||||||
|
|
||||||
|
float[] color = new float[]
|
||||||
|
{
|
||||||
|
sampler.BorderColor.Red,
|
||||||
|
sampler.BorderColor.Green,
|
||||||
|
sampler.BorderColor.Blue,
|
||||||
|
sampler.BorderColor.Alpha
|
||||||
|
};
|
||||||
|
|
||||||
|
GL.TexParameter(target, TextureParameterName.TextureBorderColor, color);
|
||||||
|
|
||||||
|
if (sampler.DepthCompare)
|
||||||
|
{
|
||||||
|
GL.TexParameter(target, TextureParameterName.TextureCompareMode, (int)All.CompareRToTexture);
|
||||||
|
GL.TexParameter(target, TextureParameterName.TextureCompareFunc, (int)OglEnumConverter.GetDepthCompareFunc(sampler.DepthCompareFunc));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL.TexParameter(target, TextureParameterName.TextureCompareMode, (int)All.None);
|
||||||
|
GL.TexParameter(target, TextureParameterName.TextureCompareFunc, (int)All.Never);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
using Ryujinx.Graphics.Gal.OpenGL;
|
|
||||||
using Ryujinx.Graphics.Texture;
|
using Ryujinx.Graphics.Texture;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -51,9 +50,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
public const string SsyStackName = "ssy_stack";
|
public const string SsyStackName = "ssy_stack";
|
||||||
public const string SsyCursorName = "ssy_cursor";
|
public const string SsyCursorName = "ssy_cursor";
|
||||||
|
|
||||||
private string[] StagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" };
|
private string[] _stagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" };
|
||||||
|
|
||||||
private string StagePrefix;
|
private string _stagePrefix;
|
||||||
|
|
||||||
private Dictionary<ShaderIrOp, ShaderDeclInfo> m_CbTextures;
|
private Dictionary<ShaderIrOp, ShaderDeclInfo> m_CbTextures;
|
||||||
|
|
||||||
|
@ -83,9 +82,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public GalShaderType ShaderType { get; private set; }
|
public GalShaderType ShaderType { get; private set; }
|
||||||
|
|
||||||
private GlslDecl(GalShaderType ShaderType)
|
private GlslDecl(GalShaderType shaderType)
|
||||||
{
|
{
|
||||||
this.ShaderType = ShaderType;
|
ShaderType = shaderType;
|
||||||
|
|
||||||
m_CbTextures = new Dictionary<ShaderIrOp, ShaderDeclInfo>();
|
m_CbTextures = new Dictionary<ShaderIrOp, ShaderDeclInfo>();
|
||||||
|
|
||||||
|
@ -101,187 +100,187 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
m_Preds = new Dictionary<int, ShaderDeclInfo>();
|
m_Preds = new Dictionary<int, ShaderDeclInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlslDecl(ShaderIrBlock[] Blocks, GalShaderType ShaderType, ShaderHeader Header) : this(ShaderType)
|
public GlslDecl(ShaderIrBlock[] blocks, GalShaderType shaderType, ShaderHeader header) : this(shaderType)
|
||||||
{
|
{
|
||||||
StagePrefix = StagePrefixes[(int)ShaderType] + "_";
|
_stagePrefix = _stagePrefixes[(int)shaderType] + "_";
|
||||||
|
|
||||||
if (ShaderType == GalShaderType.Fragment)
|
if (shaderType == GalShaderType.Fragment)
|
||||||
{
|
{
|
||||||
int Index = 0;
|
int index = 0;
|
||||||
|
|
||||||
for (int Attachment = 0; Attachment < 8; Attachment++)
|
for (int attachment = 0; attachment < 8; attachment++)
|
||||||
{
|
{
|
||||||
for (int Component = 0; Component < 4; Component++)
|
for (int component = 0; component < 4; component++)
|
||||||
{
|
{
|
||||||
if (Header.OmapTargets[Attachment].ComponentEnabled(Component))
|
if (header.OmapTargets[attachment].ComponentEnabled(component))
|
||||||
{
|
{
|
||||||
m_Gprs.TryAdd(Index, new ShaderDeclInfo(GetGprName(Index), Index));
|
m_Gprs.TryAdd(index, new ShaderDeclInfo(GetGprName(index), index));
|
||||||
|
|
||||||
Index++;
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Header.OmapDepth)
|
if (header.OmapDepth)
|
||||||
{
|
{
|
||||||
Index = Header.DepthRegister;
|
index = header.DepthRegister;
|
||||||
|
|
||||||
m_Gprs.TryAdd(Index, new ShaderDeclInfo(GetGprName(Index), Index));
|
m_Gprs.TryAdd(index, new ShaderDeclInfo(GetGprName(index), index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ShaderIrBlock Block in Blocks)
|
foreach (ShaderIrBlock block in blocks)
|
||||||
{
|
{
|
||||||
ShaderIrNode[] Nodes = Block.GetNodes();
|
ShaderIrNode[] nodes = block.GetNodes();
|
||||||
|
|
||||||
foreach (ShaderIrNode Node in Nodes)
|
foreach (ShaderIrNode node in nodes)
|
||||||
{
|
{
|
||||||
Traverse(Nodes, null, Node);
|
Traverse(nodes, null, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GlslDecl Merge(GlslDecl VpA, GlslDecl VpB)
|
public static GlslDecl Merge(GlslDecl vpA, GlslDecl vpB)
|
||||||
{
|
{
|
||||||
GlslDecl Combined = new GlslDecl(GalShaderType.Vertex);
|
GlslDecl combined = new GlslDecl(GalShaderType.Vertex);
|
||||||
|
|
||||||
Merge(Combined.m_Textures, VpA.m_Textures, VpB.m_Textures);
|
Merge(combined.m_Textures, vpA.m_Textures, vpB.m_Textures);
|
||||||
Merge(Combined.m_Uniforms, VpA.m_Uniforms, VpB.m_Uniforms);
|
Merge(combined.m_Uniforms, vpA.m_Uniforms, vpB.m_Uniforms);
|
||||||
|
|
||||||
Merge(Combined.m_Attributes, VpA.m_Attributes, VpB.m_Attributes);
|
Merge(combined.m_Attributes, vpA.m_Attributes, vpB.m_Attributes);
|
||||||
Merge(Combined.m_OutAttributes, VpA.m_OutAttributes, VpB.m_OutAttributes);
|
Merge(combined.m_OutAttributes, vpA.m_OutAttributes, vpB.m_OutAttributes);
|
||||||
|
|
||||||
Merge(Combined.m_Gprs, VpA.m_Gprs, VpB.m_Gprs);
|
Merge(combined.m_Gprs, vpA.m_Gprs, vpB.m_Gprs);
|
||||||
Merge(Combined.m_GprsHalf, VpA.m_GprsHalf, VpB.m_GprsHalf);
|
Merge(combined.m_GprsHalf, vpA.m_GprsHalf, vpB.m_GprsHalf);
|
||||||
Merge(Combined.m_Preds, VpA.m_Preds, VpB.m_Preds);
|
Merge(combined.m_Preds, vpA.m_Preds, vpB.m_Preds);
|
||||||
|
|
||||||
//Merge input attributes.
|
//Merge input attributes.
|
||||||
foreach (KeyValuePair<int, ShaderDeclInfo> KV in VpA.m_InAttributes)
|
foreach (KeyValuePair<int, ShaderDeclInfo> kv in vpA.m_InAttributes)
|
||||||
{
|
{
|
||||||
Combined.m_InAttributes.TryAdd(KV.Key, KV.Value);
|
combined.m_InAttributes.TryAdd(kv.Key, kv.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (KeyValuePair<int, ShaderDeclInfo> KV in VpB.m_InAttributes)
|
foreach (KeyValuePair<int, ShaderDeclInfo> kv in vpB.m_InAttributes)
|
||||||
{
|
{
|
||||||
//If Vertex Program A already writes to this attribute,
|
//If Vertex Program A already writes to this attribute,
|
||||||
//then we don't need to add it as an input attribute since
|
//then we don't need to add it as an input attribute since
|
||||||
//Vertex Program A will already have written to it anyway,
|
//Vertex Program A will already have written to it anyway,
|
||||||
//and there's no guarantee that there is an input attribute
|
//and there's no guarantee that there is an input attribute
|
||||||
//for this slot.
|
//for this slot.
|
||||||
if (!VpA.m_OutAttributes.ContainsKey(KV.Key))
|
if (!vpA.m_OutAttributes.ContainsKey(kv.Key))
|
||||||
{
|
{
|
||||||
Combined.m_InAttributes.TryAdd(KV.Key, KV.Value);
|
combined.m_InAttributes.TryAdd(kv.Key, kv.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Combined;
|
return combined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetGprName(int Index)
|
public static string GetGprName(int index)
|
||||||
{
|
{
|
||||||
return GprName + Index;
|
return GprName + index;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Merge(
|
private static void Merge(
|
||||||
Dictionary<int, ShaderDeclInfo> C,
|
Dictionary<int, ShaderDeclInfo> c,
|
||||||
Dictionary<int, ShaderDeclInfo> A,
|
Dictionary<int, ShaderDeclInfo> a,
|
||||||
Dictionary<int, ShaderDeclInfo> B)
|
Dictionary<int, ShaderDeclInfo> b)
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<int, ShaderDeclInfo> KV in A)
|
foreach (KeyValuePair<int, ShaderDeclInfo> kv in a)
|
||||||
{
|
{
|
||||||
C.TryAdd(KV.Key, KV.Value);
|
c.TryAdd(kv.Key, kv.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (KeyValuePair<int, ShaderDeclInfo> KV in B)
|
foreach (KeyValuePair<int, ShaderDeclInfo> kv in b)
|
||||||
{
|
{
|
||||||
C.TryAdd(KV.Key, KV.Value);
|
c.TryAdd(kv.Key, kv.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Traverse(ShaderIrNode[] Nodes, ShaderIrNode Parent, ShaderIrNode Node)
|
private void Traverse(ShaderIrNode[] nodes, ShaderIrNode parent, ShaderIrNode node)
|
||||||
{
|
{
|
||||||
switch (Node)
|
switch (node)
|
||||||
{
|
{
|
||||||
case ShaderIrAsg Asg:
|
case ShaderIrAsg asg:
|
||||||
{
|
{
|
||||||
Traverse(Nodes, Asg, Asg.Dst);
|
Traverse(nodes, asg, asg.Dst);
|
||||||
Traverse(Nodes, Asg, Asg.Src);
|
Traverse(nodes, asg, asg.Src);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ShaderIrCond Cond:
|
case ShaderIrCond cond:
|
||||||
{
|
{
|
||||||
Traverse(Nodes, Cond, Cond.Pred);
|
Traverse(nodes, cond, cond.Pred);
|
||||||
Traverse(Nodes, Cond, Cond.Child);
|
Traverse(nodes, cond, cond.Child);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ShaderIrOp Op:
|
case ShaderIrOp op:
|
||||||
{
|
{
|
||||||
Traverse(Nodes, Op, Op.OperandA);
|
Traverse(nodes, op, op.OperandA);
|
||||||
Traverse(Nodes, Op, Op.OperandB);
|
Traverse(nodes, op, op.OperandB);
|
||||||
Traverse(Nodes, Op, Op.OperandC);
|
Traverse(nodes, op, op.OperandC);
|
||||||
|
|
||||||
if (Op.Inst == ShaderIrInst.Texq ||
|
if (op.Inst == ShaderIrInst.Texq ||
|
||||||
Op.Inst == ShaderIrInst.Texs ||
|
op.Inst == ShaderIrInst.Texs ||
|
||||||
Op.Inst == ShaderIrInst.Tld4 ||
|
op.Inst == ShaderIrInst.Tld4 ||
|
||||||
Op.Inst == ShaderIrInst.Txlf)
|
op.Inst == ShaderIrInst.Txlf)
|
||||||
{
|
{
|
||||||
int Handle = ((ShaderIrOperImm)Op.OperandC).Value;
|
int handle = ((ShaderIrOperImm)op.OperandC).Value;
|
||||||
|
|
||||||
int Index = Handle - TexStartIndex;
|
int index = handle - TexStartIndex;
|
||||||
|
|
||||||
string Name = StagePrefix + TextureName + Index;
|
string name = _stagePrefix + TextureName + index;
|
||||||
|
|
||||||
GalTextureTarget TextureTarget;
|
GalTextureTarget textureTarget;
|
||||||
|
|
||||||
TextureInstructionSuffix TextureInstructionSuffix;
|
TextureInstructionSuffix textureInstructionSuffix;
|
||||||
|
|
||||||
// TODO: Non 2D texture type for TEXQ?
|
// TODO: Non 2D texture type for TEXQ?
|
||||||
if (Op.Inst == ShaderIrInst.Texq)
|
if (op.Inst == ShaderIrInst.Texq)
|
||||||
{
|
{
|
||||||
TextureTarget = GalTextureTarget.TwoD;
|
textureTarget = GalTextureTarget.TwoD;
|
||||||
TextureInstructionSuffix = TextureInstructionSuffix.None;
|
textureInstructionSuffix = TextureInstructionSuffix.None;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData);
|
ShaderIrMetaTex meta = ((ShaderIrMetaTex)op.MetaData);
|
||||||
|
|
||||||
TextureTarget = Meta.TextureTarget;
|
textureTarget = meta.TextureTarget;
|
||||||
TextureInstructionSuffix = Meta.TextureInstructionSuffix;
|
textureInstructionSuffix = meta.TextureInstructionSuffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Handle, false, 0, 1, TextureTarget, TextureInstructionSuffix));
|
m_Textures.TryAdd(handle, new ShaderDeclInfo(name, handle, false, 0, 1, textureTarget, textureInstructionSuffix));
|
||||||
}
|
}
|
||||||
else if (Op.Inst == ShaderIrInst.Texb)
|
else if (op.Inst == ShaderIrInst.Texb)
|
||||||
{
|
{
|
||||||
ShaderIrNode HandleSrc = null;
|
ShaderIrNode handleSrc = null;
|
||||||
|
|
||||||
int Index = Array.IndexOf(Nodes, Parent) - 1;
|
int index = Array.IndexOf(nodes, parent) - 1;
|
||||||
|
|
||||||
for (; Index >= 0; Index--)
|
for (; index >= 0; index--)
|
||||||
{
|
{
|
||||||
ShaderIrNode Curr = Nodes[Index];
|
ShaderIrNode curr = nodes[index];
|
||||||
|
|
||||||
if (Curr is ShaderIrAsg Asg && Asg.Dst is ShaderIrOperGpr Gpr)
|
if (curr is ShaderIrAsg asg && asg.Dst is ShaderIrOperGpr gpr)
|
||||||
{
|
{
|
||||||
if (Gpr.Index == ((ShaderIrOperGpr)Op.OperandC).Index)
|
if (gpr.Index == ((ShaderIrOperGpr)op.OperandC).Index)
|
||||||
{
|
{
|
||||||
HandleSrc = Asg.Src;
|
handleSrc = asg.Src;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HandleSrc != null && HandleSrc is ShaderIrOperCbuf Cbuf)
|
if (handleSrc != null && handleSrc is ShaderIrOperCbuf cbuf)
|
||||||
{
|
{
|
||||||
ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData);
|
ShaderIrMetaTex meta = ((ShaderIrMetaTex)op.MetaData);
|
||||||
string Name = StagePrefix + TextureName + "_cb" + Cbuf.Index + "_" + Cbuf.Pos;
|
string name = _stagePrefix + TextureName + "_cb" + cbuf.Index + "_" + cbuf.Pos;
|
||||||
|
|
||||||
m_CbTextures.Add(Op, new ShaderDeclInfo(Name, Cbuf.Pos, true, Cbuf.Index, 1, Meta.TextureTarget, Meta.TextureInstructionSuffix));
|
m_CbTextures.Add(op, new ShaderDeclInfo(name, cbuf.Pos, true, cbuf.Index, 1, meta.TextureTarget, meta.TextureInstructionSuffix));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -291,93 +290,93 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ShaderIrOperCbuf Cbuf:
|
case ShaderIrOperCbuf cbuf:
|
||||||
{
|
{
|
||||||
if (!m_Uniforms.ContainsKey(Cbuf.Index))
|
if (!m_Uniforms.ContainsKey(cbuf.Index))
|
||||||
{
|
{
|
||||||
string Name = StagePrefix + UniformName + Cbuf.Index;
|
string name = _stagePrefix + UniformName + cbuf.Index;
|
||||||
|
|
||||||
ShaderDeclInfo DeclInfo = new ShaderDeclInfo(Name, Cbuf.Pos, true, Cbuf.Index);
|
ShaderDeclInfo declInfo = new ShaderDeclInfo(name, cbuf.Pos, true, cbuf.Index);
|
||||||
|
|
||||||
m_Uniforms.Add(Cbuf.Index, DeclInfo);
|
m_Uniforms.Add(cbuf.Index, declInfo);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ShaderIrOperAbuf Abuf:
|
case ShaderIrOperAbuf abuf:
|
||||||
{
|
{
|
||||||
//This is a built-in variable.
|
//This is a built-in variable.
|
||||||
if (Abuf.Offs == LayerAttr ||
|
if (abuf.Offs == LayerAttr ||
|
||||||
Abuf.Offs == PointSizeAttr ||
|
abuf.Offs == PointSizeAttr ||
|
||||||
Abuf.Offs == PointCoordAttrX ||
|
abuf.Offs == PointCoordAttrX ||
|
||||||
Abuf.Offs == PointCoordAttrY ||
|
abuf.Offs == PointCoordAttrY ||
|
||||||
Abuf.Offs == VertexIdAttr ||
|
abuf.Offs == VertexIdAttr ||
|
||||||
Abuf.Offs == InstanceIdAttr ||
|
abuf.Offs == InstanceIdAttr ||
|
||||||
Abuf.Offs == FaceAttr)
|
abuf.Offs == FaceAttr)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Index = Abuf.Offs >> 4;
|
int index = abuf.Offs >> 4;
|
||||||
int Elem = (Abuf.Offs >> 2) & 3;
|
int elem = (abuf.Offs >> 2) & 3;
|
||||||
|
|
||||||
int GlslIndex = Index - AttrStartIndex;
|
int glslIndex = index - AttrStartIndex;
|
||||||
|
|
||||||
if (GlslIndex < 0)
|
if (glslIndex < 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderDeclInfo DeclInfo;
|
ShaderDeclInfo declInfo;
|
||||||
|
|
||||||
if (Parent is ShaderIrAsg Asg && Asg.Dst == Node)
|
if (parent is ShaderIrAsg asg && asg.Dst == node)
|
||||||
{
|
{
|
||||||
if (!m_OutAttributes.TryGetValue(Index, out DeclInfo))
|
if (!m_OutAttributes.TryGetValue(index, out declInfo))
|
||||||
{
|
{
|
||||||
DeclInfo = new ShaderDeclInfo(OutAttrName + GlslIndex, GlslIndex);
|
declInfo = new ShaderDeclInfo(OutAttrName + glslIndex, glslIndex);
|
||||||
|
|
||||||
m_OutAttributes.Add(Index, DeclInfo);
|
m_OutAttributes.Add(index, declInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!m_InAttributes.TryGetValue(Index, out DeclInfo))
|
if (!m_InAttributes.TryGetValue(index, out declInfo))
|
||||||
{
|
{
|
||||||
DeclInfo = new ShaderDeclInfo(InAttrName + GlslIndex, GlslIndex);
|
declInfo = new ShaderDeclInfo(InAttrName + glslIndex, glslIndex);
|
||||||
|
|
||||||
m_InAttributes.Add(Index, DeclInfo);
|
m_InAttributes.Add(index, declInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclInfo.Enlarge(Elem + 1);
|
declInfo.Enlarge(elem + 1);
|
||||||
|
|
||||||
if (!m_Attributes.ContainsKey(Index))
|
if (!m_Attributes.ContainsKey(index))
|
||||||
{
|
{
|
||||||
DeclInfo = new ShaderDeclInfo(AttrName + GlslIndex, GlslIndex, false, 0, 4);
|
declInfo = new ShaderDeclInfo(AttrName + glslIndex, glslIndex, false, 0, 4);
|
||||||
|
|
||||||
m_Attributes.Add(Index, DeclInfo);
|
m_Attributes.Add(index, declInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
Traverse(Nodes, Abuf, Abuf.Vertex);
|
Traverse(nodes, abuf, abuf.Vertex);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ShaderIrOperGpr Gpr:
|
case ShaderIrOperGpr gpr:
|
||||||
{
|
{
|
||||||
if (!Gpr.IsConst)
|
if (!gpr.IsConst)
|
||||||
{
|
{
|
||||||
string Name = GetGprName(Gpr.Index);
|
string name = GetGprName(gpr.Index);
|
||||||
|
|
||||||
if (Gpr.RegisterSize == ShaderRegisterSize.Single)
|
if (gpr.RegisterSize == ShaderRegisterSize.Single)
|
||||||
{
|
{
|
||||||
m_Gprs.TryAdd(Gpr.Index, new ShaderDeclInfo(Name, Gpr.Index));
|
m_Gprs.TryAdd(gpr.Index, new ShaderDeclInfo(name, gpr.Index));
|
||||||
}
|
}
|
||||||
else if (Gpr.RegisterSize == ShaderRegisterSize.Half)
|
else if (gpr.RegisterSize == ShaderRegisterSize.Half)
|
||||||
{
|
{
|
||||||
Name += "_h" + Gpr.HalfPart;
|
name += "_h" + gpr.HalfPart;
|
||||||
|
|
||||||
m_GprsHalf.TryAdd((Gpr.Index << 1) | Gpr.HalfPart, new ShaderDeclInfo(Name, Gpr.Index));
|
m_GprsHalf.TryAdd((gpr.Index << 1) | gpr.HalfPart, new ShaderDeclInfo(name, gpr.Index));
|
||||||
}
|
}
|
||||||
else /* if (Gpr.RegisterSize == ShaderRegisterSize.Double) */
|
else /* if (Gpr.RegisterSize == ShaderRegisterSize.Double) */
|
||||||
{
|
{
|
||||||
|
@ -387,35 +386,35 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ShaderIrOperPred Pred:
|
case ShaderIrOperPred pred:
|
||||||
{
|
{
|
||||||
if (!Pred.IsConst && !HasName(m_Preds, Pred.Index))
|
if (!pred.IsConst && !HasName(m_Preds, pred.Index))
|
||||||
{
|
{
|
||||||
string Name = PredName + Pred.Index;
|
string name = PredName + pred.Index;
|
||||||
|
|
||||||
m_Preds.TryAdd(Pred.Index, new ShaderDeclInfo(Name, Pred.Index));
|
m_Preds.TryAdd(pred.Index, new ShaderDeclInfo(name, pred.Index));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool HasName(Dictionary<int, ShaderDeclInfo> Decls, int Index)
|
private bool HasName(Dictionary<int, ShaderDeclInfo> decls, int index)
|
||||||
{
|
{
|
||||||
//This is used to check if the dictionary already contains
|
//This is used to check if the dictionary already contains
|
||||||
//a entry for a vector at a given index position.
|
//a entry for a vector at a given index position.
|
||||||
//Used to enable turning gprs into vectors.
|
//Used to enable turning gprs into vectors.
|
||||||
int VecIndex = Index & ~3;
|
int vecIndex = index & ~3;
|
||||||
|
|
||||||
if (Decls.TryGetValue(VecIndex, out ShaderDeclInfo DeclInfo))
|
if (decls.TryGetValue(vecIndex, out ShaderDeclInfo declInfo))
|
||||||
{
|
{
|
||||||
if (DeclInfo.Size > 1 && Index < VecIndex + DeclInfo.Size)
|
if (declInfo.Size > 1 && index < vecIndex + declInfo.Size)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Decls.ContainsKey(Index);
|
return decls.ContainsKey(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10,13 +10,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
public IEnumerable<ShaderDeclInfo> Uniforms { get; private set; }
|
public IEnumerable<ShaderDeclInfo> Uniforms { get; private set; }
|
||||||
|
|
||||||
public GlslProgram(
|
public GlslProgram(
|
||||||
string Code,
|
string code,
|
||||||
IEnumerable<ShaderDeclInfo> Textures,
|
IEnumerable<ShaderDeclInfo> textures,
|
||||||
IEnumerable<ShaderDeclInfo> Uniforms)
|
IEnumerable<ShaderDeclInfo> uniforms)
|
||||||
{
|
{
|
||||||
this.Code = Code;
|
Code = code;
|
||||||
this.Textures = Textures;
|
Textures = textures;
|
||||||
this.Uniforms = Uniforms;
|
Uniforms = uniforms;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -4,54 +4,54 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static partial class ShaderDecode
|
static partial class ShaderDecode
|
||||||
{
|
{
|
||||||
public static void Bra(ShaderIrBlock Block, long OpCode, int Position)
|
public static void Bra(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
if ((OpCode & 0x20) != 0)
|
if ((opCode & 0x20) != 0)
|
||||||
{
|
{
|
||||||
//This reads the target offset from the constant buffer.
|
//This reads the target offset from the constant buffer.
|
||||||
//Almost impossible to support with GLSL.
|
//Almost impossible to support with GLSL.
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrOperImm Imm = new ShaderIrOperImm(Position + OpCode.Branch());
|
ShaderIrOperImm imm = new ShaderIrOperImm(position + opCode.Branch());
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Bra, Imm)));
|
block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Bra, imm)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Exit(ShaderIrBlock Block, long OpCode, int Position)
|
public static void Exit(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
int CCode = (int)OpCode & 0x1f;
|
int cCode = (int)opCode & 0x1f;
|
||||||
|
|
||||||
//TODO: Figure out what the other condition codes mean...
|
//TODO: Figure out what the other condition codes mean...
|
||||||
if (CCode == 0xf)
|
if (cCode == 0xf)
|
||||||
{
|
{
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Exit)));
|
block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Exit)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Kil(ShaderIrBlock Block, long OpCode, int Position)
|
public static void Kil(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Kil)));
|
block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Kil)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ssy(ShaderIrBlock Block, long OpCode, int Position)
|
public static void Ssy(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
if ((OpCode & 0x20) != 0)
|
if ((opCode & 0x20) != 0)
|
||||||
{
|
{
|
||||||
//This reads the target offset from the constant buffer.
|
//This reads the target offset from the constant buffer.
|
||||||
//Almost impossible to support with GLSL.
|
//Almost impossible to support with GLSL.
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrOperImm Imm = new ShaderIrOperImm(Position + OpCode.Branch());
|
ShaderIrOperImm imm = new ShaderIrOperImm(position + opCode.Branch());
|
||||||
|
|
||||||
Block.AddNode(new ShaderIrOp(ShaderIrInst.Ssy, Imm));
|
block.AddNode(new ShaderIrOp(ShaderIrInst.Ssy, imm));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sync(ShaderIrBlock Block, long OpCode, int Position)
|
public static void Sync(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
//TODO: Implement Sync condition codes
|
//TODO: Implement Sync condition codes
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Sync)));
|
block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Sync)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode, int Position);
|
delegate void ShaderDecodeFunc(ShaderIrBlock block, long opCode, int position);
|
||||||
}
|
}
|
|
@ -5,74 +5,74 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
private static readonly ShaderIrOperImmf ImmfZero = new ShaderIrOperImmf(0);
|
private static readonly ShaderIrOperImmf ImmfZero = new ShaderIrOperImmf(0);
|
||||||
private static readonly ShaderIrOperImmf ImmfOne = new ShaderIrOperImmf(1);
|
private static readonly ShaderIrOperImmf ImmfOne = new ShaderIrOperImmf(1);
|
||||||
|
|
||||||
public static ShaderIrNode GetAluFabsFneg(ShaderIrNode Node, bool Abs, bool Neg)
|
public static ShaderIrNode GetAluFabsFneg(ShaderIrNode node, bool abs, bool neg)
|
||||||
{
|
{
|
||||||
return GetAluFneg(GetAluFabs(Node, Abs), Neg);
|
return GetAluFneg(GetAluFabs(node, abs), neg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrNode GetAluFabs(ShaderIrNode Node, bool Abs)
|
public static ShaderIrNode GetAluFabs(ShaderIrNode node, bool abs)
|
||||||
{
|
{
|
||||||
return Abs ? new ShaderIrOp(ShaderIrInst.Fabs, Node) : Node;
|
return abs ? new ShaderIrOp(ShaderIrInst.Fabs, node) : node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrNode GetAluFneg(ShaderIrNode Node, bool Neg)
|
public static ShaderIrNode GetAluFneg(ShaderIrNode node, bool neg)
|
||||||
{
|
{
|
||||||
return Neg ? new ShaderIrOp(ShaderIrInst.Fneg, Node) : Node;
|
return neg ? new ShaderIrOp(ShaderIrInst.Fneg, node) : node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrNode GetAluFsat(ShaderIrNode Node, bool Sat)
|
public static ShaderIrNode GetAluFsat(ShaderIrNode node, bool sat)
|
||||||
{
|
{
|
||||||
return Sat ? new ShaderIrOp(ShaderIrInst.Fclamp, Node, ImmfZero, ImmfOne) : Node;
|
return sat ? new ShaderIrOp(ShaderIrInst.Fclamp, node, ImmfZero, ImmfOne) : node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrNode GetAluIabsIneg(ShaderIrNode Node, bool Abs, bool Neg)
|
public static ShaderIrNode GetAluIabsIneg(ShaderIrNode node, bool abs, bool neg)
|
||||||
{
|
{
|
||||||
return GetAluIneg(GetAluIabs(Node, Abs), Neg);
|
return GetAluIneg(GetAluIabs(node, abs), neg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrNode GetAluIabs(ShaderIrNode Node, bool Abs)
|
public static ShaderIrNode GetAluIabs(ShaderIrNode node, bool abs)
|
||||||
{
|
{
|
||||||
return Abs ? new ShaderIrOp(ShaderIrInst.Abs, Node) : Node;
|
return abs ? new ShaderIrOp(ShaderIrInst.Abs, node) : node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrNode GetAluIneg(ShaderIrNode Node, bool Neg)
|
public static ShaderIrNode GetAluIneg(ShaderIrNode node, bool neg)
|
||||||
{
|
{
|
||||||
return Neg ? new ShaderIrOp(ShaderIrInst.Neg, Node) : Node;
|
return neg ? new ShaderIrOp(ShaderIrInst.Neg, node) : node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrNode GetAluNot(ShaderIrNode Node, bool Not)
|
public static ShaderIrNode GetAluNot(ShaderIrNode node, bool not)
|
||||||
{
|
{
|
||||||
return Not ? new ShaderIrOp(ShaderIrInst.Not, Node) : Node;
|
return not ? new ShaderIrOp(ShaderIrInst.Not, node) : node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrNode ExtendTo32(ShaderIrNode Node, bool Signed, int Size)
|
public static ShaderIrNode ExtendTo32(ShaderIrNode node, bool signed, int size)
|
||||||
{
|
{
|
||||||
int Shift = 32 - Size;
|
int shift = 32 - size;
|
||||||
|
|
||||||
ShaderIrInst RightShift = Signed
|
ShaderIrInst rightShift = signed
|
||||||
? ShaderIrInst.Asr
|
? ShaderIrInst.Asr
|
||||||
: ShaderIrInst.Lsr;
|
: ShaderIrInst.Lsr;
|
||||||
|
|
||||||
Node = new ShaderIrOp(ShaderIrInst.Lsl, Node, new ShaderIrOperImm(Shift));
|
node = new ShaderIrOp(ShaderIrInst.Lsl, node, new ShaderIrOperImm(shift));
|
||||||
Node = new ShaderIrOp(RightShift, Node, new ShaderIrOperImm(Shift));
|
node = new ShaderIrOp(rightShift, node, new ShaderIrOperImm(shift));
|
||||||
|
|
||||||
return Node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrNode ExtendTo32(ShaderIrNode Node, bool Signed, ShaderIrNode Size)
|
public static ShaderIrNode ExtendTo32(ShaderIrNode node, bool signed, ShaderIrNode size)
|
||||||
{
|
{
|
||||||
ShaderIrOperImm WordSize = new ShaderIrOperImm(32);
|
ShaderIrOperImm wordSize = new ShaderIrOperImm(32);
|
||||||
|
|
||||||
ShaderIrOp Shift = new ShaderIrOp(ShaderIrInst.Sub, WordSize, Size);
|
ShaderIrOp shift = new ShaderIrOp(ShaderIrInst.Sub, wordSize, size);
|
||||||
|
|
||||||
ShaderIrInst RightShift = Signed
|
ShaderIrInst rightShift = signed
|
||||||
? ShaderIrInst.Asr
|
? ShaderIrInst.Asr
|
||||||
: ShaderIrInst.Lsr;
|
: ShaderIrInst.Lsr;
|
||||||
|
|
||||||
Node = new ShaderIrOp(ShaderIrInst.Lsl, Node, Shift);
|
node = new ShaderIrOp(ShaderIrInst.Lsl, node, shift);
|
||||||
Node = new ShaderIrOp(RightShift, Node, Shift);
|
node = new ShaderIrOp(rightShift, node, shift);
|
||||||
|
|
||||||
return Node;
|
return node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -25,400 +25,400 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
F64 = 3
|
F64 = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2f_C(ShaderIrBlock Block, long OpCode, int Position)
|
public static void F2f_C(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
EmitF2f(Block, OpCode, ShaderOper.CR);
|
EmitF2F(block, opCode, ShaderOper.Cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2f_I(ShaderIrBlock Block, long OpCode, int Position)
|
public static void F2f_I(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
EmitF2f(Block, OpCode, ShaderOper.Immf);
|
EmitF2F(block, opCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2f_R(ShaderIrBlock Block, long OpCode, int Position)
|
public static void F2f_R(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
EmitF2f(Block, OpCode, ShaderOper.RR);
|
EmitF2F(block, opCode, ShaderOper.Rr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2i_C(ShaderIrBlock Block, long OpCode, int Position)
|
public static void F2i_C(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
EmitF2i(Block, OpCode, ShaderOper.CR);
|
EmitF2I(block, opCode, ShaderOper.Cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2i_I(ShaderIrBlock Block, long OpCode, int Position)
|
public static void F2i_I(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
EmitF2i(Block, OpCode, ShaderOper.Immf);
|
EmitF2I(block, opCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2i_R(ShaderIrBlock Block, long OpCode, int Position)
|
public static void F2i_R(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
EmitF2i(Block, OpCode, ShaderOper.RR);
|
EmitF2I(block, opCode, ShaderOper.Rr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2f_C(ShaderIrBlock Block, long OpCode, int Position)
|
public static void I2f_C(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
EmitI2f(Block, OpCode, ShaderOper.CR);
|
EmitI2F(block, opCode, ShaderOper.Cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2f_I(ShaderIrBlock Block, long OpCode, int Position)
|
public static void I2f_I(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
EmitI2f(Block, OpCode, ShaderOper.Imm);
|
EmitI2F(block, opCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2f_R(ShaderIrBlock Block, long OpCode, int Position)
|
public static void I2f_R(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
EmitI2f(Block, OpCode, ShaderOper.RR);
|
EmitI2F(block, opCode, ShaderOper.Rr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2i_C(ShaderIrBlock Block, long OpCode, int Position)
|
public static void I2i_C(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
EmitI2i(Block, OpCode, ShaderOper.CR);
|
EmitI2I(block, opCode, ShaderOper.Cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2i_I(ShaderIrBlock Block, long OpCode, int Position)
|
public static void I2i_I(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
EmitI2i(Block, OpCode, ShaderOper.Imm);
|
EmitI2I(block, opCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2i_R(ShaderIrBlock Block, long OpCode, int Position)
|
public static void I2i_R(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
EmitI2i(Block, OpCode, ShaderOper.RR);
|
EmitI2I(block, opCode, ShaderOper.Rr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Isberd(ShaderIrBlock Block, long OpCode, int 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
|
//This instruction seems to be used to translate from an address to a vertex index in a GS
|
||||||
//Stub it as such
|
//Stub it as such
|
||||||
|
|
||||||
Block.AddNode(new ShaderIrCmnt("Stubbed."));
|
block.AddNode(new ShaderIrCmnt("Stubbed."));
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OpCode.Gpr8())));
|
block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), opCode.Gpr8())));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mov_C(ShaderIrBlock Block, long OpCode, int Position)
|
public static void Mov_C(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
ShaderIrOperCbuf Cbuf = OpCode.Cbuf34();
|
ShaderIrOperCbuf cbuf = opCode.Cbuf34();
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Cbuf)));
|
block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), cbuf)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mov_I(ShaderIrBlock Block, long OpCode, int Position)
|
public static void Mov_I(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
ShaderIrOperImm Imm = OpCode.Imm19_20();
|
ShaderIrOperImm imm = opCode.Imm19_20();
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Imm)));
|
block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), imm)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mov_I32(ShaderIrBlock Block, long OpCode, int Position)
|
public static void Mov_I32(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
ShaderIrOperImm Imm = OpCode.Imm32_20();
|
ShaderIrOperImm imm = opCode.Imm32_20();
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Imm)));
|
block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), imm)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mov_R(ShaderIrBlock Block, long OpCode, int Position)
|
public static void Mov_R(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
ShaderIrOperGpr Gpr = OpCode.Gpr20();
|
ShaderIrOperGpr gpr = opCode.Gpr20();
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Gpr)));
|
block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), gpr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sel_C(ShaderIrBlock Block, long OpCode, int Position)
|
public static void Sel_C(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
EmitSel(Block, OpCode, ShaderOper.CR);
|
EmitSel(block, opCode, ShaderOper.Cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sel_I(ShaderIrBlock Block, long OpCode, int Position)
|
public static void Sel_I(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
EmitSel(Block, OpCode, ShaderOper.Imm);
|
EmitSel(block, opCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sel_R(ShaderIrBlock Block, long OpCode, int Position)
|
public static void Sel_R(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
EmitSel(Block, OpCode, ShaderOper.RR);
|
EmitSel(block, opCode, ShaderOper.Rr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mov_S(ShaderIrBlock Block, long OpCode, int Position)
|
public static void Mov_S(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
Block.AddNode(new ShaderIrCmnt("Stubbed."));
|
block.AddNode(new ShaderIrCmnt("Stubbed."));
|
||||||
|
|
||||||
//Zero is used as a special number to get a valid "0 * 0 + VertexIndex" in a GS
|
//Zero is used as a special number to get a valid "0 * 0 + VertexIndex" in a GS
|
||||||
ShaderIrNode Source = new ShaderIrOperImm(0);
|
ShaderIrNode source = new ShaderIrOperImm(0);
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Source)));
|
block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), source)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitF2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
private static void EmitF2F(ShaderIrBlock block, long opCode, ShaderOper oper)
|
||||||
{
|
{
|
||||||
bool NegA = OpCode.Read(45);
|
bool negA = opCode.Read(45);
|
||||||
bool AbsA = OpCode.Read(49);
|
bool absA = opCode.Read(49);
|
||||||
|
|
||||||
ShaderIrNode OperA;
|
ShaderIrNode operA;
|
||||||
|
|
||||||
switch (Oper)
|
switch (oper)
|
||||||
{
|
{
|
||||||
case ShaderOper.CR: OperA = OpCode.Cbuf34(); break;
|
case ShaderOper.Cr: operA = opCode.Cbuf34(); break;
|
||||||
case ShaderOper.Immf: OperA = OpCode.Immf19_20(); break;
|
case ShaderOper.Immf: operA = opCode.Immf19_20(); break;
|
||||||
case ShaderOper.RR: OperA = OpCode.Gpr20(); break;
|
case ShaderOper.Rr: operA = opCode.Gpr20(); break;
|
||||||
|
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(oper));
|
||||||
}
|
}
|
||||||
|
|
||||||
OperA = GetAluFabsFneg(OperA, AbsA, NegA);
|
operA = GetAluFabsFneg(operA, absA, negA);
|
||||||
|
|
||||||
ShaderIrInst RoundInst = GetRoundInst(OpCode);
|
ShaderIrInst roundInst = GetRoundInst(opCode);
|
||||||
|
|
||||||
if (RoundInst != ShaderIrInst.Invalid)
|
if (roundInst != ShaderIrInst.Invalid)
|
||||||
{
|
{
|
||||||
OperA = new ShaderIrOp(RoundInst, OperA);
|
operA = new ShaderIrOp(roundInst, operA);
|
||||||
}
|
}
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OperA)));
|
block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operA)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitF2i(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
private static void EmitF2I(ShaderIrBlock block, long opCode, ShaderOper oper)
|
||||||
{
|
{
|
||||||
IntType Type = GetIntType(OpCode);
|
IntType type = GetIntType(opCode);
|
||||||
|
|
||||||
if (Type == IntType.U64 ||
|
if (type == IntType.U64 ||
|
||||||
Type == IntType.S64)
|
type == IntType.S64)
|
||||||
{
|
{
|
||||||
//TODO: 64-bits support.
|
//TODO: 64-bits support.
|
||||||
//Note: GLSL doesn't support 64-bits integers.
|
//Note: GLSL doesn't support 64-bits integers.
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NegA = OpCode.Read(45);
|
bool negA = opCode.Read(45);
|
||||||
bool AbsA = OpCode.Read(49);
|
bool absA = opCode.Read(49);
|
||||||
|
|
||||||
ShaderIrNode OperA;
|
ShaderIrNode operA;
|
||||||
|
|
||||||
switch (Oper)
|
switch (oper)
|
||||||
{
|
{
|
||||||
case ShaderOper.CR: OperA = OpCode.Cbuf34(); break;
|
case ShaderOper.Cr: operA = opCode.Cbuf34(); break;
|
||||||
case ShaderOper.Immf: OperA = OpCode.Immf19_20(); break;
|
case ShaderOper.Immf: operA = opCode.Immf19_20(); break;
|
||||||
case ShaderOper.RR: OperA = OpCode.Gpr20(); break;
|
case ShaderOper.Rr: operA = opCode.Gpr20(); break;
|
||||||
|
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(oper));
|
||||||
}
|
}
|
||||||
|
|
||||||
OperA = GetAluFabsFneg(OperA, AbsA, NegA);
|
operA = GetAluFabsFneg(operA, absA, negA);
|
||||||
|
|
||||||
ShaderIrInst RoundInst = GetRoundInst(OpCode);
|
ShaderIrInst roundInst = GetRoundInst(opCode);
|
||||||
|
|
||||||
if (RoundInst != ShaderIrInst.Invalid)
|
if (roundInst != ShaderIrInst.Invalid)
|
||||||
{
|
{
|
||||||
OperA = new ShaderIrOp(RoundInst, OperA);
|
operA = new ShaderIrOp(roundInst, operA);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Signed = Type >= IntType.S8;
|
bool signed = type >= IntType.S8;
|
||||||
|
|
||||||
int Size = 8 << ((int)Type & 3);
|
int size = 8 << ((int)type & 3);
|
||||||
|
|
||||||
if (Size < 32)
|
if (size < 32)
|
||||||
{
|
{
|
||||||
uint Mask = uint.MaxValue >> (32 - Size);
|
uint mask = uint.MaxValue >> (32 - size);
|
||||||
|
|
||||||
float CMin = 0;
|
float cMin = 0;
|
||||||
float CMax = Mask;
|
float cMax = mask;
|
||||||
|
|
||||||
if (Signed)
|
if (signed)
|
||||||
{
|
{
|
||||||
uint HalfMask = Mask >> 1;
|
uint halfMask = mask >> 1;
|
||||||
|
|
||||||
CMin -= HalfMask + 1;
|
cMin -= halfMask + 1;
|
||||||
CMax = HalfMask;
|
cMax = halfMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrOperImmf IMin = new ShaderIrOperImmf(CMin);
|
ShaderIrOperImmf min = new ShaderIrOperImmf(cMin);
|
||||||
ShaderIrOperImmf IMax = new ShaderIrOperImmf(CMax);
|
ShaderIrOperImmf max = new ShaderIrOperImmf(cMax);
|
||||||
|
|
||||||
OperA = new ShaderIrOp(ShaderIrInst.Fclamp, OperA, IMin, IMax);
|
operA = new ShaderIrOp(ShaderIrInst.Fclamp, operA, min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrInst Inst = Signed
|
ShaderIrInst inst = signed
|
||||||
? ShaderIrInst.Ftos
|
? ShaderIrInst.Ftos
|
||||||
: ShaderIrInst.Ftou;
|
: ShaderIrInst.Ftou;
|
||||||
|
|
||||||
ShaderIrNode Op = new ShaderIrOp(Inst, OperA);
|
ShaderIrNode op = new ShaderIrOp(inst, operA);
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitI2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
private static void EmitI2F(ShaderIrBlock block, long opCode, ShaderOper oper)
|
||||||
{
|
{
|
||||||
IntType Type = GetIntType(OpCode);
|
IntType type = GetIntType(opCode);
|
||||||
|
|
||||||
if (Type == IntType.U64 ||
|
if (type == IntType.U64 ||
|
||||||
Type == IntType.S64)
|
type == IntType.S64)
|
||||||
{
|
{
|
||||||
//TODO: 64-bits support.
|
//TODO: 64-bits support.
|
||||||
//Note: GLSL doesn't support 64-bits integers.
|
//Note: GLSL doesn't support 64-bits integers.
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Sel = OpCode.Read(41, 3);
|
int sel = opCode.Read(41, 3);
|
||||||
|
|
||||||
bool NegA = OpCode.Read(45);
|
bool negA = opCode.Read(45);
|
||||||
bool AbsA = OpCode.Read(49);
|
bool absA = opCode.Read(49);
|
||||||
|
|
||||||
ShaderIrNode OperA;
|
ShaderIrNode operA;
|
||||||
|
|
||||||
switch (Oper)
|
switch (oper)
|
||||||
{
|
{
|
||||||
case ShaderOper.CR: OperA = OpCode.Cbuf34(); break;
|
case ShaderOper.Cr: operA = opCode.Cbuf34(); break;
|
||||||
case ShaderOper.Imm: OperA = OpCode.Imm19_20(); break;
|
case ShaderOper.Imm: operA = opCode.Imm19_20(); break;
|
||||||
case ShaderOper.RR: OperA = OpCode.Gpr20(); break;
|
case ShaderOper.Rr: operA = opCode.Gpr20(); break;
|
||||||
|
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(oper));
|
||||||
}
|
}
|
||||||
|
|
||||||
OperA = GetAluIabsIneg(OperA, AbsA, NegA);
|
operA = GetAluIabsIneg(operA, absA, negA);
|
||||||
|
|
||||||
bool Signed = Type >= IntType.S8;
|
bool signed = type >= IntType.S8;
|
||||||
|
|
||||||
int Shift = Sel * 8;
|
int shift = sel * 8;
|
||||||
|
|
||||||
int Size = 8 << ((int)Type & 3);
|
int size = 8 << ((int)type & 3);
|
||||||
|
|
||||||
if (Shift != 0)
|
if (shift != 0)
|
||||||
{
|
{
|
||||||
OperA = new ShaderIrOp(ShaderIrInst.Asr, OperA, new ShaderIrOperImm(Shift));
|
operA = new ShaderIrOp(ShaderIrInst.Asr, operA, new ShaderIrOperImm(shift));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Size < 32)
|
if (size < 32)
|
||||||
{
|
{
|
||||||
OperA = ExtendTo32(OperA, Signed, Size);
|
operA = ExtendTo32(operA, signed, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrInst Inst = Signed
|
ShaderIrInst inst = signed
|
||||||
? ShaderIrInst.Stof
|
? ShaderIrInst.Stof
|
||||||
: ShaderIrInst.Utof;
|
: ShaderIrInst.Utof;
|
||||||
|
|
||||||
ShaderIrNode Op = new ShaderIrOp(Inst, OperA);
|
ShaderIrNode op = new ShaderIrOp(inst, operA);
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitI2i(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
private static void EmitI2I(ShaderIrBlock block, long opCode, ShaderOper oper)
|
||||||
{
|
{
|
||||||
IntType Type = GetIntType(OpCode);
|
IntType type = GetIntType(opCode);
|
||||||
|
|
||||||
if (Type == IntType.U64 ||
|
if (type == IntType.U64 ||
|
||||||
Type == IntType.S64)
|
type == IntType.S64)
|
||||||
{
|
{
|
||||||
//TODO: 64-bits support.
|
//TODO: 64-bits support.
|
||||||
//Note: GLSL doesn't support 64-bits integers.
|
//Note: GLSL doesn't support 64-bits integers.
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Sel = OpCode.Read(41, 3);
|
int sel = opCode.Read(41, 3);
|
||||||
|
|
||||||
bool NegA = OpCode.Read(45);
|
bool negA = opCode.Read(45);
|
||||||
bool AbsA = OpCode.Read(49);
|
bool absA = opCode.Read(49);
|
||||||
bool SatA = OpCode.Read(50);
|
bool satA = opCode.Read(50);
|
||||||
|
|
||||||
ShaderIrNode OperA;
|
ShaderIrNode operA;
|
||||||
|
|
||||||
switch (Oper)
|
switch (oper)
|
||||||
{
|
{
|
||||||
case ShaderOper.CR: OperA = OpCode.Cbuf34(); break;
|
case ShaderOper.Cr: operA = opCode.Cbuf34(); break;
|
||||||
case ShaderOper.Immf: OperA = OpCode.Immf19_20(); break;
|
case ShaderOper.Immf: operA = opCode.Immf19_20(); break;
|
||||||
case ShaderOper.RR: OperA = OpCode.Gpr20(); break;
|
case ShaderOper.Rr: operA = opCode.Gpr20(); break;
|
||||||
|
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(oper));
|
||||||
}
|
}
|
||||||
|
|
||||||
OperA = GetAluIabsIneg(OperA, AbsA, NegA);
|
operA = GetAluIabsIneg(operA, absA, negA);
|
||||||
|
|
||||||
bool Signed = Type >= IntType.S8;
|
bool signed = type >= IntType.S8;
|
||||||
|
|
||||||
int Shift = Sel * 8;
|
int shift = sel * 8;
|
||||||
|
|
||||||
int Size = 8 << ((int)Type & 3);
|
int size = 8 << ((int)type & 3);
|
||||||
|
|
||||||
if (Shift != 0)
|
if (shift != 0)
|
||||||
{
|
{
|
||||||
OperA = new ShaderIrOp(ShaderIrInst.Asr, OperA, new ShaderIrOperImm(Shift));
|
operA = new ShaderIrOp(ShaderIrInst.Asr, operA, new ShaderIrOperImm(shift));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Size < 32)
|
if (size < 32)
|
||||||
{
|
{
|
||||||
uint Mask = uint.MaxValue >> (32 - Size);
|
uint mask = uint.MaxValue >> (32 - size);
|
||||||
|
|
||||||
if (SatA)
|
if (satA)
|
||||||
{
|
{
|
||||||
uint CMin = 0;
|
uint cMin = 0;
|
||||||
uint CMax = Mask;
|
uint cMax = mask;
|
||||||
|
|
||||||
if (Signed)
|
if (signed)
|
||||||
{
|
{
|
||||||
uint HalfMask = Mask >> 1;
|
uint halfMask = mask >> 1;
|
||||||
|
|
||||||
CMin -= HalfMask + 1;
|
cMin -= halfMask + 1;
|
||||||
CMax = HalfMask;
|
cMax = halfMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrOperImm IMin = new ShaderIrOperImm((int)CMin);
|
ShaderIrOperImm min = new ShaderIrOperImm((int)cMin);
|
||||||
ShaderIrOperImm IMax = new ShaderIrOperImm((int)CMax);
|
ShaderIrOperImm max = new ShaderIrOperImm((int)cMax);
|
||||||
|
|
||||||
OperA = new ShaderIrOp(Signed
|
operA = new ShaderIrOp(signed
|
||||||
? ShaderIrInst.Clamps
|
? ShaderIrInst.Clamps
|
||||||
: ShaderIrInst.Clampu, OperA, IMin, IMax);
|
: ShaderIrInst.Clampu, operA, min, max);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OperA = ExtendTo32(OperA, Signed, Size);
|
operA = ExtendTo32(operA, signed, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OperA)));
|
block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operA)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitSel(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
private static void EmitSel(ShaderIrBlock block, long opCode, ShaderOper oper)
|
||||||
{
|
{
|
||||||
ShaderIrOperGpr Dst = OpCode.Gpr0();
|
ShaderIrOperGpr dst = opCode.Gpr0();
|
||||||
ShaderIrNode Pred = OpCode.Pred39N();
|
ShaderIrNode pred = opCode.Pred39N();
|
||||||
|
|
||||||
ShaderIrNode ResultA = OpCode.Gpr8();
|
ShaderIrNode resultA = opCode.Gpr8();
|
||||||
ShaderIrNode ResultB;
|
ShaderIrNode resultB;
|
||||||
|
|
||||||
switch (Oper)
|
switch (oper)
|
||||||
{
|
{
|
||||||
case ShaderOper.CR: ResultB = OpCode.Cbuf34(); break;
|
case ShaderOper.Cr: resultB = opCode.Cbuf34(); break;
|
||||||
case ShaderOper.Imm: ResultB = OpCode.Imm19_20(); break;
|
case ShaderOper.Imm: resultB = opCode.Imm19_20(); break;
|
||||||
case ShaderOper.RR: ResultB = OpCode.Gpr20(); break;
|
case ShaderOper.Rr: resultB = opCode.Gpr20(); break;
|
||||||
|
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(oper));
|
||||||
}
|
}
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrCond(Pred, new ShaderIrAsg(Dst, ResultA), false)));
|
block.AddNode(opCode.PredNode(new ShaderIrCond(pred, new ShaderIrAsg(dst, resultA), false)));
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrCond(Pred, new ShaderIrAsg(Dst, ResultB), true)));
|
block.AddNode(opCode.PredNode(new ShaderIrCond(pred, new ShaderIrAsg(dst, resultB), true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IntType GetIntType(long OpCode)
|
private static IntType GetIntType(long opCode)
|
||||||
{
|
{
|
||||||
bool Signed = OpCode.Read(13);
|
bool signed = opCode.Read(13);
|
||||||
|
|
||||||
IntType Type = (IntType)(OpCode.Read(10, 3));
|
IntType type = (IntType)(opCode.Read(10, 3));
|
||||||
|
|
||||||
if (Signed)
|
if (signed)
|
||||||
{
|
{
|
||||||
Type += (int)IntType.S8;
|
type += (int)IntType.S8;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FloatType GetFloatType(long OpCode)
|
private static FloatType GetFloatType(long opCode)
|
||||||
{
|
{
|
||||||
return (FloatType)(OpCode.Read(8, 3));
|
return (FloatType)(opCode.Read(8, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrInst GetRoundInst(long OpCode)
|
private static ShaderIrInst GetRoundInst(long opCode)
|
||||||
{
|
{
|
||||||
switch (OpCode.Read(39, 3))
|
switch (opCode.Read(39, 3))
|
||||||
{
|
{
|
||||||
case 1: return ShaderIrInst.Floor;
|
case 1: return ShaderIrInst.Floor;
|
||||||
case 2: return ShaderIrInst.Ceil;
|
case 2: return ShaderIrInst.Ceil;
|
||||||
|
|
|
@ -4,227 +4,227 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static partial class ShaderDecode
|
static partial class ShaderDecode
|
||||||
{
|
{
|
||||||
private static int Read(this long OpCode, int Position, int Mask)
|
private static int Read(this long opCode, int position, int mask)
|
||||||
{
|
{
|
||||||
return (int)(OpCode >> Position) & Mask;
|
return (int)(opCode >> position) & mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool Read(this long OpCode, int Position)
|
private static bool Read(this long opCode, int position)
|
||||||
{
|
{
|
||||||
return ((OpCode >> Position) & 1) != 0;
|
return ((opCode >> position) & 1) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int Branch(this long OpCode)
|
private static int Branch(this long opCode)
|
||||||
{
|
{
|
||||||
return ((int)(OpCode >> 20) << 8) >> 8;
|
return ((int)(opCode >> 20) << 8) >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool HasArray(this long OpCode)
|
private static bool HasArray(this long opCode)
|
||||||
{
|
{
|
||||||
return OpCode.Read(0x1c);
|
return opCode.Read(0x1c);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperAbuf[] Abuf20(this long OpCode)
|
private static ShaderIrOperAbuf[] Abuf20(this long opCode)
|
||||||
{
|
{
|
||||||
int Abuf = OpCode.Read(20, 0x3ff);
|
int abuf = opCode.Read(20, 0x3ff);
|
||||||
int Size = OpCode.Read(47, 3);
|
int size = opCode.Read(47, 3);
|
||||||
|
|
||||||
ShaderIrOperGpr Vertex = OpCode.Gpr39();
|
ShaderIrOperGpr vertex = opCode.Gpr39();
|
||||||
|
|
||||||
ShaderIrOperAbuf[] Opers = new ShaderIrOperAbuf[Size + 1];
|
ShaderIrOperAbuf[] opers = new ShaderIrOperAbuf[size + 1];
|
||||||
|
|
||||||
for (int Index = 0; Index <= Size; Index++)
|
for (int index = 0; index <= size; index++)
|
||||||
{
|
{
|
||||||
Opers[Index] = new ShaderIrOperAbuf(Abuf + Index * 4, Vertex);
|
opers[index] = new ShaderIrOperAbuf(abuf + index * 4, vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Opers;
|
return opers;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperAbuf Abuf28(this long OpCode)
|
private static ShaderIrOperAbuf Abuf28(this long opCode)
|
||||||
{
|
{
|
||||||
int Abuf = OpCode.Read(28, 0x3ff);
|
int abuf = opCode.Read(28, 0x3ff);
|
||||||
|
|
||||||
return new ShaderIrOperAbuf(Abuf, OpCode.Gpr39());
|
return new ShaderIrOperAbuf(abuf, opCode.Gpr39());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperCbuf Cbuf34(this long OpCode)
|
private static ShaderIrOperCbuf Cbuf34(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperCbuf(
|
return new ShaderIrOperCbuf(
|
||||||
OpCode.Read(34, 0x1f),
|
opCode.Read(34, 0x1f),
|
||||||
OpCode.Read(20, 0x3fff));
|
opCode.Read(20, 0x3fff));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperGpr Gpr8(this long OpCode)
|
private static ShaderIrOperGpr Gpr8(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperGpr(OpCode.Read(8, 0xff));
|
return new ShaderIrOperGpr(opCode.Read(8, 0xff));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperGpr Gpr20(this long OpCode)
|
private static ShaderIrOperGpr Gpr20(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperGpr(OpCode.Read(20, 0xff));
|
return new ShaderIrOperGpr(opCode.Read(20, 0xff));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperGpr Gpr39(this long OpCode)
|
private static ShaderIrOperGpr Gpr39(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperGpr(OpCode.Read(39, 0xff));
|
return new ShaderIrOperGpr(opCode.Read(39, 0xff));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperGpr Gpr0(this long OpCode)
|
private static ShaderIrOperGpr Gpr0(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperGpr(OpCode.Read(0, 0xff));
|
return new ShaderIrOperGpr(opCode.Read(0, 0xff));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperGpr Gpr28(this long OpCode)
|
private static ShaderIrOperGpr Gpr28(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperGpr(OpCode.Read(28, 0xff));
|
return new ShaderIrOperGpr(opCode.Read(28, 0xff));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperGpr[] GprHalfVec8(this long OpCode)
|
private static ShaderIrOperGpr[] GprHalfVec8(this long opCode)
|
||||||
{
|
{
|
||||||
return GetGprHalfVec2(OpCode.Read(8, 0xff), OpCode.Read(47, 3));
|
return GetGprHalfVec2(opCode.Read(8, 0xff), opCode.Read(47, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperGpr[] GprHalfVec20(this long OpCode)
|
private static ShaderIrOperGpr[] GprHalfVec20(this long opCode)
|
||||||
{
|
{
|
||||||
return GetGprHalfVec2(OpCode.Read(20, 0xff), OpCode.Read(28, 3));
|
return GetGprHalfVec2(opCode.Read(20, 0xff), opCode.Read(28, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperGpr[] GetGprHalfVec2(int Gpr, int Mask)
|
private static ShaderIrOperGpr[] GetGprHalfVec2(int gpr, int mask)
|
||||||
{
|
{
|
||||||
if (Mask == 1)
|
if (mask == 1)
|
||||||
{
|
{
|
||||||
//This value is used for FP32, the whole 32-bits register
|
//This value is used for FP32, the whole 32-bits register
|
||||||
//is used as each element on the vector.
|
//is used as each element on the vector.
|
||||||
return new ShaderIrOperGpr[]
|
return new ShaderIrOperGpr[]
|
||||||
{
|
{
|
||||||
new ShaderIrOperGpr(Gpr),
|
new ShaderIrOperGpr(gpr),
|
||||||
new ShaderIrOperGpr(Gpr)
|
new ShaderIrOperGpr(gpr)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrOperGpr Low = new ShaderIrOperGpr(Gpr, 0);
|
ShaderIrOperGpr low = new ShaderIrOperGpr(gpr, 0);
|
||||||
ShaderIrOperGpr High = new ShaderIrOperGpr(Gpr, 1);
|
ShaderIrOperGpr high = new ShaderIrOperGpr(gpr, 1);
|
||||||
|
|
||||||
return new ShaderIrOperGpr[]
|
return new ShaderIrOperGpr[]
|
||||||
{
|
{
|
||||||
(Mask & 1) != 0 ? High : Low,
|
(mask & 1) != 0 ? high : low,
|
||||||
(Mask & 2) != 0 ? High : Low
|
(mask & 2) != 0 ? high : low
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperGpr GprHalf0(this long OpCode, int HalfPart)
|
private static ShaderIrOperGpr GprHalf0(this long opCode, int halfPart)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperGpr(OpCode.Read(0, 0xff), HalfPart);
|
return new ShaderIrOperGpr(opCode.Read(0, 0xff), halfPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperGpr GprHalf28(this long OpCode, int HalfPart)
|
private static ShaderIrOperGpr GprHalf28(this long opCode, int halfPart)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperGpr(OpCode.Read(28, 0xff), HalfPart);
|
return new ShaderIrOperGpr(opCode.Read(28, 0xff), halfPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperImm Imm5_39(this long OpCode)
|
private static ShaderIrOperImm Imm5_39(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperImm(OpCode.Read(39, 0x1f));
|
return new ShaderIrOperImm(opCode.Read(39, 0x1f));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperImm Imm13_36(this long OpCode)
|
private static ShaderIrOperImm Imm13_36(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperImm(OpCode.Read(36, 0x1fff));
|
return new ShaderIrOperImm(opCode.Read(36, 0x1fff));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperImm Imm32_20(this long OpCode)
|
private static ShaderIrOperImm Imm32_20(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperImm((int)(OpCode >> 20));
|
return new ShaderIrOperImm((int)(opCode >> 20));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperImmf Immf32_20(this long OpCode)
|
private static ShaderIrOperImmf Immf32_20(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperImmf(BitConverter.Int32BitsToSingle((int)(OpCode >> 20)));
|
return new ShaderIrOperImmf(BitConverter.Int32BitsToSingle((int)(opCode >> 20)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperImm ImmU16_20(this long OpCode)
|
private static ShaderIrOperImm ImmU16_20(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperImm(OpCode.Read(20, 0xffff));
|
return new ShaderIrOperImm(opCode.Read(20, 0xffff));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperImm Imm19_20(this long OpCode)
|
private static ShaderIrOperImm Imm19_20(this long opCode)
|
||||||
{
|
{
|
||||||
int Value = OpCode.Read(20, 0x7ffff);
|
int value = opCode.Read(20, 0x7ffff);
|
||||||
|
|
||||||
bool Neg = OpCode.Read(56);
|
bool neg = opCode.Read(56);
|
||||||
|
|
||||||
if (Neg)
|
if (neg)
|
||||||
{
|
{
|
||||||
Value = -Value;
|
value = -value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ShaderIrOperImm(Value);
|
return new ShaderIrOperImm(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperImmf Immf19_20(this long OpCode)
|
private static ShaderIrOperImmf Immf19_20(this long opCode)
|
||||||
{
|
{
|
||||||
uint Imm = (uint)(OpCode >> 20) & 0x7ffff;
|
uint imm = (uint)(opCode >> 20) & 0x7ffff;
|
||||||
|
|
||||||
bool Neg = OpCode.Read(56);
|
bool neg = opCode.Read(56);
|
||||||
|
|
||||||
Imm <<= 12;
|
imm <<= 12;
|
||||||
|
|
||||||
if (Neg)
|
if (neg)
|
||||||
{
|
{
|
||||||
Imm |= 0x80000000;
|
imm |= 0x80000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Value = BitConverter.Int32BitsToSingle((int)Imm);
|
float value = BitConverter.Int32BitsToSingle((int)imm);
|
||||||
|
|
||||||
return new ShaderIrOperImmf(Value);
|
return new ShaderIrOperImmf(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperPred Pred0(this long OpCode)
|
private static ShaderIrOperPred Pred0(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperPred(OpCode.Read(0, 7));
|
return new ShaderIrOperPred(opCode.Read(0, 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperPred Pred3(this long OpCode)
|
private static ShaderIrOperPred Pred3(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperPred(OpCode.Read(3, 7));
|
return new ShaderIrOperPred(opCode.Read(3, 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperPred Pred12(this long OpCode)
|
private static ShaderIrOperPred Pred12(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperPred(OpCode.Read(12, 7));
|
return new ShaderIrOperPred(opCode.Read(12, 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperPred Pred29(this long OpCode)
|
private static ShaderIrOperPred Pred29(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperPred(OpCode.Read(29, 7));
|
return new ShaderIrOperPred(opCode.Read(29, 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrNode Pred39N(this long OpCode)
|
private static ShaderIrNode Pred39N(this long opCode)
|
||||||
{
|
{
|
||||||
ShaderIrNode Node = OpCode.Pred39();
|
ShaderIrNode node = opCode.Pred39();
|
||||||
|
|
||||||
if (OpCode.Read(42))
|
if (opCode.Read(42))
|
||||||
{
|
{
|
||||||
Node = new ShaderIrOp(ShaderIrInst.Bnot, Node);
|
node = new ShaderIrOp(ShaderIrInst.Bnot, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperPred Pred39(this long OpCode)
|
private static ShaderIrOperPred Pred39(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperPred(OpCode.Read(39, 7));
|
return new ShaderIrOperPred(opCode.Read(39, 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperPred Pred48(this long OpCode)
|
private static ShaderIrOperPred Pred48(this long opCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperPred(OpCode.Read(48, 7));
|
return new ShaderIrOperPred(opCode.Read(48, 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrInst Cmp(this long OpCode)
|
private static ShaderIrInst Cmp(this long opCode)
|
||||||
{
|
{
|
||||||
switch (OpCode.Read(49, 7))
|
switch (opCode.Read(49, 7))
|
||||||
{
|
{
|
||||||
case 1: return ShaderIrInst.Clt;
|
case 1: return ShaderIrInst.Clt;
|
||||||
case 2: return ShaderIrInst.Ceq;
|
case 2: return ShaderIrInst.Ceq;
|
||||||
|
@ -234,12 +234,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
case 6: return ShaderIrInst.Cge;
|
case 6: return ShaderIrInst.Cge;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(OpCode));
|
throw new ArgumentException(nameof(opCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrInst CmpF(this long OpCode)
|
private static ShaderIrInst CmpF(this long opCode)
|
||||||
{
|
{
|
||||||
switch (OpCode.Read(48, 0xf))
|
switch (opCode.Read(48, 0xf))
|
||||||
{
|
{
|
||||||
case 0x1: return ShaderIrInst.Fclt;
|
case 0x1: return ShaderIrInst.Fclt;
|
||||||
case 0x2: return ShaderIrInst.Fceq;
|
case 0x2: return ShaderIrInst.Fceq;
|
||||||
|
@ -257,57 +257,57 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
case 0xe: return ShaderIrInst.Fcgeu;
|
case 0xe: return ShaderIrInst.Fcgeu;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(OpCode));
|
throw new ArgumentException(nameof(opCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrInst BLop45(this long OpCode)
|
private static ShaderIrInst BLop45(this long opCode)
|
||||||
{
|
{
|
||||||
switch (OpCode.Read(45, 3))
|
switch (opCode.Read(45, 3))
|
||||||
{
|
{
|
||||||
case 0: return ShaderIrInst.Band;
|
case 0: return ShaderIrInst.Band;
|
||||||
case 1: return ShaderIrInst.Bor;
|
case 1: return ShaderIrInst.Bor;
|
||||||
case 2: return ShaderIrInst.Bxor;
|
case 2: return ShaderIrInst.Bxor;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(OpCode));
|
throw new ArgumentException(nameof(opCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrInst BLop24(this long OpCode)
|
private static ShaderIrInst BLop24(this long opCode)
|
||||||
{
|
{
|
||||||
switch (OpCode.Read(24, 3))
|
switch (opCode.Read(24, 3))
|
||||||
{
|
{
|
||||||
case 0: return ShaderIrInst.Band;
|
case 0: return ShaderIrInst.Band;
|
||||||
case 1: return ShaderIrInst.Bor;
|
case 1: return ShaderIrInst.Bor;
|
||||||
case 2: return ShaderIrInst.Bxor;
|
case 2: return ShaderIrInst.Bxor;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(OpCode));
|
throw new ArgumentException(nameof(opCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrNode PredNode(this long OpCode, ShaderIrNode Node)
|
private static ShaderIrNode PredNode(this long opCode, ShaderIrNode node)
|
||||||
{
|
{
|
||||||
ShaderIrOperPred Pred = OpCode.PredNode();
|
ShaderIrOperPred pred = opCode.PredNode();
|
||||||
|
|
||||||
if (Pred.Index != ShaderIrOperPred.UnusedIndex)
|
if (pred.Index != ShaderIrOperPred.UnusedIndex)
|
||||||
{
|
{
|
||||||
bool Inv = OpCode.Read(19);
|
bool inv = opCode.Read(19);
|
||||||
|
|
||||||
Node = new ShaderIrCond(Pred, Node, Inv);
|
node = new ShaderIrCond(pred, node, inv);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOperPred PredNode(this long OpCode)
|
private static ShaderIrOperPred PredNode(this long opCode)
|
||||||
{
|
{
|
||||||
int Pred = OpCode.Read(16, 0xf);
|
int pred = opCode.Read(16, 0xf);
|
||||||
|
|
||||||
if (Pred != 0xf)
|
if (pred != 0xf)
|
||||||
{
|
{
|
||||||
Pred &= 7;
|
pred &= 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ShaderIrOperPred(Pred);
|
return new ShaderIrOperPred(pred);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,23 +2,23 @@
|
||||||
{
|
{
|
||||||
static partial class ShaderDecode
|
static partial class ShaderDecode
|
||||||
{
|
{
|
||||||
public static void Out_R(ShaderIrBlock Block, long OpCode, int Position)
|
public static void Out_R(ShaderIrBlock block, long opCode, int position)
|
||||||
{
|
{
|
||||||
//TODO: Those registers have to be used for something
|
//TODO: Those registers have to be used for something
|
||||||
ShaderIrOperGpr Gpr0 = OpCode.Gpr0();
|
ShaderIrOperGpr gpr0 = opCode.Gpr0();
|
||||||
ShaderIrOperGpr Gpr8 = OpCode.Gpr8();
|
ShaderIrOperGpr gpr8 = opCode.Gpr8();
|
||||||
ShaderIrOperGpr Gpr20 = OpCode.Gpr20();
|
ShaderIrOperGpr gpr20 = opCode.Gpr20();
|
||||||
|
|
||||||
int Type = OpCode.Read(39, 3);
|
int type = opCode.Read(39, 3);
|
||||||
|
|
||||||
if ((Type & 1) != 0)
|
if ((type & 1) != 0)
|
||||||
{
|
{
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Emit)));
|
block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Emit)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((Type & 2) != 0)
|
if ((type & 2) != 0)
|
||||||
{
|
{
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Cut)));
|
block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Cut)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,74 +8,74 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private const bool AddDbgComments = true;
|
private const bool AddDbgComments = true;
|
||||||
|
|
||||||
public static ShaderIrBlock[] Decode(IGalMemory Memory, long Start)
|
public static ShaderIrBlock[] Decode(IGalMemory memory, long start)
|
||||||
{
|
{
|
||||||
Dictionary<int, ShaderIrBlock> Visited = new Dictionary<int, ShaderIrBlock>();
|
Dictionary<int, ShaderIrBlock> visited = new Dictionary<int, ShaderIrBlock>();
|
||||||
Dictionary<int, ShaderIrBlock> VisitedEnd = new Dictionary<int, ShaderIrBlock>();
|
Dictionary<int, ShaderIrBlock> visitedEnd = new Dictionary<int, ShaderIrBlock>();
|
||||||
|
|
||||||
Queue<ShaderIrBlock> Blocks = new Queue<ShaderIrBlock>();
|
Queue<ShaderIrBlock> blocks = new Queue<ShaderIrBlock>();
|
||||||
|
|
||||||
long Beginning = Start + HeaderSize;
|
long beginning = start + HeaderSize;
|
||||||
|
|
||||||
ShaderIrBlock Enqueue(int Position, ShaderIrBlock Source = null)
|
ShaderIrBlock Enqueue(int position, ShaderIrBlock source = null)
|
||||||
{
|
{
|
||||||
if (!Visited.TryGetValue(Position, out ShaderIrBlock Output))
|
if (!visited.TryGetValue(position, out ShaderIrBlock output))
|
||||||
{
|
{
|
||||||
Output = new ShaderIrBlock(Position);
|
output = new ShaderIrBlock(position);
|
||||||
|
|
||||||
Blocks.Enqueue(Output);
|
blocks.Enqueue(output);
|
||||||
|
|
||||||
Visited.Add(Position, Output);
|
visited.Add(position, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Source != null)
|
if (source != null)
|
||||||
{
|
{
|
||||||
Output.Sources.Add(Source);
|
output.Sources.Add(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrBlock Entry = Enqueue(0);
|
ShaderIrBlock entry = Enqueue(0);
|
||||||
|
|
||||||
while (Blocks.Count > 0)
|
while (blocks.Count > 0)
|
||||||
{
|
{
|
||||||
ShaderIrBlock Current = Blocks.Dequeue();
|
ShaderIrBlock current = blocks.Dequeue();
|
||||||
|
|
||||||
FillBlock(Memory, Current, Beginning);
|
FillBlock(memory, current, beginning);
|
||||||
|
|
||||||
//Set child blocks. "Branch" is the block the branch instruction
|
//Set child blocks. "Branch" is the block the branch instruction
|
||||||
//points to (when taken), "Next" is the block at the next address,
|
//points to (when taken), "Next" is the block at the next address,
|
||||||
//executed when the branch is not taken. For Unconditional Branches
|
//executed when the branch is not taken. For Unconditional Branches
|
||||||
//or end of shader, Next is null.
|
//or end of shader, Next is null.
|
||||||
if (Current.Nodes.Count > 0)
|
if (current.Nodes.Count > 0)
|
||||||
{
|
{
|
||||||
ShaderIrNode LastNode = Current.GetLastNode();
|
ShaderIrNode lastNode = current.GetLastNode();
|
||||||
|
|
||||||
ShaderIrOp InnerOp = GetInnermostOp(LastNode);
|
ShaderIrOp innerOp = GetInnermostOp(lastNode);
|
||||||
|
|
||||||
if (InnerOp?.Inst == ShaderIrInst.Bra)
|
if (innerOp?.Inst == ShaderIrInst.Bra)
|
||||||
{
|
{
|
||||||
int Target = ((ShaderIrOperImm)InnerOp.OperandA).Value;
|
int target = ((ShaderIrOperImm)innerOp.OperandA).Value;
|
||||||
|
|
||||||
Current.Branch = Enqueue(Target, Current);
|
current.Branch = Enqueue(target, current);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ShaderIrNode Node in Current.Nodes)
|
foreach (ShaderIrNode node in current.Nodes)
|
||||||
{
|
{
|
||||||
InnerOp = GetInnermostOp(Node);
|
innerOp = GetInnermostOp(node);
|
||||||
|
|
||||||
if (InnerOp is ShaderIrOp CurrOp && CurrOp.Inst == ShaderIrInst.Ssy)
|
if (innerOp is ShaderIrOp currOp && currOp.Inst == ShaderIrInst.Ssy)
|
||||||
{
|
{
|
||||||
int Target = ((ShaderIrOperImm)CurrOp.OperandA).Value;
|
int target = ((ShaderIrOperImm)currOp.OperandA).Value;
|
||||||
|
|
||||||
Enqueue(Target, Current);
|
Enqueue(target, current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NodeHasNext(LastNode))
|
if (NodeHasNext(lastNode))
|
||||||
{
|
{
|
||||||
Current.Next = Enqueue(Current.EndPosition);
|
current.Next = Enqueue(current.EndPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,136 +83,136 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
//then we need to split the bigger block and have two small blocks,
|
//then we need to split the bigger block and have two small blocks,
|
||||||
//the end position of the bigger "Current" block should then be == to
|
//the end position of the bigger "Current" block should then be == to
|
||||||
//the position of the "Smaller" block.
|
//the position of the "Smaller" block.
|
||||||
while (VisitedEnd.TryGetValue(Current.EndPosition, out ShaderIrBlock Smaller))
|
while (visitedEnd.TryGetValue(current.EndPosition, out ShaderIrBlock smaller))
|
||||||
{
|
{
|
||||||
if (Current.Position > Smaller.Position)
|
if (current.Position > smaller.Position)
|
||||||
{
|
{
|
||||||
ShaderIrBlock Temp = Smaller;
|
ShaderIrBlock temp = smaller;
|
||||||
|
|
||||||
Smaller = Current;
|
smaller = current;
|
||||||
Current = Temp;
|
current = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Current.EndPosition = Smaller.Position;
|
current.EndPosition = smaller.Position;
|
||||||
Current.Next = Smaller;
|
current.Next = smaller;
|
||||||
Current.Branch = null;
|
current.Branch = null;
|
||||||
|
|
||||||
Current.Nodes.RemoveRange(
|
current.Nodes.RemoveRange(
|
||||||
Current.Nodes.Count - Smaller.Nodes.Count,
|
current.Nodes.Count - smaller.Nodes.Count,
|
||||||
Smaller.Nodes.Count);
|
smaller.Nodes.Count);
|
||||||
|
|
||||||
VisitedEnd[Smaller.EndPosition] = Smaller;
|
visitedEnd[smaller.EndPosition] = smaller;
|
||||||
}
|
}
|
||||||
|
|
||||||
VisitedEnd.Add(Current.EndPosition, Current);
|
visitedEnd.Add(current.EndPosition, current);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Make and sort Graph blocks array by position.
|
//Make and sort Graph blocks array by position.
|
||||||
ShaderIrBlock[] Graph = new ShaderIrBlock[Visited.Count];
|
ShaderIrBlock[] graph = new ShaderIrBlock[visited.Count];
|
||||||
|
|
||||||
while (Visited.Count > 0)
|
while (visited.Count > 0)
|
||||||
{
|
{
|
||||||
uint FirstPos = uint.MaxValue;
|
uint firstPos = uint.MaxValue;
|
||||||
|
|
||||||
foreach (ShaderIrBlock Block in Visited.Values)
|
foreach (ShaderIrBlock block in visited.Values)
|
||||||
{
|
{
|
||||||
if (FirstPos > (uint)Block.Position)
|
if (firstPos > (uint)block.Position)
|
||||||
FirstPos = (uint)Block.Position;
|
firstPos = (uint)block.Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrBlock Current = Visited[(int)FirstPos];
|
ShaderIrBlock current = visited[(int)firstPos];
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
Graph[Graph.Length - Visited.Count] = Current;
|
graph[graph.Length - visited.Count] = current;
|
||||||
|
|
||||||
Visited.Remove(Current.Position);
|
visited.Remove(current.Position);
|
||||||
|
|
||||||
Current = Current.Next;
|
current = current.Next;
|
||||||
}
|
}
|
||||||
while (Current != null);
|
while (current != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Graph;
|
return graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FillBlock(IGalMemory Memory, ShaderIrBlock Block, long Beginning)
|
private static void FillBlock(IGalMemory memory, ShaderIrBlock block, long beginning)
|
||||||
{
|
{
|
||||||
int Position = Block.Position;
|
int position = block.Position;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
//Ignore scheduling instructions, which are written every 32 bytes.
|
//Ignore scheduling instructions, which are written every 32 bytes.
|
||||||
if ((Position & 0x1f) == 0)
|
if ((position & 0x1f) == 0)
|
||||||
{
|
{
|
||||||
Position += 8;
|
position += 8;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint Word0 = (uint)Memory.ReadInt32(Position + Beginning + 0);
|
uint word0 = (uint)memory.ReadInt32(position + beginning + 0);
|
||||||
uint Word1 = (uint)Memory.ReadInt32(Position + Beginning + 4);
|
uint word1 = (uint)memory.ReadInt32(position + beginning + 4);
|
||||||
|
|
||||||
Position += 8;
|
position += 8;
|
||||||
|
|
||||||
long OpCode = Word0 | (long)Word1 << 32;
|
long opCode = word0 | (long)word1 << 32;
|
||||||
|
|
||||||
ShaderDecodeFunc Decode = ShaderOpCodeTable.GetDecoder(OpCode);
|
ShaderDecodeFunc decode = ShaderOpCodeTable.GetDecoder(opCode);
|
||||||
|
|
||||||
if (AddDbgComments)
|
if (AddDbgComments)
|
||||||
{
|
{
|
||||||
string DbgOpCode = $"0x{(Position - 8):x16}: 0x{OpCode:x16} ";
|
string dbgOpCode = $"0x{(position - 8):x16}: 0x{opCode:x16} ";
|
||||||
|
|
||||||
DbgOpCode += (Decode?.Method.Name ?? "???");
|
dbgOpCode += (decode?.Method.Name ?? "???");
|
||||||
|
|
||||||
if (Decode == ShaderDecode.Bra || Decode == ShaderDecode.Ssy)
|
if (decode == ShaderDecode.Bra || decode == ShaderDecode.Ssy)
|
||||||
{
|
{
|
||||||
int Offset = ((int)(OpCode >> 20) << 8) >> 8;
|
int offset = ((int)(opCode >> 20) << 8) >> 8;
|
||||||
|
|
||||||
long Target = Position + Offset;
|
long target = position + offset;
|
||||||
|
|
||||||
DbgOpCode += " (0x" + Target.ToString("x16") + ")";
|
dbgOpCode += " (0x" + target.ToString("x16") + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
Block.AddNode(new ShaderIrCmnt(DbgOpCode));
|
block.AddNode(new ShaderIrCmnt(dbgOpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Decode == null)
|
if (decode == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Decode(Block, OpCode, Position);
|
decode(block, opCode, position);
|
||||||
}
|
}
|
||||||
while (!IsFlowChange(Block.GetLastNode()));
|
while (!IsFlowChange(block.GetLastNode()));
|
||||||
|
|
||||||
Block.EndPosition = Position;
|
block.EndPosition = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsFlowChange(ShaderIrNode Node)
|
private static bool IsFlowChange(ShaderIrNode node)
|
||||||
{
|
{
|
||||||
return !NodeHasNext(GetInnermostOp(Node));
|
return !NodeHasNext(GetInnermostOp(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderIrOp GetInnermostOp(ShaderIrNode Node)
|
private static ShaderIrOp GetInnermostOp(ShaderIrNode node)
|
||||||
{
|
{
|
||||||
if (Node is ShaderIrCond Cond)
|
if (node is ShaderIrCond cond)
|
||||||
{
|
{
|
||||||
Node = Cond.Child;
|
node = cond.Child;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Node is ShaderIrOp Op ? Op : null;
|
return node is ShaderIrOp op ? op : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool NodeHasNext(ShaderIrNode Node)
|
private static bool NodeHasNext(ShaderIrNode node)
|
||||||
{
|
{
|
||||||
if (!(Node is ShaderIrOp Op))
|
if (!(node is ShaderIrOp op))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Op.Inst != ShaderIrInst.Exit &&
|
return op.Inst != ShaderIrInst.Exit &&
|
||||||
Op.Inst != ShaderIrInst.Bra;
|
op.Inst != ShaderIrInst.Bra;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,9 +11,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public bool Enabled => Red || Green || Blue || Alpha;
|
public bool Enabled => Red || Green || Blue || Alpha;
|
||||||
|
|
||||||
public bool ComponentEnabled(int Component)
|
public bool ComponentEnabled(int component)
|
||||||
{
|
{
|
||||||
switch (Component)
|
switch (component)
|
||||||
{
|
{
|
||||||
case 0: return Red;
|
case 0: return Red;
|
||||||
case 1: return Green;
|
case 1: return Green;
|
||||||
|
@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
case 3: return Alpha;
|
case 3: return Alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Component));
|
throw new ArgumentException(nameof(component));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,88 +59,88 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
public bool OmapSampleMask { get; private set; }
|
public bool OmapSampleMask { get; private set; }
|
||||||
public bool OmapDepth { get; private set; }
|
public bool OmapDepth { get; private set; }
|
||||||
|
|
||||||
public ShaderHeader(IGalMemory Memory, long Position)
|
public ShaderHeader(IGalMemory memory, long position)
|
||||||
{
|
{
|
||||||
uint CommonWord0 = (uint)Memory.ReadInt32(Position + 0);
|
uint commonWord0 = (uint)memory.ReadInt32(position + 0);
|
||||||
uint CommonWord1 = (uint)Memory.ReadInt32(Position + 4);
|
uint commonWord1 = (uint)memory.ReadInt32(position + 4);
|
||||||
uint CommonWord2 = (uint)Memory.ReadInt32(Position + 8);
|
uint commonWord2 = (uint)memory.ReadInt32(position + 8);
|
||||||
uint CommonWord3 = (uint)Memory.ReadInt32(Position + 12);
|
uint commonWord3 = (uint)memory.ReadInt32(position + 12);
|
||||||
uint CommonWord4 = (uint)Memory.ReadInt32(Position + 16);
|
uint commonWord4 = (uint)memory.ReadInt32(position + 16);
|
||||||
|
|
||||||
SphType = ReadBits(CommonWord0, 0, 5);
|
SphType = ReadBits(commonWord0, 0, 5);
|
||||||
Version = ReadBits(CommonWord0, 5, 5);
|
Version = ReadBits(commonWord0, 5, 5);
|
||||||
ShaderType = ReadBits(CommonWord0, 10, 4);
|
ShaderType = ReadBits(commonWord0, 10, 4);
|
||||||
MrtEnable = ReadBits(CommonWord0, 14, 1) != 0;
|
MrtEnable = ReadBits(commonWord0, 14, 1) != 0;
|
||||||
KillsPixels = ReadBits(CommonWord0, 15, 1) != 0;
|
KillsPixels = ReadBits(commonWord0, 15, 1) != 0;
|
||||||
DoesGlobalStore = ReadBits(CommonWord0, 16, 1) != 0;
|
DoesGlobalStore = ReadBits(commonWord0, 16, 1) != 0;
|
||||||
SassVersion = ReadBits(CommonWord0, 17, 4);
|
SassVersion = ReadBits(commonWord0, 17, 4);
|
||||||
DoesLoadOrStore = ReadBits(CommonWord0, 26, 1) != 0;
|
DoesLoadOrStore = ReadBits(commonWord0, 26, 1) != 0;
|
||||||
DoesFp64 = ReadBits(CommonWord0, 27, 1) != 0;
|
DoesFp64 = ReadBits(commonWord0, 27, 1) != 0;
|
||||||
StreamOutMask = ReadBits(CommonWord0, 28, 4);
|
StreamOutMask = ReadBits(commonWord0, 28, 4);
|
||||||
|
|
||||||
ShaderLocalMemoryLowSize = ReadBits(CommonWord1, 0, 24);
|
ShaderLocalMemoryLowSize = ReadBits(commonWord1, 0, 24);
|
||||||
PerPatchAttributeCount = ReadBits(CommonWord1, 24, 8);
|
PerPatchAttributeCount = ReadBits(commonWord1, 24, 8);
|
||||||
|
|
||||||
ShaderLocalMemoryHighSize = ReadBits(CommonWord2, 0, 24);
|
ShaderLocalMemoryHighSize = ReadBits(commonWord2, 0, 24);
|
||||||
ThreadsPerInputPrimitive = ReadBits(CommonWord2, 24, 8);
|
ThreadsPerInputPrimitive = ReadBits(commonWord2, 24, 8);
|
||||||
|
|
||||||
ShaderLocalMemoryCrsSize = ReadBits(CommonWord3, 0, 24);
|
ShaderLocalMemoryCrsSize = ReadBits(commonWord3, 0, 24);
|
||||||
OutputTopology = ReadBits(CommonWord3, 24, 4);
|
OutputTopology = ReadBits(commonWord3, 24, 4);
|
||||||
|
|
||||||
MaxOutputVertexCount = ReadBits(CommonWord4, 0, 12);
|
MaxOutputVertexCount = ReadBits(commonWord4, 0, 12);
|
||||||
StoreReqStart = ReadBits(CommonWord4, 12, 8);
|
StoreReqStart = ReadBits(commonWord4, 12, 8);
|
||||||
StoreReqEnd = ReadBits(CommonWord4, 24, 8);
|
StoreReqEnd = ReadBits(commonWord4, 24, 8);
|
||||||
|
|
||||||
//Type 2 (fragment?) reading
|
//Type 2 (fragment?) reading
|
||||||
uint Type2OmapTarget = (uint)Memory.ReadInt32(Position + 72);
|
uint type2OmapTarget = (uint)memory.ReadInt32(position + 72);
|
||||||
uint Type2Omap = (uint)Memory.ReadInt32(Position + 76);
|
uint type2Omap = (uint)memory.ReadInt32(position + 76);
|
||||||
|
|
||||||
OmapTargets = new OmapTarget[8];
|
OmapTargets = new OmapTarget[8];
|
||||||
|
|
||||||
for (int i = 0; i < OmapTargets.Length; i++)
|
for (int i = 0; i < OmapTargets.Length; i++)
|
||||||
{
|
{
|
||||||
int Offset = i * 4;
|
int offset = i * 4;
|
||||||
|
|
||||||
OmapTargets[i] = new OmapTarget
|
OmapTargets[i] = new OmapTarget
|
||||||
{
|
{
|
||||||
Red = ReadBits(Type2OmapTarget, Offset + 0, 1) != 0,
|
Red = ReadBits(type2OmapTarget, offset + 0, 1) != 0,
|
||||||
Green = ReadBits(Type2OmapTarget, Offset + 1, 1) != 0,
|
Green = ReadBits(type2OmapTarget, offset + 1, 1) != 0,
|
||||||
Blue = ReadBits(Type2OmapTarget, Offset + 2, 1) != 0,
|
Blue = ReadBits(type2OmapTarget, offset + 2, 1) != 0,
|
||||||
Alpha = ReadBits(Type2OmapTarget, Offset + 3, 1) != 0
|
Alpha = ReadBits(type2OmapTarget, offset + 3, 1) != 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
OmapSampleMask = ReadBits(Type2Omap, 0, 1) != 0;
|
OmapSampleMask = ReadBits(type2Omap, 0, 1) != 0;
|
||||||
OmapDepth = ReadBits(Type2Omap, 1, 1) != 0;
|
OmapDepth = ReadBits(type2Omap, 1, 1) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int DepthRegister
|
public int DepthRegister
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
int Count = 0;
|
int count = 0;
|
||||||
|
|
||||||
for (int Index = 0; Index < OmapTargets.Length; Index++)
|
for (int index = 0; index < OmapTargets.Length; index++)
|
||||||
{
|
{
|
||||||
for (int Component = 0; Component < 4; Component++)
|
for (int component = 0; component < 4; component++)
|
||||||
{
|
{
|
||||||
if (OmapTargets[Index].ComponentEnabled(Component))
|
if (OmapTargets[index].ComponentEnabled(component))
|
||||||
{
|
{
|
||||||
Count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depth register is always two registers after the last color output
|
// Depth register is always two registers after the last color output
|
||||||
return Count + 1;
|
return count + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int ReadBits(uint Word, int Offset, int BitWidth)
|
private static int ReadBits(uint word, int offset, int bitWidth)
|
||||||
{
|
{
|
||||||
uint Mask = (1u << BitWidth) - 1u;
|
uint mask = (1u << bitWidth) - 1u;
|
||||||
|
|
||||||
return (int)((Word >> Offset) & Mask);
|
return (int)((word >> offset) & mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,10 +5,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
public ShaderIrNode Dst { get; set; }
|
public ShaderIrNode Dst { get; set; }
|
||||||
public ShaderIrNode Src { get; set; }
|
public ShaderIrNode Src { get; set; }
|
||||||
|
|
||||||
public ShaderIrAsg(ShaderIrNode Dst, ShaderIrNode Src)
|
public ShaderIrAsg(ShaderIrNode dst, ShaderIrNode src)
|
||||||
{
|
{
|
||||||
this.Dst = Dst;
|
Dst = dst;
|
||||||
this.Src = Src;
|
Src = src;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,18 +14,18 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public List<ShaderIrNode> Nodes { get; private set; }
|
public List<ShaderIrNode> Nodes { get; private set; }
|
||||||
|
|
||||||
public ShaderIrBlock(int Position)
|
public ShaderIrBlock(int position)
|
||||||
{
|
{
|
||||||
this.Position = Position;
|
Position = position;
|
||||||
|
|
||||||
Sources = new List<ShaderIrBlock>();
|
Sources = new List<ShaderIrBlock>();
|
||||||
|
|
||||||
Nodes = new List<ShaderIrNode>();
|
Nodes = new List<ShaderIrNode>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddNode(ShaderIrNode Node)
|
public void AddNode(ShaderIrNode node)
|
||||||
{
|
{
|
||||||
Nodes.Add(Node);
|
Nodes.Add(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderIrNode[] GetNodes()
|
public ShaderIrNode[] GetNodes()
|
||||||
|
|
|
@ -4,9 +4,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
public string Comment { get; private set; }
|
public string Comment { get; private set; }
|
||||||
|
|
||||||
public ShaderIrCmnt(string Comment)
|
public ShaderIrCmnt(string comment)
|
||||||
{
|
{
|
||||||
this.Comment = Comment;
|
Comment = comment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,11 +7,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public bool Not { get; private set; }
|
public bool Not { get; private set; }
|
||||||
|
|
||||||
public ShaderIrCond(ShaderIrNode Pred, ShaderIrNode Child, bool Not)
|
public ShaderIrCond(ShaderIrNode pred, ShaderIrNode child, bool not)
|
||||||
{
|
{
|
||||||
this.Pred = Pred;
|
Pred = pred;
|
||||||
this.Child = Child;
|
Child = child;
|
||||||
this.Not = Not;
|
Not = not;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,9 +4,9 @@
|
||||||
{
|
{
|
||||||
public ShaderIpaMode Mode { get; private set; }
|
public ShaderIpaMode Mode { get; private set; }
|
||||||
|
|
||||||
public ShaderIrMetaIpa(ShaderIpaMode Mode)
|
public ShaderIrMetaIpa(ShaderIpaMode mode)
|
||||||
{
|
{
|
||||||
this.Mode = Mode;
|
Mode = mode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,12 +13,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
public ShaderIrOperGpr DepthCompare;
|
public ShaderIrOperGpr DepthCompare;
|
||||||
public int Component; // for TLD4(S)
|
public int Component; // for TLD4(S)
|
||||||
|
|
||||||
public ShaderIrMetaTex(int Elem, GalTextureTarget TextureTarget, TextureInstructionSuffix TextureInstructionSuffix, params ShaderIrNode[] Coordinates)
|
public ShaderIrMetaTex(int elem, GalTextureTarget textureTarget, TextureInstructionSuffix textureInstructionSuffix, params ShaderIrNode[] coordinates)
|
||||||
{
|
{
|
||||||
this.Elem = Elem;
|
Elem = elem;
|
||||||
this.TextureTarget = TextureTarget;
|
TextureTarget = textureTarget;
|
||||||
this.TextureInstructionSuffix = TextureInstructionSuffix;
|
TextureInstructionSuffix = textureInstructionSuffix;
|
||||||
this.Coordinates = Coordinates;
|
Coordinates = coordinates;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,10 +6,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public int Elem { get; private set; }
|
public int Elem { get; private set; }
|
||||||
|
|
||||||
public ShaderIrMetaTexq(ShaderTexqInfo Info, int Elem)
|
public ShaderIrMetaTexq(ShaderTexqInfo info, int elem)
|
||||||
{
|
{
|
||||||
this.Info = Info;
|
Info = info;
|
||||||
this.Elem = Elem;
|
Elem = elem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,17 +9,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
public ShaderIrMeta MetaData { get; set; }
|
public ShaderIrMeta MetaData { get; set; }
|
||||||
|
|
||||||
public ShaderIrOp(
|
public ShaderIrOp(
|
||||||
ShaderIrInst Inst,
|
ShaderIrInst inst,
|
||||||
ShaderIrNode OperandA = null,
|
ShaderIrNode operandA = null,
|
||||||
ShaderIrNode OperandB = null,
|
ShaderIrNode operandB = null,
|
||||||
ShaderIrNode OperandC = null,
|
ShaderIrNode operandC = null,
|
||||||
ShaderIrMeta MetaData = null)
|
ShaderIrMeta metaData = null)
|
||||||
{
|
{
|
||||||
this.Inst = Inst;
|
Inst = inst;
|
||||||
this.OperandA = OperandA;
|
OperandA = operandA;
|
||||||
this.OperandB = OperandB;
|
OperandB = operandB;
|
||||||
this.OperandC = OperandC;
|
OperandC = operandC;
|
||||||
this.MetaData = MetaData;
|
MetaData = metaData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,10 +6,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public ShaderIrNode Vertex { get; private set; }
|
public ShaderIrNode Vertex { get; private set; }
|
||||||
|
|
||||||
public ShaderIrOperAbuf(int Offs, ShaderIrNode Vertex)
|
public ShaderIrOperAbuf(int offs, ShaderIrNode vertex)
|
||||||
{
|
{
|
||||||
this.Offs = Offs;
|
Offs = offs;
|
||||||
this.Vertex = Vertex;
|
Vertex = vertex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,11 +7,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public ShaderIrNode Offs { get; private set; }
|
public ShaderIrNode Offs { get; private set; }
|
||||||
|
|
||||||
public ShaderIrOperCbuf(int Index, int Pos, ShaderIrNode Offs = null)
|
public ShaderIrOperCbuf(int index, int pos, ShaderIrNode offs = null)
|
||||||
{
|
{
|
||||||
this.Index = Index;
|
Index = index;
|
||||||
this.Pos = Pos;
|
Pos = pos;
|
||||||
this.Offs = Offs;
|
Offs = offs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,35 +2,35 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
class ShaderIrOperGpr : ShaderIrNode
|
class ShaderIrOperGpr : ShaderIrNode
|
||||||
{
|
{
|
||||||
public const int ZRIndex = 0xff;
|
public const int ZrIndex = 0xff;
|
||||||
|
|
||||||
public bool IsConst => Index == ZRIndex;
|
public bool IsConst => Index == ZrIndex;
|
||||||
|
|
||||||
public bool IsValidRegister => (uint)Index <= ZRIndex;
|
public bool IsValidRegister => (uint)Index <= ZrIndex;
|
||||||
|
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
public int HalfPart { get; set; }
|
public int HalfPart { get; set; }
|
||||||
|
|
||||||
public ShaderRegisterSize RegisterSize { get; private set; }
|
public ShaderRegisterSize RegisterSize { get; private set; }
|
||||||
|
|
||||||
public ShaderIrOperGpr(int Index)
|
public ShaderIrOperGpr(int index)
|
||||||
{
|
{
|
||||||
this.Index = Index;
|
Index = index;
|
||||||
|
|
||||||
RegisterSize = ShaderRegisterSize.Single;
|
RegisterSize = ShaderRegisterSize.Single;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderIrOperGpr(int Index, int HalfPart)
|
public ShaderIrOperGpr(int index, int halfPart)
|
||||||
{
|
{
|
||||||
this.Index = Index;
|
Index = index;
|
||||||
this.HalfPart = HalfPart;
|
HalfPart = halfPart;
|
||||||
|
|
||||||
RegisterSize = ShaderRegisterSize.Half;
|
RegisterSize = ShaderRegisterSize.Half;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrOperGpr MakeTemporary(int Index = 0)
|
public static ShaderIrOperGpr MakeTemporary(int index = 0)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperGpr(0x100 + Index);
|
return new ShaderIrOperGpr(0x100 + index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,9 +4,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
public int Value { get; private set; }
|
public int Value { get; private set; }
|
||||||
|
|
||||||
public ShaderIrOperImm(int Value)
|
public ShaderIrOperImm(int value)
|
||||||
{
|
{
|
||||||
this.Value = Value;
|
Value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,9 +4,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
public float Value { get; private set; }
|
public float Value { get; private set; }
|
||||||
|
|
||||||
public ShaderIrOperImmf(float Value)
|
public ShaderIrOperImmf(float value)
|
||||||
{
|
{
|
||||||
this.Value = Value;
|
Value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,9 +9,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
|
|
||||||
public ShaderIrOperPred(int Index)
|
public ShaderIrOperPred(int index)
|
||||||
{
|
{
|
||||||
this.Index = Index;
|
Index = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,18 +12,18 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public int XBits;
|
public int XBits;
|
||||||
|
|
||||||
public ShaderDecodeEntry(ShaderDecodeFunc Func, int XBits)
|
public ShaderDecodeEntry(ShaderDecodeFunc func, int xBits)
|
||||||
{
|
{
|
||||||
this.Func = Func;
|
Func = func;
|
||||||
this.XBits = XBits;
|
XBits = xBits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ShaderDecodeEntry[] OpCodes;
|
private static ShaderDecodeEntry[] _opCodes;
|
||||||
|
|
||||||
static ShaderOpCodeTable()
|
static ShaderOpCodeTable()
|
||||||
{
|
{
|
||||||
OpCodes = new ShaderDecodeEntry[1 << EncodingBits];
|
_opCodes = new ShaderDecodeEntry[1 << EncodingBits];
|
||||||
|
|
||||||
#region Instructions
|
#region Instructions
|
||||||
Set("0100110000000x", ShaderDecode.Bfe_C);
|
Set("0100110000000x", ShaderDecode.Bfe_C);
|
||||||
|
@ -123,7 +123,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Set("1101x00xxxxxxx", ShaderDecode.Texs);
|
Set("1101x00xxxxxxx", ShaderDecode.Texs);
|
||||||
Set("1101101xxxxxxx", ShaderDecode.Tlds);
|
Set("1101101xxxxxxx", ShaderDecode.Tlds);
|
||||||
Set("110010xxxx111x", ShaderDecode.Tld4);
|
Set("110010xxxx111x", ShaderDecode.Tld4);
|
||||||
Set("1101111100xxxx", ShaderDecode.Tld4s);
|
Set("1101111100xxxx", ShaderDecode.Tld4S);
|
||||||
Set("01011111xxxxxx", ShaderDecode.Vmad);
|
Set("01011111xxxxxx", ShaderDecode.Vmad);
|
||||||
Set("0100111xxxxxxx", ShaderDecode.Xmad_CR);
|
Set("0100111xxxxxxx", ShaderDecode.Xmad_CR);
|
||||||
Set("0011011x00xxxx", ShaderDecode.Xmad_I);
|
Set("0011011x00xxxx", ShaderDecode.Xmad_I);
|
||||||
|
@ -132,59 +132,59 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Set(string Encoding, ShaderDecodeFunc Func)
|
private static void Set(string encoding, ShaderDecodeFunc func)
|
||||||
{
|
{
|
||||||
if (Encoding.Length != EncodingBits)
|
if (encoding.Length != EncodingBits)
|
||||||
{
|
{
|
||||||
throw new ArgumentException(nameof(Encoding));
|
throw new ArgumentException(nameof(encoding));
|
||||||
}
|
}
|
||||||
|
|
||||||
int Bit = Encoding.Length - 1;
|
int bit = encoding.Length - 1;
|
||||||
int Value = 0;
|
int value = 0;
|
||||||
int XMask = 0;
|
int xMask = 0;
|
||||||
int XBits = 0;
|
int xBits = 0;
|
||||||
|
|
||||||
int[] XPos = new int[Encoding.Length];
|
int[] xPos = new int[encoding.Length];
|
||||||
|
|
||||||
for (int Index = 0; Index < Encoding.Length; Index++, Bit--)
|
for (int index = 0; index < encoding.Length; index++, bit--)
|
||||||
{
|
{
|
||||||
char Chr = Encoding[Index];
|
char chr = encoding[index];
|
||||||
|
|
||||||
if (Chr == '1')
|
if (chr == '1')
|
||||||
{
|
{
|
||||||
Value |= 1 << Bit;
|
value |= 1 << bit;
|
||||||
}
|
}
|
||||||
else if (Chr == 'x')
|
else if (chr == 'x')
|
||||||
{
|
{
|
||||||
XMask |= 1 << Bit;
|
xMask |= 1 << bit;
|
||||||
|
|
||||||
XPos[XBits++] = Bit;
|
xPos[xBits++] = bit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
XMask = ~XMask;
|
xMask = ~xMask;
|
||||||
|
|
||||||
ShaderDecodeEntry Entry = new ShaderDecodeEntry(Func, XBits);
|
ShaderDecodeEntry entry = new ShaderDecodeEntry(func, xBits);
|
||||||
|
|
||||||
for (int Index = 0; Index < (1 << XBits); Index++)
|
for (int index = 0; index < (1 << xBits); index++)
|
||||||
{
|
{
|
||||||
Value &= XMask;
|
value &= xMask;
|
||||||
|
|
||||||
for (int X = 0; X < XBits; X++)
|
for (int x = 0; x < xBits; x++)
|
||||||
{
|
{
|
||||||
Value |= ((Index >> X) & 1) << XPos[X];
|
value |= ((index >> x) & 1) << xPos[x];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OpCodes[Value] == null || OpCodes[Value].XBits > XBits)
|
if (_opCodes[value] == null || _opCodes[value].XBits > xBits)
|
||||||
{
|
{
|
||||||
OpCodes[Value] = Entry;
|
_opCodes[value] = entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderDecodeFunc GetDecoder(long OpCode)
|
public static ShaderDecodeFunc GetDecoder(long opCode)
|
||||||
{
|
{
|
||||||
return OpCodes[(ulong)OpCode >> (64 - EncodingBits)]?.Func;
|
return _opCodes[(ulong)opCode >> (64 - EncodingBits)]?.Func;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,10 +2,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
enum ShaderOper
|
enum ShaderOper
|
||||||
{
|
{
|
||||||
CR,
|
Cr,
|
||||||
Imm,
|
Imm,
|
||||||
Immf,
|
Immf,
|
||||||
RC,
|
Rc,
|
||||||
RR
|
Rr
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,29 +16,29 @@ namespace Ryujinx.Graphics.Gal
|
||||||
public TextureInstructionSuffix TextureSuffix { get; private set; }
|
public TextureInstructionSuffix TextureSuffix { get; private set; }
|
||||||
|
|
||||||
public ShaderDeclInfo(
|
public ShaderDeclInfo(
|
||||||
string Name,
|
string name,
|
||||||
int Index,
|
int index,
|
||||||
bool IsCb = false,
|
bool isCb = false,
|
||||||
int Cbuf = 0,
|
int cbuf = 0,
|
||||||
int Size = 1,
|
int size = 1,
|
||||||
GalTextureTarget TextureTarget = GalTextureTarget.TwoD,
|
GalTextureTarget textureTarget = GalTextureTarget.TwoD,
|
||||||
TextureInstructionSuffix TextureSuffix = TextureInstructionSuffix.None)
|
TextureInstructionSuffix textureSuffix = TextureInstructionSuffix.None)
|
||||||
{
|
{
|
||||||
this.Name = Name;
|
Name = name;
|
||||||
this.Index = Index;
|
Index = index;
|
||||||
this.IsCb = IsCb;
|
IsCb = isCb;
|
||||||
this.Cbuf = Cbuf;
|
Cbuf = cbuf;
|
||||||
this.Size = Size;
|
Size = size;
|
||||||
|
|
||||||
this.TextureTarget = TextureTarget;
|
TextureTarget = textureTarget;
|
||||||
this.TextureSuffix = TextureSuffix;
|
TextureSuffix = textureSuffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Enlarge(int NewSize)
|
internal void Enlarge(int newSize)
|
||||||
{
|
{
|
||||||
if (Size < NewSize)
|
if (Size < newSize)
|
||||||
{
|
{
|
||||||
Size = NewSize;
|
Size = newSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,67 +5,67 @@ namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
static class ShaderDumper
|
static class ShaderDumper
|
||||||
{
|
{
|
||||||
private static string RuntimeDir;
|
private static string _runtimeDir;
|
||||||
|
|
||||||
public static int DumpIndex { get; private set; } = 1;
|
public static int DumpIndex { get; private set; } = 1;
|
||||||
|
|
||||||
public static void Dump(IGalMemory Memory, long Position, GalShaderType Type, string ExtSuffix = "")
|
public static void Dump(IGalMemory memory, long position, GalShaderType type, string extSuffix = "")
|
||||||
{
|
{
|
||||||
if (!IsDumpEnabled())
|
if (!IsDumpEnabled())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string FileName = "Shader" + DumpIndex.ToString("d4") + "." + ShaderExtension(Type) + ExtSuffix + ".bin";
|
string fileName = "Shader" + DumpIndex.ToString("d4") + "." + ShaderExtension(type) + extSuffix + ".bin";
|
||||||
|
|
||||||
string FullPath = Path.Combine(FullDir(), FileName);
|
string fullPath = Path.Combine(FullDir(), fileName);
|
||||||
string CodePath = Path.Combine(CodeDir(), FileName);
|
string codePath = Path.Combine(CodeDir(), fileName);
|
||||||
|
|
||||||
DumpIndex++;
|
DumpIndex++;
|
||||||
|
|
||||||
using (FileStream FullFile = File.Create(FullPath))
|
using (FileStream fullFile = File.Create(fullPath))
|
||||||
using (FileStream CodeFile = File.Create(CodePath))
|
using (FileStream codeFile = File.Create(codePath))
|
||||||
{
|
{
|
||||||
BinaryWriter FullWriter = new BinaryWriter(FullFile);
|
BinaryWriter fullWriter = new BinaryWriter(fullFile);
|
||||||
BinaryWriter CodeWriter = new BinaryWriter(CodeFile);
|
BinaryWriter codeWriter = new BinaryWriter(codeFile);
|
||||||
|
|
||||||
for (long i = 0; i < 0x50; i += 4)
|
for (long i = 0; i < 0x50; i += 4)
|
||||||
{
|
{
|
||||||
FullWriter.Write(Memory.ReadInt32(Position + i));
|
fullWriter.Write(memory.ReadInt32(position + i));
|
||||||
}
|
}
|
||||||
|
|
||||||
long Offset = 0;
|
long offset = 0;
|
||||||
|
|
||||||
ulong Instruction = 0;
|
ulong instruction = 0;
|
||||||
|
|
||||||
//Dump until a NOP instruction is found
|
//Dump until a NOP instruction is found
|
||||||
while ((Instruction >> 48 & 0xfff8) != 0x50b0)
|
while ((instruction >> 48 & 0xfff8) != 0x50b0)
|
||||||
{
|
{
|
||||||
uint Word0 = (uint)Memory.ReadInt32(Position + 0x50 + Offset + 0);
|
uint word0 = (uint)memory.ReadInt32(position + 0x50 + offset + 0);
|
||||||
uint Word1 = (uint)Memory.ReadInt32(Position + 0x50 + Offset + 4);
|
uint word1 = (uint)memory.ReadInt32(position + 0x50 + offset + 4);
|
||||||
|
|
||||||
Instruction = Word0 | (ulong)Word1 << 32;
|
instruction = word0 | (ulong)word1 << 32;
|
||||||
|
|
||||||
//Zero instructions (other kind of NOP) stop immediatly,
|
//Zero instructions (other kind of NOP) stop immediatly,
|
||||||
//this is to avoid two rows of zeroes
|
//this is to avoid two rows of zeroes
|
||||||
if (Instruction == 0)
|
if (instruction == 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
FullWriter.Write(Instruction);
|
fullWriter.Write(instruction);
|
||||||
CodeWriter.Write(Instruction);
|
codeWriter.Write(instruction);
|
||||||
|
|
||||||
Offset += 8;
|
offset += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Align to meet nvdisasm requeriments
|
//Align to meet nvdisasm requeriments
|
||||||
while (Offset % 0x20 != 0)
|
while (offset % 0x20 != 0)
|
||||||
{
|
{
|
||||||
FullWriter.Write(0);
|
fullWriter.Write(0);
|
||||||
CodeWriter.Write(0);
|
codeWriter.Write(0);
|
||||||
|
|
||||||
Offset += 4;
|
offset += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,37 +87,37 @@ namespace Ryujinx.Graphics.Gal
|
||||||
|
|
||||||
private static string DumpDir()
|
private static string DumpDir()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(RuntimeDir))
|
if (string.IsNullOrEmpty(_runtimeDir))
|
||||||
{
|
{
|
||||||
int Index = 1;
|
int index = 1;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
RuntimeDir = Path.Combine(GraphicsConfig.ShadersDumpPath, "Dumps" + Index.ToString("d2"));
|
_runtimeDir = Path.Combine(GraphicsConfig.ShadersDumpPath, "Dumps" + index.ToString("d2"));
|
||||||
|
|
||||||
Index++;
|
index++;
|
||||||
}
|
}
|
||||||
while (Directory.Exists(RuntimeDir));
|
while (Directory.Exists(_runtimeDir));
|
||||||
|
|
||||||
Directory.CreateDirectory(RuntimeDir);
|
Directory.CreateDirectory(_runtimeDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
return RuntimeDir;
|
return _runtimeDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string CreateAndReturn(string Dir)
|
private static string CreateAndReturn(string dir)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(Dir))
|
if (!Directory.Exists(dir))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(Dir);
|
Directory.CreateDirectory(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string ShaderExtension(GalShaderType Type)
|
private static string ShaderExtension(GalShaderType type)
|
||||||
{
|
{
|
||||||
switch (Type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case GalShaderType.Vertex: return "vert";
|
case GalShaderType.Vertex: return "vert";
|
||||||
case GalShaderType.TessControl: return "tesc";
|
case GalShaderType.TessControl: return "tesc";
|
||||||
|
@ -125,7 +125,7 @@ namespace Ryujinx.Graphics.Gal
|
||||||
case GalShaderType.Geometry: return "geom";
|
case GalShaderType.Geometry: return "geom";
|
||||||
case GalShaderType.Fragment: return "frag";
|
case GalShaderType.Fragment: return "frag";
|
||||||
|
|
||||||
default: throw new ArgumentException(nameof(Type));
|
default: throw new ArgumentException(nameof(type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,6 @@ namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
public ShaderException() : base() { }
|
public ShaderException() : base() { }
|
||||||
|
|
||||||
public ShaderException(string Message) : base(Message) { }
|
public ShaderException(string message) : base(message) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,15 +10,15 @@ namespace Ryujinx.Graphics
|
||||||
public bool IsLastCall => MethodCount <= 1;
|
public bool IsLastCall => MethodCount <= 1;
|
||||||
|
|
||||||
public GpuMethodCall(
|
public GpuMethodCall(
|
||||||
int Method,
|
int method,
|
||||||
int Argument,
|
int argument,
|
||||||
int SubChannel = 0,
|
int subChannel = 0,
|
||||||
int MethodCount = 0)
|
int methodCount = 0)
|
||||||
{
|
{
|
||||||
this.Method = Method;
|
Method = method;
|
||||||
this.Argument = Argument;
|
Argument = argument;
|
||||||
this.SubChannel = SubChannel;
|
SubChannel = subChannel;
|
||||||
this.MethodCount = MethodCount;
|
MethodCount = methodCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using Ryujinx.Graphics.Memory;
|
using Ryujinx.Graphics.Memory;
|
||||||
using Ryujinx.Graphics.Texture;
|
using Ryujinx.Graphics.Texture;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics
|
namespace Ryujinx.Graphics
|
||||||
|
@ -18,124 +16,124 @@ namespace Ryujinx.Graphics
|
||||||
ZetaBuffer
|
ZetaBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
private NvGpu Gpu;
|
private NvGpu _gpu;
|
||||||
|
|
||||||
private HashSet<long>[] UploadedKeys;
|
private HashSet<long>[] _uploadedKeys;
|
||||||
|
|
||||||
private Dictionary<long, ImageType> ImageTypes;
|
private Dictionary<long, ImageType> _imageTypes;
|
||||||
private Dictionary<long, int> MirroredTextures;
|
private Dictionary<long, int> _mirroredTextures;
|
||||||
|
|
||||||
public GpuResourceManager(NvGpu Gpu)
|
public GpuResourceManager(NvGpu gpu)
|
||||||
{
|
{
|
||||||
this.Gpu = Gpu;
|
_gpu = gpu;
|
||||||
|
|
||||||
UploadedKeys = new HashSet<long>[(int)NvGpuBufferType.Count];
|
_uploadedKeys = new HashSet<long>[(int)NvGpuBufferType.Count];
|
||||||
|
|
||||||
for (int Index = 0; Index < UploadedKeys.Length; Index++)
|
for (int index = 0; index < _uploadedKeys.Length; index++)
|
||||||
{
|
{
|
||||||
UploadedKeys[Index] = new HashSet<long>();
|
_uploadedKeys[index] = new HashSet<long>();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageTypes = new Dictionary<long, ImageType>();
|
_imageTypes = new Dictionary<long, ImageType>();
|
||||||
MirroredTextures = new Dictionary<long, int>();
|
_mirroredTextures = new Dictionary<long, int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendColorBuffer(NvGpuVmm Vmm, long Position, int Attachment, GalImage NewImage)
|
public void SendColorBuffer(NvGpuVmm vmm, long position, int attachment, GalImage newImage)
|
||||||
{
|
{
|
||||||
long Size = (uint)ImageUtils.GetSize(NewImage);
|
long size = (uint)ImageUtils.GetSize(newImage);
|
||||||
|
|
||||||
ImageTypes[Position] = ImageType.ColorBuffer;
|
_imageTypes[position] = ImageType.ColorBuffer;
|
||||||
|
|
||||||
if (!TryReuse(Vmm, Position, NewImage))
|
if (!TryReuse(vmm, position, newImage))
|
||||||
{
|
{
|
||||||
Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage);
|
_gpu.Renderer.Texture.Create(position, (int)size, newImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
Gpu.Renderer.RenderTarget.BindColor(Position, Attachment);
|
_gpu.Renderer.RenderTarget.BindColor(position, attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendZetaBuffer(NvGpuVmm Vmm, long Position, GalImage NewImage)
|
public void SendZetaBuffer(NvGpuVmm vmm, long position, GalImage newImage)
|
||||||
{
|
{
|
||||||
long Size = (uint)ImageUtils.GetSize(NewImage);
|
long size = (uint)ImageUtils.GetSize(newImage);
|
||||||
|
|
||||||
ImageTypes[Position] = ImageType.ZetaBuffer;
|
_imageTypes[position] = ImageType.ZetaBuffer;
|
||||||
|
|
||||||
if (!TryReuse(Vmm, Position, NewImage))
|
if (!TryReuse(vmm, position, newImage))
|
||||||
{
|
{
|
||||||
Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage);
|
_gpu.Renderer.Texture.Create(position, (int)size, newImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
Gpu.Renderer.RenderTarget.BindZeta(Position);
|
_gpu.Renderer.RenderTarget.BindZeta(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage)
|
public void SendTexture(NvGpuVmm vmm, long position, GalImage newImage)
|
||||||
{
|
{
|
||||||
PrepareSendTexture(Vmm, Position, NewImage);
|
PrepareSendTexture(vmm, position, newImage);
|
||||||
|
|
||||||
ImageTypes[Position] = ImageType.Texture;
|
_imageTypes[position] = ImageType.Texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetTextureLayer(long Position, out int LayerIndex)
|
public bool TryGetTextureLayer(long position, out int layerIndex)
|
||||||
{
|
{
|
||||||
if (MirroredTextures.TryGetValue(Position, out LayerIndex))
|
if (_mirroredTextures.TryGetValue(position, out layerIndex))
|
||||||
{
|
{
|
||||||
ImageType Type = ImageTypes[Position];
|
ImageType type = _imageTypes[position];
|
||||||
|
|
||||||
// FIXME(thog): I'm actually unsure if we should deny all other image type, gpu testing needs to be done here.
|
// FIXME(thog): I'm actually unsure if we should deny all other image type, gpu testing needs to be done here.
|
||||||
if (Type != ImageType.Texture && Type != ImageType.TextureArrayLayer)
|
if (type != ImageType.Texture && type != ImageType.TextureArrayLayer)
|
||||||
{
|
{
|
||||||
LayerIndex = -1;
|
layerIndex = -1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LayerIndex = -1;
|
layerIndex = -1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTextureArrayLayer(long Position, int LayerIndex)
|
public void SetTextureArrayLayer(long position, int layerIndex)
|
||||||
{
|
{
|
||||||
ImageTypes[Position] = ImageType.TextureArrayLayer;
|
_imageTypes[position] = ImageType.TextureArrayLayer;
|
||||||
MirroredTextures[Position] = LayerIndex;
|
_mirroredTextures[position] = layerIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrepareSendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage)
|
private void PrepareSendTexture(NvGpuVmm vmm, long position, GalImage newImage)
|
||||||
{
|
{
|
||||||
long Size = ImageUtils.GetSize(NewImage);
|
long size = ImageUtils.GetSize(newImage);
|
||||||
|
|
||||||
bool SkipCheck = false;
|
bool skipCheck = false;
|
||||||
|
|
||||||
if (ImageTypes.TryGetValue(Position, out ImageType OldType))
|
if (_imageTypes.TryGetValue(position, out ImageType oldType))
|
||||||
{
|
{
|
||||||
if (OldType == ImageType.ColorBuffer || OldType == ImageType.ZetaBuffer)
|
if (oldType == ImageType.ColorBuffer || oldType == ImageType.ZetaBuffer)
|
||||||
{
|
{
|
||||||
//Avoid data destruction
|
//Avoid data destruction
|
||||||
MemoryRegionModified(Vmm, Position, Size, NvGpuBufferType.Texture);
|
MemoryRegionModified(vmm, position, size, NvGpuBufferType.Texture);
|
||||||
|
|
||||||
SkipCheck = true;
|
skipCheck = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SkipCheck || !MemoryRegionModified(Vmm, Position, Size, NvGpuBufferType.Texture))
|
if (skipCheck || !MemoryRegionModified(vmm, position, size, NvGpuBufferType.Texture))
|
||||||
{
|
{
|
||||||
if (TryReuse(Vmm, Position, NewImage))
|
if (TryReuse(vmm, position, newImage))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] Data = ImageUtils.ReadTexture(Vmm, NewImage, Position);
|
byte[] data = ImageUtils.ReadTexture(vmm, newImage, position);
|
||||||
|
|
||||||
Gpu.Renderer.Texture.Create(Position, Data, NewImage);
|
_gpu.Renderer.Texture.Create(position, data, newImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryReuse(NvGpuVmm Vmm, long Position, GalImage NewImage)
|
private bool TryReuse(NvGpuVmm vmm, long position, GalImage newImage)
|
||||||
{
|
{
|
||||||
if (Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage) && CachedImage.TextureTarget == NewImage.TextureTarget && CachedImage.SizeMatches(NewImage))
|
if (_gpu.Renderer.Texture.TryGetImage(position, out GalImage cachedImage) && cachedImage.TextureTarget == newImage.TextureTarget && cachedImage.SizeMatches(newImage))
|
||||||
{
|
{
|
||||||
Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage);
|
_gpu.Renderer.RenderTarget.Reinterpret(position, newImage);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -143,29 +141,29 @@ namespace Ryujinx.Graphics
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool MemoryRegionModified(NvGpuVmm Vmm, long Position, long Size, NvGpuBufferType Type)
|
public bool MemoryRegionModified(NvGpuVmm vmm, long position, long size, NvGpuBufferType type)
|
||||||
{
|
{
|
||||||
HashSet<long> Uploaded = UploadedKeys[(int)Type];
|
HashSet<long> uploaded = _uploadedKeys[(int)type];
|
||||||
|
|
||||||
if (!Uploaded.Add(Position))
|
if (!uploaded.Add(position))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Vmm.IsRegionModified(Position, Size, Type);
|
return vmm.IsRegionModified(position, size, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearPbCache()
|
public void ClearPbCache()
|
||||||
{
|
{
|
||||||
for (int Index = 0; Index < UploadedKeys.Length; Index++)
|
for (int index = 0; index < _uploadedKeys.Length; index++)
|
||||||
{
|
{
|
||||||
UploadedKeys[Index].Clear();
|
_uploadedKeys[index].Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearPbCache(NvGpuBufferType Type)
|
public void ClearPbCache(NvGpuBufferType type)
|
||||||
{
|
{
|
||||||
UploadedKeys[(int)Type].Clear();
|
_uploadedKeys[(int)type].Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,6 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
{
|
{
|
||||||
int[] Registers { get; }
|
int[] Registers { get; }
|
||||||
|
|
||||||
void CallMethod(NvGpuVmm Vmm, GpuMethodCall MethCall);
|
void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -42,78 +42,78 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
BitwiseNotAnd = 12
|
BitwiseNotAnd = 12
|
||||||
}
|
}
|
||||||
|
|
||||||
private NvGpuFifo PFifo;
|
private NvGpuFifo _pFifo;
|
||||||
private INvGpuEngine Engine;
|
private INvGpuEngine _engine;
|
||||||
|
|
||||||
public Queue<int> Fifo { get; private set; }
|
public Queue<int> Fifo { get; private set; }
|
||||||
|
|
||||||
private int[] Gprs;
|
private int[] _gprs;
|
||||||
|
|
||||||
private int MethAddr;
|
private int _methAddr;
|
||||||
private int MethIncr;
|
private int _methIncr;
|
||||||
|
|
||||||
private bool Carry;
|
private bool _carry;
|
||||||
|
|
||||||
private int OpCode;
|
private int _opCode;
|
||||||
|
|
||||||
private int PipeOp;
|
private int _pipeOp;
|
||||||
|
|
||||||
private int Pc;
|
private int _pc;
|
||||||
|
|
||||||
public MacroInterpreter(NvGpuFifo PFifo, INvGpuEngine Engine)
|
public MacroInterpreter(NvGpuFifo pFifo, INvGpuEngine engine)
|
||||||
{
|
{
|
||||||
this.PFifo = PFifo;
|
_pFifo = pFifo;
|
||||||
this.Engine = Engine;
|
_engine = engine;
|
||||||
|
|
||||||
Fifo = new Queue<int>();
|
Fifo = new Queue<int>();
|
||||||
|
|
||||||
Gprs = new int[8];
|
_gprs = new int[8];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Execute(NvGpuVmm Vmm, int[] Mme, int Position, int Param)
|
public void Execute(NvGpuVmm vmm, int[] mme, int position, int param)
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
|
|
||||||
Gprs[1] = Param;
|
_gprs[1] = param;
|
||||||
|
|
||||||
Pc = Position;
|
_pc = position;
|
||||||
|
|
||||||
FetchOpCode(Mme);
|
FetchOpCode(mme);
|
||||||
|
|
||||||
while (Step(Vmm, Mme));
|
while (Step(vmm, mme));
|
||||||
|
|
||||||
//Due to the delay slot, we still need to execute
|
//Due to the delay slot, we still need to execute
|
||||||
//one more instruction before we actually exit.
|
//one more instruction before we actually exit.
|
||||||
Step(Vmm, Mme);
|
Step(vmm, mme);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Reset()
|
private void Reset()
|
||||||
{
|
{
|
||||||
for (int Index = 0; Index < Gprs.Length; Index++)
|
for (int index = 0; index < _gprs.Length; index++)
|
||||||
{
|
{
|
||||||
Gprs[Index] = 0;
|
_gprs[index] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
MethAddr = 0;
|
_methAddr = 0;
|
||||||
MethIncr = 0;
|
_methIncr = 0;
|
||||||
|
|
||||||
Carry = false;
|
_carry = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool Step(NvGpuVmm Vmm, int[] Mme)
|
private bool Step(NvGpuVmm vmm, int[] mme)
|
||||||
{
|
{
|
||||||
int BaseAddr = Pc - 1;
|
int baseAddr = _pc - 1;
|
||||||
|
|
||||||
FetchOpCode(Mme);
|
FetchOpCode(mme);
|
||||||
|
|
||||||
if ((OpCode & 7) < 7)
|
if ((_opCode & 7) < 7)
|
||||||
{
|
{
|
||||||
//Operation produces a value.
|
//Operation produces a value.
|
||||||
AssignmentOperation AsgOp = (AssignmentOperation)((OpCode >> 4) & 7);
|
AssignmentOperation asgOp = (AssignmentOperation)((_opCode >> 4) & 7);
|
||||||
|
|
||||||
int Result = GetAluResult();
|
int result = GetAluResult();
|
||||||
|
|
||||||
switch (AsgOp)
|
switch (asgOp)
|
||||||
{
|
{
|
||||||
//Fetch parameter and ignore result.
|
//Fetch parameter and ignore result.
|
||||||
case AssignmentOperation.IgnoreAndFetch:
|
case AssignmentOperation.IgnoreAndFetch:
|
||||||
|
@ -126,7 +126,7 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
//Move result.
|
//Move result.
|
||||||
case AssignmentOperation.Move:
|
case AssignmentOperation.Move:
|
||||||
{
|
{
|
||||||
SetDstGpr(Result);
|
SetDstGpr(result);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -134,9 +134,9 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
//Move result and use as Method Address.
|
//Move result and use as Method Address.
|
||||||
case AssignmentOperation.MoveAndSetMaddr:
|
case AssignmentOperation.MoveAndSetMaddr:
|
||||||
{
|
{
|
||||||
SetDstGpr(Result);
|
SetDstGpr(result);
|
||||||
|
|
||||||
SetMethAddr(Result);
|
SetMethAddr(result);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
{
|
{
|
||||||
SetDstGpr(FetchParam());
|
SetDstGpr(FetchParam());
|
||||||
|
|
||||||
Send(Vmm, Result);
|
Send(vmm, result);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -154,9 +154,9 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
//Move and send result.
|
//Move and send result.
|
||||||
case AssignmentOperation.MoveAndSend:
|
case AssignmentOperation.MoveAndSend:
|
||||||
{
|
{
|
||||||
SetDstGpr(Result);
|
SetDstGpr(result);
|
||||||
|
|
||||||
Send(Vmm, Result);
|
Send(vmm, result);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
{
|
{
|
||||||
SetDstGpr(FetchParam());
|
SetDstGpr(FetchParam());
|
||||||
|
|
||||||
SetMethAddr(Result);
|
SetMethAddr(result);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -174,11 +174,11 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
//Move result and use as Method Address, then fetch and send paramter.
|
//Move result and use as Method Address, then fetch and send paramter.
|
||||||
case AssignmentOperation.MoveAndSetMaddrThenFetchAndSend:
|
case AssignmentOperation.MoveAndSetMaddrThenFetchAndSend:
|
||||||
{
|
{
|
||||||
SetDstGpr(Result);
|
SetDstGpr(result);
|
||||||
|
|
||||||
SetMethAddr(Result);
|
SetMethAddr(result);
|
||||||
|
|
||||||
Send(Vmm, FetchParam());
|
Send(vmm, FetchParam());
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -186,11 +186,11 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
//Move result and use as Method Address, then send bits 17:12 of result.
|
//Move result and use as Method Address, then send bits 17:12 of result.
|
||||||
case AssignmentOperation.MoveAndSetMaddrThenSendHigh:
|
case AssignmentOperation.MoveAndSetMaddrThenSendHigh:
|
||||||
{
|
{
|
||||||
SetDstGpr(Result);
|
SetDstGpr(result);
|
||||||
|
|
||||||
SetMethAddr(Result);
|
SetMethAddr(result);
|
||||||
|
|
||||||
Send(Vmm, (Result >> 12) & 0x3f);
|
Send(vmm, (result >> 12) & 0x3f);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -199,50 +199,50 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Branch.
|
//Branch.
|
||||||
bool OnNotZero = ((OpCode >> 4) & 1) != 0;
|
bool onNotZero = ((_opCode >> 4) & 1) != 0;
|
||||||
|
|
||||||
bool Taken = OnNotZero
|
bool taken = onNotZero
|
||||||
? GetGprA() != 0
|
? GetGprA() != 0
|
||||||
: GetGprA() == 0;
|
: GetGprA() == 0;
|
||||||
|
|
||||||
if (Taken)
|
if (taken)
|
||||||
{
|
{
|
||||||
Pc = BaseAddr + GetImm();
|
_pc = baseAddr + GetImm();
|
||||||
|
|
||||||
bool NoDelays = (OpCode & 0x20) != 0;
|
bool noDelays = (_opCode & 0x20) != 0;
|
||||||
|
|
||||||
if (NoDelays)
|
if (noDelays)
|
||||||
{
|
{
|
||||||
FetchOpCode(Mme);
|
FetchOpCode(mme);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Exit = (OpCode & 0x80) != 0;
|
bool exit = (_opCode & 0x80) != 0;
|
||||||
|
|
||||||
return !Exit;
|
return !exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FetchOpCode(int[] Mme)
|
private void FetchOpCode(int[] mme)
|
||||||
{
|
{
|
||||||
OpCode = PipeOp;
|
_opCode = _pipeOp;
|
||||||
|
|
||||||
PipeOp = Mme[Pc++];
|
_pipeOp = mme[_pc++];
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetAluResult()
|
private int GetAluResult()
|
||||||
{
|
{
|
||||||
AluOperation Op = (AluOperation)(OpCode & 7);
|
AluOperation op = (AluOperation)(_opCode & 7);
|
||||||
|
|
||||||
switch (Op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case AluOperation.AluReg:
|
case AluOperation.AluReg:
|
||||||
{
|
{
|
||||||
AluRegOperation AluOp = (AluRegOperation)((OpCode >> 17) & 0x1f);
|
AluRegOperation aluOp = (AluRegOperation)((_opCode >> 17) & 0x1f);
|
||||||
|
|
||||||
return GetAluResult(AluOp, GetGprA(), GetGprB());
|
return GetAluResult(aluOp, GetGprA(), GetGprB());
|
||||||
}
|
}
|
||||||
|
|
||||||
case AluOperation.AddImmediate:
|
case AluOperation.AddImmediate:
|
||||||
|
@ -254,40 +254,40 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
case AluOperation.BitfieldExtractLslImm:
|
case AluOperation.BitfieldExtractLslImm:
|
||||||
case AluOperation.BitfieldExtractLslReg:
|
case AluOperation.BitfieldExtractLslReg:
|
||||||
{
|
{
|
||||||
int BfSrcBit = (OpCode >> 17) & 0x1f;
|
int bfSrcBit = (_opCode >> 17) & 0x1f;
|
||||||
int BfSize = (OpCode >> 22) & 0x1f;
|
int bfSize = (_opCode >> 22) & 0x1f;
|
||||||
int BfDstBit = (OpCode >> 27) & 0x1f;
|
int bfDstBit = (_opCode >> 27) & 0x1f;
|
||||||
|
|
||||||
int BfMask = (1 << BfSize) - 1;
|
int bfMask = (1 << bfSize) - 1;
|
||||||
|
|
||||||
int Dst = GetGprA();
|
int dst = GetGprA();
|
||||||
int Src = GetGprB();
|
int src = GetGprB();
|
||||||
|
|
||||||
switch (Op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case AluOperation.BitfieldReplace:
|
case AluOperation.BitfieldReplace:
|
||||||
{
|
{
|
||||||
Src = (int)((uint)Src >> BfSrcBit) & BfMask;
|
src = (int)((uint)src >> bfSrcBit) & bfMask;
|
||||||
|
|
||||||
Dst &= ~(BfMask << BfDstBit);
|
dst &= ~(bfMask << bfDstBit);
|
||||||
|
|
||||||
Dst |= Src << BfDstBit;
|
dst |= src << bfDstBit;
|
||||||
|
|
||||||
return Dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AluOperation.BitfieldExtractLslImm:
|
case AluOperation.BitfieldExtractLslImm:
|
||||||
{
|
{
|
||||||
Src = (int)((uint)Src >> Dst) & BfMask;
|
src = (int)((uint)src >> dst) & bfMask;
|
||||||
|
|
||||||
return Src << BfDstBit;
|
return src << bfDstBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AluOperation.BitfieldExtractLslReg:
|
case AluOperation.BitfieldExtractLslReg:
|
||||||
{
|
{
|
||||||
Src = (int)((uint)Src >> BfSrcBit) & BfMask;
|
src = (int)((uint)src >> bfSrcBit) & bfMask;
|
||||||
|
|
||||||
return Src << Dst;
|
return src << dst;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,117 +300,117 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(OpCode));
|
throw new ArgumentException(nameof(_opCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetAluResult(AluRegOperation AluOp, int A, int B)
|
private int GetAluResult(AluRegOperation aluOp, int a, int b)
|
||||||
{
|
{
|
||||||
switch (AluOp)
|
switch (aluOp)
|
||||||
{
|
{
|
||||||
case AluRegOperation.Add:
|
case AluRegOperation.Add:
|
||||||
{
|
{
|
||||||
ulong Result = (ulong)A + (ulong)B;
|
ulong result = (ulong)a + (ulong)b;
|
||||||
|
|
||||||
Carry = Result > 0xffffffff;
|
_carry = result > 0xffffffff;
|
||||||
|
|
||||||
return (int)Result;
|
return (int)result;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AluRegOperation.AddWithCarry:
|
case AluRegOperation.AddWithCarry:
|
||||||
{
|
{
|
||||||
ulong Result = (ulong)A + (ulong)B + (Carry ? 1UL : 0UL);
|
ulong result = (ulong)a + (ulong)b + (_carry ? 1UL : 0UL);
|
||||||
|
|
||||||
Carry = Result > 0xffffffff;
|
_carry = result > 0xffffffff;
|
||||||
|
|
||||||
return (int)Result;
|
return (int)result;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AluRegOperation.Subtract:
|
case AluRegOperation.Subtract:
|
||||||
{
|
{
|
||||||
ulong Result = (ulong)A - (ulong)B;
|
ulong result = (ulong)a - (ulong)b;
|
||||||
|
|
||||||
Carry = Result < 0x100000000;
|
_carry = result < 0x100000000;
|
||||||
|
|
||||||
return (int)Result;
|
return (int)result;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AluRegOperation.SubtractWithBorrow:
|
case AluRegOperation.SubtractWithBorrow:
|
||||||
{
|
{
|
||||||
ulong Result = (ulong)A - (ulong)B - (Carry ? 0UL : 1UL);
|
ulong result = (ulong)a - (ulong)b - (_carry ? 0UL : 1UL);
|
||||||
|
|
||||||
Carry = Result < 0x100000000;
|
_carry = result < 0x100000000;
|
||||||
|
|
||||||
return (int)Result;
|
return (int)result;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AluRegOperation.BitwiseExclusiveOr: return A ^ B;
|
case AluRegOperation.BitwiseExclusiveOr: return a ^ b;
|
||||||
case AluRegOperation.BitwiseOr: return A | B;
|
case AluRegOperation.BitwiseOr: return a | b;
|
||||||
case AluRegOperation.BitwiseAnd: return A & B;
|
case AluRegOperation.BitwiseAnd: return a & b;
|
||||||
case AluRegOperation.BitwiseAndNot: return A & ~B;
|
case AluRegOperation.BitwiseAndNot: return a & ~b;
|
||||||
case AluRegOperation.BitwiseNotAnd: return ~(A & B);
|
case AluRegOperation.BitwiseNotAnd: return ~(a & b);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(AluOp));
|
throw new ArgumentOutOfRangeException(nameof(aluOp));
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetImm()
|
private int GetImm()
|
||||||
{
|
{
|
||||||
//Note: The immediate is signed, the sign-extension is intended here.
|
//Note: The immediate is signed, the sign-extension is intended here.
|
||||||
return OpCode >> 14;
|
return _opCode >> 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetMethAddr(int Value)
|
private void SetMethAddr(int value)
|
||||||
{
|
{
|
||||||
MethAddr = (Value >> 0) & 0xfff;
|
_methAddr = (value >> 0) & 0xfff;
|
||||||
MethIncr = (Value >> 12) & 0x3f;
|
_methIncr = (value >> 12) & 0x3f;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetDstGpr(int Value)
|
private void SetDstGpr(int value)
|
||||||
{
|
{
|
||||||
Gprs[(OpCode >> 8) & 7] = Value;
|
_gprs[(_opCode >> 8) & 7] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetGprA()
|
private int GetGprA()
|
||||||
{
|
{
|
||||||
return GetGprValue((OpCode >> 11) & 7);
|
return GetGprValue((_opCode >> 11) & 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetGprB()
|
private int GetGprB()
|
||||||
{
|
{
|
||||||
return GetGprValue((OpCode >> 14) & 7);
|
return GetGprValue((_opCode >> 14) & 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetGprValue(int Index)
|
private int GetGprValue(int index)
|
||||||
{
|
{
|
||||||
return Index != 0 ? Gprs[Index] : 0;
|
return index != 0 ? _gprs[index] : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int FetchParam()
|
private int FetchParam()
|
||||||
{
|
{
|
||||||
int Value;
|
int value;
|
||||||
|
|
||||||
if (!Fifo.TryDequeue(out Value))
|
if (!Fifo.TryDequeue(out value))
|
||||||
{
|
{
|
||||||
Logger.PrintWarning(LogClass.Gpu, "Macro attempted to fetch an inexistent argument.");
|
Logger.PrintWarning(LogClass.Gpu, "Macro attempted to fetch an inexistent argument.");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int Read(int Reg)
|
private int Read(int reg)
|
||||||
{
|
{
|
||||||
return Engine.Registers[Reg];
|
return _engine.Registers[reg];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Send(NvGpuVmm Vmm, int Value)
|
private void Send(NvGpuVmm vmm, int value)
|
||||||
{
|
{
|
||||||
GpuMethodCall MethCall = new GpuMethodCall(MethAddr, Value);
|
GpuMethodCall methCall = new GpuMethodCall(_methAddr, value);
|
||||||
|
|
||||||
Engine.CallMethod(Vmm, MethCall);
|
_engine.CallMethod(vmm, methCall);
|
||||||
|
|
||||||
MethAddr += MethIncr;
|
_methAddr += _methIncr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using Ryujinx.Graphics.Memory;
|
using Ryujinx.Graphics.Memory;
|
||||||
using Ryujinx.Graphics.Texture;
|
using Ryujinx.Graphics.Texture;
|
||||||
|
@ -20,187 +19,187 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
|
|
||||||
public int[] Registers { get; private set; }
|
public int[] Registers { get; private set; }
|
||||||
|
|
||||||
private NvGpu Gpu;
|
private NvGpu _gpu;
|
||||||
|
|
||||||
public NvGpuEngine2d(NvGpu Gpu)
|
public NvGpuEngine2d(NvGpu gpu)
|
||||||
{
|
{
|
||||||
this.Gpu = Gpu;
|
_gpu = gpu;
|
||||||
|
|
||||||
Registers = new int[0x238];
|
Registers = new int[0x238];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CallMethod(NvGpuVmm Vmm, GpuMethodCall MethCall)
|
public void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall)
|
||||||
{
|
{
|
||||||
WriteRegister(MethCall);
|
WriteRegister(methCall);
|
||||||
|
|
||||||
if ((NvGpuEngine2dReg)MethCall.Method == NvGpuEngine2dReg.BlitSrcYInt)
|
if ((NvGpuEngine2dReg)methCall.Method == NvGpuEngine2dReg.BlitSrcYInt)
|
||||||
{
|
{
|
||||||
TextureCopy(Vmm);
|
TextureCopy(vmm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TextureCopy(NvGpuVmm Vmm)
|
private void TextureCopy(NvGpuVmm vmm)
|
||||||
{
|
{
|
||||||
CopyOperation Operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation);
|
CopyOperation operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation);
|
||||||
|
|
||||||
int DstFormat = ReadRegister(NvGpuEngine2dReg.DstFormat);
|
int dstFormat = ReadRegister(NvGpuEngine2dReg.DstFormat);
|
||||||
bool DstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0;
|
bool dstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0;
|
||||||
int DstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth);
|
int dstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth);
|
||||||
int DstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight);
|
int dstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight);
|
||||||
int DstDepth = ReadRegister(NvGpuEngine2dReg.DstDepth);
|
int dstDepth = ReadRegister(NvGpuEngine2dReg.DstDepth);
|
||||||
int DstLayer = ReadRegister(NvGpuEngine2dReg.DstLayer);
|
int dstLayer = ReadRegister(NvGpuEngine2dReg.DstLayer);
|
||||||
int DstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch);
|
int dstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch);
|
||||||
int DstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions);
|
int dstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions);
|
||||||
|
|
||||||
int SrcFormat = ReadRegister(NvGpuEngine2dReg.SrcFormat);
|
int srcFormat = ReadRegister(NvGpuEngine2dReg.SrcFormat);
|
||||||
bool SrcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0;
|
bool srcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0;
|
||||||
int SrcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth);
|
int srcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth);
|
||||||
int SrcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight);
|
int srcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight);
|
||||||
int SrcDepth = ReadRegister(NvGpuEngine2dReg.SrcDepth);
|
int srcDepth = ReadRegister(NvGpuEngine2dReg.SrcDepth);
|
||||||
int SrcLayer = ReadRegister(NvGpuEngine2dReg.SrcLayer);
|
int srcLayer = ReadRegister(NvGpuEngine2dReg.SrcLayer);
|
||||||
int SrcPitch = ReadRegister(NvGpuEngine2dReg.SrcPitch);
|
int srcPitch = ReadRegister(NvGpuEngine2dReg.SrcPitch);
|
||||||
int SrcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions);
|
int srcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions);
|
||||||
|
|
||||||
int DstBlitX = ReadRegister(NvGpuEngine2dReg.BlitDstX);
|
int dstBlitX = ReadRegister(NvGpuEngine2dReg.BlitDstX);
|
||||||
int DstBlitY = ReadRegister(NvGpuEngine2dReg.BlitDstY);
|
int dstBlitY = ReadRegister(NvGpuEngine2dReg.BlitDstY);
|
||||||
int DstBlitW = ReadRegister(NvGpuEngine2dReg.BlitDstW);
|
int dstBlitW = ReadRegister(NvGpuEngine2dReg.BlitDstW);
|
||||||
int DstBlitH = ReadRegister(NvGpuEngine2dReg.BlitDstH);
|
int dstBlitH = ReadRegister(NvGpuEngine2dReg.BlitDstH);
|
||||||
|
|
||||||
long BlitDuDx = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDuDxFract);
|
long blitDuDx = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDuDxFract);
|
||||||
long BlitDvDy = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDvDyFract);
|
long blitDvDy = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDvDyFract);
|
||||||
|
|
||||||
long SrcBlitX = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcXFract);
|
long srcBlitX = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcXFract);
|
||||||
long SrcBlitY = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcYFract);
|
long srcBlitY = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcYFract);
|
||||||
|
|
||||||
GalImageFormat SrcImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)SrcFormat);
|
GalImageFormat srcImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)srcFormat);
|
||||||
GalImageFormat DstImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)DstFormat);
|
GalImageFormat dstImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)dstFormat);
|
||||||
|
|
||||||
GalMemoryLayout SrcLayout = GetLayout(SrcLinear);
|
GalMemoryLayout srcLayout = GetLayout(srcLinear);
|
||||||
GalMemoryLayout DstLayout = GetLayout(DstLinear);
|
GalMemoryLayout dstLayout = GetLayout(dstLinear);
|
||||||
|
|
||||||
int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf);
|
int srcBlockHeight = 1 << ((srcBlkDim >> 4) & 0xf);
|
||||||
int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
|
int dstBlockHeight = 1 << ((dstBlkDim >> 4) & 0xf);
|
||||||
|
|
||||||
long SrcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress);
|
long srcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress);
|
||||||
long DstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress);
|
long dstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress);
|
||||||
|
|
||||||
long SrcKey = Vmm.GetPhysicalAddress(SrcAddress);
|
long srcKey = vmm.GetPhysicalAddress(srcAddress);
|
||||||
long DstKey = Vmm.GetPhysicalAddress(DstAddress);
|
long dstKey = vmm.GetPhysicalAddress(dstAddress);
|
||||||
|
|
||||||
bool IsSrcLayered = false;
|
bool isSrcLayered = false;
|
||||||
bool IsDstLayered = false;
|
bool isDstLayered = false;
|
||||||
|
|
||||||
GalTextureTarget SrcTarget = GalTextureTarget.TwoD;
|
GalTextureTarget srcTarget = GalTextureTarget.TwoD;
|
||||||
|
|
||||||
if (SrcDepth != 0)
|
if (srcDepth != 0)
|
||||||
{
|
{
|
||||||
SrcTarget = GalTextureTarget.TwoDArray;
|
srcTarget = GalTextureTarget.TwoDArray;
|
||||||
SrcDepth++;
|
srcDepth++;
|
||||||
IsSrcLayered = true;
|
isSrcLayered = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SrcDepth = 1;
|
srcDepth = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
GalTextureTarget DstTarget = GalTextureTarget.TwoD;
|
GalTextureTarget dstTarget = GalTextureTarget.TwoD;
|
||||||
|
|
||||||
if (DstDepth != 0)
|
if (dstDepth != 0)
|
||||||
{
|
{
|
||||||
DstTarget = GalTextureTarget.TwoDArray;
|
dstTarget = GalTextureTarget.TwoDArray;
|
||||||
DstDepth++;
|
dstDepth++;
|
||||||
IsDstLayered = true;
|
isDstLayered = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DstDepth = 1;
|
dstDepth = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
GalImage SrcTexture = new GalImage(
|
GalImage srcTexture = new GalImage(
|
||||||
SrcWidth,
|
srcWidth,
|
||||||
SrcHeight,
|
srcHeight,
|
||||||
1, SrcDepth, 1,
|
1, srcDepth, 1,
|
||||||
SrcBlockHeight, 1,
|
srcBlockHeight, 1,
|
||||||
SrcLayout,
|
srcLayout,
|
||||||
SrcImgFormat,
|
srcImgFormat,
|
||||||
SrcTarget);
|
srcTarget);
|
||||||
|
|
||||||
GalImage DstTexture = new GalImage(
|
GalImage dstTexture = new GalImage(
|
||||||
DstWidth,
|
dstWidth,
|
||||||
DstHeight,
|
dstHeight,
|
||||||
1, DstDepth, 1,
|
1, dstDepth, 1,
|
||||||
DstBlockHeight, 1,
|
dstBlockHeight, 1,
|
||||||
DstLayout,
|
dstLayout,
|
||||||
DstImgFormat,
|
dstImgFormat,
|
||||||
DstTarget);
|
dstTarget);
|
||||||
|
|
||||||
SrcTexture.Pitch = SrcPitch;
|
srcTexture.Pitch = srcPitch;
|
||||||
DstTexture.Pitch = DstPitch;
|
dstTexture.Pitch = dstPitch;
|
||||||
|
|
||||||
long GetLayerOffset(GalImage Image, int Layer)
|
long GetLayerOffset(GalImage image, int layer)
|
||||||
{
|
{
|
||||||
int TargetMipLevel = Image.MaxMipmapLevel <= 1 ? 1 : Image.MaxMipmapLevel - 1;
|
int targetMipLevel = image.MaxMipmapLevel <= 1 ? 1 : image.MaxMipmapLevel - 1;
|
||||||
return ImageUtils.GetLayerOffset(Image, TargetMipLevel) * Layer;
|
return ImageUtils.GetLayerOffset(image, targetMipLevel) * layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrcLayerIndex = -1;
|
int srcLayerIndex = -1;
|
||||||
|
|
||||||
if (IsSrcLayered && Gpu.ResourceManager.TryGetTextureLayer(SrcKey, out SrcLayerIndex) && SrcLayerIndex != 0)
|
if (isSrcLayered && _gpu.ResourceManager.TryGetTextureLayer(srcKey, out srcLayerIndex) && srcLayerIndex != 0)
|
||||||
{
|
{
|
||||||
SrcKey = SrcKey - GetLayerOffset(SrcTexture, SrcLayerIndex);
|
srcKey = srcKey - GetLayerOffset(srcTexture, srcLayerIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
int DstLayerIndex = -1;
|
int dstLayerIndex = -1;
|
||||||
|
|
||||||
if (IsDstLayered && Gpu.ResourceManager.TryGetTextureLayer(DstKey, out DstLayerIndex) && DstLayerIndex != 0)
|
if (isDstLayered && _gpu.ResourceManager.TryGetTextureLayer(dstKey, out dstLayerIndex) && dstLayerIndex != 0)
|
||||||
{
|
{
|
||||||
DstKey = DstKey - GetLayerOffset(DstTexture, DstLayerIndex);
|
dstKey = dstKey - GetLayerOffset(dstTexture, dstLayerIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
Gpu.ResourceManager.SendTexture(Vmm, SrcKey, SrcTexture);
|
_gpu.ResourceManager.SendTexture(vmm, srcKey, srcTexture);
|
||||||
Gpu.ResourceManager.SendTexture(Vmm, DstKey, DstTexture);
|
_gpu.ResourceManager.SendTexture(vmm, dstKey, dstTexture);
|
||||||
|
|
||||||
if (IsSrcLayered && SrcLayerIndex == -1)
|
if (isSrcLayered && srcLayerIndex == -1)
|
||||||
{
|
{
|
||||||
for (int Layer = 0; Layer < SrcTexture.LayerCount; Layer++)
|
for (int layer = 0; layer < srcTexture.LayerCount; layer++)
|
||||||
{
|
{
|
||||||
Gpu.ResourceManager.SetTextureArrayLayer(SrcKey + GetLayerOffset(SrcTexture, Layer), Layer);
|
_gpu.ResourceManager.SetTextureArrayLayer(srcKey + GetLayerOffset(srcTexture, layer), layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrcLayerIndex = 0;
|
srcLayerIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsDstLayered && DstLayerIndex == -1)
|
if (isDstLayered && dstLayerIndex == -1)
|
||||||
{
|
{
|
||||||
for (int Layer = 0; Layer < DstTexture.LayerCount; Layer++)
|
for (int layer = 0; layer < dstTexture.LayerCount; layer++)
|
||||||
{
|
{
|
||||||
Gpu.ResourceManager.SetTextureArrayLayer(DstKey + GetLayerOffset(DstTexture, Layer), Layer);
|
_gpu.ResourceManager.SetTextureArrayLayer(dstKey + GetLayerOffset(dstTexture, layer), layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
DstLayerIndex = 0;
|
dstLayerIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrcBlitX1 = (int)(SrcBlitX >> 32);
|
int srcBlitX1 = (int)(srcBlitX >> 32);
|
||||||
int SrcBlitY1 = (int)(SrcBlitY >> 32);
|
int srcBlitY1 = (int)(srcBlitY >> 32);
|
||||||
|
|
||||||
int SrcBlitX2 = (int)(SrcBlitX + DstBlitW * BlitDuDx >> 32);
|
int srcBlitX2 = (int)(srcBlitX + dstBlitW * blitDuDx >> 32);
|
||||||
int SrcBlitY2 = (int)(SrcBlitY + DstBlitH * BlitDvDy >> 32);
|
int srcBlitY2 = (int)(srcBlitY + dstBlitH * blitDvDy >> 32);
|
||||||
|
|
||||||
Gpu.Renderer.RenderTarget.Copy(
|
_gpu.Renderer.RenderTarget.Copy(
|
||||||
SrcTexture,
|
srcTexture,
|
||||||
DstTexture,
|
dstTexture,
|
||||||
SrcKey,
|
srcKey,
|
||||||
DstKey,
|
dstKey,
|
||||||
SrcLayerIndex,
|
srcLayerIndex,
|
||||||
DstLayerIndex,
|
dstLayerIndex,
|
||||||
SrcBlitX1,
|
srcBlitX1,
|
||||||
SrcBlitY1,
|
srcBlitY1,
|
||||||
SrcBlitX2,
|
srcBlitX2,
|
||||||
SrcBlitY2,
|
srcBlitY2,
|
||||||
DstBlitX,
|
dstBlitX,
|
||||||
DstBlitY,
|
dstBlitY,
|
||||||
DstBlitX + DstBlitW,
|
dstBlitX + dstBlitW,
|
||||||
DstBlitY + DstBlitH);
|
dstBlitY + dstBlitH);
|
||||||
|
|
||||||
//Do a guest side copy aswell. This is necessary when
|
//Do a guest side copy aswell. This is necessary when
|
||||||
//the texture is modified by the guest, however it doesn't
|
//the texture is modified by the guest, however it doesn't
|
||||||
|
@ -209,51 +208,51 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
|
|
||||||
// FIXME: SUPPORT MULTILAYER CORRECTLY HERE (this will cause weird stuffs on the first layer)
|
// FIXME: SUPPORT MULTILAYER CORRECTLY HERE (this will cause weird stuffs on the first layer)
|
||||||
ImageUtils.CopyTexture(
|
ImageUtils.CopyTexture(
|
||||||
Vmm,
|
vmm,
|
||||||
SrcTexture,
|
srcTexture,
|
||||||
DstTexture,
|
dstTexture,
|
||||||
SrcAddress,
|
srcAddress,
|
||||||
DstAddress,
|
dstAddress,
|
||||||
SrcBlitX1,
|
srcBlitX1,
|
||||||
SrcBlitY1,
|
srcBlitY1,
|
||||||
DstBlitX,
|
dstBlitX,
|
||||||
DstBlitY,
|
dstBlitY,
|
||||||
DstBlitW,
|
dstBlitW,
|
||||||
DstBlitH);
|
dstBlitH);
|
||||||
|
|
||||||
Vmm.IsRegionModified(DstKey, ImageUtils.GetSize(DstTexture), NvGpuBufferType.Texture);
|
vmm.IsRegionModified(dstKey, ImageUtils.GetSize(dstTexture), NvGpuBufferType.Texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GalMemoryLayout GetLayout(bool Linear)
|
private static GalMemoryLayout GetLayout(bool linear)
|
||||||
{
|
{
|
||||||
return Linear
|
return linear
|
||||||
? GalMemoryLayout.Pitch
|
? GalMemoryLayout.Pitch
|
||||||
: GalMemoryLayout.BlockLinear;
|
: GalMemoryLayout.BlockLinear;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long MakeInt64From2xInt32(NvGpuEngine2dReg Reg)
|
private long MakeInt64From2xInt32(NvGpuEngine2dReg reg)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
(long)Registers[(int)Reg + 0] << 32 |
|
(long)Registers[(int)reg + 0] << 32 |
|
||||||
(uint)Registers[(int)Reg + 1];
|
(uint)Registers[(int)reg + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteRegister(GpuMethodCall MethCall)
|
private void WriteRegister(GpuMethodCall methCall)
|
||||||
{
|
{
|
||||||
Registers[MethCall.Method] = MethCall.Argument;
|
Registers[methCall.Method] = methCall.Argument;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long ReadRegisterFixed1_31_32(NvGpuEngine2dReg Reg)
|
private long ReadRegisterFixed1_31_32(NvGpuEngine2dReg reg)
|
||||||
{
|
{
|
||||||
long Low = (uint)ReadRegister(Reg + 0);
|
long low = (uint)ReadRegister(reg + 0);
|
||||||
long High = (uint)ReadRegister(Reg + 1);
|
long high = (uint)ReadRegister(reg + 1);
|
||||||
|
|
||||||
return Low | (High << 32);
|
return low | (high << 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int ReadRegister(NvGpuEngine2dReg Reg)
|
private int ReadRegister(NvGpuEngine2dReg reg)
|
||||||
{
|
{
|
||||||
return Registers[(int)Reg];
|
return Registers[(int)reg];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -32,13 +32,13 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
StencilBackMask = 0x3d6,
|
StencilBackMask = 0x3d6,
|
||||||
StencilBackFuncMask = 0x3d7,
|
StencilBackFuncMask = 0x3d7,
|
||||||
ColorMaskCommon = 0x3e4,
|
ColorMaskCommon = 0x3e4,
|
||||||
RTSeparateFragData = 0x3eb,
|
RtSeparateFragData = 0x3eb,
|
||||||
ZetaAddress = 0x3f8,
|
ZetaAddress = 0x3f8,
|
||||||
ZetaFormat = 0x3fa,
|
ZetaFormat = 0x3fa,
|
||||||
ZetaBlockDimensions = 0x3fb,
|
ZetaBlockDimensions = 0x3fb,
|
||||||
ZetaLayerStride = 0x3fc,
|
ZetaLayerStride = 0x3fc,
|
||||||
VertexAttribNFormat = 0x458,
|
VertexAttribNFormat = 0x458,
|
||||||
RTControl = 0x487,
|
RtControl = 0x487,
|
||||||
ZetaHoriz = 0x48a,
|
ZetaHoriz = 0x48a,
|
||||||
ZetaVert = 0x48b,
|
ZetaVert = 0x48b,
|
||||||
ZetaArrayMode = 0x48c,
|
ZetaArrayMode = 0x48c,
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Graphics.Memory;
|
using Ryujinx.Graphics.Memory;
|
||||||
using Ryujinx.Graphics.Texture;
|
using Ryujinx.Graphics.Texture;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -9,188 +8,188 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
{
|
{
|
||||||
public int[] Registers { get; private set; }
|
public int[] Registers { get; private set; }
|
||||||
|
|
||||||
private NvGpu Gpu;
|
private NvGpu _gpu;
|
||||||
|
|
||||||
private Dictionary<int, NvGpuMethod> Methods;
|
private Dictionary<int, NvGpuMethod> _methods;
|
||||||
|
|
||||||
public NvGpuEngineM2mf(NvGpu Gpu)
|
public NvGpuEngineM2mf(NvGpu gpu)
|
||||||
{
|
{
|
||||||
this.Gpu = Gpu;
|
_gpu = gpu;
|
||||||
|
|
||||||
Registers = new int[0x1d6];
|
Registers = new int[0x1d6];
|
||||||
|
|
||||||
Methods = new Dictionary<int, NvGpuMethod>();
|
_methods = new Dictionary<int, NvGpuMethod>();
|
||||||
|
|
||||||
void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method)
|
void AddMethod(int meth, int count, int stride, NvGpuMethod method)
|
||||||
{
|
{
|
||||||
while (Count-- > 0)
|
while (count-- > 0)
|
||||||
{
|
{
|
||||||
Methods.Add(Meth, Method);
|
_methods.Add(meth, method);
|
||||||
|
|
||||||
Meth += Stride;
|
meth += stride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AddMethod(0xc0, 1, 1, Execute);
|
AddMethod(0xc0, 1, 1, Execute);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CallMethod(NvGpuVmm Vmm, GpuMethodCall MethCall)
|
public void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall)
|
||||||
{
|
{
|
||||||
if (Methods.TryGetValue(MethCall.Method, out NvGpuMethod Method))
|
if (_methods.TryGetValue(methCall.Method, out NvGpuMethod method))
|
||||||
{
|
{
|
||||||
Method(Vmm, MethCall);
|
method(vmm, methCall);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteRegister(MethCall);
|
WriteRegister(methCall);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Execute(NvGpuVmm Vmm, GpuMethodCall MethCall)
|
private void Execute(NvGpuVmm vmm, GpuMethodCall methCall)
|
||||||
{
|
{
|
||||||
//TODO: Some registers and copy modes are still not implemented.
|
//TODO: Some registers and copy modes are still not implemented.
|
||||||
int Control = MethCall.Argument;
|
int control = methCall.Argument;
|
||||||
|
|
||||||
bool SrcLinear = ((Control >> 7) & 1) != 0;
|
bool srcLinear = ((control >> 7) & 1) != 0;
|
||||||
bool DstLinear = ((Control >> 8) & 1) != 0;
|
bool dstLinear = ((control >> 8) & 1) != 0;
|
||||||
bool Copy2d = ((Control >> 9) & 1) != 0;
|
bool copy2D = ((control >> 9) & 1) != 0;
|
||||||
|
|
||||||
long SrcAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.SrcAddress);
|
long srcAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.SrcAddress);
|
||||||
long DstAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.DstAddress);
|
long dstAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.DstAddress);
|
||||||
|
|
||||||
int SrcPitch = ReadRegister(NvGpuEngineM2mfReg.SrcPitch);
|
int srcPitch = ReadRegister(NvGpuEngineM2mfReg.SrcPitch);
|
||||||
int DstPitch = ReadRegister(NvGpuEngineM2mfReg.DstPitch);
|
int dstPitch = ReadRegister(NvGpuEngineM2mfReg.DstPitch);
|
||||||
|
|
||||||
int XCount = ReadRegister(NvGpuEngineM2mfReg.XCount);
|
int xCount = ReadRegister(NvGpuEngineM2mfReg.XCount);
|
||||||
int YCount = ReadRegister(NvGpuEngineM2mfReg.YCount);
|
int yCount = ReadRegister(NvGpuEngineM2mfReg.YCount);
|
||||||
|
|
||||||
int Swizzle = ReadRegister(NvGpuEngineM2mfReg.Swizzle);
|
int swizzle = ReadRegister(NvGpuEngineM2mfReg.Swizzle);
|
||||||
|
|
||||||
int DstBlkDim = ReadRegister(NvGpuEngineM2mfReg.DstBlkDim);
|
int dstBlkDim = ReadRegister(NvGpuEngineM2mfReg.DstBlkDim);
|
||||||
int DstSizeX = ReadRegister(NvGpuEngineM2mfReg.DstSizeX);
|
int dstSizeX = ReadRegister(NvGpuEngineM2mfReg.DstSizeX);
|
||||||
int DstSizeY = ReadRegister(NvGpuEngineM2mfReg.DstSizeY);
|
int dstSizeY = ReadRegister(NvGpuEngineM2mfReg.DstSizeY);
|
||||||
int DstSizeZ = ReadRegister(NvGpuEngineM2mfReg.DstSizeZ);
|
int dstSizeZ = ReadRegister(NvGpuEngineM2mfReg.DstSizeZ);
|
||||||
int DstPosXY = ReadRegister(NvGpuEngineM2mfReg.DstPosXY);
|
int dstPosXY = ReadRegister(NvGpuEngineM2mfReg.DstPosXY);
|
||||||
int DstPosZ = ReadRegister(NvGpuEngineM2mfReg.DstPosZ);
|
int dstPosZ = ReadRegister(NvGpuEngineM2mfReg.DstPosZ);
|
||||||
|
|
||||||
int SrcBlkDim = ReadRegister(NvGpuEngineM2mfReg.SrcBlkDim);
|
int srcBlkDim = ReadRegister(NvGpuEngineM2mfReg.SrcBlkDim);
|
||||||
int SrcSizeX = ReadRegister(NvGpuEngineM2mfReg.SrcSizeX);
|
int srcSizeX = ReadRegister(NvGpuEngineM2mfReg.SrcSizeX);
|
||||||
int SrcSizeY = ReadRegister(NvGpuEngineM2mfReg.SrcSizeY);
|
int srcSizeY = ReadRegister(NvGpuEngineM2mfReg.SrcSizeY);
|
||||||
int SrcSizeZ = ReadRegister(NvGpuEngineM2mfReg.SrcSizeZ);
|
int srcSizeZ = ReadRegister(NvGpuEngineM2mfReg.SrcSizeZ);
|
||||||
int SrcPosXY = ReadRegister(NvGpuEngineM2mfReg.SrcPosXY);
|
int srcPosXY = ReadRegister(NvGpuEngineM2mfReg.SrcPosXY);
|
||||||
int SrcPosZ = ReadRegister(NvGpuEngineM2mfReg.SrcPosZ);
|
int srcPosZ = ReadRegister(NvGpuEngineM2mfReg.SrcPosZ);
|
||||||
|
|
||||||
int SrcCpp = ((Swizzle >> 20) & 7) + 1;
|
int srcCpp = ((swizzle >> 20) & 7) + 1;
|
||||||
int DstCpp = ((Swizzle >> 24) & 7) + 1;
|
int dstCpp = ((swizzle >> 24) & 7) + 1;
|
||||||
|
|
||||||
int DstPosX = (DstPosXY >> 0) & 0xffff;
|
int dstPosX = (dstPosXY >> 0) & 0xffff;
|
||||||
int DstPosY = (DstPosXY >> 16) & 0xffff;
|
int dstPosY = (dstPosXY >> 16) & 0xffff;
|
||||||
|
|
||||||
int SrcPosX = (SrcPosXY >> 0) & 0xffff;
|
int srcPosX = (srcPosXY >> 0) & 0xffff;
|
||||||
int SrcPosY = (SrcPosXY >> 16) & 0xffff;
|
int srcPosY = (srcPosXY >> 16) & 0xffff;
|
||||||
|
|
||||||
int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf);
|
int srcBlockHeight = 1 << ((srcBlkDim >> 4) & 0xf);
|
||||||
int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
|
int dstBlockHeight = 1 << ((dstBlkDim >> 4) & 0xf);
|
||||||
|
|
||||||
long SrcPA = Vmm.GetPhysicalAddress(SrcAddress);
|
long srcPa = vmm.GetPhysicalAddress(srcAddress);
|
||||||
long DstPA = Vmm.GetPhysicalAddress(DstAddress);
|
long dstPa = vmm.GetPhysicalAddress(dstAddress);
|
||||||
|
|
||||||
if (Copy2d)
|
if (copy2D)
|
||||||
{
|
{
|
||||||
if (SrcLinear)
|
if (srcLinear)
|
||||||
{
|
{
|
||||||
SrcPosX = SrcPosY = SrcPosZ = 0;
|
srcPosX = srcPosY = srcPosZ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DstLinear)
|
if (dstLinear)
|
||||||
{
|
{
|
||||||
DstPosX = DstPosY = DstPosZ = 0;
|
dstPosX = dstPosY = dstPosZ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SrcLinear && DstLinear)
|
if (srcLinear && dstLinear)
|
||||||
{
|
{
|
||||||
for (int Y = 0; Y < YCount; Y++)
|
for (int y = 0; y < yCount; y++)
|
||||||
{
|
{
|
||||||
int SrcOffset = (SrcPosY + Y) * SrcPitch + SrcPosX * SrcCpp;
|
int srcOffset = (srcPosY + y) * srcPitch + srcPosX * srcCpp;
|
||||||
int DstOffset = (DstPosY + Y) * DstPitch + DstPosX * DstCpp;
|
int dstOffset = (dstPosY + y) * dstPitch + dstPosX * dstCpp;
|
||||||
|
|
||||||
long Src = SrcPA + (uint)SrcOffset;
|
long src = srcPa + (uint)srcOffset;
|
||||||
long Dst = DstPA + (uint)DstOffset;
|
long dst = dstPa + (uint)dstOffset;
|
||||||
|
|
||||||
Vmm.Memory.CopyBytes(Src, Dst, XCount * SrcCpp);
|
vmm.Memory.CopyBytes(src, dst, xCount * srcCpp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ISwizzle SrcSwizzle;
|
ISwizzle srcSwizzle;
|
||||||
|
|
||||||
if (SrcLinear)
|
if (srcLinear)
|
||||||
{
|
{
|
||||||
SrcSwizzle = new LinearSwizzle(SrcPitch, SrcCpp, SrcSizeX, SrcSizeY);
|
srcSwizzle = new LinearSwizzle(srcPitch, srcCpp, srcSizeX, srcSizeY);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SrcSwizzle = new BlockLinearSwizzle(
|
srcSwizzle = new BlockLinearSwizzle(
|
||||||
SrcSizeX,
|
srcSizeX,
|
||||||
SrcSizeY, 1,
|
srcSizeY, 1,
|
||||||
SrcBlockHeight, 1,
|
srcBlockHeight, 1,
|
||||||
SrcCpp);
|
srcCpp);
|
||||||
}
|
}
|
||||||
|
|
||||||
ISwizzle DstSwizzle;
|
ISwizzle dstSwizzle;
|
||||||
|
|
||||||
if (DstLinear)
|
if (dstLinear)
|
||||||
{
|
{
|
||||||
DstSwizzle = new LinearSwizzle(DstPitch, DstCpp, SrcSizeX, SrcSizeY);
|
dstSwizzle = new LinearSwizzle(dstPitch, dstCpp, srcSizeX, srcSizeY);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DstSwizzle = new BlockLinearSwizzle(
|
dstSwizzle = new BlockLinearSwizzle(
|
||||||
DstSizeX,
|
dstSizeX,
|
||||||
DstSizeY, 1,
|
dstSizeY, 1,
|
||||||
DstBlockHeight, 1,
|
dstBlockHeight, 1,
|
||||||
DstCpp);
|
dstCpp);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int Y = 0; Y < YCount; Y++)
|
for (int y = 0; y < yCount; y++)
|
||||||
for (int X = 0; X < XCount; X++)
|
for (int x = 0; x < xCount; x++)
|
||||||
{
|
{
|
||||||
int SrcOffset = SrcSwizzle.GetSwizzleOffset(SrcPosX + X, SrcPosY + Y, 0);
|
int srcOffset = srcSwizzle.GetSwizzleOffset(srcPosX + x, srcPosY + y, 0);
|
||||||
int DstOffset = DstSwizzle.GetSwizzleOffset(DstPosX + X, DstPosY + Y, 0);
|
int dstOffset = dstSwizzle.GetSwizzleOffset(dstPosX + x, dstPosY + y, 0);
|
||||||
|
|
||||||
long Src = SrcPA + (uint)SrcOffset;
|
long src = srcPa + (uint)srcOffset;
|
||||||
long Dst = DstPA + (uint)DstOffset;
|
long dst = dstPa + (uint)dstOffset;
|
||||||
|
|
||||||
Vmm.Memory.CopyBytes(Src, Dst, SrcCpp);
|
vmm.Memory.CopyBytes(src, dst, srcCpp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Vmm.Memory.CopyBytes(SrcPA, DstPA, XCount);
|
vmm.Memory.CopyBytes(srcPa, dstPa, xCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long MakeInt64From2xInt32(NvGpuEngineM2mfReg Reg)
|
private long MakeInt64From2xInt32(NvGpuEngineM2mfReg reg)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
(long)Registers[(int)Reg + 0] << 32 |
|
(long)Registers[(int)reg + 0] << 32 |
|
||||||
(uint)Registers[(int)Reg + 1];
|
(uint)Registers[(int)reg + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteRegister(GpuMethodCall MethCall)
|
private void WriteRegister(GpuMethodCall methCall)
|
||||||
{
|
{
|
||||||
Registers[MethCall.Method] = MethCall.Argument;
|
Registers[methCall.Method] = methCall.Argument;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int ReadRegister(NvGpuEngineM2mfReg Reg)
|
private int ReadRegister(NvGpuEngineM2mfReg reg)
|
||||||
{
|
{
|
||||||
return Registers[(int)Reg];
|
return Registers[(int)reg];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteRegister(NvGpuEngineM2mfReg Reg, int Value)
|
private void WriteRegister(NvGpuEngineM2mfReg reg, int value)
|
||||||
{
|
{
|
||||||
Registers[(int)Reg] = Value;
|
Registers[(int)reg] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Graphics.Memory;
|
using Ryujinx.Graphics.Memory;
|
||||||
using Ryujinx.Graphics.Texture;
|
using Ryujinx.Graphics.Texture;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -9,41 +8,41 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
{
|
{
|
||||||
public int[] Registers { get; private set; }
|
public int[] Registers { get; private set; }
|
||||||
|
|
||||||
private NvGpu Gpu;
|
private NvGpu _gpu;
|
||||||
|
|
||||||
private Dictionary<int, NvGpuMethod> Methods;
|
private Dictionary<int, NvGpuMethod> _methods;
|
||||||
|
|
||||||
private int CopyStartX;
|
private int _copyStartX;
|
||||||
private int CopyStartY;
|
private int _copyStartY;
|
||||||
|
|
||||||
private int CopyWidth;
|
private int _copyWidth;
|
||||||
private int CopyHeight;
|
private int _copyHeight;
|
||||||
private int CopyGobBlockHeight;
|
private int _copyGobBlockHeight;
|
||||||
|
|
||||||
private long CopyAddress;
|
private long _copyAddress;
|
||||||
|
|
||||||
private int CopyOffset;
|
private int _copyOffset;
|
||||||
private int CopySize;
|
private int _copySize;
|
||||||
|
|
||||||
private bool CopyLinear;
|
private bool _copyLinear;
|
||||||
|
|
||||||
private byte[] Buffer;
|
private byte[] _buffer;
|
||||||
|
|
||||||
public NvGpuEngineP2mf(NvGpu Gpu)
|
public NvGpuEngineP2mf(NvGpu gpu)
|
||||||
{
|
{
|
||||||
this.Gpu = Gpu;
|
_gpu = gpu;
|
||||||
|
|
||||||
Registers = new int[0x80];
|
Registers = new int[0x80];
|
||||||
|
|
||||||
Methods = new Dictionary<int, NvGpuMethod>();
|
_methods = new Dictionary<int, NvGpuMethod>();
|
||||||
|
|
||||||
void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method)
|
void AddMethod(int meth, int count, int stride, NvGpuMethod method)
|
||||||
{
|
{
|
||||||
while (Count-- > 0)
|
while (count-- > 0)
|
||||||
{
|
{
|
||||||
Methods.Add(Meth, Method);
|
_methods.Add(meth, method);
|
||||||
|
|
||||||
Meth += Stride;
|
meth += stride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,115 +50,115 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
AddMethod(0x6d, 1, 1, PushData);
|
AddMethod(0x6d, 1, 1, PushData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CallMethod(NvGpuVmm Vmm, GpuMethodCall MethCall)
|
public void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall)
|
||||||
{
|
{
|
||||||
if (Methods.TryGetValue(MethCall.Method, out NvGpuMethod Method))
|
if (_methods.TryGetValue(methCall.Method, out NvGpuMethod method))
|
||||||
{
|
{
|
||||||
Method(Vmm, MethCall);
|
method(vmm, methCall);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteRegister(MethCall);
|
WriteRegister(methCall);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Execute(NvGpuVmm Vmm, GpuMethodCall MethCall)
|
private void Execute(NvGpuVmm vmm, GpuMethodCall methCall)
|
||||||
{
|
{
|
||||||
//TODO: Some registers and copy modes are still not implemented.
|
//TODO: Some registers and copy modes are still not implemented.
|
||||||
int Control = MethCall.Argument;
|
int control = methCall.Argument;
|
||||||
|
|
||||||
long DstAddress = MakeInt64From2xInt32(NvGpuEngineP2mfReg.DstAddress);
|
long dstAddress = MakeInt64From2xInt32(NvGpuEngineP2mfReg.DstAddress);
|
||||||
|
|
||||||
int DstPitch = ReadRegister(NvGpuEngineP2mfReg.DstPitch);
|
int dstPitch = ReadRegister(NvGpuEngineP2mfReg.DstPitch);
|
||||||
int DstBlkDim = ReadRegister(NvGpuEngineP2mfReg.DstBlockDim);
|
int dstBlkDim = ReadRegister(NvGpuEngineP2mfReg.DstBlockDim);
|
||||||
|
|
||||||
int DstX = ReadRegister(NvGpuEngineP2mfReg.DstX);
|
int dstX = ReadRegister(NvGpuEngineP2mfReg.DstX);
|
||||||
int DstY = ReadRegister(NvGpuEngineP2mfReg.DstY);
|
int dstY = ReadRegister(NvGpuEngineP2mfReg.DstY);
|
||||||
|
|
||||||
int DstWidth = ReadRegister(NvGpuEngineP2mfReg.DstWidth);
|
int dstWidth = ReadRegister(NvGpuEngineP2mfReg.DstWidth);
|
||||||
int DstHeight = ReadRegister(NvGpuEngineP2mfReg.DstHeight);
|
int dstHeight = ReadRegister(NvGpuEngineP2mfReg.DstHeight);
|
||||||
|
|
||||||
int LineLengthIn = ReadRegister(NvGpuEngineP2mfReg.LineLengthIn);
|
int lineLengthIn = ReadRegister(NvGpuEngineP2mfReg.LineLengthIn);
|
||||||
int LineCount = ReadRegister(NvGpuEngineP2mfReg.LineCount);
|
int lineCount = ReadRegister(NvGpuEngineP2mfReg.LineCount);
|
||||||
|
|
||||||
CopyLinear = (Control & 1) != 0;
|
_copyLinear = (control & 1) != 0;
|
||||||
|
|
||||||
CopyGobBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
|
_copyGobBlockHeight = 1 << ((dstBlkDim >> 4) & 0xf);
|
||||||
|
|
||||||
CopyStartX = DstX;
|
_copyStartX = dstX;
|
||||||
CopyStartY = DstY;
|
_copyStartY = dstY;
|
||||||
|
|
||||||
CopyWidth = DstWidth;
|
_copyWidth = dstWidth;
|
||||||
CopyHeight = DstHeight;
|
_copyHeight = dstHeight;
|
||||||
|
|
||||||
CopyAddress = DstAddress;
|
_copyAddress = dstAddress;
|
||||||
|
|
||||||
CopyOffset = 0;
|
_copyOffset = 0;
|
||||||
CopySize = LineLengthIn * LineCount;
|
_copySize = lineLengthIn * lineCount;
|
||||||
|
|
||||||
Buffer = new byte[CopySize];
|
_buffer = new byte[_copySize];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PushData(NvGpuVmm Vmm, GpuMethodCall MethCall)
|
private void PushData(NvGpuVmm vmm, GpuMethodCall methCall)
|
||||||
{
|
{
|
||||||
if (Buffer == null)
|
if (_buffer == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int Shift = 0; Shift < 32 && CopyOffset < CopySize; Shift += 8, CopyOffset++)
|
for (int shift = 0; shift < 32 && _copyOffset < _copySize; shift += 8, _copyOffset++)
|
||||||
{
|
{
|
||||||
Buffer[CopyOffset] = (byte)(MethCall.Argument >> Shift);
|
_buffer[_copyOffset] = (byte)(methCall.Argument >> shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MethCall.IsLastCall)
|
if (methCall.IsLastCall)
|
||||||
{
|
{
|
||||||
if (CopyLinear)
|
if (_copyLinear)
|
||||||
{
|
{
|
||||||
Vmm.WriteBytes(CopyAddress, Buffer);
|
vmm.WriteBytes(_copyAddress, _buffer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BlockLinearSwizzle Swizzle = new BlockLinearSwizzle(
|
BlockLinearSwizzle swizzle = new BlockLinearSwizzle(
|
||||||
CopyWidth,
|
_copyWidth,
|
||||||
CopyHeight, 1,
|
_copyHeight, 1,
|
||||||
CopyGobBlockHeight, 1, 1);
|
_copyGobBlockHeight, 1, 1);
|
||||||
|
|
||||||
int SrcOffset = 0;
|
int srcOffset = 0;
|
||||||
|
|
||||||
for (int Y = CopyStartY; Y < CopyHeight && SrcOffset < CopySize; Y++)
|
for (int y = _copyStartY; y < _copyHeight && srcOffset < _copySize; y++)
|
||||||
for (int X = CopyStartX; X < CopyWidth && SrcOffset < CopySize; X++)
|
for (int x = _copyStartX; x < _copyWidth && srcOffset < _copySize; x++)
|
||||||
{
|
{
|
||||||
int DstOffset = Swizzle.GetSwizzleOffset(X, Y, 0);
|
int dstOffset = swizzle.GetSwizzleOffset(x, y, 0);
|
||||||
|
|
||||||
Vmm.WriteByte(CopyAddress + DstOffset, Buffer[SrcOffset++]);
|
vmm.WriteByte(_copyAddress + dstOffset, _buffer[srcOffset++]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer = null;
|
_buffer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long MakeInt64From2xInt32(NvGpuEngineP2mfReg Reg)
|
private long MakeInt64From2xInt32(NvGpuEngineP2mfReg reg)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
(long)Registers[(int)Reg + 0] << 32 |
|
(long)Registers[(int)reg + 0] << 32 |
|
||||||
(uint)Registers[(int)Reg + 1];
|
(uint)Registers[(int)reg + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteRegister(GpuMethodCall MethCall)
|
private void WriteRegister(GpuMethodCall methCall)
|
||||||
{
|
{
|
||||||
Registers[MethCall.Method] = MethCall.Argument;
|
Registers[methCall.Method] = methCall.Argument;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int ReadRegister(NvGpuEngineP2mfReg Reg)
|
private int ReadRegister(NvGpuEngineP2mfReg reg)
|
||||||
{
|
{
|
||||||
return Registers[(int)Reg];
|
return Registers[(int)reg];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteRegister(NvGpuEngineP2mfReg Reg, int Value)
|
private void WriteRegister(NvGpuEngineP2mfReg reg, int value)
|
||||||
{
|
{
|
||||||
Registers[(int)Reg] = Value;
|
Registers[(int)reg] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,166 +11,166 @@ namespace Ryujinx.Graphics.Graphics3d
|
||||||
//a guess here and use 256kb as the size. Increase if needed.
|
//a guess here and use 256kb as the size. Increase if needed.
|
||||||
private const int MmeWords = 256 * 256;
|
private const int MmeWords = 256 * 256;
|
||||||
|
|
||||||
private NvGpu Gpu;
|
private NvGpu _gpu;
|
||||||
|
|
||||||
private NvGpuEngine[] SubChannels;
|
private NvGpuEngine[] _subChannels;
|
||||||
|
|
||||||
private struct CachedMacro
|
private struct CachedMacro
|
||||||
{
|
{
|
||||||
public int Position { get; private set; }
|
public int Position { get; private set; }
|
||||||
|
|
||||||
private bool ExecutionPending;
|
private bool _executionPending;
|
||||||
private int Argument;
|
private int _argument;
|
||||||
|
|
||||||
private MacroInterpreter Interpreter;
|
private MacroInterpreter _interpreter;
|
||||||
|
|
||||||
public CachedMacro(NvGpuFifo PFifo, INvGpuEngine Engine, int Position)
|
public CachedMacro(NvGpuFifo pFifo, INvGpuEngine engine, int position)
|
||||||
{
|
{
|
||||||
this.Position = Position;
|
Position = position;
|
||||||
|
|
||||||
ExecutionPending = false;
|
_executionPending = false;
|
||||||
Argument = 0;
|
_argument = 0;
|
||||||
|
|
||||||
Interpreter = new MacroInterpreter(PFifo, Engine);
|
_interpreter = new MacroInterpreter(pFifo, engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartExecution(int Argument)
|
public void StartExecution(int argument)
|
||||||
{
|
{
|
||||||
this.Argument = Argument;
|
_argument = argument;
|
||||||
|
|
||||||
ExecutionPending = true;
|
_executionPending = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Execute(NvGpuVmm Vmm, int[] Mme)
|
public void Execute(NvGpuVmm vmm, int[] mme)
|
||||||
{
|
{
|
||||||
if (ExecutionPending)
|
if (_executionPending)
|
||||||
{
|
{
|
||||||
ExecutionPending = false;
|
_executionPending = false;
|
||||||
|
|
||||||
Interpreter?.Execute(Vmm, Mme, Position, Argument);
|
_interpreter?.Execute(vmm, mme, Position, _argument);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PushArgument(int Argument)
|
public void PushArgument(int argument)
|
||||||
{
|
{
|
||||||
Interpreter?.Fifo.Enqueue(Argument);
|
_interpreter?.Fifo.Enqueue(argument);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int CurrMacroPosition;
|
private int _currMacroPosition;
|
||||||
private int CurrMacroBindIndex;
|
private int _currMacroBindIndex;
|
||||||
|
|
||||||
private CachedMacro[] Macros;
|
private CachedMacro[] _macros;
|
||||||
|
|
||||||
private int[] Mme;
|
private int[] _mme;
|
||||||
|
|
||||||
public NvGpuFifo(NvGpu Gpu)
|
public NvGpuFifo(NvGpu gpu)
|
||||||
{
|
{
|
||||||
this.Gpu = Gpu;
|
_gpu = gpu;
|
||||||
|
|
||||||
SubChannels = new NvGpuEngine[8];
|
_subChannels = new NvGpuEngine[8];
|
||||||
|
|
||||||
Macros = new CachedMacro[MacrosCount];
|
_macros = new CachedMacro[MacrosCount];
|
||||||
|
|
||||||
Mme = new int[MmeWords];
|
_mme = new int[MmeWords];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CallMethod(NvGpuVmm Vmm, GpuMethodCall MethCall)
|
public void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall)
|
||||||
{
|
{
|
||||||
if ((NvGpuFifoMeth)MethCall.Method == NvGpuFifoMeth.BindChannel)
|
if ((NvGpuFifoMeth)methCall.Method == NvGpuFifoMeth.BindChannel)
|
||||||
{
|
{
|
||||||
NvGpuEngine Engine = (NvGpuEngine)MethCall.Argument;
|
NvGpuEngine engine = (NvGpuEngine)methCall.Argument;
|
||||||
|
|
||||||
SubChannels[MethCall.SubChannel] = Engine;
|
_subChannels[methCall.SubChannel] = engine;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (SubChannels[MethCall.SubChannel])
|
switch (_subChannels[methCall.SubChannel])
|
||||||
{
|
{
|
||||||
case NvGpuEngine._2d: Call2dMethod (Vmm, MethCall); break;
|
case NvGpuEngine._2d: Call2dMethod (vmm, methCall); break;
|
||||||
case NvGpuEngine._3d: Call3dMethod (Vmm, MethCall); break;
|
case NvGpuEngine._3d: Call3dMethod (vmm, methCall); break;
|
||||||
case NvGpuEngine.P2mf: CallP2mfMethod(Vmm, MethCall); break;
|
case NvGpuEngine.P2mf: CallP2mfMethod(vmm, methCall); break;
|
||||||
case NvGpuEngine.M2mf: CallM2mfMethod(Vmm, MethCall); break;
|
case NvGpuEngine.M2mf: CallM2mfMethod(vmm, methCall); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Call2dMethod(NvGpuVmm Vmm, GpuMethodCall MethCall)
|
private void Call2dMethod(NvGpuVmm vmm, GpuMethodCall methCall)
|
||||||
{
|
{
|
||||||
Gpu.Engine2d.CallMethod(Vmm, MethCall);
|
_gpu.Engine2d.CallMethod(vmm, methCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Call3dMethod(NvGpuVmm Vmm, GpuMethodCall MethCall)
|
private void Call3dMethod(NvGpuVmm vmm, GpuMethodCall methCall)
|
||||||
{
|
{
|
||||||
if (MethCall.Method < 0x80)
|
if (methCall.Method < 0x80)
|
||||||
{
|
{
|
||||||
switch ((NvGpuFifoMeth)MethCall.Method)
|
switch ((NvGpuFifoMeth)methCall.Method)
|
||||||
{
|
{
|
||||||
case NvGpuFifoMeth.SetMacroUploadAddress:
|
case NvGpuFifoMeth.SetMacroUploadAddress:
|
||||||
{
|
{
|
||||||
CurrMacroPosition = MethCall.Argument;
|
_currMacroPosition = methCall.Argument;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NvGpuFifoMeth.SendMacroCodeData:
|
case NvGpuFifoMeth.SendMacroCodeData:
|
||||||
{
|
{
|
||||||
Mme[CurrMacroPosition++] = MethCall.Argument;
|
_mme[_currMacroPosition++] = methCall.Argument;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NvGpuFifoMeth.SetMacroBindingIndex:
|
case NvGpuFifoMeth.SetMacroBindingIndex:
|
||||||
{
|
{
|
||||||
CurrMacroBindIndex = MethCall.Argument;
|
_currMacroBindIndex = methCall.Argument;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case NvGpuFifoMeth.BindMacro:
|
case NvGpuFifoMeth.BindMacro:
|
||||||
{
|
{
|
||||||
int Position = MethCall.Argument;
|
int position = methCall.Argument;
|
||||||
|
|
||||||
Macros[CurrMacroBindIndex] = new CachedMacro(this, Gpu.Engine3d, Position);
|
_macros[_currMacroBindIndex] = new CachedMacro(this, _gpu.Engine3d, position);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default: CallP2mfMethod(Vmm, MethCall); break;
|
default: CallP2mfMethod(vmm, methCall); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (MethCall.Method < 0xe00)
|
else if (methCall.Method < 0xe00)
|
||||||
{
|
{
|
||||||
Gpu.Engine3d.CallMethod(Vmm, MethCall);
|
_gpu.Engine3d.CallMethod(vmm, methCall);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int MacroIndex = (MethCall.Method >> 1) & MacroIndexMask;
|
int macroIndex = (methCall.Method >> 1) & MacroIndexMask;
|
||||||
|
|
||||||
if ((MethCall.Method & 1) != 0)
|
if ((methCall.Method & 1) != 0)
|
||||||
{
|
{
|
||||||
Macros[MacroIndex].PushArgument(MethCall.Argument);
|
_macros[macroIndex].PushArgument(methCall.Argument);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Macros[MacroIndex].StartExecution(MethCall.Argument);
|
_macros[macroIndex].StartExecution(methCall.Argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MethCall.IsLastCall)
|
if (methCall.IsLastCall)
|
||||||
{
|
{
|
||||||
Macros[MacroIndex].Execute(Vmm, Mme);
|
_macros[macroIndex].Execute(vmm, _mme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CallP2mfMethod(NvGpuVmm Vmm, GpuMethodCall MethCall)
|
private void CallP2mfMethod(NvGpuVmm vmm, GpuMethodCall methCall)
|
||||||
{
|
{
|
||||||
Gpu.EngineP2mf.CallMethod(Vmm, MethCall);
|
_gpu.EngineP2mf.CallMethod(vmm, methCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CallM2mfMethod(NvGpuVmm Vmm, GpuMethodCall MethCall)
|
private void CallM2mfMethod(NvGpuVmm vmm, GpuMethodCall methCall)
|
||||||
{
|
{
|
||||||
Gpu.EngineM2mf.CallMethod(Vmm, MethCall);
|
_gpu.EngineM2mf.CallMethod(vmm, methCall);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,5 +2,5 @@ using Ryujinx.Graphics.Memory;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Graphics3d
|
namespace Ryujinx.Graphics.Graphics3d
|
||||||
{
|
{
|
||||||
delegate void NvGpuMethod(NvGpuVmm Vmm, GpuMethodCall MethCall);
|
delegate void NvGpuMethod(NvGpuVmm vmm, GpuMethodCall methCall);
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,138 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Texture
|
|
||||||
{
|
|
||||||
class ASTCPixel
|
|
||||||
{
|
|
||||||
public short R { get; set; }
|
|
||||||
public short G { get; set; }
|
|
||||||
public short B { get; set; }
|
|
||||||
public short A { get; set; }
|
|
||||||
|
|
||||||
byte[] BitDepth = new byte[4];
|
|
||||||
|
|
||||||
public ASTCPixel(short _A, short _R, short _G, short _B)
|
|
||||||
{
|
|
||||||
A = _A;
|
|
||||||
R = _R;
|
|
||||||
G = _G;
|
|
||||||
B = _B;
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
BitDepth[i] = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClampByte()
|
|
||||||
{
|
|
||||||
R = Math.Min(Math.Max(R, (short)0), (short)255);
|
|
||||||
G = Math.Min(Math.Max(G, (short)0), (short)255);
|
|
||||||
B = Math.Min(Math.Max(B, (short)0), (short)255);
|
|
||||||
A = Math.Min(Math.Max(A, (short)0), (short)255);
|
|
||||||
}
|
|
||||||
|
|
||||||
public short GetComponent(int Index)
|
|
||||||
{
|
|
||||||
switch(Index)
|
|
||||||
{
|
|
||||||
case 0: return A;
|
|
||||||
case 1: return R;
|
|
||||||
case 2: return G;
|
|
||||||
case 3: return B;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetComponent(int Index, int Value)
|
|
||||||
{
|
|
||||||
switch (Index)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
A = (short)Value;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
R = (short)Value;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
G = (short)Value;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
B = (short)Value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ChangeBitDepth(byte[] Depth)
|
|
||||||
{
|
|
||||||
for(int i = 0; i< 4; i++)
|
|
||||||
{
|
|
||||||
int Value = ChangeBitDepth(GetComponent(i), BitDepth[i], Depth[i]);
|
|
||||||
|
|
||||||
SetComponent(i, Value);
|
|
||||||
BitDepth[i] = Depth[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
short ChangeBitDepth(short Value, byte OldDepth, byte NewDepth)
|
|
||||||
{
|
|
||||||
Debug.Assert(NewDepth <= 8);
|
|
||||||
Debug.Assert(OldDepth <= 8);
|
|
||||||
|
|
||||||
if (OldDepth == NewDepth)
|
|
||||||
{
|
|
||||||
// Do nothing
|
|
||||||
return Value;
|
|
||||||
}
|
|
||||||
else if (OldDepth == 0 && NewDepth != 0)
|
|
||||||
{
|
|
||||||
return (short)((1 << NewDepth) - 1);
|
|
||||||
}
|
|
||||||
else if (NewDepth > OldDepth)
|
|
||||||
{
|
|
||||||
return (short)BitArrayStream.Replicate(Value, OldDepth, NewDepth);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// oldDepth > newDepth
|
|
||||||
if (NewDepth == 0)
|
|
||||||
{
|
|
||||||
return 0xFF;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
byte BitsWasted = (byte)(OldDepth - NewDepth);
|
|
||||||
short TempValue = Value;
|
|
||||||
|
|
||||||
TempValue = (short)((TempValue + (1 << (BitsWasted - 1))) >> BitsWasted);
|
|
||||||
TempValue = Math.Min(Math.Max((short)0, TempValue), (short)((1 << NewDepth) - 1));
|
|
||||||
|
|
||||||
return (byte)(TempValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Pack()
|
|
||||||
{
|
|
||||||
ASTCPixel NewPixel = new ASTCPixel(A, R, G, B);
|
|
||||||
byte[] eightBitDepth = { 8, 8, 8, 8 };
|
|
||||||
|
|
||||||
NewPixel.ChangeBitDepth(eightBitDepth);
|
|
||||||
|
|
||||||
return (byte)NewPixel.A << 24 |
|
|
||||||
(byte)NewPixel.B << 16 |
|
|
||||||
(byte)NewPixel.G << 8 |
|
|
||||||
(byte)NewPixel.R << 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds more precision to the blue channel as described
|
|
||||||
// in C.2.14
|
|
||||||
public static ASTCPixel BlueContract(int a, int r, int g, int b)
|
|
||||||
{
|
|
||||||
return new ASTCPixel((short)(a),
|
|
||||||
(short)((r + b) >> 1),
|
|
||||||
(short)((g + b) >> 1),
|
|
||||||
(short)(b));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
1385
Ryujinx.Graphics/Graphics3d/Texture/AstcDecoder.cs
Normal file
1385
Ryujinx.Graphics/Graphics3d/Texture/AstcDecoder.cs
Normal file
File diff suppressed because it is too large
Load diff
138
Ryujinx.Graphics/Graphics3d/Texture/AstcPixel.cs
Normal file
138
Ryujinx.Graphics/Graphics3d/Texture/AstcPixel.cs
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Texture
|
||||||
|
{
|
||||||
|
class AstcPixel
|
||||||
|
{
|
||||||
|
public short R { get; set; }
|
||||||
|
public short G { get; set; }
|
||||||
|
public short B { get; set; }
|
||||||
|
public short A { get; set; }
|
||||||
|
|
||||||
|
byte[] _bitDepth = new byte[4];
|
||||||
|
|
||||||
|
public AstcPixel(short a, short r, short g, short b)
|
||||||
|
{
|
||||||
|
A = a;
|
||||||
|
R = r;
|
||||||
|
G = g;
|
||||||
|
B = b;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
_bitDepth[i] = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClampByte()
|
||||||
|
{
|
||||||
|
R = Math.Min(Math.Max(R, (short)0), (short)255);
|
||||||
|
G = Math.Min(Math.Max(G, (short)0), (short)255);
|
||||||
|
B = Math.Min(Math.Max(B, (short)0), (short)255);
|
||||||
|
A = Math.Min(Math.Max(A, (short)0), (short)255);
|
||||||
|
}
|
||||||
|
|
||||||
|
public short GetComponent(int index)
|
||||||
|
{
|
||||||
|
switch(index)
|
||||||
|
{
|
||||||
|
case 0: return A;
|
||||||
|
case 1: return R;
|
||||||
|
case 2: return G;
|
||||||
|
case 3: return B;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetComponent(int index, int value)
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
A = (short)value;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
R = (short)value;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
G = (short)value;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
B = (short)value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ChangeBitDepth(byte[] depth)
|
||||||
|
{
|
||||||
|
for(int i = 0; i< 4; i++)
|
||||||
|
{
|
||||||
|
int value = ChangeBitDepth(GetComponent(i), _bitDepth[i], depth[i]);
|
||||||
|
|
||||||
|
SetComponent(i, value);
|
||||||
|
_bitDepth[i] = depth[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
short ChangeBitDepth(short value, byte oldDepth, byte newDepth)
|
||||||
|
{
|
||||||
|
Debug.Assert(newDepth <= 8);
|
||||||
|
Debug.Assert(oldDepth <= 8);
|
||||||
|
|
||||||
|
if (oldDepth == newDepth)
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else if (oldDepth == 0 && newDepth != 0)
|
||||||
|
{
|
||||||
|
return (short)((1 << newDepth) - 1);
|
||||||
|
}
|
||||||
|
else if (newDepth > oldDepth)
|
||||||
|
{
|
||||||
|
return (short)BitArrayStream.Replicate(value, oldDepth, newDepth);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// oldDepth > newDepth
|
||||||
|
if (newDepth == 0)
|
||||||
|
{
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
byte bitsWasted = (byte)(oldDepth - newDepth);
|
||||||
|
short tempValue = value;
|
||||||
|
|
||||||
|
tempValue = (short)((tempValue + (1 << (bitsWasted - 1))) >> bitsWasted);
|
||||||
|
tempValue = Math.Min(Math.Max((short)0, tempValue), (short)((1 << newDepth) - 1));
|
||||||
|
|
||||||
|
return (byte)(tempValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Pack()
|
||||||
|
{
|
||||||
|
AstcPixel newPixel = new AstcPixel(A, R, G, B);
|
||||||
|
byte[] eightBitDepth = { 8, 8, 8, 8 };
|
||||||
|
|
||||||
|
newPixel.ChangeBitDepth(eightBitDepth);
|
||||||
|
|
||||||
|
return (byte)newPixel.A << 24 |
|
||||||
|
(byte)newPixel.B << 16 |
|
||||||
|
(byte)newPixel.G << 8 |
|
||||||
|
(byte)newPixel.R << 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds more precision to the blue channel as described
|
||||||
|
// in C.2.14
|
||||||
|
public static AstcPixel BlueContract(int a, int r, int g, int b)
|
||||||
|
{
|
||||||
|
return new AstcPixel((short)(a),
|
||||||
|
(short)((r + b) >> 1),
|
||||||
|
(short)((g + b) >> 1),
|
||||||
|
(short)(b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,103 +9,103 @@ namespace Ryujinx.Graphics.Texture
|
||||||
|
|
||||||
public int Position { get; private set; }
|
public int Position { get; private set; }
|
||||||
|
|
||||||
public BitArrayStream(BitArray BitArray)
|
public BitArrayStream(BitArray bitArray)
|
||||||
{
|
{
|
||||||
BitsArray = BitArray;
|
BitsArray = bitArray;
|
||||||
Position = 0;
|
Position = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public short ReadBits(int Length)
|
public short ReadBits(int length)
|
||||||
{
|
{
|
||||||
int RetValue = 0;
|
int retValue = 0;
|
||||||
for (int i = Position; i < Position + Length; i++)
|
for (int i = Position; i < Position + length; i++)
|
||||||
{
|
{
|
||||||
if (BitsArray[i])
|
if (BitsArray[i])
|
||||||
{
|
{
|
||||||
RetValue |= 1 << (i - Position);
|
retValue |= 1 << (i - Position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Position += Length;
|
Position += length;
|
||||||
return (short)RetValue;
|
return (short)retValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ReadBits(int Start, int End)
|
public int ReadBits(int start, int end)
|
||||||
{
|
{
|
||||||
int RetValue = 0;
|
int retValue = 0;
|
||||||
for (int i = Start; i <= End; i++)
|
for (int i = start; i <= end; i++)
|
||||||
{
|
{
|
||||||
if (BitsArray[i])
|
if (BitsArray[i])
|
||||||
{
|
{
|
||||||
RetValue |= 1 << (i - Start);
|
retValue |= 1 << (i - start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return RetValue;
|
return retValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ReadBit(int Index)
|
public int ReadBit(int index)
|
||||||
{
|
{
|
||||||
return Convert.ToInt32(BitsArray[Index]);
|
return Convert.ToInt32(BitsArray[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteBits(int Value, int Length)
|
public void WriteBits(int value, int length)
|
||||||
{
|
{
|
||||||
for (int i = Position; i < Position + Length; i++)
|
for (int i = Position; i < Position + length; i++)
|
||||||
{
|
{
|
||||||
BitsArray[i] = ((Value >> (i - Position)) & 1) != 0;
|
BitsArray[i] = ((value >> (i - Position)) & 1) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Position += Length;
|
Position += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] ToByteArray()
|
public byte[] ToByteArray()
|
||||||
{
|
{
|
||||||
byte[] RetArray = new byte[(BitsArray.Length + 7) / 8];
|
byte[] retArray = new byte[(BitsArray.Length + 7) / 8];
|
||||||
BitsArray.CopyTo(RetArray, 0);
|
BitsArray.CopyTo(retArray, 0);
|
||||||
return RetArray;
|
return retArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int Replicate(int Value, int NumberBits, int ToBit)
|
public static int Replicate(int value, int numberBits, int toBit)
|
||||||
{
|
{
|
||||||
if (NumberBits == 0) return 0;
|
if (numberBits == 0) return 0;
|
||||||
if (ToBit == 0) return 0;
|
if (toBit == 0) return 0;
|
||||||
|
|
||||||
int TempValue = Value & ((1 << NumberBits) - 1);
|
int tempValue = value & ((1 << numberBits) - 1);
|
||||||
int RetValue = TempValue;
|
int retValue = tempValue;
|
||||||
int ResLength = NumberBits;
|
int resLength = numberBits;
|
||||||
|
|
||||||
while (ResLength < ToBit)
|
while (resLength < toBit)
|
||||||
{
|
{
|
||||||
int Comp = 0;
|
int comp = 0;
|
||||||
if (NumberBits > ToBit - ResLength)
|
if (numberBits > toBit - resLength)
|
||||||
{
|
{
|
||||||
int NewShift = ToBit - ResLength;
|
int newShift = toBit - resLength;
|
||||||
Comp = NumberBits - NewShift;
|
comp = numberBits - newShift;
|
||||||
NumberBits = NewShift;
|
numberBits = newShift;
|
||||||
}
|
}
|
||||||
RetValue <<= NumberBits;
|
retValue <<= numberBits;
|
||||||
RetValue |= TempValue >> Comp;
|
retValue |= tempValue >> comp;
|
||||||
ResLength += NumberBits;
|
resLength += numberBits;
|
||||||
}
|
}
|
||||||
return RetValue;
|
return retValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int PopCnt(int Number)
|
public static int PopCnt(int number)
|
||||||
{
|
{
|
||||||
int Counter;
|
int counter;
|
||||||
for (Counter = 0; Number != 0; Counter++)
|
for (counter = 0; number != 0; counter++)
|
||||||
{
|
{
|
||||||
Number &= Number - 1;
|
number &= number - 1;
|
||||||
}
|
}
|
||||||
return Counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Swap<T>(ref T lhs, ref T rhs)
|
public static void Swap<T>(ref T lhs, ref T rhs)
|
||||||
{
|
{
|
||||||
T Temp = lhs;
|
T temp = lhs;
|
||||||
lhs = rhs;
|
lhs = rhs;
|
||||||
rhs = Temp;
|
rhs = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transfers a bit as described in C.2.14
|
// Transfers a bit as described in C.2.14
|
||||||
|
|
|
@ -10,98 +10,98 @@ namespace Ryujinx.Graphics.Texture
|
||||||
|
|
||||||
private const int GobSize = GobWidth * GobHeight;
|
private const int GobSize = GobWidth * GobHeight;
|
||||||
|
|
||||||
private int TexWidth;
|
private int _texWidth;
|
||||||
private int TexHeight;
|
private int _texHeight;
|
||||||
private int TexDepth;
|
private int _texDepth;
|
||||||
private int TexGobBlockHeight;
|
private int _texGobBlockHeight;
|
||||||
private int TexGobBlockDepth;
|
private int _texGobBlockDepth;
|
||||||
private int TexBpp;
|
private int _texBpp;
|
||||||
|
|
||||||
private int BhMask;
|
private int _bhMask;
|
||||||
private int BdMask;
|
private int _bdMask;
|
||||||
|
|
||||||
private int BhShift;
|
private int _bhShift;
|
||||||
private int BdShift;
|
private int _bdShift;
|
||||||
private int BppShift;
|
private int _bppShift;
|
||||||
|
|
||||||
private int XShift;
|
private int _xShift;
|
||||||
|
|
||||||
private int RobSize;
|
private int _robSize;
|
||||||
private int SliceSize;
|
private int _sliceSize;
|
||||||
|
|
||||||
private int BaseOffset;
|
private int _baseOffset;
|
||||||
|
|
||||||
public BlockLinearSwizzle(
|
public BlockLinearSwizzle(
|
||||||
int Width,
|
int width,
|
||||||
int Height,
|
int height,
|
||||||
int Depth,
|
int depth,
|
||||||
int GobBlockHeight,
|
int gobBlockHeight,
|
||||||
int GobBlockDepth,
|
int gobBlockDepth,
|
||||||
int Bpp)
|
int bpp)
|
||||||
{
|
{
|
||||||
TexWidth = Width;
|
_texWidth = width;
|
||||||
TexHeight = Height;
|
_texHeight = height;
|
||||||
TexDepth = Depth;
|
_texDepth = depth;
|
||||||
TexGobBlockHeight = GobBlockHeight;
|
_texGobBlockHeight = gobBlockHeight;
|
||||||
TexGobBlockDepth = GobBlockDepth;
|
_texGobBlockDepth = gobBlockDepth;
|
||||||
TexBpp = Bpp;
|
_texBpp = bpp;
|
||||||
|
|
||||||
BppShift = BitUtils.CountTrailingZeros32(Bpp);
|
_bppShift = BitUtils.CountTrailingZeros32(bpp);
|
||||||
|
|
||||||
SetMipLevel(0);
|
SetMipLevel(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetMipLevel(int Level)
|
public void SetMipLevel(int level)
|
||||||
{
|
{
|
||||||
BaseOffset = GetMipOffset(Level);
|
_baseOffset = GetMipOffset(level);
|
||||||
|
|
||||||
int Width = Math.Max(1, TexWidth >> Level);
|
int width = Math.Max(1, _texWidth >> level);
|
||||||
int Height = Math.Max(1, TexHeight >> Level);
|
int height = Math.Max(1, _texHeight >> level);
|
||||||
int Depth = Math.Max(1, TexDepth >> Level);
|
int depth = Math.Max(1, _texDepth >> level);
|
||||||
|
|
||||||
GobBlockSizes GbSizes = AdjustGobBlockSizes(Height, Depth);
|
GobBlockSizes gbSizes = AdjustGobBlockSizes(height, depth);
|
||||||
|
|
||||||
BhMask = GbSizes.Height - 1;
|
_bhMask = gbSizes.Height - 1;
|
||||||
BdMask = GbSizes.Depth - 1;
|
_bdMask = gbSizes.Depth - 1;
|
||||||
|
|
||||||
BhShift = BitUtils.CountTrailingZeros32(GbSizes.Height);
|
_bhShift = BitUtils.CountTrailingZeros32(gbSizes.Height);
|
||||||
BdShift = BitUtils.CountTrailingZeros32(GbSizes.Depth);
|
_bdShift = BitUtils.CountTrailingZeros32(gbSizes.Depth);
|
||||||
|
|
||||||
XShift = BitUtils.CountTrailingZeros32(GobSize * GbSizes.Height * GbSizes.Depth);
|
_xShift = BitUtils.CountTrailingZeros32(GobSize * gbSizes.Height * gbSizes.Depth);
|
||||||
|
|
||||||
RobAndSliceSizes GsSizes = GetRobAndSliceSizes(Width, Height, GbSizes);
|
RobAndSliceSizes gsSizes = GetRobAndSliceSizes(width, height, gbSizes);
|
||||||
|
|
||||||
RobSize = GsSizes.RobSize;
|
_robSize = gsSizes.RobSize;
|
||||||
SliceSize = GsSizes.SliceSize;
|
_sliceSize = gsSizes.SliceSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetImageSize(int MipsCount)
|
public int GetImageSize(int mipsCount)
|
||||||
{
|
{
|
||||||
int Size = GetMipOffset(MipsCount);
|
int size = GetMipOffset(mipsCount);
|
||||||
|
|
||||||
Size = (Size + 0x1fff) & ~0x1fff;
|
size = (size + 0x1fff) & ~0x1fff;
|
||||||
|
|
||||||
return Size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetMipOffset(int Level)
|
public int GetMipOffset(int level)
|
||||||
{
|
{
|
||||||
int TotalSize = 0;
|
int totalSize = 0;
|
||||||
|
|
||||||
for (int Index = 0; Index < Level; Index++)
|
for (int index = 0; index < level; index++)
|
||||||
{
|
{
|
||||||
int Width = Math.Max(1, TexWidth >> Index);
|
int width = Math.Max(1, _texWidth >> index);
|
||||||
int Height = Math.Max(1, TexHeight >> Index);
|
int height = Math.Max(1, _texHeight >> index);
|
||||||
int Depth = Math.Max(1, TexDepth >> Index);
|
int depth = Math.Max(1, _texDepth >> index);
|
||||||
|
|
||||||
GobBlockSizes GbSizes = AdjustGobBlockSizes(Height, Depth);
|
GobBlockSizes gbSizes = AdjustGobBlockSizes(height, depth);
|
||||||
|
|
||||||
RobAndSliceSizes RsSizes = GetRobAndSliceSizes(Width, Height, GbSizes);
|
RobAndSliceSizes rsSizes = GetRobAndSliceSizes(width, height, gbSizes);
|
||||||
|
|
||||||
TotalSize += BitUtils.DivRoundUp(Depth, GbSizes.Depth) * RsSizes.SliceSize;
|
totalSize += BitUtils.DivRoundUp(depth, gbSizes.Depth) * rsSizes.SliceSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TotalSize;
|
return totalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct GobBlockSizes
|
private struct GobBlockSizes
|
||||||
|
@ -109,32 +109,32 @@ namespace Ryujinx.Graphics.Texture
|
||||||
public int Height;
|
public int Height;
|
||||||
public int Depth;
|
public int Depth;
|
||||||
|
|
||||||
public GobBlockSizes(int GobBlockHeight, int GobBlockDepth)
|
public GobBlockSizes(int gobBlockHeight, int gobBlockDepth)
|
||||||
{
|
{
|
||||||
this.Height = GobBlockHeight;
|
Height = gobBlockHeight;
|
||||||
this.Depth = GobBlockDepth;
|
Depth = gobBlockDepth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private GobBlockSizes AdjustGobBlockSizes(int Height, int Depth)
|
private GobBlockSizes AdjustGobBlockSizes(int height, int depth)
|
||||||
{
|
{
|
||||||
int GobBlockHeight = TexGobBlockHeight;
|
int gobBlockHeight = _texGobBlockHeight;
|
||||||
int GobBlockDepth = TexGobBlockDepth;
|
int gobBlockDepth = _texGobBlockDepth;
|
||||||
|
|
||||||
int Pow2Height = BitUtils.Pow2RoundUp(Height);
|
int pow2Height = BitUtils.Pow2RoundUp(height);
|
||||||
int Pow2Depth = BitUtils.Pow2RoundUp(Depth);
|
int pow2Depth = BitUtils.Pow2RoundUp(depth);
|
||||||
|
|
||||||
while (GobBlockHeight * GobHeight > Pow2Height && GobBlockHeight > 1)
|
while (gobBlockHeight * GobHeight > pow2Height && gobBlockHeight > 1)
|
||||||
{
|
{
|
||||||
GobBlockHeight >>= 1;
|
gobBlockHeight >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (GobBlockDepth > Pow2Depth && GobBlockDepth > 1)
|
while (gobBlockDepth > pow2Depth && gobBlockDepth > 1)
|
||||||
{
|
{
|
||||||
GobBlockDepth >>= 1;
|
gobBlockDepth >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GobBlockSizes(GobBlockHeight, GobBlockDepth);
|
return new GobBlockSizes(gobBlockHeight, gobBlockDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct RobAndSliceSizes
|
private struct RobAndSliceSizes
|
||||||
|
@ -142,45 +142,45 @@ namespace Ryujinx.Graphics.Texture
|
||||||
public int RobSize;
|
public int RobSize;
|
||||||
public int SliceSize;
|
public int SliceSize;
|
||||||
|
|
||||||
public RobAndSliceSizes(int RobSize, int SliceSize)
|
public RobAndSliceSizes(int robSize, int sliceSize)
|
||||||
{
|
{
|
||||||
this.RobSize = RobSize;
|
RobSize = robSize;
|
||||||
this.SliceSize = SliceSize;
|
SliceSize = sliceSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private RobAndSliceSizes GetRobAndSliceSizes(int Width, int Height, GobBlockSizes GbSizes)
|
private RobAndSliceSizes GetRobAndSliceSizes(int width, int height, GobBlockSizes gbSizes)
|
||||||
{
|
{
|
||||||
int WidthInGobs = BitUtils.DivRoundUp(Width * TexBpp, GobWidth);
|
int widthInGobs = BitUtils.DivRoundUp(width * _texBpp, GobWidth);
|
||||||
|
|
||||||
int RobSize = GobSize * GbSizes.Height * GbSizes.Depth * WidthInGobs;
|
int robSize = GobSize * gbSizes.Height * gbSizes.Depth * widthInGobs;
|
||||||
|
|
||||||
int SliceSize = BitUtils.DivRoundUp(Height, GbSizes.Height * GobHeight) * RobSize;
|
int sliceSize = BitUtils.DivRoundUp(height, gbSizes.Height * GobHeight) * robSize;
|
||||||
|
|
||||||
return new RobAndSliceSizes(RobSize, SliceSize);
|
return new RobAndSliceSizes(robSize, sliceSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetSwizzleOffset(int X, int Y, int Z)
|
public int GetSwizzleOffset(int x, int y, int z)
|
||||||
{
|
{
|
||||||
X <<= BppShift;
|
x <<= _bppShift;
|
||||||
|
|
||||||
int YH = Y / GobHeight;
|
int yh = y / GobHeight;
|
||||||
|
|
||||||
int Position = (Z >> BdShift) * SliceSize + (YH >> BhShift) * RobSize;
|
int position = (z >> _bdShift) * _sliceSize + (yh >> _bhShift) * _robSize;
|
||||||
|
|
||||||
Position += (X / GobWidth) << XShift;
|
position += (x / GobWidth) << _xShift;
|
||||||
|
|
||||||
Position += (YH & BhMask) * GobSize;
|
position += (yh & _bhMask) * GobSize;
|
||||||
|
|
||||||
Position += ((Z & BdMask) * GobSize) << BhShift;
|
position += ((z & _bdMask) * GobSize) << _bhShift;
|
||||||
|
|
||||||
Position += ((X & 0x3f) >> 5) << 8;
|
position += ((x & 0x3f) >> 5) << 8;
|
||||||
Position += ((Y & 0x07) >> 1) << 6;
|
position += ((y & 0x07) >> 1) << 6;
|
||||||
Position += ((X & 0x1f) >> 4) << 5;
|
position += ((x & 0x1f) >> 4) << 5;
|
||||||
Position += ((Y & 0x01) >> 0) << 4;
|
position += ((y & 0x01) >> 0) << 4;
|
||||||
Position += ((X & 0x0f) >> 0) << 0;
|
position += ((x & 0x0f) >> 0) << 0;
|
||||||
|
|
||||||
return BaseOffset + Position;
|
return _baseOffset + position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,12 +2,12 @@ namespace Ryujinx.Graphics.Texture
|
||||||
{
|
{
|
||||||
interface ISwizzle
|
interface ISwizzle
|
||||||
{
|
{
|
||||||
int GetSwizzleOffset(int X, int Y, int Z);
|
int GetSwizzleOffset(int x, int y, int z);
|
||||||
|
|
||||||
void SetMipLevel(int Level);
|
void SetMipLevel(int level);
|
||||||
|
|
||||||
int GetMipOffset(int Level);
|
int GetMipOffset(int level);
|
||||||
|
|
||||||
int GetImageSize(int MipsCount);
|
int GetImageSize(int mipsCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using Ryujinx.Common;
|
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using Ryujinx.Graphics.Memory;
|
using Ryujinx.Graphics.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
@ -29,13 +28,13 @@ namespace Ryujinx.Graphics.Texture
|
||||||
|
|
||||||
public TargetBuffer Target { get; private set; }
|
public TargetBuffer Target { get; private set; }
|
||||||
|
|
||||||
public ImageDescriptor(int BytesPerPixel, int BlockWidth, int BlockHeight, int BlockDepth, TargetBuffer Target)
|
public ImageDescriptor(int bytesPerPixel, int blockWidth, int blockHeight, int blockDepth, TargetBuffer target)
|
||||||
{
|
{
|
||||||
this.BytesPerPixel = BytesPerPixel;
|
BytesPerPixel = bytesPerPixel;
|
||||||
this.BlockWidth = BlockWidth;
|
BlockWidth = blockWidth;
|
||||||
this.BlockHeight = BlockHeight;
|
BlockHeight = blockHeight;
|
||||||
this.BlockDepth = BlockDepth;
|
BlockDepth = blockDepth;
|
||||||
this.Target = Target;
|
Target = target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,26 +45,26 @@ namespace Ryujinx.Graphics.Texture
|
||||||
private const GalImageFormat Float = GalImageFormat.Float;
|
private const GalImageFormat Float = GalImageFormat.Float;
|
||||||
private const GalImageFormat Srgb = GalImageFormat.Srgb;
|
private const GalImageFormat Srgb = GalImageFormat.Srgb;
|
||||||
|
|
||||||
private static readonly Dictionary<GalTextureFormat, GalImageFormat> s_TextureTable =
|
private static readonly Dictionary<GalTextureFormat, GalImageFormat> TextureTable =
|
||||||
new Dictionary<GalTextureFormat, GalImageFormat>()
|
new Dictionary<GalTextureFormat, GalImageFormat>()
|
||||||
{
|
{
|
||||||
{ GalTextureFormat.RGBA32, GalImageFormat.RGBA32 | Sint | Uint | Float },
|
{ GalTextureFormat.Rgba32, GalImageFormat.Rgba32 | Sint | Uint | Float },
|
||||||
{ GalTextureFormat.RGBA16, GalImageFormat.RGBA16 | Snorm | Unorm | Sint | Uint | Float },
|
{ GalTextureFormat.Rgba16, GalImageFormat.Rgba16 | Snorm | Unorm | Sint | Uint | Float },
|
||||||
{ GalTextureFormat.RG32, GalImageFormat.RG32 | Sint | Uint | Float },
|
{ GalTextureFormat.Rg32, GalImageFormat.Rg32 | Sint | Uint | Float },
|
||||||
{ GalTextureFormat.RGBA8, GalImageFormat.RGBA8 | Snorm | Unorm | Sint | Uint | Srgb },
|
{ GalTextureFormat.Rgba8, GalImageFormat.Rgba8 | Snorm | Unorm | Sint | Uint | Srgb },
|
||||||
{ GalTextureFormat.RGB10A2, GalImageFormat.RGB10A2 | Snorm | Unorm | Sint | Uint },
|
{ GalTextureFormat.Rgb10A2, GalImageFormat.Rgb10A2 | Snorm | Unorm | Sint | Uint },
|
||||||
{ GalTextureFormat.RG8, GalImageFormat.RG8 | Snorm | Unorm | Sint | Uint },
|
{ GalTextureFormat.Rg8, GalImageFormat.Rg8 | Snorm | Unorm | Sint | Uint },
|
||||||
{ GalTextureFormat.R16, GalImageFormat.R16 | Snorm | Unorm | Sint | Uint | Float },
|
{ GalTextureFormat.R16, GalImageFormat.R16 | Snorm | Unorm | Sint | Uint | Float },
|
||||||
{ GalTextureFormat.R8, GalImageFormat.R8 | Snorm | Unorm | Sint | Uint },
|
{ GalTextureFormat.R8, GalImageFormat.R8 | Snorm | Unorm | Sint | Uint },
|
||||||
{ GalTextureFormat.RG16, GalImageFormat.RG16 | Snorm | Unorm | Sint | Float },
|
{ GalTextureFormat.Rg16, GalImageFormat.Rg16 | Snorm | Unorm | Sint | Float },
|
||||||
{ GalTextureFormat.R32, GalImageFormat.R32 | Sint | Uint | Float },
|
{ GalTextureFormat.R32, GalImageFormat.R32 | Sint | Uint | Float },
|
||||||
{ GalTextureFormat.RGBA4, GalImageFormat.RGBA4 | Unorm },
|
{ GalTextureFormat.Rgba4, GalImageFormat.Rgba4 | Unorm },
|
||||||
{ GalTextureFormat.RGB5A1, GalImageFormat.RGB5A1 | Unorm },
|
{ GalTextureFormat.Rgb5A1, GalImageFormat.Rgb5A1 | Unorm },
|
||||||
{ GalTextureFormat.RGB565, GalImageFormat.RGB565 | Unorm },
|
{ GalTextureFormat.Rgb565, GalImageFormat.Rgb565 | Unorm },
|
||||||
{ GalTextureFormat.R11G11B10F, GalImageFormat.R11G11B10 | Float },
|
{ GalTextureFormat.R11G11B10F, GalImageFormat.R11G11B10 | Float },
|
||||||
{ GalTextureFormat.D24S8, GalImageFormat.D24S8 | Unorm | Uint },
|
{ GalTextureFormat.D24S8, GalImageFormat.D24S8 | Unorm | Uint },
|
||||||
{ GalTextureFormat.D32F, GalImageFormat.D32 | Float },
|
{ GalTextureFormat.D32F, GalImageFormat.D32 | Float },
|
||||||
{ GalTextureFormat.D32FX24S8, GalImageFormat.D32S8 | Float },
|
{ GalTextureFormat.D32Fx24S8, GalImageFormat.D32S8 | Float },
|
||||||
{ GalTextureFormat.D16, GalImageFormat.D16 | Unorm },
|
{ GalTextureFormat.D16, GalImageFormat.D16 | Unorm },
|
||||||
|
|
||||||
//Compressed formats
|
//Compressed formats
|
||||||
|
@ -93,27 +92,27 @@ namespace Ryujinx.Graphics.Texture
|
||||||
{ GalTextureFormat.Astc2D10x6, GalImageFormat.Astc2D10x6 | Unorm | Srgb }
|
{ GalTextureFormat.Astc2D10x6, GalImageFormat.Astc2D10x6 | Unorm | Srgb }
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly Dictionary<GalImageFormat, ImageDescriptor> s_ImageTable =
|
private static readonly Dictionary<GalImageFormat, ImageDescriptor> ImageTable =
|
||||||
new Dictionary<GalImageFormat, ImageDescriptor>()
|
new Dictionary<GalImageFormat, ImageDescriptor>()
|
||||||
{
|
{
|
||||||
{ GalImageFormat.RGBA32, new ImageDescriptor(16, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.Rgba32, new ImageDescriptor(16, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.RGBA16, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.Rgba16, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.RG32, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.Rg32, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.RGBX8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.Rgbx8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.RGBA8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.Rgba8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.BGRA8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.Bgra8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.RGB10A2, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.Rgb10A2, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.R32, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.R32, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.RGBA4, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.Rgba4, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.BptcSfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
|
{ GalImageFormat.BptcSfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.BptcUfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
|
{ GalImageFormat.BptcUfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.BGR5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.Bgr5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.RGB5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.Rgb5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.RGB565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.Rgb565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.BGR565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.Bgr565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.BptcUnorm, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
|
{ GalImageFormat.BptcUnorm, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.RG16, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.Rg16, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.RG8, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.Rg8, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.R16, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.R16, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.R8, new ImageDescriptor(1, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.R8, new ImageDescriptor(1, 1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.R11G11B10, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
|
{ GalImageFormat.R11G11B10, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
|
||||||
|
@ -145,77 +144,77 @@ namespace Ryujinx.Graphics.Texture
|
||||||
};
|
};
|
||||||
|
|
||||||
public static GalImageFormat ConvertTexture(
|
public static GalImageFormat ConvertTexture(
|
||||||
GalTextureFormat Format,
|
GalTextureFormat format,
|
||||||
GalTextureType RType,
|
GalTextureType rType,
|
||||||
GalTextureType GType,
|
GalTextureType gType,
|
||||||
GalTextureType BType,
|
GalTextureType bType,
|
||||||
GalTextureType AType,
|
GalTextureType aType,
|
||||||
bool ConvSrgb)
|
bool convSrgb)
|
||||||
{
|
{
|
||||||
if (!s_TextureTable.TryGetValue(Format, out GalImageFormat ImageFormat))
|
if (!TextureTable.TryGetValue(format, out GalImageFormat imageFormat))
|
||||||
{
|
{
|
||||||
throw new NotImplementedException($"Format 0x{((int)Format):x} not implemented!");
|
throw new NotImplementedException($"Format 0x{((int)format):x} not implemented!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!HasDepth(ImageFormat) && (RType != GType || RType != BType || RType != AType))
|
if (!HasDepth(imageFormat) && (rType != gType || rType != bType || rType != aType))
|
||||||
{
|
{
|
||||||
throw new NotImplementedException($"Per component types are not implemented!");
|
throw new NotImplementedException("Per component types are not implemented!");
|
||||||
}
|
}
|
||||||
|
|
||||||
GalImageFormat FormatType = ConvSrgb ? Srgb : GetFormatType(RType);
|
GalImageFormat formatType = convSrgb ? Srgb : GetFormatType(rType);
|
||||||
|
|
||||||
GalImageFormat CombinedFormat = (ImageFormat & GalImageFormat.FormatMask) | FormatType;
|
GalImageFormat combinedFormat = (imageFormat & GalImageFormat.FormatMask) | formatType;
|
||||||
|
|
||||||
if (!ImageFormat.HasFlag(FormatType))
|
if (!imageFormat.HasFlag(formatType))
|
||||||
{
|
{
|
||||||
throw new NotImplementedException($"Format \"{CombinedFormat}\" not implemented!");
|
throw new NotImplementedException($"Format \"{combinedFormat}\" not implemented!");
|
||||||
}
|
}
|
||||||
|
|
||||||
return CombinedFormat;
|
return combinedFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GalImageFormat ConvertSurface(GalSurfaceFormat Format)
|
public static GalImageFormat ConvertSurface(GalSurfaceFormat format)
|
||||||
{
|
{
|
||||||
switch (Format)
|
switch (format)
|
||||||
{
|
{
|
||||||
case GalSurfaceFormat.RGBA32Float: return GalImageFormat.RGBA32 | Float;
|
case GalSurfaceFormat.Rgba32Float: return GalImageFormat.Rgba32 | Float;
|
||||||
case GalSurfaceFormat.RGBA32Uint: return GalImageFormat.RGBA32 | Uint;
|
case GalSurfaceFormat.Rgba32Uint: return GalImageFormat.Rgba32 | Uint;
|
||||||
case GalSurfaceFormat.RGBA16Float: return GalImageFormat.RGBA16 | Float;
|
case GalSurfaceFormat.Rgba16Float: return GalImageFormat.Rgba16 | Float;
|
||||||
case GalSurfaceFormat.RGBA16Unorm: return GalImageFormat.RGBA16 | Unorm;
|
case GalSurfaceFormat.Rgba16Unorm: return GalImageFormat.Rgba16 | Unorm;
|
||||||
case GalSurfaceFormat.RG32Float: return GalImageFormat.RG32 | Float;
|
case GalSurfaceFormat.Rg32Float: return GalImageFormat.Rg32 | Float;
|
||||||
case GalSurfaceFormat.RG32Sint: return GalImageFormat.RG32 | Sint;
|
case GalSurfaceFormat.Rg32Sint: return GalImageFormat.Rg32 | Sint;
|
||||||
case GalSurfaceFormat.RG32Uint: return GalImageFormat.RG32 | Uint;
|
case GalSurfaceFormat.Rg32Uint: return GalImageFormat.Rg32 | Uint;
|
||||||
case GalSurfaceFormat.BGRA8Unorm: return GalImageFormat.BGRA8 | Unorm;
|
case GalSurfaceFormat.Bgra8Unorm: return GalImageFormat.Bgra8 | Unorm;
|
||||||
case GalSurfaceFormat.BGRA8Srgb: return GalImageFormat.BGRA8 | Srgb;
|
case GalSurfaceFormat.Bgra8Srgb: return GalImageFormat.Bgra8 | Srgb;
|
||||||
case GalSurfaceFormat.RGB10A2Unorm: return GalImageFormat.RGB10A2 | Unorm;
|
case GalSurfaceFormat.Rgb10A2Unorm: return GalImageFormat.Rgb10A2 | Unorm;
|
||||||
case GalSurfaceFormat.RGBA8Unorm: return GalImageFormat.RGBA8 | Unorm;
|
case GalSurfaceFormat.Rgba8Unorm: return GalImageFormat.Rgba8 | Unorm;
|
||||||
case GalSurfaceFormat.RGBA8Srgb: return GalImageFormat.RGBA8 | Srgb;
|
case GalSurfaceFormat.Rgba8Srgb: return GalImageFormat.Rgba8 | Srgb;
|
||||||
case GalSurfaceFormat.RGBA8Snorm: return GalImageFormat.RGBA8 | Snorm;
|
case GalSurfaceFormat.Rgba8Snorm: return GalImageFormat.Rgba8 | Snorm;
|
||||||
case GalSurfaceFormat.RG16Snorm: return GalImageFormat.RG16 | Snorm;
|
case GalSurfaceFormat.Rg16Snorm: return GalImageFormat.Rg16 | Snorm;
|
||||||
case GalSurfaceFormat.RG16Unorm: return GalImageFormat.RG16 | Unorm;
|
case GalSurfaceFormat.Rg16Unorm: return GalImageFormat.Rg16 | Unorm;
|
||||||
case GalSurfaceFormat.RG16Sint: return GalImageFormat.RG16 | Sint;
|
case GalSurfaceFormat.Rg16Sint: return GalImageFormat.Rg16 | Sint;
|
||||||
case GalSurfaceFormat.RG16Float: return GalImageFormat.RG16 | Float;
|
case GalSurfaceFormat.Rg16Float: return GalImageFormat.Rg16 | Float;
|
||||||
case GalSurfaceFormat.R11G11B10Float: return GalImageFormat.R11G11B10 | Float;
|
case GalSurfaceFormat.R11G11B10Float: return GalImageFormat.R11G11B10 | Float;
|
||||||
case GalSurfaceFormat.R32Float: return GalImageFormat.R32 | Float;
|
case GalSurfaceFormat.R32Float: return GalImageFormat.R32 | Float;
|
||||||
case GalSurfaceFormat.R32Uint: return GalImageFormat.R32 | Uint;
|
case GalSurfaceFormat.R32Uint: return GalImageFormat.R32 | Uint;
|
||||||
case GalSurfaceFormat.RG8Unorm: return GalImageFormat.RG8 | Unorm;
|
case GalSurfaceFormat.Rg8Unorm: return GalImageFormat.Rg8 | Unorm;
|
||||||
case GalSurfaceFormat.RG8Snorm: return GalImageFormat.RG8 | Snorm;
|
case GalSurfaceFormat.Rg8Snorm: return GalImageFormat.Rg8 | Snorm;
|
||||||
case GalSurfaceFormat.R16Float: return GalImageFormat.R16 | Float;
|
case GalSurfaceFormat.R16Float: return GalImageFormat.R16 | Float;
|
||||||
case GalSurfaceFormat.R16Unorm: return GalImageFormat.R16 | Unorm;
|
case GalSurfaceFormat.R16Unorm: return GalImageFormat.R16 | Unorm;
|
||||||
case GalSurfaceFormat.R16Uint: return GalImageFormat.R16 | Uint;
|
case GalSurfaceFormat.R16Uint: return GalImageFormat.R16 | Uint;
|
||||||
case GalSurfaceFormat.R8Unorm: return GalImageFormat.R8 | Unorm;
|
case GalSurfaceFormat.R8Unorm: return GalImageFormat.R8 | Unorm;
|
||||||
case GalSurfaceFormat.R8Uint: return GalImageFormat.R8 | Uint;
|
case GalSurfaceFormat.R8Uint: return GalImageFormat.R8 | Uint;
|
||||||
case GalSurfaceFormat.B5G6R5Unorm: return GalImageFormat.RGB565 | Unorm;
|
case GalSurfaceFormat.B5G6R5Unorm: return GalImageFormat.Rgb565 | Unorm;
|
||||||
case GalSurfaceFormat.BGR5A1Unorm: return GalImageFormat.BGR5A1 | Unorm;
|
case GalSurfaceFormat.Bgr5A1Unorm: return GalImageFormat.Bgr5A1 | Unorm;
|
||||||
case GalSurfaceFormat.RGBX8Unorm: return GalImageFormat.RGBX8 | Unorm;
|
case GalSurfaceFormat.Rgbx8Unorm: return GalImageFormat.Rgbx8 | Unorm;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException(Format.ToString());
|
throw new NotImplementedException(format.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GalImageFormat ConvertZeta(GalZetaFormat Format)
|
public static GalImageFormat ConvertZeta(GalZetaFormat format)
|
||||||
{
|
{
|
||||||
switch (Format)
|
switch (format)
|
||||||
{
|
{
|
||||||
case GalZetaFormat.D32Float: return GalImageFormat.D32 | Float;
|
case GalZetaFormat.D32Float: return GalImageFormat.D32 | Float;
|
||||||
case GalZetaFormat.S8D24Unorm: return GalImageFormat.D24S8 | Unorm;
|
case GalZetaFormat.S8D24Unorm: return GalImageFormat.D24S8 | Unorm;
|
||||||
|
@ -225,268 +224,268 @@ namespace Ryujinx.Graphics.Texture
|
||||||
case GalZetaFormat.D32S8X24Float: return GalImageFormat.D32S8 | Float;
|
case GalZetaFormat.D32S8X24Float: return GalImageFormat.D32S8 | Float;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException(Format.ToString());
|
throw new NotImplementedException(format.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] ReadTexture(IMemory Memory, GalImage Image, long Position)
|
public static byte[] ReadTexture(IMemory memory, GalImage image, long position)
|
||||||
{
|
{
|
||||||
MemoryManager CpuMemory;
|
MemoryManager cpuMemory;
|
||||||
|
|
||||||
if (Memory is NvGpuVmm Vmm)
|
if (memory is NvGpuVmm vmm)
|
||||||
{
|
{
|
||||||
CpuMemory = Vmm.Memory;
|
cpuMemory = vmm.Memory;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CpuMemory = (MemoryManager)Memory;
|
cpuMemory = (MemoryManager)memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Image);
|
ISwizzle swizzle = TextureHelper.GetSwizzle(image);
|
||||||
|
|
||||||
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
ImageDescriptor desc = GetImageDescriptor(image.Format);
|
||||||
|
|
||||||
(int Width, int Height, int Depth) = GetImageSizeInBlocks(Image);
|
(int width, int height, int depth) = GetImageSizeInBlocks(image);
|
||||||
|
|
||||||
int BytesPerPixel = Desc.BytesPerPixel;
|
int bytesPerPixel = desc.BytesPerPixel;
|
||||||
|
|
||||||
//Note: Each row of the texture needs to be aligned to 4 bytes.
|
//Note: Each row of the texture needs to be aligned to 4 bytes.
|
||||||
int Pitch = (Width * BytesPerPixel + 3) & ~3;
|
int pitch = (width * bytesPerPixel + 3) & ~3;
|
||||||
|
|
||||||
|
|
||||||
int DataLayerSize = Height * Pitch * Depth;
|
int dataLayerSize = height * pitch * depth;
|
||||||
byte[] Data = new byte[DataLayerSize * Image.LayerCount];
|
byte[] data = new byte[dataLayerSize * image.LayerCount];
|
||||||
|
|
||||||
int TargetMipLevel = Image.MaxMipmapLevel <= 1 ? 1 : Image.MaxMipmapLevel - 1;
|
int targetMipLevel = image.MaxMipmapLevel <= 1 ? 1 : image.MaxMipmapLevel - 1;
|
||||||
int LayerOffset = ImageUtils.GetLayerOffset(Image, TargetMipLevel);
|
int layerOffset = GetLayerOffset(image, targetMipLevel);
|
||||||
|
|
||||||
for (int Layer = 0; Layer < Image.LayerCount; Layer++)
|
for (int layer = 0; layer < image.LayerCount; layer++)
|
||||||
{
|
{
|
||||||
for (int Z = 0; Z < Depth; Z++)
|
for (int z = 0; z < depth; z++)
|
||||||
{
|
{
|
||||||
for (int Y = 0; Y < Height; Y++)
|
for (int y = 0; y < height; y++)
|
||||||
{
|
{
|
||||||
int OutOffs = (DataLayerSize * Layer) + Y * Pitch + (Z * Width * Height * BytesPerPixel);
|
int outOffs = (dataLayerSize * layer) + y * pitch + (z * width * height * bytesPerPixel);
|
||||||
|
|
||||||
for (int X = 0; X < Width; X++)
|
for (int x = 0; x < width; x++)
|
||||||
{
|
{
|
||||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y, Z);
|
long offset = (uint)swizzle.GetSwizzleOffset(x, y, z);
|
||||||
|
|
||||||
CpuMemory.ReadBytes(Position + (LayerOffset * Layer) + Offset, Data, OutOffs, BytesPerPixel);
|
cpuMemory.ReadBytes(position + (layerOffset * layer) + offset, data, outOffs, bytesPerPixel);
|
||||||
|
|
||||||
OutOffs += BytesPerPixel;
|
outOffs += bytesPerPixel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WriteTexture(NvGpuVmm Vmm, GalImage Image, long Position, byte[] Data)
|
public static void WriteTexture(NvGpuVmm vmm, GalImage image, long position, byte[] data)
|
||||||
{
|
{
|
||||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Image);
|
ISwizzle swizzle = TextureHelper.GetSwizzle(image);
|
||||||
|
|
||||||
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
ImageDescriptor desc = GetImageDescriptor(image.Format);
|
||||||
|
|
||||||
(int Width, int Height, int Depth) = ImageUtils.GetImageSizeInBlocks(Image);
|
(int width, int height, int depth) = GetImageSizeInBlocks(image);
|
||||||
|
|
||||||
int BytesPerPixel = Desc.BytesPerPixel;
|
int bytesPerPixel = desc.BytesPerPixel;
|
||||||
|
|
||||||
int InOffs = 0;
|
int inOffs = 0;
|
||||||
|
|
||||||
for (int Z = 0; Z < Depth; Z++)
|
for (int z = 0; z < depth; z++)
|
||||||
for (int Y = 0; Y < Height; Y++)
|
for (int y = 0; y < height; y++)
|
||||||
for (int X = 0; X < Width; X++)
|
for (int x = 0; x < width; x++)
|
||||||
{
|
{
|
||||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y, Z);
|
long offset = (uint)swizzle.GetSwizzleOffset(x, y, z);
|
||||||
|
|
||||||
Vmm.Memory.WriteBytes(Position + Offset, Data, InOffs, BytesPerPixel);
|
vmm.Memory.WriteBytes(position + offset, data, inOffs, bytesPerPixel);
|
||||||
|
|
||||||
InOffs += BytesPerPixel;
|
inOffs += bytesPerPixel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Support non 2D
|
// TODO: Support non 2D
|
||||||
public static bool CopyTexture(
|
public static bool CopyTexture(
|
||||||
NvGpuVmm Vmm,
|
NvGpuVmm vmm,
|
||||||
GalImage SrcImage,
|
GalImage srcImage,
|
||||||
GalImage DstImage,
|
GalImage dstImage,
|
||||||
long SrcAddress,
|
long srcAddress,
|
||||||
long DstAddress,
|
long dstAddress,
|
||||||
int SrcX,
|
int srcX,
|
||||||
int SrcY,
|
int srcY,
|
||||||
int DstX,
|
int dstX,
|
||||||
int DstY,
|
int dstY,
|
||||||
int Width,
|
int width,
|
||||||
int Height)
|
int height)
|
||||||
{
|
{
|
||||||
ISwizzle SrcSwizzle = TextureHelper.GetSwizzle(SrcImage);
|
ISwizzle srcSwizzle = TextureHelper.GetSwizzle(srcImage);
|
||||||
ISwizzle DstSwizzle = TextureHelper.GetSwizzle(DstImage);
|
ISwizzle dstSwizzle = TextureHelper.GetSwizzle(dstImage);
|
||||||
|
|
||||||
ImageDescriptor Desc = GetImageDescriptor(SrcImage.Format);
|
ImageDescriptor desc = GetImageDescriptor(srcImage.Format);
|
||||||
|
|
||||||
if (GetImageDescriptor(DstImage.Format).BytesPerPixel != Desc.BytesPerPixel)
|
if (GetImageDescriptor(dstImage.Format).BytesPerPixel != desc.BytesPerPixel)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int BytesPerPixel = Desc.BytesPerPixel;
|
int bytesPerPixel = desc.BytesPerPixel;
|
||||||
|
|
||||||
for (int Y = 0; Y < Height; Y++)
|
for (int y = 0; y < height; y++)
|
||||||
for (int X = 0; X < Width; X++)
|
for (int x = 0; x < width; x++)
|
||||||
{
|
{
|
||||||
long SrcOffset = (uint)SrcSwizzle.GetSwizzleOffset(SrcX + X, SrcY + Y, 0);
|
long srcOffset = (uint)srcSwizzle.GetSwizzleOffset(srcX + x, srcY + y, 0);
|
||||||
long DstOffset = (uint)DstSwizzle.GetSwizzleOffset(DstX + X, DstY + Y, 0);
|
long dstOffset = (uint)dstSwizzle.GetSwizzleOffset(dstX + x, dstY + y, 0);
|
||||||
|
|
||||||
byte[] Texel = Vmm.ReadBytes(SrcAddress + SrcOffset, BytesPerPixel);
|
byte[] texel = vmm.ReadBytes(srcAddress + srcOffset, bytesPerPixel);
|
||||||
|
|
||||||
Vmm.WriteBytes(DstAddress + DstOffset, Texel);
|
vmm.WriteBytes(dstAddress + dstOffset, texel);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetSize(GalImage Image)
|
public static int GetSize(GalImage image)
|
||||||
{
|
{
|
||||||
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
ImageDescriptor desc = GetImageDescriptor(image.Format);
|
||||||
|
|
||||||
int ComponentCount = GetCoordsCountTextureTarget(Image.TextureTarget);
|
int componentCount = GetCoordsCountTextureTarget(image.TextureTarget);
|
||||||
|
|
||||||
if (IsArray(Image.TextureTarget))
|
if (IsArray(image.TextureTarget))
|
||||||
ComponentCount--;
|
componentCount--;
|
||||||
|
|
||||||
int Width = DivRoundUp(Image.Width, Desc.BlockWidth);
|
int width = DivRoundUp(image.Width, desc.BlockWidth);
|
||||||
int Height = DivRoundUp(Image.Height, Desc.BlockHeight);
|
int height = DivRoundUp(image.Height, desc.BlockHeight);
|
||||||
int Depth = DivRoundUp(Image.Depth, Desc.BlockDepth);
|
int depth = DivRoundUp(image.Depth, desc.BlockDepth);
|
||||||
|
|
||||||
switch (ComponentCount)
|
switch (componentCount)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
return Desc.BytesPerPixel * Width * Image.LayerCount;
|
return desc.BytesPerPixel * width * image.LayerCount;
|
||||||
case 2:
|
case 2:
|
||||||
return Desc.BytesPerPixel * Width * Height * Image.LayerCount;
|
return desc.BytesPerPixel * width * height * image.LayerCount;
|
||||||
case 3:
|
case 3:
|
||||||
return Desc.BytesPerPixel * Width * Height * Depth * Image.LayerCount;
|
return desc.BytesPerPixel * width * height * depth * image.LayerCount;
|
||||||
default:
|
default:
|
||||||
throw new InvalidOperationException($"Invalid component count: {ComponentCount}");
|
throw new InvalidOperationException($"Invalid component count: {componentCount}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetGpuSize(GalImage Image, bool forcePitch = false)
|
public static int GetGpuSize(GalImage image, bool forcePitch = false)
|
||||||
{
|
{
|
||||||
return TextureHelper.GetSwizzle(Image).GetImageSize(Image.MaxMipmapLevel) * Image.LayerCount;
|
return TextureHelper.GetSwizzle(image).GetImageSize(image.MaxMipmapLevel) * image.LayerCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetLayerOffset(GalImage Image, int MipLevel)
|
public static int GetLayerOffset(GalImage image, int mipLevel)
|
||||||
{
|
{
|
||||||
if (MipLevel <= 0)
|
if (mipLevel <= 0)
|
||||||
{
|
{
|
||||||
MipLevel = 1;
|
mipLevel = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TextureHelper.GetSwizzle(Image).GetMipOffset(MipLevel);
|
return TextureHelper.GetSwizzle(image).GetMipOffset(mipLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetPitch(GalImageFormat Format, int Width)
|
public static int GetPitch(GalImageFormat format, int width)
|
||||||
{
|
{
|
||||||
ImageDescriptor Desc = GetImageDescriptor(Format);
|
ImageDescriptor desc = GetImageDescriptor(format);
|
||||||
|
|
||||||
int Pitch = Desc.BytesPerPixel * DivRoundUp(Width, Desc.BlockWidth);
|
int pitch = desc.BytesPerPixel * DivRoundUp(width, desc.BlockWidth);
|
||||||
|
|
||||||
Pitch = (Pitch + 0x1f) & ~0x1f;
|
pitch = (pitch + 0x1f) & ~0x1f;
|
||||||
|
|
||||||
return Pitch;
|
return pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetBlockWidth(GalImageFormat Format)
|
public static int GetBlockWidth(GalImageFormat format)
|
||||||
{
|
{
|
||||||
return GetImageDescriptor(Format).BlockWidth;
|
return GetImageDescriptor(format).BlockWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetBlockHeight(GalImageFormat Format)
|
public static int GetBlockHeight(GalImageFormat format)
|
||||||
{
|
{
|
||||||
return GetImageDescriptor(Format).BlockHeight;
|
return GetImageDescriptor(format).BlockHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetBlockDepth(GalImageFormat Format)
|
public static int GetBlockDepth(GalImageFormat format)
|
||||||
{
|
{
|
||||||
return GetImageDescriptor(Format).BlockDepth;
|
return GetImageDescriptor(format).BlockDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetAlignedWidth(GalImage Image)
|
public static int GetAlignedWidth(GalImage image)
|
||||||
{
|
{
|
||||||
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
ImageDescriptor desc = GetImageDescriptor(image.Format);
|
||||||
|
|
||||||
int AlignMask;
|
int alignMask;
|
||||||
|
|
||||||
if (Image.Layout == GalMemoryLayout.BlockLinear)
|
if (image.Layout == GalMemoryLayout.BlockLinear)
|
||||||
{
|
{
|
||||||
AlignMask = Image.TileWidth * (64 / Desc.BytesPerPixel) - 1;
|
alignMask = image.TileWidth * (64 / desc.BytesPerPixel) - 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AlignMask = (32 / Desc.BytesPerPixel) - 1;
|
alignMask = (32 / desc.BytesPerPixel) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (Image.Width + AlignMask) & ~AlignMask;
|
return (image.Width + alignMask) & ~alignMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (int Width, int Height, int Depth) GetImageSizeInBlocks(GalImage Image)
|
public static (int Width, int Height, int Depth) GetImageSizeInBlocks(GalImage image)
|
||||||
{
|
{
|
||||||
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
ImageDescriptor desc = GetImageDescriptor(image.Format);
|
||||||
|
|
||||||
return (DivRoundUp(Image.Width, Desc.BlockWidth),
|
return (DivRoundUp(image.Width, desc.BlockWidth),
|
||||||
DivRoundUp(Image.Height, Desc.BlockHeight),
|
DivRoundUp(image.Height, desc.BlockHeight),
|
||||||
DivRoundUp(Image.Depth, Desc.BlockDepth));
|
DivRoundUp(image.Depth, desc.BlockDepth));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetBytesPerPixel(GalImageFormat Format)
|
public static int GetBytesPerPixel(GalImageFormat format)
|
||||||
{
|
{
|
||||||
return GetImageDescriptor(Format).BytesPerPixel;
|
return GetImageDescriptor(format).BytesPerPixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int DivRoundUp(int LHS, int RHS)
|
private static int DivRoundUp(int lhs, int rhs)
|
||||||
{
|
{
|
||||||
return (LHS + (RHS - 1)) / RHS;
|
return (lhs + (rhs - 1)) / rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool HasColor(GalImageFormat Format)
|
public static bool HasColor(GalImageFormat format)
|
||||||
{
|
{
|
||||||
return (GetImageDescriptor(Format).Target & TargetBuffer.Color) != 0;
|
return (GetImageDescriptor(format).Target & TargetBuffer.Color) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool HasDepth(GalImageFormat Format)
|
public static bool HasDepth(GalImageFormat format)
|
||||||
{
|
{
|
||||||
return (GetImageDescriptor(Format).Target & TargetBuffer.Depth) != 0;
|
return (GetImageDescriptor(format).Target & TargetBuffer.Depth) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool HasStencil(GalImageFormat Format)
|
public static bool HasStencil(GalImageFormat format)
|
||||||
{
|
{
|
||||||
return (GetImageDescriptor(Format).Target & TargetBuffer.Stencil) != 0;
|
return (GetImageDescriptor(format).Target & TargetBuffer.Stencil) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsCompressed(GalImageFormat Format)
|
public static bool IsCompressed(GalImageFormat format)
|
||||||
{
|
{
|
||||||
ImageDescriptor Desc = GetImageDescriptor(Format);
|
ImageDescriptor desc = GetImageDescriptor(format);
|
||||||
|
|
||||||
return (Desc.BlockWidth | Desc.BlockHeight) != 1;
|
return (desc.BlockWidth | desc.BlockHeight) != 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ImageDescriptor GetImageDescriptor(GalImageFormat Format)
|
private static ImageDescriptor GetImageDescriptor(GalImageFormat format)
|
||||||
{
|
{
|
||||||
GalImageFormat PixelFormat = Format & GalImageFormat.FormatMask;
|
GalImageFormat pixelFormat = format & GalImageFormat.FormatMask;
|
||||||
|
|
||||||
if (s_ImageTable.TryGetValue(PixelFormat, out ImageDescriptor Descriptor))
|
if (ImageTable.TryGetValue(pixelFormat, out ImageDescriptor descriptor))
|
||||||
{
|
{
|
||||||
return Descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException($"Format \"{PixelFormat}\" not implemented!");
|
throw new NotImplementedException($"Format \"{pixelFormat}\" not implemented!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GalImageFormat GetFormatType(GalTextureType Type)
|
private static GalImageFormat GetFormatType(GalTextureType type)
|
||||||
{
|
{
|
||||||
switch (Type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case GalTextureType.Snorm: return Snorm;
|
case GalTextureType.Snorm: return Snorm;
|
||||||
case GalTextureType.Unorm: return Unorm;
|
case GalTextureType.Unorm: return Unorm;
|
||||||
|
@ -494,13 +493,13 @@ namespace Ryujinx.Graphics.Texture
|
||||||
case GalTextureType.Uint: return Uint;
|
case GalTextureType.Uint: return Uint;
|
||||||
case GalTextureType.Float: return Float;
|
case GalTextureType.Float: return Float;
|
||||||
|
|
||||||
default: throw new NotImplementedException(((int)Type).ToString());
|
default: throw new NotImplementedException(((int)type).ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextureTarget GetTextureTarget(GalTextureTarget GalTextureTarget)
|
public static TextureTarget GetTextureTarget(GalTextureTarget galTextureTarget)
|
||||||
{
|
{
|
||||||
switch (GalTextureTarget)
|
switch (galTextureTarget)
|
||||||
{
|
{
|
||||||
case GalTextureTarget.OneD:
|
case GalTextureTarget.OneD:
|
||||||
return TextureTarget.Texture1D;
|
return TextureTarget.Texture1D;
|
||||||
|
@ -520,13 +519,13 @@ namespace Ryujinx.Graphics.Texture
|
||||||
case GalTextureTarget.CubeArray:
|
case GalTextureTarget.CubeArray:
|
||||||
return TextureTarget.TextureCubeMapArray;
|
return TextureTarget.TextureCubeMapArray;
|
||||||
default:
|
default:
|
||||||
throw new NotSupportedException($"Texture target {GalTextureTarget} currently not supported!");
|
throw new NotSupportedException($"Texture target {galTextureTarget} currently not supported!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsArray(GalTextureTarget TextureTarget)
|
public static bool IsArray(GalTextureTarget textureTarget)
|
||||||
{
|
{
|
||||||
switch (TextureTarget)
|
switch (textureTarget)
|
||||||
{
|
{
|
||||||
case GalTextureTarget.OneDArray:
|
case GalTextureTarget.OneDArray:
|
||||||
case GalTextureTarget.TwoDArray:
|
case GalTextureTarget.TwoDArray:
|
||||||
|
@ -537,9 +536,9 @@ namespace Ryujinx.Graphics.Texture
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetCoordsCountTextureTarget(GalTextureTarget TextureTarget)
|
public static int GetCoordsCountTextureTarget(GalTextureTarget textureTarget)
|
||||||
{
|
{
|
||||||
switch (TextureTarget)
|
switch (textureTarget)
|
||||||
{
|
{
|
||||||
case GalTextureTarget.OneD:
|
case GalTextureTarget.OneD:
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -555,7 +554,7 @@ namespace Ryujinx.Graphics.Texture
|
||||||
case GalTextureTarget.CubeArray:
|
case GalTextureTarget.CubeArray:
|
||||||
return 4;
|
return 4;
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException($"TextureTarget.{TextureTarget} not implemented yet.");
|
throw new NotImplementedException($"TextureTarget.{textureTarget} not implemented yet.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,81 +12,81 @@ namespace Ryujinx.Graphics.Texture
|
||||||
Trit
|
Trit
|
||||||
}
|
}
|
||||||
|
|
||||||
EIntegerEncoding Encoding;
|
EIntegerEncoding _encoding;
|
||||||
public int NumberBits { get; private set; }
|
public int NumberBits { get; private set; }
|
||||||
public int BitValue { get; private set; }
|
public int BitValue { get; private set; }
|
||||||
public int TritValue { get; private set; }
|
public int TritValue { get; private set; }
|
||||||
public int QuintValue { get; private set; }
|
public int QuintValue { get; private set; }
|
||||||
|
|
||||||
public IntegerEncoded(EIntegerEncoding _Encoding, int NumBits)
|
public IntegerEncoded(EIntegerEncoding encoding, int numBits)
|
||||||
{
|
{
|
||||||
Encoding = _Encoding;
|
_encoding = encoding;
|
||||||
NumberBits = NumBits;
|
NumberBits = numBits;
|
||||||
BitValue = 0;
|
BitValue = 0;
|
||||||
TritValue = 0;
|
TritValue = 0;
|
||||||
QuintValue = 0;
|
QuintValue = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool MatchesEncoding(IntegerEncoded Other)
|
public bool MatchesEncoding(IntegerEncoded other)
|
||||||
{
|
{
|
||||||
return Encoding == Other.Encoding && NumberBits == Other.NumberBits;
|
return _encoding == other._encoding && NumberBits == other.NumberBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EIntegerEncoding GetEncoding()
|
public EIntegerEncoding GetEncoding()
|
||||||
{
|
{
|
||||||
return Encoding;
|
return _encoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetBitLength(int NumberVals)
|
public int GetBitLength(int numberVals)
|
||||||
{
|
{
|
||||||
int TotalBits = NumberBits * NumberVals;
|
int totalBits = NumberBits * numberVals;
|
||||||
if (Encoding == EIntegerEncoding.Trit)
|
if (_encoding == EIntegerEncoding.Trit)
|
||||||
{
|
{
|
||||||
TotalBits += (NumberVals * 8 + 4) / 5;
|
totalBits += (numberVals * 8 + 4) / 5;
|
||||||
}
|
}
|
||||||
else if (Encoding == EIntegerEncoding.Quint)
|
else if (_encoding == EIntegerEncoding.Quint)
|
||||||
{
|
{
|
||||||
TotalBits += (NumberVals * 7 + 2) / 3;
|
totalBits += (numberVals * 7 + 2) / 3;
|
||||||
}
|
}
|
||||||
return TotalBits;
|
return totalBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IntegerEncoded CreateEncoding(int MaxVal)
|
public static IntegerEncoded CreateEncoding(int maxVal)
|
||||||
{
|
{
|
||||||
while (MaxVal > 0)
|
while (maxVal > 0)
|
||||||
{
|
{
|
||||||
int Check = MaxVal + 1;
|
int check = maxVal + 1;
|
||||||
|
|
||||||
// Is maxVal a power of two?
|
// Is maxVal a power of two?
|
||||||
if ((Check & (Check - 1)) == 0)
|
if ((check & (check - 1)) == 0)
|
||||||
{
|
{
|
||||||
return new IntegerEncoded(EIntegerEncoding.JustBits, BitArrayStream.PopCnt(MaxVal));
|
return new IntegerEncoded(EIntegerEncoding.JustBits, BitArrayStream.PopCnt(maxVal));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is maxVal of the type 3*2^n - 1?
|
// Is maxVal of the type 3*2^n - 1?
|
||||||
if ((Check % 3 == 0) && ((Check / 3) & ((Check / 3) - 1)) == 0)
|
if ((check % 3 == 0) && ((check / 3) & ((check / 3) - 1)) == 0)
|
||||||
{
|
{
|
||||||
return new IntegerEncoded(EIntegerEncoding.Trit, BitArrayStream.PopCnt(Check / 3 - 1));
|
return new IntegerEncoded(EIntegerEncoding.Trit, BitArrayStream.PopCnt(check / 3 - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is maxVal of the type 5*2^n - 1?
|
// Is maxVal of the type 5*2^n - 1?
|
||||||
if ((Check % 5 == 0) && ((Check / 5) & ((Check / 5) - 1)) == 0)
|
if ((check % 5 == 0) && ((check / 5) & ((check / 5) - 1)) == 0)
|
||||||
{
|
{
|
||||||
return new IntegerEncoded(EIntegerEncoding.Quint, BitArrayStream.PopCnt(Check / 5 - 1));
|
return new IntegerEncoded(EIntegerEncoding.Quint, BitArrayStream.PopCnt(check / 5 - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apparently it can't be represented with a bounded integer sequence...
|
// Apparently it can't be represented with a bounded integer sequence...
|
||||||
// just iterate.
|
// just iterate.
|
||||||
MaxVal--;
|
maxVal--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new IntegerEncoded(EIntegerEncoding.JustBits, 0);
|
return new IntegerEncoded(EIntegerEncoding.JustBits, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DecodeTritBlock(
|
public static void DecodeTritBlock(
|
||||||
BitArrayStream BitStream,
|
BitArrayStream bitStream,
|
||||||
List<IntegerEncoded> ListIntegerEncoded,
|
List<IntegerEncoded> listIntegerEncoded,
|
||||||
int NumberBitsPerValue)
|
int numberBitsPerValue)
|
||||||
{
|
{
|
||||||
// Implement the algorithm in section C.2.12
|
// Implement the algorithm in section C.2.12
|
||||||
int[] m = new int[5];
|
int[] m = new int[5];
|
||||||
|
@ -95,170 +95,170 @@ namespace Ryujinx.Graphics.Texture
|
||||||
|
|
||||||
// Read the trit encoded block according to
|
// Read the trit encoded block according to
|
||||||
// table C.2.14
|
// table C.2.14
|
||||||
m[0] = BitStream.ReadBits(NumberBitsPerValue);
|
m[0] = bitStream.ReadBits(numberBitsPerValue);
|
||||||
T = BitStream.ReadBits(2);
|
T = bitStream.ReadBits(2);
|
||||||
m[1] = BitStream.ReadBits(NumberBitsPerValue);
|
m[1] = bitStream.ReadBits(numberBitsPerValue);
|
||||||
T |= BitStream.ReadBits(2) << 2;
|
T |= bitStream.ReadBits(2) << 2;
|
||||||
m[2] = BitStream.ReadBits(NumberBitsPerValue);
|
m[2] = bitStream.ReadBits(numberBitsPerValue);
|
||||||
T |= BitStream.ReadBits(1) << 4;
|
T |= bitStream.ReadBits(1) << 4;
|
||||||
m[3] = BitStream.ReadBits(NumberBitsPerValue);
|
m[3] = bitStream.ReadBits(numberBitsPerValue);
|
||||||
T |= BitStream.ReadBits(2) << 5;
|
T |= bitStream.ReadBits(2) << 5;
|
||||||
m[4] = BitStream.ReadBits(NumberBitsPerValue);
|
m[4] = bitStream.ReadBits(numberBitsPerValue);
|
||||||
T |= BitStream.ReadBits(1) << 7;
|
T |= bitStream.ReadBits(1) << 7;
|
||||||
|
|
||||||
int C = 0;
|
int c = 0;
|
||||||
|
|
||||||
BitArrayStream Tb = new BitArrayStream(new BitArray(new int[] { T }));
|
BitArrayStream tb = new BitArrayStream(new BitArray(new int[] { T }));
|
||||||
if (Tb.ReadBits(2, 4) == 7)
|
if (tb.ReadBits(2, 4) == 7)
|
||||||
{
|
{
|
||||||
C = (Tb.ReadBits(5, 7) << 2) | Tb.ReadBits(0, 1);
|
c = (tb.ReadBits(5, 7) << 2) | tb.ReadBits(0, 1);
|
||||||
t[4] = t[3] = 2;
|
t[4] = t[3] = 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
C = Tb.ReadBits(0, 4);
|
c = tb.ReadBits(0, 4);
|
||||||
if (Tb.ReadBits(5, 6) == 3)
|
if (tb.ReadBits(5, 6) == 3)
|
||||||
{
|
{
|
||||||
t[4] = 2;
|
t[4] = 2;
|
||||||
t[3] = Tb.ReadBit(7);
|
t[3] = tb.ReadBit(7);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
t[4] = Tb.ReadBit(7);
|
t[4] = tb.ReadBit(7);
|
||||||
t[3] = Tb.ReadBits(5, 6);
|
t[3] = tb.ReadBits(5, 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BitArrayStream Cb = new BitArrayStream(new BitArray(new int[] { C }));
|
BitArrayStream cb = new BitArrayStream(new BitArray(new int[] { c }));
|
||||||
if (Cb.ReadBits(0, 1) == 3)
|
if (cb.ReadBits(0, 1) == 3)
|
||||||
{
|
{
|
||||||
t[2] = 2;
|
t[2] = 2;
|
||||||
t[1] = Cb.ReadBit(4);
|
t[1] = cb.ReadBit(4);
|
||||||
t[0] = (Cb.ReadBit(3) << 1) | (Cb.ReadBit(2) & ~Cb.ReadBit(3));
|
t[0] = (cb.ReadBit(3) << 1) | (cb.ReadBit(2) & ~cb.ReadBit(3));
|
||||||
}
|
}
|
||||||
else if (Cb.ReadBits(2, 3) == 3)
|
else if (cb.ReadBits(2, 3) == 3)
|
||||||
{
|
{
|
||||||
t[2] = 2;
|
t[2] = 2;
|
||||||
t[1] = 2;
|
t[1] = 2;
|
||||||
t[0] = Cb.ReadBits(0, 1);
|
t[0] = cb.ReadBits(0, 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
t[2] = Cb.ReadBit(4);
|
t[2] = cb.ReadBit(4);
|
||||||
t[1] = Cb.ReadBits(2, 3);
|
t[1] = cb.ReadBits(2, 3);
|
||||||
t[0] = (Cb.ReadBit(1) << 1) | (Cb.ReadBit(0) & ~Cb.ReadBit(1));
|
t[0] = (cb.ReadBit(1) << 1) | (cb.ReadBit(0) & ~cb.ReadBit(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
IntegerEncoded IntEncoded = new IntegerEncoded(EIntegerEncoding.Trit, NumberBitsPerValue)
|
IntegerEncoded intEncoded = new IntegerEncoded(EIntegerEncoding.Trit, numberBitsPerValue)
|
||||||
{
|
{
|
||||||
BitValue = m[i],
|
BitValue = m[i],
|
||||||
TritValue = t[i]
|
TritValue = t[i]
|
||||||
};
|
};
|
||||||
ListIntegerEncoded.Add(IntEncoded);
|
listIntegerEncoded.Add(intEncoded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DecodeQuintBlock(
|
public static void DecodeQuintBlock(
|
||||||
BitArrayStream BitStream,
|
BitArrayStream bitStream,
|
||||||
List<IntegerEncoded> ListIntegerEncoded,
|
List<IntegerEncoded> listIntegerEncoded,
|
||||||
int NumberBitsPerValue)
|
int numberBitsPerValue)
|
||||||
{
|
{
|
||||||
// Implement the algorithm in section C.2.12
|
// Implement the algorithm in section C.2.12
|
||||||
int[] m = new int[3];
|
int[] m = new int[3];
|
||||||
int[] q = new int[3];
|
int[] qa = new int[3];
|
||||||
int Q;
|
int q;
|
||||||
|
|
||||||
// Read the trit encoded block according to
|
// Read the trit encoded block according to
|
||||||
// table C.2.15
|
// table C.2.15
|
||||||
m[0] = BitStream.ReadBits(NumberBitsPerValue);
|
m[0] = bitStream.ReadBits(numberBitsPerValue);
|
||||||
Q = BitStream.ReadBits(3);
|
q = bitStream.ReadBits(3);
|
||||||
m[1] = BitStream.ReadBits(NumberBitsPerValue);
|
m[1] = bitStream.ReadBits(numberBitsPerValue);
|
||||||
Q |= BitStream.ReadBits(2) << 3;
|
q |= bitStream.ReadBits(2) << 3;
|
||||||
m[2] = BitStream.ReadBits(NumberBitsPerValue);
|
m[2] = bitStream.ReadBits(numberBitsPerValue);
|
||||||
Q |= BitStream.ReadBits(2) << 5;
|
q |= bitStream.ReadBits(2) << 5;
|
||||||
|
|
||||||
BitArrayStream Qb = new BitArrayStream(new BitArray(new int[] { Q }));
|
BitArrayStream qb = new BitArrayStream(new BitArray(new int[] { q }));
|
||||||
if (Qb.ReadBits(1, 2) == 3 && Qb.ReadBits(5, 6) == 0)
|
if (qb.ReadBits(1, 2) == 3 && qb.ReadBits(5, 6) == 0)
|
||||||
{
|
{
|
||||||
q[0] = q[1] = 4;
|
qa[0] = qa[1] = 4;
|
||||||
q[2] = (Qb.ReadBit(0) << 2) | ((Qb.ReadBit(4) & ~Qb.ReadBit(0)) << 1) | (Qb.ReadBit(3) & ~Qb.ReadBit(0));
|
qa[2] = (qb.ReadBit(0) << 2) | ((qb.ReadBit(4) & ~qb.ReadBit(0)) << 1) | (qb.ReadBit(3) & ~qb.ReadBit(0));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int C = 0;
|
int c = 0;
|
||||||
if (Qb.ReadBits(1, 2) == 3)
|
if (qb.ReadBits(1, 2) == 3)
|
||||||
{
|
{
|
||||||
q[2] = 4;
|
qa[2] = 4;
|
||||||
C = (Qb.ReadBits(3, 4) << 3) | ((~Qb.ReadBits(5, 6) & 3) << 1) | Qb.ReadBit(0);
|
c = (qb.ReadBits(3, 4) << 3) | ((~qb.ReadBits(5, 6) & 3) << 1) | qb.ReadBit(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
q[2] = Qb.ReadBits(5, 6);
|
qa[2] = qb.ReadBits(5, 6);
|
||||||
C = Qb.ReadBits(0, 4);
|
c = qb.ReadBits(0, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
BitArrayStream Cb = new BitArrayStream(new BitArray(new int[] { C }));
|
BitArrayStream cb = new BitArrayStream(new BitArray(new int[] { c }));
|
||||||
if (Cb.ReadBits(0, 2) == 5)
|
if (cb.ReadBits(0, 2) == 5)
|
||||||
{
|
{
|
||||||
q[1] = 4;
|
qa[1] = 4;
|
||||||
q[0] = Cb.ReadBits(3, 4);
|
qa[0] = cb.ReadBits(3, 4);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
q[1] = Cb.ReadBits(3, 4);
|
qa[1] = cb.ReadBits(3, 4);
|
||||||
q[0] = Cb.ReadBits(0, 2);
|
qa[0] = cb.ReadBits(0, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
IntegerEncoded IntEncoded = new IntegerEncoded(EIntegerEncoding.Quint, NumberBitsPerValue)
|
IntegerEncoded intEncoded = new IntegerEncoded(EIntegerEncoding.Quint, numberBitsPerValue)
|
||||||
{
|
{
|
||||||
BitValue = m[i],
|
BitValue = m[i],
|
||||||
QuintValue = q[i]
|
QuintValue = qa[i]
|
||||||
};
|
};
|
||||||
ListIntegerEncoded.Add(IntEncoded);
|
listIntegerEncoded.Add(intEncoded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DecodeIntegerSequence(
|
public static void DecodeIntegerSequence(
|
||||||
List<IntegerEncoded> DecodeIntegerSequence,
|
List<IntegerEncoded> decodeIntegerSequence,
|
||||||
BitArrayStream BitStream,
|
BitArrayStream bitStream,
|
||||||
int MaxRange,
|
int maxRange,
|
||||||
int NumberValues)
|
int numberValues)
|
||||||
{
|
{
|
||||||
// Determine encoding parameters
|
// Determine encoding parameters
|
||||||
IntegerEncoded IntEncoded = CreateEncoding(MaxRange);
|
IntegerEncoded intEncoded = CreateEncoding(maxRange);
|
||||||
|
|
||||||
// Start decoding
|
// Start decoding
|
||||||
int NumberValuesDecoded = 0;
|
int numberValuesDecoded = 0;
|
||||||
while (NumberValuesDecoded < NumberValues)
|
while (numberValuesDecoded < numberValues)
|
||||||
{
|
{
|
||||||
switch (IntEncoded.GetEncoding())
|
switch (intEncoded.GetEncoding())
|
||||||
{
|
{
|
||||||
case EIntegerEncoding.Quint:
|
case EIntegerEncoding.Quint:
|
||||||
{
|
{
|
||||||
DecodeQuintBlock(BitStream, DecodeIntegerSequence, IntEncoded.NumberBits);
|
DecodeQuintBlock(bitStream, decodeIntegerSequence, intEncoded.NumberBits);
|
||||||
NumberValuesDecoded += 3;
|
numberValuesDecoded += 3;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EIntegerEncoding.Trit:
|
case EIntegerEncoding.Trit:
|
||||||
{
|
{
|
||||||
DecodeTritBlock(BitStream, DecodeIntegerSequence, IntEncoded.NumberBits);
|
DecodeTritBlock(bitStream, decodeIntegerSequence, intEncoded.NumberBits);
|
||||||
NumberValuesDecoded += 5;
|
numberValuesDecoded += 5;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EIntegerEncoding.JustBits:
|
case EIntegerEncoding.JustBits:
|
||||||
{
|
{
|
||||||
IntEncoded.BitValue = BitStream.ReadBits(IntEncoded.NumberBits);
|
intEncoded.BitValue = bitStream.ReadBits(intEncoded.NumberBits);
|
||||||
DecodeIntegerSequence.Add(IntEncoded);
|
decodeIntegerSequence.Add(intEncoded);
|
||||||
NumberValuesDecoded++;
|
numberValuesDecoded++;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue