Archived
1
0
Fork 0
forked from Mirror/Ryujinx

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:
Alex Barney 2019-03-03 19:45:25 -06:00 committed by jduncanator
parent 8e71ea0812
commit 1f554c1093
125 changed files with 9121 additions and 9120 deletions

View file

@ -8,41 +8,41 @@ namespace Ryujinx.Graphics
private const int MethSetMethod = 0x10;
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 MethodOffset = (Cmd >> 16) & 0xfff;
int value = (cmd >> 0) & 0xffff;
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:
{
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;
@ -50,44 +50,44 @@ namespace Ryujinx.Graphics
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;
}
}
}
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:
{
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;

View file

@ -2,7 +2,7 @@ namespace Ryujinx.Graphics
{
enum ChClassId
{
Host1x = 0x1,
Host1X = 0x1,
VideoEncodeMpeg = 0x20,
VideoEncodeNvEnc = 0x21,
VideoStreamingVi = 0x30,
@ -10,7 +10,7 @@ namespace Ryujinx.Graphics
VideoStreamingIspB = 0x34,
VideoStreamingViI2c = 0x36,
GraphicsVic = 0x5d,
Graphics3d = 0x60,
Graphics3D = 0x60,
GraphicsGpu = 0x61,
Tsec = 0xe0,
TsecB = 0xe1,

View file

@ -8,11 +8,11 @@ namespace Ryujinx.Graphics
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;
this.MethodOffset = MethodOffset;
this.Arguments = Arguments;
ClassId = classId;
MethodOffset = methodOffset;
Arguments = arguments;
}
}
}

View file

@ -6,10 +6,10 @@ namespace Ryujinx.Graphics
{
public class DmaPusher
{
private ConcurrentQueue<(NvGpuVmm, long)> IbBuffer;
private ConcurrentQueue<(NvGpuVmm, long)> _ibBuffer;
private long DmaPut;
private long DmaGet;
private long _dmaPut;
private long _dmaGet;
private struct DmaState
{
@ -21,43 +21,43 @@ namespace Ryujinx.Graphics
public int LengthPending;
}
private DmaState State;
private DmaState _state;
private bool SliEnable;
private bool SliActive;
private bool _sliEnable;
private bool _sliActive;
private bool IbEnable;
private bool NonMain;
private bool _ibEnable;
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()
{
return Event.WaitOne(8);
return _event.WaitOne(8);
}
public void DispatchCalls()
@ -67,101 +67,101 @@ namespace Ryujinx.Graphics
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.MethodCount = Word & 0xffffff;
_state.LengthPending = 0;
_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
{
int SumissionMode = (Word >> 29) & 7;
int sumissionMode = (word >> 29) & 7;
switch (SumissionMode)
switch (sumissionMode)
{
case 1:
//Incrementing.
SetNonImmediateState(Word);
SetNonImmediateState(word);
State.NonIncrementing = false;
State.IncrementOnce = false;
_state.NonIncrementing = false;
_state.IncrementOnce = false;
break;
case 3:
//Non-incrementing.
SetNonImmediateState(Word);
SetNonImmediateState(word);
State.NonIncrementing = true;
State.IncrementOnce = false;
_state.NonIncrementing = true;
_state.IncrementOnce = false;
break;
case 4:
//Immediate.
State.Method = (Word >> 0) & 0x1fff;
State.SubChannel = (Word >> 13) & 7;
State.NonIncrementing = true;
State.IncrementOnce = false;
_state.Method = (word >> 0) & 0x1fff;
_state.SubChannel = (word >> 13) & 7;
_state.NonIncrementing = true;
_state.IncrementOnce = false;
CallMethod((Word >> 16) & 0x1fff);
CallMethod((word >> 16) & 0x1fff);
break;
case 5:
//Increment-once.
SetNonImmediateState(Word);
SetNonImmediateState(word);
State.NonIncrementing = false;
State.IncrementOnce = true;
_state.NonIncrementing = false;
_state.IncrementOnce = true;
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;
DmaPut = DmaGet + Length * 4;
_dmaGet = entry & 0xfffffffffc;
_dmaPut = _dmaGet + length * 4;
NonMain = (Entry & (1L << 41)) != 0;
_nonMain = (entry & (1L << 41)) != 0;
Gpu.ResourceManager.ClearPbCache();
_gpu.ResourceManager.ClearPbCache();
}
else
{
@ -171,20 +171,20 @@ namespace Ryujinx.Graphics
return true;
}
private void SetNonImmediateState(int Word)
private void SetNonImmediateState(int word)
{
State.Method = (Word >> 0) & 0x1fff;
State.SubChannel = (Word >> 13) & 7;
State.MethodCount = (Word >> 16) & 0x1fff;
_state.Method = (word >> 0) & 0x1fff;
_state.SubChannel = (word >> 13) & 7;
_state.MethodCount = (word >> 16) & 0x1fff;
}
private void CallMethod(int Argument)
private void CallMethod(int argument)
{
Gpu.Fifo.CallMethod(Vmm, new GpuMethodCall(
State.Method,
Argument,
State.SubChannel,
State.MethodCount));
_gpu.Fifo.CallMethod(_vmm, new GpuMethodCall(
_state.Method,
argument,
_state.SubChannel,
_state.MethodCount));
}
}
}

View file

@ -5,15 +5,15 @@ namespace Ryujinx.Graphics.Gal
{
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();
}
}
}

View file

@ -8,15 +8,15 @@ namespace Ryujinx.Graphics.Gal
public float Alpha { get; private set; }
public GalColorF(
float Red,
float Green,
float Blue,
float Alpha)
float red,
float green,
float blue,
float alpha)
{
this.Red = Red;
this.Green = Green;
this.Blue = Blue;
this.Alpha = Alpha;
Red = red;
Green = green;
Blue = blue;
Alpha = alpha;
}
}
}

View file

@ -2,7 +2,7 @@
{
public enum GalFrontFace
{
CW = 0x900,
CCW = 0x901
Cw = 0x900,
Ccw = 0x901
}
}

View file

@ -25,63 +25,63 @@ namespace Ryujinx.Graphics.Gal
public GalTextureTarget TextureTarget;
public GalImage(
int Width,
int Height,
int Depth,
int LayerCount,
int TileWidth,
int GobBlockHeight,
int GobBlockDepth,
GalMemoryLayout Layout,
GalImageFormat Format,
GalTextureTarget TextureTarget,
int MaxMipmapLevel = 1,
GalTextureSource XSource = GalTextureSource.Red,
GalTextureSource YSource = GalTextureSource.Green,
GalTextureSource ZSource = GalTextureSource.Blue,
GalTextureSource WSource = GalTextureSource.Alpha)
int width,
int height,
int depth,
int layerCount,
int tileWidth,
int gobBlockHeight,
int gobBlockDepth,
GalMemoryLayout layout,
GalImageFormat format,
GalTextureTarget textureTarget,
int maxMipmapLevel = 1,
GalTextureSource xSource = GalTextureSource.Red,
GalTextureSource ySource = GalTextureSource.Green,
GalTextureSource zSource = GalTextureSource.Blue,
GalTextureSource wSource = GalTextureSource.Alpha)
{
this.Width = Width;
this.Height = Height;
this.LayerCount = LayerCount;
this.Depth = Depth;
this.TileWidth = TileWidth;
this.GobBlockHeight = GobBlockHeight;
this.GobBlockDepth = GobBlockDepth;
this.Layout = Layout;
this.Format = Format;
this.MaxMipmapLevel = MaxMipmapLevel;
this.XSource = XSource;
this.YSource = YSource;
this.ZSource = ZSource;
this.WSource = WSource;
this.TextureTarget = TextureTarget;
Width = width;
Height = height;
LayerCount = layerCount;
Depth = depth;
TileWidth = tileWidth;
GobBlockHeight = gobBlockHeight;
GobBlockDepth = gobBlockDepth;
Layout = layout;
Format = format;
MaxMipmapLevel = maxMipmapLevel;
XSource = xSource;
YSource = ySource;
ZSource = zSource;
WSource = wSource;
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) !=
ImageUtils.GetBytesPerPixel(Image.Format))
ImageUtils.GetBytesPerPixel(image.Format))
{
return false;
}
if (ImageUtils.GetAlignedWidth(this) !=
ImageUtils.GetAlignedWidth(Image))
ImageUtils.GetAlignedWidth(image))
{
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;
}
}
}

View file

@ -22,23 +22,23 @@ namespace Ryujinx.Graphics.Gal
Astc2D12x12,
Astc2DEnd,
RGBA4,
RGB565,
BGR565,
BGR5A1,
RGB5A1,
Rgba4,
Rgb565,
Bgr565,
Bgr5A1,
Rgb5A1,
R8,
RG8,
RGBX8,
RGBA8,
BGRA8,
RGB10A2,
Rg8,
Rgbx8,
Rgba8,
Bgra8,
Rgb10A2,
R16,
RG16,
RGBA16,
Rg16,
Rgba16,
R32,
RG32,
RGBA32,
Rg32,
Rgba32,
R11G11B10,
D16,
D24,

View file

@ -2,7 +2,7 @@
{
public struct ColorMaskState
{
private static readonly ColorMaskState _Default = new ColorMaskState()
private static readonly ColorMaskState DefaultBackingField = new ColorMaskState()
{
Red = true,
Green = true,
@ -10,7 +10,7 @@
Alpha = true
};
public static ColorMaskState Default => _Default;
public static ColorMaskState Default => DefaultBackingField;
public bool Red;
public bool Green;
@ -20,7 +20,7 @@
public struct BlendState
{
private static readonly BlendState _Default = new BlendState()
private static readonly BlendState DefaultBackingField = new BlendState()
{
Enabled = false,
SeparateAlpha = false,
@ -32,7 +32,7 @@
FuncDstAlpha = GalBlendFactor.Zero
};
public static BlendState Default => _Default;
public static BlendState Default => DefaultBackingField;
public bool Enabled;
public bool SeparateAlpha;
@ -111,9 +111,9 @@
{
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];

View file

@ -4,48 +4,48 @@
{
Bitmap = 0x1c,
Unknown1D = 0x1d,
RGBA32Float = 0xc0,
RGBA32Sint = 0xc1,
RGBA32Uint = 0xc2,
RGBX32Float = 0xc3,
RGBX32Sint = 0xc4,
RGBX32Uint = 0xc5,
RGBA16Unorm = 0xc6,
RGBA16Snorm = 0xc7,
RGBA16Sint = 0xc8,
RGBA16Uint = 0xc9,
RGBA16Float = 0xca,
RG32Float = 0xcb,
RG32Sint = 0xcc,
RG32Uint = 0xcd,
RGBX16Float = 0xce,
BGRA8Unorm = 0xcf,
BGRA8Srgb = 0xd0,
RGB10A2Unorm = 0xd1,
RGB10A2Uint = 0xd2,
RGBA8Unorm = 0xd5,
RGBA8Srgb = 0xd6,
RGBA8Snorm = 0xd7,
RGBA8Sint = 0xd8,
RGBA8Uint = 0xd9,
RG16Unorm = 0xda,
RG16Snorm = 0xdb,
RG16Sint = 0xdc,
RG16Uint = 0xdd,
RG16Float = 0xde,
BGR10A2Unorm = 0xdf,
Rgba32Float = 0xc0,
Rgba32Sint = 0xc1,
Rgba32Uint = 0xc2,
Rgbx32Float = 0xc3,
Rgbx32Sint = 0xc4,
Rgbx32Uint = 0xc5,
Rgba16Unorm = 0xc6,
Rgba16Snorm = 0xc7,
Rgba16Sint = 0xc8,
Rgba16Uint = 0xc9,
Rgba16Float = 0xca,
Rg32Float = 0xcb,
Rg32Sint = 0xcc,
Rg32Uint = 0xcd,
Rgbx16Float = 0xce,
Bgra8Unorm = 0xcf,
Bgra8Srgb = 0xd0,
Rgb10A2Unorm = 0xd1,
Rgb10A2Uint = 0xd2,
Rgba8Unorm = 0xd5,
Rgba8Srgb = 0xd6,
Rgba8Snorm = 0xd7,
Rgba8Sint = 0xd8,
Rgba8Uint = 0xd9,
Rg16Unorm = 0xda,
Rg16Snorm = 0xdb,
Rg16Sint = 0xdc,
Rg16Uint = 0xdd,
Rg16Float = 0xde,
Bgr10A2Unorm = 0xdf,
R11G11B10Float = 0xe0,
R32Sint = 0xe3,
R32Uint = 0xe4,
R32Float = 0xe5,
BGRX8Unorm = 0xe6,
BGRX8Srgb = 0xe7,
Bgrx8Unorm = 0xe6,
Bgrx8Srgb = 0xe7,
B5G6R5Unorm = 0xe8,
BGR5A1Unorm = 0xe9,
RG8Unorm = 0xea,
RG8Snorm = 0xeb,
RG8Sint = 0xec,
RG8Uint = 0xed,
Bgr5A1Unorm = 0xe9,
Rg8Unorm = 0xea,
Rg8Snorm = 0xeb,
Rg8Sint = 0xec,
Rg8Uint = 0xed,
R16Unorm = 0xee,
R16Snorm = 0xef,
R16Sint = 0xf0,
@ -56,13 +56,13 @@
R8Sint = 0xf5,
R8Uint = 0xf6,
A8Unorm = 0xf7,
BGR5X1Unorm = 0xf8,
RGBX8Unorm = 0xf9,
RGBX8Srgb = 0xfa,
BGR5X1UnormUnknownFB = 0xfb,
BGR5X1UnormUnknownFC = 0xfc,
BGRX8UnormUnknownFD = 0xfd,
BGRX8UnormUnknownFE = 0xfe,
Bgr5x1Unorm = 0xf8,
Rgbx8Unorm = 0xf9,
Rgbx8Srgb = 0xfa,
Bgr5x1UnormUnknownFB = 0xfb,
Bgr5x1UnormUnknownFC = 0xfc,
Bgrx8UnormUnknownFD = 0xfd,
Bgrx8UnormUnknownFE = 0xfe,
Y32UintUnknownFF = 0xff
}
}

View file

@ -2,20 +2,20 @@ namespace Ryujinx.Graphics.Gal
{
public enum GalTextureFormat
{
RGBA32 = 0x1,
RGBA16 = 0x3,
RG32 = 0x4,
RGBA8 = 0x8,
RGB10A2 = 0x9,
RG16 = 0xc,
Rgba32 = 0x1,
Rgba16 = 0x3,
Rg32 = 0x4,
Rgba8 = 0x8,
Rgb10A2 = 0x9,
Rg16 = 0xc,
R32 = 0xf,
BptcSfloat = 0x10,
BptcUfloat = 0x11,
RGBA4 = 0x12,
RGB5A1 = 0x14,
RGB565 = 0x15,
Rgba4 = 0x12,
Rgb5A1 = 0x14,
Rgb565 = 0x15,
BptcUnorm = 0x17,
RG8 = 0x18,
Rg8 = 0x18,
R16 = 0x1b,
R8 = 0x1d,
R11G11B10F = 0x21,
@ -26,7 +26,7 @@ namespace Ryujinx.Graphics.Gal
BC5 = 0x28,
D24S8 = 0x29,
D32F = 0x2f,
D32FX24S8 = 0x30,
D32Fx24S8 = 0x30,
D16 = 0x3a,
Astc2D4x4 = 0x40,
Astc2D5x5 = 0x41,

View file

@ -16,26 +16,26 @@ namespace Ryujinx.Graphics.Gal
public DepthCompareFunc DepthCompareFunc { get; private set; }
public GalTextureSampler(
GalTextureWrap AddressU,
GalTextureWrap AddressV,
GalTextureWrap AddressP,
GalTextureFilter MinFilter,
GalTextureFilter MagFilter,
GalTextureMipFilter MipFilter,
GalColorF BorderColor,
bool DepthCompare,
DepthCompareFunc DepthCompareFunc)
GalTextureWrap addressU,
GalTextureWrap addressV,
GalTextureWrap addressP,
GalTextureFilter minFilter,
GalTextureFilter magFilter,
GalTextureMipFilter mipFilter,
GalColorF borderColor,
bool depthCompare,
DepthCompareFunc depthCompareFunc)
{
this.AddressU = AddressU;
this.AddressV = AddressV;
this.AddressP = AddressP;
this.MinFilter = MinFilter;
this.MagFilter = MagFilter;
this.MipFilter = MipFilter;
this.BorderColor = BorderColor;
AddressU = addressU;
AddressV = addressV;
AddressP = addressP;
MinFilter = minFilter;
MagFilter = magFilter;
MipFilter = mipFilter;
BorderColor = borderColor;
this.DepthCompare = DepthCompare;
this.DepthCompareFunc = DepthCompareFunc;
DepthCompare = depthCompare;
DepthCompareFunc = depthCompareFunc;
}
}
}

View file

@ -6,8 +6,8 @@
Unorm = 2,
Sint = 3,
Uint = 4,
Snorm_Force_Fp16 = 5,
Unorm_Force_Fp16 = 6,
SnormForceFp16 = 5,
UnormForceFp16 = 6,
Float = 7
}
}

View file

@ -13,21 +13,21 @@ namespace Ryujinx.Graphics.Gal
public bool IsBgra { get; private set; }
public GalVertexAttrib(
int Index,
bool IsConst,
int Offset,
byte[] Data,
GalVertexAttribSize Size,
GalVertexAttribType Type,
bool IsBgra)
int index,
bool isConst,
int offset,
byte[] data,
GalVertexAttribSize size,
GalVertexAttribType type,
bool isBgra)
{
this.Index = Index;
this.IsConst = IsConst;
this.Data = Data;
this.Offset = Offset;
this.Size = Size;
this.Type = Type;
this.IsBgra = IsBgra;
Index = index;
IsConst = isConst;
Data = data;
Offset = offset;
Size = size;
Type = type;
IsBgra = isBgra;
}
}
}

View file

@ -7,11 +7,11 @@ namespace Ryujinx.Graphics.Gal
void LockCache();
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, byte[] Data);
void SetData(long key, long size, IntPtr hostAddress);
void SetData(long key, byte[] data);
}
}

View file

@ -1,7 +1,7 @@
namespace Ryujinx.Graphics.Gal
{
public unsafe interface IGalMemory
public interface IGalMemory
{
int ReadInt32(long Position);
int ReadInt32(long position);
}
}

View file

@ -2,10 +2,10 @@
{
public interface IGalPipeline
{
void Bind(GalPipelineState State);
void Unbind(GalPipelineState State);
void Bind(GalPipelineState state);
void Unbind(GalPipelineState state);
void ResetDepthMask();
void ResetColorMask(int Index);
void ResetColorMask(int index);
}
}

View file

@ -8,29 +8,29 @@ namespace Ryujinx.Graphics.Gal
void UnlockCaches();
void ClearBuffers(
GalClearBufferFlags Flags,
int Attachment,
float Red,
float Green,
float Blue,
float Alpha,
float Depth,
int Stencil);
GalClearBufferFlags flags,
int attachment,
float red,
float green,
float blue,
float alpha,
float depth,
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, byte[] Data);
void CreateVbo(long key, int dataSize, IntPtr hostAddress);
void CreateVbo(long key, byte[] data);
void CreateIbo(long Key, int DataSize, IntPtr HostAddress);
void CreateIbo(long Key, int DataSize, byte[] Buffer);
void CreateIbo(long key, int dataSize, IntPtr hostAddress);
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);
}
}

View file

@ -4,42 +4,42 @@ namespace Ryujinx.Graphics.Gal
{
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 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 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);
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);
void Reinterpret(long Key, GalImage NewImage);
void Reinterpret(long key, GalImage newImage);
}
}

View file

@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Gal
{
public interface IGalRenderer
{
void QueueAction(Action ActionMthd);
void QueueAction(Action actionMthd);
void RunActions();

View file

@ -4,16 +4,16 @@ namespace Ryujinx.Graphics.Gal
{
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> GetTextureUsage(long Key);
IEnumerable<ShaderDeclInfo> GetConstBufferUsage(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();
}

View file

@ -5,14 +5,14 @@ namespace Ryujinx.Graphics.Gal
void LockCache();
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);
}
}

View file

@ -1,4 +1,4 @@
namespace Ryujinx.Graphics.Gal.OpenGL
{
delegate void DeleteValue<T>(T Value);
delegate void DeleteValue<T>(T value);
}

View file

@ -18,10 +18,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public bool HasDepth => ImageUtils.HasDepth(Image.Format);
public bool HasStencil => ImageUtils.HasStencil(Image.Format);
public ImageHandler(int Handle, GalImage Image)
public ImageHandler(int handle, GalImage image)
{
this.Handle = Handle;
this.Image = Image;
Handle = handle;
Image = image;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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();
}
}
}

View file

@ -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;
}
}
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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();
}
}
}
}

View file

@ -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));
}
}
}
}

View file

@ -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));
}
}
}
}

View file

@ -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);
}
}
}
}

View 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;
}
}
}

View 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();
}
}
}

View file

@ -3,34 +3,34 @@ using System;
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.CCW: return FrontFaceDirection.Ccw;
case GalFrontFace.Cw: return FrontFaceDirection.Cw;
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.Back: return CullFaceMode.Back;
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.Zero: return StencilOp.Zero;
@ -42,28 +42,28 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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 &&
(int)Func <= (int)All.Always)
if ((int)func >= (int)All.Never &&
(int)func <= (int)All.Always)
{
return (All)Func;
return (All)func;
}
switch (Func)
switch (func)
{
case GalComparisonOp.Never: return All.Never;
case GalComparisonOp.Less: return All.Less;
@ -75,24 +75,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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.Int16: return DrawElementsType.UnsignedShort;
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.Lines: return PrimitiveType.Lines;
@ -109,12 +109,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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.TessControl: return ShaderType.TessControlShader;
@ -123,50 +123,50 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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.Sint: return (PixelInternalFormat.Rgba32i, PixelFormat.RgbaInteger, PixelType.Int);
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.Sint: return (PixelInternalFormat.Rgba16i, PixelFormat.RgbaInteger, PixelType.Short);
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.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.Uint: return (PixelInternalFormat.Rg32ui, PixelFormat.RgInteger, PixelType.UnsignedInt);
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.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte);
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.Srgb: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Rgba, 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.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.Unorm: return (PixelInternalFormat.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed);
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.Uint: return (PixelInternalFormat.Rgba32ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt);
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.Uint: return (PixelInternalFormat.Rgba16ui, PixelFormat.RgbaInteger, 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.Sint: return (PixelInternalFormat.Rg32i, PixelFormat.RgInteger, PixelType.Int);
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.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.Sint: return (PixelInternalFormat.Rgba8i, PixelFormat.RgbaInteger, PixelType.Byte);
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.Bgra8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, 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.Rgb10A2 | GalImageFormat.Uint: return (PixelInternalFormat.Rgb10A2ui, PixelFormat.RgbaInteger, 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.Sint: return (PixelInternalFormat.R32i, PixelFormat.Red, PixelType.Int);
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.RGB5A1 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed);
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.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.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Short);
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.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.Uint: return (PixelInternalFormat.Rg8ui, PixelFormat.RgInteger, PixelType.UnsignedByte);
case GalImageFormat.RG8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg8, PixelFormat.Rg, PixelType.UnsignedByte);
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.Rgb565 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565Reversed);
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.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, 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.Unorm: return (PixelInternalFormat.Rg16, PixelFormat.Rg, PixelType.UnsignedShort);
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.Uint: return (PixelInternalFormat.Rg8ui, PixelFormat.RgInteger, 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.Sint: return (PixelInternalFormat.R16i, PixelFormat.RedInteger, 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);
}
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:
return All.Lequal;
@ -210,13 +210,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
case DepthCompareFunc.Never:
return All.Never;
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.BptcUfloat | GalImageFormat.Float: return InternalFormat.CompressedRgbBptcUnsignedFloat;
@ -234,12 +234,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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.Red: return All.Red;
@ -250,12 +250,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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.MirroredRepeat: return TextureWrapMode.MirroredRepeat;
@ -264,9 +264,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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.MirrorClampToBorder: return (TextureWrapMode)ExtTextureMirrorClamp.MirrorClampToBorderExt;
@ -276,7 +276,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
else
{
//Fallback to non-mirrored clamps
switch (Wrap)
switch (wrap)
{
case GalTextureWrap.MirrorClampToEdge: return TextureWrapMode.ClampToEdge;
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(
GalTextureFilter MinFilter,
GalTextureMipFilter MipFilter)
GalTextureFilter minFilter,
GalTextureMipFilter mipFilter)
{
//TODO: Mip (needs mipmap support first).
switch (MinFilter)
switch (minFilter)
{
case GalTextureFilter.Nearest: return TextureMinFilter.Nearest;
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.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.FuncAddGl:
@ -337,12 +337,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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.ZeroGl:
@ -421,7 +421,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
return BlendingFactor.ConstantColor;
}
throw new ArgumentException(nameof(BlendFactor) + " \"" + BlendFactor + "\" is not valid!");
throw new ArgumentException(nameof(blendFactor) + " \"" + blendFactor + "\" is not valid!");
}
}
}

View 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;
}
}
}
}

View 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;
}
}

View file

@ -4,9 +4,9 @@ using System.Collections.Generic;
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>()
{
{ GalVertexAttribSize._32_32_32_32, 4 },
@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ GalVertexAttribSize._11_11_10, 3 }
};
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> FloatAttribTypes =
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> _floatAttribTypes =
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
{
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Float },
@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ GalVertexAttribSize._16, VertexAttribPointerType.HalfFloat }
};
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> SignedAttribTypes =
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> _signedAttribTypes =
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
{
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Int },
@ -56,7 +56,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ GalVertexAttribSize._10_10_10_2, VertexAttribPointerType.Int2101010Rev }
};
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> UnsignedAttribTypes =
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> _unsignedAttribTypes =
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
{
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.UnsignedInt },
@ -75,30 +75,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ GalVertexAttribSize._11_11_10, VertexAttribPointerType.UnsignedInt10F11F11FRev }
};
private GalPipelineState Old;
private GalPipelineState _old;
private OGLConstBuffer Buffer;
private OGLRenderTarget RenderTarget;
private OGLRasterizer Rasterizer;
private OGLShader Shader;
private OglConstBuffer _buffer;
private OglRenderTarget _renderTarget;
private OglRasterizer _rasterizer;
private OglShader _shader;
private int VaoHandle;
private int _vaoHandle;
public OGLPipeline(
OGLConstBuffer Buffer,
OGLRenderTarget RenderTarget,
OGLRasterizer Rasterizer,
OGLShader Shader)
public OglPipeline(
OglConstBuffer buffer,
OglRenderTarget renderTarget,
OglRasterizer rasterizer,
OglShader shader)
{
this.Buffer = Buffer;
this.RenderTarget = RenderTarget;
this.Rasterizer = Rasterizer;
this.Shader = Shader;
_buffer = buffer;
_renderTarget = renderTarget;
_rasterizer = rasterizer;
_shader = shader;
//These values match OpenGL's defaults
Old = new GalPipelineState
_old = new GalPipelineState
{
FrontFace = GalFrontFace.CCW,
FrontFace = GalFrontFace.Ccw,
CullFaceEnabled = false,
CullFace = GalCullFace.Back,
@ -133,11 +133,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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);
if (New.FramebufferSrgb != Old.FramebufferSrgb)
if (New.FramebufferSrgb != _old.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);
}
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);
}
if (New.DepthWriteEnabled != Old.DepthWriteEnabled)
if (New.DepthWriteEnabled != _old.DepthWriteEnabled)
{
GL.DepthMask(New.DepthWriteEnabled);
}
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 ||
New.DepthRangeFar != Old.DepthRangeFar)
if (New.DepthRangeNear != _old.DepthRangeNear ||
New.DepthRangeFar != _old.DepthRangeFar)
{
GL.DepthRange(New.DepthRangeNear, New.DepthRangeFar);
}
if (New.StencilTestEnabled != Old.StencilTestEnabled)
if (New.StencilTestEnabled != _old.StencilTestEnabled)
{
Enable(EnableCap.StencilTest, New.StencilTestEnabled);
}
if (New.StencilTwoSideEnabled != Old.StencilTwoSideEnabled)
if (New.StencilTwoSideEnabled != _old.StencilTwoSideEnabled)
{
Enable((EnableCap)All.StencilTestTwoSideExt, New.StencilTwoSideEnabled);
}
if (New.StencilTestEnabled)
{
if (New.StencilBackFuncFunc != Old.StencilBackFuncFunc ||
New.StencilBackFuncRef != Old.StencilBackFuncRef ||
New.StencilBackFuncMask != Old.StencilBackFuncMask)
if (New.StencilBackFuncFunc != _old.StencilBackFuncFunc ||
New.StencilBackFuncRef != _old.StencilBackFuncRef ||
New.StencilBackFuncMask != _old.StencilBackFuncMask)
{
GL.StencilFuncSeparate(
StencilFace.Back,
OGLEnumConverter.GetStencilFunc(New.StencilBackFuncFunc),
OglEnumConverter.GetStencilFunc(New.StencilBackFuncFunc),
New.StencilBackFuncRef,
New.StencilBackFuncMask);
}
if (New.StencilBackOpFail != Old.StencilBackOpFail ||
New.StencilBackOpZFail != Old.StencilBackOpZFail ||
New.StencilBackOpZPass != Old.StencilBackOpZPass)
if (New.StencilBackOpFail != _old.StencilBackOpFail ||
New.StencilBackOpZFail != _old.StencilBackOpZFail ||
New.StencilBackOpZPass != _old.StencilBackOpZPass)
{
GL.StencilOpSeparate(
StencilFace.Back,
OGLEnumConverter.GetStencilOp(New.StencilBackOpFail),
OGLEnumConverter.GetStencilOp(New.StencilBackOpZFail),
OGLEnumConverter.GetStencilOp(New.StencilBackOpZPass));
OglEnumConverter.GetStencilOp(New.StencilBackOpFail),
OglEnumConverter.GetStencilOp(New.StencilBackOpZFail),
OglEnumConverter.GetStencilOp(New.StencilBackOpZPass));
}
if (New.StencilBackMask != Old.StencilBackMask)
if (New.StencilBackMask != _old.StencilBackMask)
{
GL.StencilMaskSeparate(StencilFace.Back, New.StencilBackMask);
}
if (New.StencilFrontFuncFunc != Old.StencilFrontFuncFunc ||
New.StencilFrontFuncRef != Old.StencilFrontFuncRef ||
New.StencilFrontFuncMask != Old.StencilFrontFuncMask)
if (New.StencilFrontFuncFunc != _old.StencilFrontFuncFunc ||
New.StencilFrontFuncRef != _old.StencilFrontFuncRef ||
New.StencilFrontFuncMask != _old.StencilFrontFuncMask)
{
GL.StencilFuncSeparate(
StencilFace.Front,
OGLEnumConverter.GetStencilFunc(New.StencilFrontFuncFunc),
OglEnumConverter.GetStencilFunc(New.StencilFrontFuncFunc),
New.StencilFrontFuncRef,
New.StencilFrontFuncMask);
}
if (New.StencilFrontOpFail != Old.StencilFrontOpFail ||
New.StencilFrontOpZFail != Old.StencilFrontOpZFail ||
New.StencilFrontOpZPass != Old.StencilFrontOpZPass)
if (New.StencilFrontOpFail != _old.StencilFrontOpFail ||
New.StencilFrontOpZFail != _old.StencilFrontOpZFail ||
New.StencilFrontOpZPass != _old.StencilFrontOpZPass)
{
GL.StencilOpSeparate(
StencilFace.Front,
OGLEnumConverter.GetStencilOp(New.StencilFrontOpFail),
OGLEnumConverter.GetStencilOp(New.StencilFrontOpZFail),
OGLEnumConverter.GetStencilOp(New.StencilFrontOpZPass));
OglEnumConverter.GetStencilOp(New.StencilFrontOpFail),
OglEnumConverter.GetStencilOp(New.StencilFrontOpZFail),
OglEnumConverter.GetStencilOp(New.StencilFrontOpZPass));
}
if (New.StencilFrontMask != Old.StencilFrontMask)
if (New.StencilFrontMask != _old.StencilFrontMask)
{
GL.StencilMaskSeparate(StencilFace.Front, New.StencilFrontMask);
}
@ -277,42 +277,42 @@ namespace Ryujinx.Graphics.Gal.OpenGL
int scissorsApplied = 0;
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
// 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);
applyToAll = true;
}
else
{
GL.Enable(IndexedEnableCap.ScissorTest, Index);
GL.Enable(IndexedEnableCap.ScissorTest, index);
}
if (New.ScissorTestEnabled[Index] != Old.ScissorTestEnabled[Index] ||
New.ScissorTestX[Index] != Old.ScissorTestX[Index] ||
New.ScissorTestY[Index] != Old.ScissorTestY[Index] ||
New.ScissorTestWidth[Index] != Old.ScissorTestWidth[Index] ||
New.ScissorTestHeight[Index] != Old.ScissorTestHeight[Index])
if (New.ScissorTestEnabled[index] != _old.ScissorTestEnabled[index] ||
New.ScissorTestX[index] != _old.ScissorTestX[index] ||
New.ScissorTestY[index] != _old.ScissorTestY[index] ||
New.ScissorTestWidth[index] != _old.ScissorTestWidth[index] ||
New.ScissorTestHeight[index] != _old.ScissorTestHeight[index])
{
if (applyToAll)
{
GL.Scissor(New.ScissorTestX[Index], New.ScissorTestY[Index],
New.ScissorTestWidth[Index], New.ScissorTestHeight[Index]);
GL.Scissor(New.ScissorTestX[index], New.ScissorTestY[index],
New.ScissorTestWidth[index], New.ScissorTestHeight[index]);
}
else
{
GL.ScissorIndexed(Index, New.ScissorTestX[Index], New.ScissorTestY[Index],
New.ScissorTestWidth[Index], New.ScissorTestHeight[Index]);
GL.ScissorIndexed(index, New.ScissorTestX[index], New.ScissorTestY[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 (!OGLExtension.Required.ViewportArray || ++scissorsApplied == New.ScissorTestCount)
// If all scissor tests have been applied, or viewport arrays are unavailable we can skip remaining iterations
if (!OglExtension.Required.ViewportArray || ++scissorsApplied == New.ScissorTestCount)
{
break;
}
@ -323,26 +323,26 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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
{
if (New.BlendIndependent != Old.BlendIndependent)
if (New.BlendIndependent != _old.BlendIndependent)
{
SetAllBlendState(New.Blends[0]);
}
else
{
SetBlendState(New.Blends[0], Old.Blends[0]);
SetBlendState(New.Blends[0], _old.Blends[0]);
}
}
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(
New.ColorMasks[0].Red,
@ -353,39 +353,39 @@ namespace Ryujinx.Graphics.Gal.OpenGL
}
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(
Index,
New.ColorMasks[Index].Red,
New.ColorMasks[Index].Green,
New.ColorMasks[Index].Blue,
New.ColorMasks[Index].Alpha);
index,
New.ColorMasks[index].Red,
New.ColorMasks[index].Green,
New.ColorMasks[index].Blue,
New.ColorMasks[index].Alpha);
}
}
}
if (New.PrimitiveRestartEnabled != Old.PrimitiveRestartEnabled)
if (New.PrimitiveRestartEnabled != _old.PrimitiveRestartEnabled)
{
Enable(EnableCap.PrimitiveRestart, New.PrimitiveRestartEnabled);
}
if (New.PrimitiveRestartEnabled)
{
if (New.PrimitiveRestartIndex != Old.PrimitiveRestartIndex)
if (New.PrimitiveRestartIndex != _old.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);
}
@ -400,29 +400,29 @@ namespace Ryujinx.Graphics.Gal.OpenGL
if (New.SeparateAlpha)
{
GL.BlendEquationSeparate(
OGLEnumConverter.GetBlendEquation(New.EquationRgb),
OGLEnumConverter.GetBlendEquation(New.EquationAlpha));
OglEnumConverter.GetBlendEquation(New.EquationRgb),
OglEnumConverter.GetBlendEquation(New.EquationAlpha));
GL.BlendFuncSeparate(
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb),
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstAlpha));
(BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
(BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb),
(BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
(BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstAlpha));
}
else
{
GL.BlendEquation(OGLEnumConverter.GetBlendEquation(New.EquationRgb));
GL.BlendEquation(OglEnumConverter.GetBlendEquation(New.EquationRgb));
GL.BlendFunc(
OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
OGLEnumConverter.GetBlendFactor(New.FuncDstRgb));
OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
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);
}
@ -431,91 +431,91 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{
if (New.SeparateAlpha)
{
if (New.EquationRgb != Old.EquationRgb ||
New.EquationAlpha != Old.EquationAlpha)
if (New.EquationRgb != old.EquationRgb ||
New.EquationAlpha != old.EquationAlpha)
{
GL.BlendEquationSeparate(
OGLEnumConverter.GetBlendEquation(New.EquationRgb),
OGLEnumConverter.GetBlendEquation(New.EquationAlpha));
OglEnumConverter.GetBlendEquation(New.EquationRgb),
OglEnumConverter.GetBlendEquation(New.EquationAlpha));
}
if (New.FuncSrcRgb != Old.FuncSrcRgb ||
New.FuncDstRgb != Old.FuncDstRgb ||
New.FuncSrcAlpha != Old.FuncSrcAlpha ||
New.FuncDstAlpha != Old.FuncDstAlpha)
if (New.FuncSrcRgb != old.FuncSrcRgb ||
New.FuncDstRgb != old.FuncDstRgb ||
New.FuncSrcAlpha != old.FuncSrcAlpha ||
New.FuncDstAlpha != old.FuncDstAlpha)
{
GL.BlendFuncSeparate(
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb),
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstAlpha));
(BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
(BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb),
(BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
(BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstAlpha));
}
}
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 ||
New.FuncDstRgb != Old.FuncDstRgb)
if (New.FuncSrcRgb != old.FuncSrcRgb ||
New.FuncDstRgb != old.FuncDstRgb)
{
GL.BlendFunc(
OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
OGLEnumConverter.GetBlendFactor(New.FuncDstRgb));
OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
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.SeparateAlpha)
{
if (New.EquationRgb != Old.EquationRgb ||
New.EquationAlpha != Old.EquationAlpha)
if (New.EquationRgb != old.EquationRgb ||
New.EquationAlpha != old.EquationAlpha)
{
GL.BlendEquationSeparate(
Index,
OGLEnumConverter.GetBlendEquation(New.EquationRgb),
OGLEnumConverter.GetBlendEquation(New.EquationAlpha));
index,
OglEnumConverter.GetBlendEquation(New.EquationRgb),
OglEnumConverter.GetBlendEquation(New.EquationAlpha));
}
if (New.FuncSrcRgb != Old.FuncSrcRgb ||
New.FuncDstRgb != Old.FuncDstRgb ||
New.FuncSrcAlpha != Old.FuncSrcAlpha ||
New.FuncDstAlpha != Old.FuncDstAlpha)
if (New.FuncSrcRgb != old.FuncSrcRgb ||
New.FuncDstRgb != old.FuncDstRgb ||
New.FuncSrcAlpha != old.FuncSrcAlpha ||
New.FuncDstAlpha != old.FuncDstAlpha)
{
GL.BlendFuncSeparate(
Index,
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb),
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstAlpha));
index,
(BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
(BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb),
(BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
(BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstAlpha));
}
}
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 ||
New.FuncDstRgb != Old.FuncDstRgb)
if (New.FuncSrcRgb != old.FuncSrcRgb ||
New.FuncDstRgb != old.FuncDstRgb)
{
GL.BlendFunc(
Index,
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb));
index,
(BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
(BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb));
}
}
}
@ -523,310 +523,310 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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.TessControl);
BindIfNotNull(Shader.Current.TessEvaluation);
BindIfNotNull(Shader.Current.Geometry);
BindIfNotNull(Shader.Current.Fragment);
BindIfNotNull(_shader.Current.Vertex);
BindIfNotNull(_shader.Current.TessControl);
BindIfNotNull(_shader.Current.TessEvaluation);
BindIfNotNull(_shader.Current.Geometry);
BindIfNotNull(_shader.Current.Fragment);
}
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;
}
if (VaoHandle == 0)
if (_vaoHandle == 0)
{
VaoHandle = GL.GenVertexArray();
_vaoHandle = GL.GenVertexArray();
//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
GL.BindVertexArray(VaoHandle);
GL.BindVertexArray(_vaoHandle);
}
foreach (GalVertexAttrib Attrib in Binding.Attribs)
foreach (GalVertexAttrib attrib in binding.Attribs)
{
//Skip uninitialized attributes.
if (Attrib.Size == 0)
if (attrib.Size == 0)
{
continue;
}
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
GL.BindBuffer(BufferTarget.ArrayBuffer, vboHandle);
bool Unsigned =
Attrib.Type == GalVertexAttribType.Unorm ||
Attrib.Type == GalVertexAttribType.Uint ||
Attrib.Type == GalVertexAttribType.Uscaled;
bool unsigned =
attrib.Type == GalVertexAttribType.Unorm ||
attrib.Type == GalVertexAttribType.Uint ||
attrib.Type == GalVertexAttribType.Uscaled;
bool Normalize =
Attrib.Type == GalVertexAttribType.Snorm ||
Attrib.Type == GalVertexAttribType.Unorm;
bool normalize =
attrib.Type == GalVertexAttribType.Snorm ||
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
{
if (Unsigned)
if (unsigned)
{
Type = GetType(UnsignedAttribTypes, Attrib);
type = GetType(_unsignedAttribTypes, attrib);
}
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 ||
Attrib.Type == GalVertexAttribType.Uint)
if (attrib.Type == GalVertexAttribType.Sint ||
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
{
GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Binding.Stride, Offset);
GL.VertexAttribPointer(attrib.Index, size, type, normalize, binding.Stride, offset);
}
}
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
{
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 ||
Attrib.Size == GalVertexAttribSize._11_11_10)
if (attrib.Size == GalVertexAttribSize._10_10_10_2 ||
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_8:
case GalVertexAttribSize._8_8_8:
case GalVertexAttribSize._8_8_8_8:
GL.VertexAttrib4N((uint)Attrib.Index, Ptr);
GL.VertexAttrib4N((uint)attrib.Index, ptr);
break;
case GalVertexAttribSize._16:
case GalVertexAttribSize._16_16:
case GalVertexAttribSize._16_16_16:
case GalVertexAttribSize._16_16_16_16:
GL.VertexAttrib4N((uint)Attrib.Index, (ushort*)Ptr);
GL.VertexAttrib4N((uint)attrib.Index, (ushort*)ptr);
break;
case GalVertexAttribSize._32:
case GalVertexAttribSize._32_32:
case GalVertexAttribSize._32_32_32:
case GalVertexAttribSize._32_32_32_32:
GL.VertexAttrib4N((uint)Attrib.Index, (uint*)Ptr);
GL.VertexAttrib4N((uint)attrib.Index, (uint*)ptr);
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_8:
case GalVertexAttribSize._8_8_8:
case GalVertexAttribSize._8_8_8_8:
GL.VertexAttrib4N((uint)Attrib.Index, (sbyte*)Ptr);
GL.VertexAttrib4N((uint)attrib.Index, (sbyte*)ptr);
break;
case GalVertexAttribSize._16:
case GalVertexAttribSize._16_16:
case GalVertexAttribSize._16_16_16:
case GalVertexAttribSize._16_16_16_16:
GL.VertexAttrib4N((uint)Attrib.Index, (short*)Ptr);
GL.VertexAttrib4N((uint)attrib.Index, (short*)ptr);
break;
case GalVertexAttribSize._32:
case GalVertexAttribSize._32_32:
case GalVertexAttribSize._32_32_32:
case GalVertexAttribSize._32_32_32_32:
GL.VertexAttrib4N((uint)Attrib.Index, (int*)Ptr);
GL.VertexAttrib4N((uint)attrib.Index, (int*)ptr);
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_8:
case GalVertexAttribSize._8_8_8:
case GalVertexAttribSize._8_8_8_8:
GL.VertexAttribI4((uint)Attrib.Index, Ptr);
GL.VertexAttribI4((uint)attrib.Index, ptr);
break;
case GalVertexAttribSize._16:
case GalVertexAttribSize._16_16:
case GalVertexAttribSize._16_16_16:
case GalVertexAttribSize._16_16_16_16:
GL.VertexAttribI4((uint)Attrib.Index, (ushort*)Ptr);
GL.VertexAttribI4((uint)attrib.Index, (ushort*)ptr);
break;
case GalVertexAttribSize._32:
case GalVertexAttribSize._32_32:
case GalVertexAttribSize._32_32_32:
case GalVertexAttribSize._32_32_32_32:
GL.VertexAttribI4((uint)Attrib.Index, (uint*)Ptr);
GL.VertexAttribI4((uint)attrib.Index, (uint*)ptr);
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_8:
case GalVertexAttribSize._8_8_8:
case GalVertexAttribSize._8_8_8_8:
GL.VertexAttribI4((uint)Attrib.Index, (sbyte*)Ptr);
GL.VertexAttribI4((uint)attrib.Index, (sbyte*)ptr);
break;
case GalVertexAttribSize._16:
case GalVertexAttribSize._16_16:
case GalVertexAttribSize._16_16_16:
case GalVertexAttribSize._16_16_16_16:
GL.VertexAttribI4((uint)Attrib.Index, (short*)Ptr);
GL.VertexAttribI4((uint)attrib.Index, (short*)ptr);
break;
case GalVertexAttribSize._32:
case GalVertexAttribSize._32_32:
case GalVertexAttribSize._32_32_32:
case GalVertexAttribSize._32_32_32_32:
GL.VertexAttribI4((uint)Attrib.Index, (int*)Ptr);
GL.VertexAttribI4((uint)attrib.Index, (int*)ptr);
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_32:
case GalVertexAttribSize._32_32_32:
case GalVertexAttribSize._32_32_32_32:
GL.VertexAttrib4(Attrib.Index, (float*)Ptr);
GL.VertexAttrib4(attrib.Index, (float*)ptr);
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
{
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
{
GL.Disable(Cap, Index);
GL.Disable(cap, index);
}
}
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;
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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();
}
}
}
}

View 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));
}
}
}
}

View 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));
}
}
}
}

View file

@ -3,7 +3,7 @@ using System;
namespace Ryujinx.Graphics.Gal.OpenGL
{
class OGLStreamBuffer : IDisposable
class OglStreamBuffer : IDisposable
{
public int Handle { get; protected set; }
@ -11,30 +11,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL
protected BufferTarget Target { get; private set; }
public OGLStreamBuffer(BufferTarget Target, long Size)
public OglStreamBuffer(BufferTarget target, long size)
{
this.Target = Target;
this.Size = Size;
Target = target;
Size = size;
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.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.BufferSubData(Target, IntPtr.Zero, (IntPtr)Data.Length, Data);
GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)data.Length, data);
}
public void Dispose()
@ -42,9 +42,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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);

View 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);
}
}
}
}

View file

@ -1,4 +1,3 @@
using Ryujinx.Graphics.Gal.OpenGL;
using Ryujinx.Graphics.Texture;
using System;
using System.Collections.Generic;
@ -51,9 +50,9 @@ namespace Ryujinx.Graphics.Gal.Shader
public const string SsyStackName = "ssy_stack";
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;
@ -83,9 +82,9 @@ namespace Ryujinx.Graphics.Gal.Shader
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>();
@ -101,187 +100,187 @@ namespace Ryujinx.Graphics.Gal.Shader
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_Uniforms, VpA.m_Uniforms, VpB.m_Uniforms);
Merge(combined.m_Textures, vpA.m_Textures, vpB.m_Textures);
Merge(combined.m_Uniforms, vpA.m_Uniforms, vpB.m_Uniforms);
Merge(Combined.m_Attributes, VpA.m_Attributes, VpB.m_Attributes);
Merge(Combined.m_OutAttributes, VpA.m_OutAttributes, VpB.m_OutAttributes);
Merge(combined.m_Attributes, vpA.m_Attributes, vpB.m_Attributes);
Merge(combined.m_OutAttributes, vpA.m_OutAttributes, vpB.m_OutAttributes);
Merge(Combined.m_Gprs, VpA.m_Gprs, VpB.m_Gprs);
Merge(Combined.m_GprsHalf, VpA.m_GprsHalf, VpB.m_GprsHalf);
Merge(Combined.m_Preds, VpA.m_Preds, VpB.m_Preds);
Merge(combined.m_Gprs, vpA.m_Gprs, vpB.m_Gprs);
Merge(combined.m_GprsHalf, vpA.m_GprsHalf, vpB.m_GprsHalf);
Merge(combined.m_Preds, vpA.m_Preds, vpB.m_Preds);
//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,
//then we don't need to add it as an input attribute since
//Vertex Program A will already have written to it anyway,
//and there's no guarantee that there is an input attribute
//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(
Dictionary<int, ShaderDeclInfo> C,
Dictionary<int, ShaderDeclInfo> A,
Dictionary<int, ShaderDeclInfo> B)
Dictionary<int, ShaderDeclInfo> c,
Dictionary<int, ShaderDeclInfo> a,
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.Src);
Traverse(nodes, asg, asg.Dst);
Traverse(nodes, asg, asg.Src);
break;
}
case ShaderIrCond Cond:
case ShaderIrCond cond:
{
Traverse(Nodes, Cond, Cond.Pred);
Traverse(Nodes, Cond, Cond.Child);
Traverse(nodes, cond, cond.Pred);
Traverse(nodes, cond, cond.Child);
break;
}
case ShaderIrOp Op:
case ShaderIrOp op:
{
Traverse(Nodes, Op, Op.OperandA);
Traverse(Nodes, Op, Op.OperandB);
Traverse(Nodes, Op, Op.OperandC);
Traverse(nodes, op, op.OperandA);
Traverse(nodes, op, op.OperandB);
Traverse(nodes, op, op.OperandC);
if (Op.Inst == ShaderIrInst.Texq ||
Op.Inst == ShaderIrInst.Texs ||
Op.Inst == ShaderIrInst.Tld4 ||
Op.Inst == ShaderIrInst.Txlf)
if (op.Inst == ShaderIrInst.Texq ||
op.Inst == ShaderIrInst.Texs ||
op.Inst == ShaderIrInst.Tld4 ||
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?
if (Op.Inst == ShaderIrInst.Texq)
if (op.Inst == ShaderIrInst.Texq)
{
TextureTarget = GalTextureTarget.TwoD;
TextureInstructionSuffix = TextureInstructionSuffix.None;
textureTarget = GalTextureTarget.TwoD;
textureInstructionSuffix = TextureInstructionSuffix.None;
}
else
{
ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData);
ShaderIrMetaTex meta = ((ShaderIrMetaTex)op.MetaData);
TextureTarget = Meta.TextureTarget;
TextureInstructionSuffix = Meta.TextureInstructionSuffix;
textureTarget = meta.TextureTarget;
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;
}
}
}
if (HandleSrc != null && HandleSrc is ShaderIrOperCbuf Cbuf)
if (handleSrc != null && handleSrc is ShaderIrOperCbuf cbuf)
{
ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData);
string Name = StagePrefix + TextureName + "_cb" + Cbuf.Index + "_" + Cbuf.Pos;
ShaderIrMetaTex meta = ((ShaderIrMetaTex)op.MetaData);
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
{
@ -291,93 +290,93 @@ namespace Ryujinx.Graphics.Gal.Shader
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;
}
case ShaderIrOperAbuf Abuf:
case ShaderIrOperAbuf abuf:
{
//This is a built-in variable.
if (Abuf.Offs == LayerAttr ||
Abuf.Offs == PointSizeAttr ||
Abuf.Offs == PointCoordAttrX ||
Abuf.Offs == PointCoordAttrY ||
Abuf.Offs == VertexIdAttr ||
Abuf.Offs == InstanceIdAttr ||
Abuf.Offs == FaceAttr)
if (abuf.Offs == LayerAttr ||
abuf.Offs == PointSizeAttr ||
abuf.Offs == PointCoordAttrX ||
abuf.Offs == PointCoordAttrY ||
abuf.Offs == VertexIdAttr ||
abuf.Offs == InstanceIdAttr ||
abuf.Offs == FaceAttr)
{
break;
}
int Index = Abuf.Offs >> 4;
int Elem = (Abuf.Offs >> 2) & 3;
int index = abuf.Offs >> 4;
int elem = (abuf.Offs >> 2) & 3;
int GlslIndex = Index - AttrStartIndex;
int glslIndex = index - AttrStartIndex;
if (GlslIndex < 0)
if (glslIndex < 0)
{
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
{
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;
}
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) */
{
@ -387,35 +386,35 @@ namespace Ryujinx.Graphics.Gal.Shader
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;
}
}
}
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
//a entry for a vector at a given index position.
//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 Decls.ContainsKey(Index);
return decls.ContainsKey(index);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -10,13 +10,13 @@ namespace Ryujinx.Graphics.Gal.Shader
public IEnumerable<ShaderDeclInfo> Uniforms { get; private set; }
public GlslProgram(
string Code,
IEnumerable<ShaderDeclInfo> Textures,
IEnumerable<ShaderDeclInfo> Uniforms)
string code,
IEnumerable<ShaderDeclInfo> textures,
IEnumerable<ShaderDeclInfo> uniforms)
{
this.Code = Code;
this.Textures = Textures;
this.Uniforms = Uniforms;
Code = code;
Textures = textures;
Uniforms = uniforms;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -4,54 +4,54 @@ namespace Ryujinx.Graphics.Gal.Shader
{
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.
//Almost impossible to support with GLSL.
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...
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.
//Almost impossible to support with GLSL.
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
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Sync)));
block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Sync)));
}
}
}

View file

@ -1,4 +1,4 @@
namespace Ryujinx.Graphics.Gal.Shader
{
delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode, int Position);
delegate void ShaderDecodeFunc(ShaderIrBlock block, long opCode, int position);
}

View file

@ -5,74 +5,74 @@ namespace Ryujinx.Graphics.Gal.Shader
private static readonly ShaderIrOperImmf ImmfZero = new ShaderIrOperImmf(0);
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.Lsr;
Node = new ShaderIrOp(ShaderIrInst.Lsl, Node, new ShaderIrOperImm(Shift));
Node = new ShaderIrOp(RightShift, Node, new ShaderIrOperImm(Shift));
node = new ShaderIrOp(ShaderIrInst.Lsl, 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.Lsr;
Node = new ShaderIrOp(ShaderIrInst.Lsl, Node, Shift);
Node = new ShaderIrOp(RightShift, Node, Shift);
node = new ShaderIrOp(ShaderIrInst.Lsl, node, shift);
node = new ShaderIrOp(rightShift, node, shift);
return Node;
return node;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -25,400 +25,400 @@ namespace Ryujinx.Graphics.Gal.Shader
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
//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
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 AbsA = OpCode.Read(49);
bool negA = opCode.Read(45);
bool absA = opCode.Read(49);
ShaderIrNode OperA;
ShaderIrNode operA;
switch (Oper)
switch (oper)
{
case ShaderOper.CR: OperA = OpCode.Cbuf34(); break;
case ShaderOper.Immf: OperA = OpCode.Immf19_20(); break;
case ShaderOper.RR: OperA = OpCode.Gpr20(); break;
case ShaderOper.Cr: operA = opCode.Cbuf34(); break;
case ShaderOper.Immf: operA = opCode.Immf19_20(); 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 ||
Type == IntType.S64)
if (type == IntType.U64 ||
type == IntType.S64)
{
//TODO: 64-bits support.
//Note: GLSL doesn't support 64-bits integers.
throw new NotImplementedException();
}
bool NegA = OpCode.Read(45);
bool AbsA = OpCode.Read(49);
bool negA = opCode.Read(45);
bool absA = opCode.Read(49);
ShaderIrNode OperA;
ShaderIrNode operA;
switch (Oper)
switch (oper)
{
case ShaderOper.CR: OperA = OpCode.Cbuf34(); break;
case ShaderOper.Immf: OperA = OpCode.Immf19_20(); break;
case ShaderOper.RR: OperA = OpCode.Gpr20(); break;
case ShaderOper.Cr: operA = opCode.Cbuf34(); break;
case ShaderOper.Immf: operA = opCode.Immf19_20(); 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 CMax = Mask;
float cMin = 0;
float cMax = mask;
if (Signed)
if (signed)
{
uint HalfMask = Mask >> 1;
uint halfMask = mask >> 1;
CMin -= HalfMask + 1;
CMax = HalfMask;
cMin -= halfMask + 1;
cMax = halfMask;
}
ShaderIrOperImmf IMin = new ShaderIrOperImmf(CMin);
ShaderIrOperImmf IMax = new ShaderIrOperImmf(CMax);
ShaderIrOperImmf min = new ShaderIrOperImmf(cMin);
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.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 ||
Type == IntType.S64)
if (type == IntType.U64 ||
type == IntType.S64)
{
//TODO: 64-bits support.
//Note: GLSL doesn't support 64-bits integers.
throw new NotImplementedException();
}
int Sel = OpCode.Read(41, 3);
int sel = opCode.Read(41, 3);
bool NegA = OpCode.Read(45);
bool AbsA = OpCode.Read(49);
bool negA = opCode.Read(45);
bool absA = opCode.Read(49);
ShaderIrNode OperA;
ShaderIrNode operA;
switch (Oper)
switch (oper)
{
case ShaderOper.CR: OperA = OpCode.Cbuf34(); break;
case ShaderOper.Imm: OperA = OpCode.Imm19_20(); break;
case ShaderOper.RR: OperA = OpCode.Gpr20(); break;
case ShaderOper.Cr: operA = opCode.Cbuf34(); break;
case ShaderOper.Imm: operA = opCode.Imm19_20(); 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.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 ||
Type == IntType.S64)
if (type == IntType.U64 ||
type == IntType.S64)
{
//TODO: 64-bits support.
//Note: GLSL doesn't support 64-bits integers.
throw new NotImplementedException();
}
int Sel = OpCode.Read(41, 3);
int sel = opCode.Read(41, 3);
bool NegA = OpCode.Read(45);
bool AbsA = OpCode.Read(49);
bool SatA = OpCode.Read(50);
bool negA = opCode.Read(45);
bool absA = opCode.Read(49);
bool satA = opCode.Read(50);
ShaderIrNode OperA;
ShaderIrNode operA;
switch (Oper)
switch (oper)
{
case ShaderOper.CR: OperA = OpCode.Cbuf34(); break;
case ShaderOper.Immf: OperA = OpCode.Immf19_20(); break;
case ShaderOper.RR: OperA = OpCode.Gpr20(); break;
case ShaderOper.Cr: operA = opCode.Cbuf34(); break;
case ShaderOper.Immf: operA = opCode.Immf19_20(); 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 CMax = Mask;
uint cMin = 0;
uint cMax = mask;
if (Signed)
if (signed)
{
uint HalfMask = Mask >> 1;
uint halfMask = mask >> 1;
CMin -= HalfMask + 1;
CMax = HalfMask;
cMin -= halfMask + 1;
cMax = halfMask;
}
ShaderIrOperImm IMin = new ShaderIrOperImm((int)CMin);
ShaderIrOperImm IMax = new ShaderIrOperImm((int)CMax);
ShaderIrOperImm min = new ShaderIrOperImm((int)cMin);
ShaderIrOperImm max = new ShaderIrOperImm((int)cMax);
OperA = new ShaderIrOp(Signed
operA = new ShaderIrOp(signed
? ShaderIrInst.Clamps
: ShaderIrInst.Clampu, OperA, IMin, IMax);
: ShaderIrInst.Clampu, operA, min, max);
}
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();
ShaderIrNode Pred = OpCode.Pred39N();
ShaderIrOperGpr dst = opCode.Gpr0();
ShaderIrNode pred = opCode.Pred39N();
ShaderIrNode ResultA = OpCode.Gpr8();
ShaderIrNode ResultB;
ShaderIrNode resultA = opCode.Gpr8();
ShaderIrNode resultB;
switch (Oper)
switch (oper)
{
case ShaderOper.CR: ResultB = OpCode.Cbuf34(); break;
case ShaderOper.Imm: ResultB = OpCode.Imm19_20(); break;
case ShaderOper.RR: ResultB = OpCode.Gpr20(); break;
case ShaderOper.Cr: resultB = opCode.Cbuf34(); break;
case ShaderOper.Imm: resultB = opCode.Imm19_20(); 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 2: return ShaderIrInst.Ceil;

View file

@ -4,227 +4,227 @@ namespace Ryujinx.Graphics.Gal.Shader
{
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 Size = OpCode.Read(47, 3);
int abuf = opCode.Read(20, 0x3ff);
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(
OpCode.Read(34, 0x1f),
OpCode.Read(20, 0x3fff));
opCode.Read(34, 0x1f),
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
//is used as each element on the vector.
return new ShaderIrOperGpr[]
{
new ShaderIrOperGpr(Gpr),
new ShaderIrOperGpr(Gpr)
new ShaderIrOperGpr(gpr),
new ShaderIrOperGpr(gpr)
};
}
ShaderIrOperGpr Low = new ShaderIrOperGpr(Gpr, 0);
ShaderIrOperGpr High = new ShaderIrOperGpr(Gpr, 1);
ShaderIrOperGpr low = new ShaderIrOperGpr(gpr, 0);
ShaderIrOperGpr high = new ShaderIrOperGpr(gpr, 1);
return new ShaderIrOperGpr[]
{
(Mask & 1) != 0 ? High : Low,
(Mask & 2) != 0 ? High : Low
(mask & 1) != 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 2: return ShaderIrInst.Ceq;
@ -234,12 +234,12 @@ namespace Ryujinx.Graphics.Gal.Shader
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 0x2: return ShaderIrInst.Fceq;
@ -257,57 +257,57 @@ namespace Ryujinx.Graphics.Gal.Shader
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 1: return ShaderIrInst.Bor;
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 1: return ShaderIrInst.Bor;
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);
}
}
}

View file

@ -2,23 +2,23 @@
{
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
ShaderIrOperGpr Gpr0 = OpCode.Gpr0();
ShaderIrOperGpr Gpr8 = OpCode.Gpr8();
ShaderIrOperGpr Gpr20 = OpCode.Gpr20();
ShaderIrOperGpr gpr0 = opCode.Gpr0();
ShaderIrOperGpr gpr8 = opCode.Gpr8();
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)));
}
}
}

View file

@ -8,74 +8,74 @@ namespace Ryujinx.Graphics.Gal.Shader
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> VisitedEnd = new Dictionary<int, ShaderIrBlock>();
Dictionary<int, ShaderIrBlock> visited = 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
//points to (when taken), "Next" is the block at the next address,
//executed when the branch is not taken. For Unconditional Branches
//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,
//the end position of the bigger "Current" block should then be == to
//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;
Current = Temp;
smaller = current;
current = temp;
}
Current.EndPosition = Smaller.Position;
Current.Next = Smaller;
Current.Branch = null;
current.EndPosition = smaller.Position;
current.Next = smaller;
current.Branch = null;
Current.Nodes.RemoveRange(
Current.Nodes.Count - Smaller.Nodes.Count,
Smaller.Nodes.Count);
current.Nodes.RemoveRange(
current.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.
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)
FirstPos = (uint)Block.Position;
if (firstPos > (uint)block.Position)
firstPos = (uint)block.Position;
}
ShaderIrBlock Current = Visited[(int)FirstPos];
ShaderIrBlock current = visited[(int)firstPos];
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
{
//Ignore scheduling instructions, which are written every 32 bytes.
if ((Position & 0x1f) == 0)
if ((position & 0x1f) == 0)
{
Position += 8;
position += 8;
continue;
}
uint Word0 = (uint)Memory.ReadInt32(Position + Beginning + 0);
uint Word1 = (uint)Memory.ReadInt32(Position + Beginning + 4);
uint word0 = (uint)memory.ReadInt32(position + beginning + 0);
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)
{
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;
}
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 Op.Inst != ShaderIrInst.Exit &&
Op.Inst != ShaderIrInst.Bra;
return op.Inst != ShaderIrInst.Exit &&
op.Inst != ShaderIrInst.Bra;
}
}
}

View file

@ -11,9 +11,9 @@ namespace Ryujinx.Graphics.Gal.Shader
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 1: return Green;
@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Gal.Shader
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 OmapDepth { get; private set; }
public ShaderHeader(IGalMemory Memory, long Position)
public ShaderHeader(IGalMemory memory, long position)
{
uint CommonWord0 = (uint)Memory.ReadInt32(Position + 0);
uint CommonWord1 = (uint)Memory.ReadInt32(Position + 4);
uint CommonWord2 = (uint)Memory.ReadInt32(Position + 8);
uint CommonWord3 = (uint)Memory.ReadInt32(Position + 12);
uint CommonWord4 = (uint)Memory.ReadInt32(Position + 16);
uint commonWord0 = (uint)memory.ReadInt32(position + 0);
uint commonWord1 = (uint)memory.ReadInt32(position + 4);
uint commonWord2 = (uint)memory.ReadInt32(position + 8);
uint commonWord3 = (uint)memory.ReadInt32(position + 12);
uint commonWord4 = (uint)memory.ReadInt32(position + 16);
SphType = ReadBits(CommonWord0, 0, 5);
Version = ReadBits(CommonWord0, 5, 5);
ShaderType = ReadBits(CommonWord0, 10, 4);
MrtEnable = ReadBits(CommonWord0, 14, 1) != 0;
KillsPixels = ReadBits(CommonWord0, 15, 1) != 0;
DoesGlobalStore = ReadBits(CommonWord0, 16, 1) != 0;
SassVersion = ReadBits(CommonWord0, 17, 4);
DoesLoadOrStore = ReadBits(CommonWord0, 26, 1) != 0;
DoesFp64 = ReadBits(CommonWord0, 27, 1) != 0;
StreamOutMask = ReadBits(CommonWord0, 28, 4);
SphType = ReadBits(commonWord0, 0, 5);
Version = ReadBits(commonWord0, 5, 5);
ShaderType = ReadBits(commonWord0, 10, 4);
MrtEnable = ReadBits(commonWord0, 14, 1) != 0;
KillsPixels = ReadBits(commonWord0, 15, 1) != 0;
DoesGlobalStore = ReadBits(commonWord0, 16, 1) != 0;
SassVersion = ReadBits(commonWord0, 17, 4);
DoesLoadOrStore = ReadBits(commonWord0, 26, 1) != 0;
DoesFp64 = ReadBits(commonWord0, 27, 1) != 0;
StreamOutMask = ReadBits(commonWord0, 28, 4);
ShaderLocalMemoryLowSize = ReadBits(CommonWord1, 0, 24);
PerPatchAttributeCount = ReadBits(CommonWord1, 24, 8);
ShaderLocalMemoryLowSize = ReadBits(commonWord1, 0, 24);
PerPatchAttributeCount = ReadBits(commonWord1, 24, 8);
ShaderLocalMemoryHighSize = ReadBits(CommonWord2, 0, 24);
ThreadsPerInputPrimitive = ReadBits(CommonWord2, 24, 8);
ShaderLocalMemoryHighSize = ReadBits(commonWord2, 0, 24);
ThreadsPerInputPrimitive = ReadBits(commonWord2, 24, 8);
ShaderLocalMemoryCrsSize = ReadBits(CommonWord3, 0, 24);
OutputTopology = ReadBits(CommonWord3, 24, 4);
ShaderLocalMemoryCrsSize = ReadBits(commonWord3, 0, 24);
OutputTopology = ReadBits(commonWord3, 24, 4);
MaxOutputVertexCount = ReadBits(CommonWord4, 0, 12);
StoreReqStart = ReadBits(CommonWord4, 12, 8);
StoreReqEnd = ReadBits(CommonWord4, 24, 8);
MaxOutputVertexCount = ReadBits(commonWord4, 0, 12);
StoreReqStart = ReadBits(commonWord4, 12, 8);
StoreReqEnd = ReadBits(commonWord4, 24, 8);
//Type 2 (fragment?) reading
uint Type2OmapTarget = (uint)Memory.ReadInt32(Position + 72);
uint Type2Omap = (uint)Memory.ReadInt32(Position + 76);
uint type2OmapTarget = (uint)memory.ReadInt32(position + 72);
uint type2Omap = (uint)memory.ReadInt32(position + 76);
OmapTargets = new OmapTarget[8];
for (int i = 0; i < OmapTargets.Length; i++)
{
int Offset = i * 4;
int offset = i * 4;
OmapTargets[i] = new OmapTarget
{
Red = ReadBits(Type2OmapTarget, Offset + 0, 1) != 0,
Green = ReadBits(Type2OmapTarget, Offset + 1, 1) != 0,
Blue = ReadBits(Type2OmapTarget, Offset + 2, 1) != 0,
Alpha = ReadBits(Type2OmapTarget, Offset + 3, 1) != 0
Red = ReadBits(type2OmapTarget, offset + 0, 1) != 0,
Green = ReadBits(type2OmapTarget, offset + 1, 1) != 0,
Blue = ReadBits(type2OmapTarget, offset + 2, 1) != 0,
Alpha = ReadBits(type2OmapTarget, offset + 3, 1) != 0
};
}
OmapSampleMask = ReadBits(Type2Omap, 0, 1) != 0;
OmapDepth = ReadBits(Type2Omap, 1, 1) != 0;
OmapSampleMask = ReadBits(type2Omap, 0, 1) != 0;
OmapDepth = ReadBits(type2Omap, 1, 1) != 0;
}
public int DepthRegister
{
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
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);
}
}
}

View file

@ -5,10 +5,10 @@ namespace Ryujinx.Graphics.Gal.Shader
public ShaderIrNode Dst { get; set; }
public ShaderIrNode Src { get; set; }
public ShaderIrAsg(ShaderIrNode Dst, ShaderIrNode Src)
public ShaderIrAsg(ShaderIrNode dst, ShaderIrNode src)
{
this.Dst = Dst;
this.Src = Src;
Dst = dst;
Src = src;
}
}
}

View file

@ -14,18 +14,18 @@ namespace Ryujinx.Graphics.Gal.Shader
public List<ShaderIrNode> Nodes { get; private set; }
public ShaderIrBlock(int Position)
public ShaderIrBlock(int position)
{
this.Position = Position;
Position = position;
Sources = new List<ShaderIrBlock>();
Nodes = new List<ShaderIrNode>();
}
public void AddNode(ShaderIrNode Node)
public void AddNode(ShaderIrNode node)
{
Nodes.Add(Node);
Nodes.Add(node);
}
public ShaderIrNode[] GetNodes()

View file

@ -4,9 +4,9 @@ namespace Ryujinx.Graphics.Gal.Shader
{
public string Comment { get; private set; }
public ShaderIrCmnt(string Comment)
public ShaderIrCmnt(string comment)
{
this.Comment = Comment;
Comment = comment;
}
}
}

View file

@ -7,11 +7,11 @@ namespace Ryujinx.Graphics.Gal.Shader
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;
this.Child = Child;
this.Not = Not;
Pred = pred;
Child = child;
Not = not;
}
}
}

View file

@ -4,9 +4,9 @@
{
public ShaderIpaMode Mode { get; private set; }
public ShaderIrMetaIpa(ShaderIpaMode Mode)
public ShaderIrMetaIpa(ShaderIpaMode mode)
{
this.Mode = Mode;
Mode = mode;
}
}
}

View file

@ -13,12 +13,12 @@ namespace Ryujinx.Graphics.Gal.Shader
public ShaderIrOperGpr DepthCompare;
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;
this.TextureTarget = TextureTarget;
this.TextureInstructionSuffix = TextureInstructionSuffix;
this.Coordinates = Coordinates;
Elem = elem;
TextureTarget = textureTarget;
TextureInstructionSuffix = textureInstructionSuffix;
Coordinates = coordinates;
}
}
}

View file

@ -6,10 +6,10 @@ namespace Ryujinx.Graphics.Gal.Shader
public int Elem { get; private set; }
public ShaderIrMetaTexq(ShaderTexqInfo Info, int Elem)
public ShaderIrMetaTexq(ShaderTexqInfo info, int elem)
{
this.Info = Info;
this.Elem = Elem;
Info = info;
Elem = elem;
}
}
}

View file

@ -9,17 +9,17 @@ namespace Ryujinx.Graphics.Gal.Shader
public ShaderIrMeta MetaData { get; set; }
public ShaderIrOp(
ShaderIrInst Inst,
ShaderIrNode OperandA = null,
ShaderIrNode OperandB = null,
ShaderIrNode OperandC = null,
ShaderIrMeta MetaData = null)
ShaderIrInst inst,
ShaderIrNode operandA = null,
ShaderIrNode operandB = null,
ShaderIrNode operandC = null,
ShaderIrMeta metaData = null)
{
this.Inst = Inst;
this.OperandA = OperandA;
this.OperandB = OperandB;
this.OperandC = OperandC;
this.MetaData = MetaData;
Inst = inst;
OperandA = operandA;
OperandB = operandB;
OperandC = operandC;
MetaData = metaData;
}
}
}

View file

@ -6,10 +6,10 @@ namespace Ryujinx.Graphics.Gal.Shader
public ShaderIrNode Vertex { get; private set; }
public ShaderIrOperAbuf(int Offs, ShaderIrNode Vertex)
public ShaderIrOperAbuf(int offs, ShaderIrNode vertex)
{
this.Offs = Offs;
this.Vertex = Vertex;
Offs = offs;
Vertex = vertex;
}
}
}

View file

@ -7,11 +7,11 @@ namespace Ryujinx.Graphics.Gal.Shader
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;
this.Pos = Pos;
this.Offs = Offs;
Index = index;
Pos = pos;
Offs = offs;
}
}
}

View file

@ -2,35 +2,35 @@ namespace Ryujinx.Graphics.Gal.Shader
{
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 HalfPart { get; set; }
public ShaderRegisterSize RegisterSize { get; private set; }
public ShaderIrOperGpr(int Index)
public ShaderIrOperGpr(int index)
{
this.Index = Index;
Index = index;
RegisterSize = ShaderRegisterSize.Single;
}
public ShaderIrOperGpr(int Index, int HalfPart)
public ShaderIrOperGpr(int index, int halfPart)
{
this.Index = Index;
this.HalfPart = HalfPart;
Index = index;
HalfPart = halfPart;
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);
}
}
}

View file

@ -4,9 +4,9 @@ namespace Ryujinx.Graphics.Gal.Shader
{
public int Value { get; private set; }
public ShaderIrOperImm(int Value)
public ShaderIrOperImm(int value)
{
this.Value = Value;
Value = value;
}
}
}

View file

@ -4,9 +4,9 @@ namespace Ryujinx.Graphics.Gal.Shader
{
public float Value { get; private set; }
public ShaderIrOperImmf(float Value)
public ShaderIrOperImmf(float value)
{
this.Value = Value;
Value = value;
}
}
}

View file

@ -9,9 +9,9 @@ namespace Ryujinx.Graphics.Gal.Shader
public int Index { get; set; }
public ShaderIrOperPred(int Index)
public ShaderIrOperPred(int index)
{
this.Index = Index;
Index = index;
}
}
}

View file

@ -12,18 +12,18 @@ namespace Ryujinx.Graphics.Gal.Shader
public int XBits;
public ShaderDecodeEntry(ShaderDecodeFunc Func, int XBits)
public ShaderDecodeEntry(ShaderDecodeFunc func, int xBits)
{
this.Func = Func;
this.XBits = XBits;
Func = func;
XBits = xBits;
}
}
private static ShaderDecodeEntry[] OpCodes;
private static ShaderDecodeEntry[] _opCodes;
static ShaderOpCodeTable()
{
OpCodes = new ShaderDecodeEntry[1 << EncodingBits];
_opCodes = new ShaderDecodeEntry[1 << EncodingBits];
#region Instructions
Set("0100110000000x", ShaderDecode.Bfe_C);
@ -123,7 +123,7 @@ namespace Ryujinx.Graphics.Gal.Shader
Set("1101x00xxxxxxx", ShaderDecode.Texs);
Set("1101101xxxxxxx", ShaderDecode.Tlds);
Set("110010xxxx111x", ShaderDecode.Tld4);
Set("1101111100xxxx", ShaderDecode.Tld4s);
Set("1101111100xxxx", ShaderDecode.Tld4S);
Set("01011111xxxxxx", ShaderDecode.Vmad);
Set("0100111xxxxxxx", ShaderDecode.Xmad_CR);
Set("0011011x00xxxx", ShaderDecode.Xmad_I);
@ -132,59 +132,59 @@ namespace Ryujinx.Graphics.Gal.Shader
#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 Value = 0;
int XMask = 0;
int XBits = 0;
int bit = encoding.Length - 1;
int value = 0;
int xMask = 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;
}
}
}

View file

@ -2,10 +2,10 @@ namespace Ryujinx.Graphics.Gal.Shader
{
enum ShaderOper
{
CR,
Cr,
Imm,
Immf,
RC,
RR
Rc,
Rr
}
}

View file

@ -16,29 +16,29 @@ namespace Ryujinx.Graphics.Gal
public TextureInstructionSuffix TextureSuffix { get; private set; }
public ShaderDeclInfo(
string Name,
int Index,
bool IsCb = false,
int Cbuf = 0,
int Size = 1,
GalTextureTarget TextureTarget = GalTextureTarget.TwoD,
TextureInstructionSuffix TextureSuffix = TextureInstructionSuffix.None)
string name,
int index,
bool isCb = false,
int cbuf = 0,
int size = 1,
GalTextureTarget textureTarget = GalTextureTarget.TwoD,
TextureInstructionSuffix textureSuffix = TextureInstructionSuffix.None)
{
this.Name = Name;
this.Index = Index;
this.IsCb = IsCb;
this.Cbuf = Cbuf;
this.Size = Size;
Name = name;
Index = index;
IsCb = isCb;
Cbuf = cbuf;
Size = size;
this.TextureTarget = TextureTarget;
this.TextureSuffix = TextureSuffix;
TextureTarget = textureTarget;
TextureSuffix = textureSuffix;
}
internal void Enlarge(int NewSize)
internal void Enlarge(int newSize)
{
if (Size < NewSize)
if (Size < newSize)
{
Size = NewSize;
Size = newSize;
}
}
}

View file

@ -5,67 +5,67 @@ namespace Ryujinx.Graphics.Gal
{
static class ShaderDumper
{
private static string RuntimeDir;
private static string _runtimeDir;
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())
{
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 CodePath = Path.Combine(CodeDir(), FileName);
string fullPath = Path.Combine(FullDir(), fileName);
string codePath = Path.Combine(CodeDir(), fileName);
DumpIndex++;
using (FileStream FullFile = File.Create(FullPath))
using (FileStream CodeFile = File.Create(CodePath))
using (FileStream fullFile = File.Create(fullPath))
using (FileStream codeFile = File.Create(codePath))
{
BinaryWriter FullWriter = new BinaryWriter(FullFile);
BinaryWriter CodeWriter = new BinaryWriter(CodeFile);
BinaryWriter fullWriter = new BinaryWriter(fullFile);
BinaryWriter codeWriter = new BinaryWriter(codeFile);
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
while ((Instruction >> 48 & 0xfff8) != 0x50b0)
while ((instruction >> 48 & 0xfff8) != 0x50b0)
{
uint Word0 = (uint)Memory.ReadInt32(Position + 0x50 + Offset + 0);
uint Word1 = (uint)Memory.ReadInt32(Position + 0x50 + Offset + 4);
uint word0 = (uint)memory.ReadInt32(position + 0x50 + offset + 0);
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,
//this is to avoid two rows of zeroes
if (Instruction == 0)
if (instruction == 0)
{
break;
}
FullWriter.Write(Instruction);
CodeWriter.Write(Instruction);
fullWriter.Write(instruction);
codeWriter.Write(instruction);
Offset += 8;
offset += 8;
}
//Align to meet nvdisasm requeriments
while (Offset % 0x20 != 0)
while (offset % 0x20 != 0)
{
FullWriter.Write(0);
CodeWriter.Write(0);
fullWriter.Write(0);
codeWriter.Write(0);
Offset += 4;
offset += 4;
}
}
}
@ -87,37 +87,37 @@ namespace Ryujinx.Graphics.Gal
private static string DumpDir()
{
if (string.IsNullOrEmpty(RuntimeDir))
if (string.IsNullOrEmpty(_runtimeDir))
{
int Index = 1;
int index = 1;
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.TessControl: return "tesc";
@ -125,7 +125,7 @@ namespace Ryujinx.Graphics.Gal
case GalShaderType.Geometry: return "geom";
case GalShaderType.Fragment: return "frag";
default: throw new ArgumentException(nameof(Type));
default: throw new ArgumentException(nameof(type));
}
}
}

View file

@ -6,6 +6,6 @@ namespace Ryujinx.Graphics.Gal
{
public ShaderException() : base() { }
public ShaderException(string Message) : base(Message) { }
public ShaderException(string message) : base(message) { }
}
}

View file

@ -10,15 +10,15 @@ namespace Ryujinx.Graphics
public bool IsLastCall => MethodCount <= 1;
public GpuMethodCall(
int Method,
int Argument,
int SubChannel = 0,
int MethodCount = 0)
int method,
int argument,
int subChannel = 0,
int methodCount = 0)
{
this.Method = Method;
this.Argument = Argument;
this.SubChannel = SubChannel;
this.MethodCount = MethodCount;
Method = method;
Argument = argument;
SubChannel = subChannel;
MethodCount = methodCount;
}
}
}

View file

@ -1,8 +1,6 @@
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gal;
using Ryujinx.Graphics.Memory;
using Ryujinx.Graphics.Texture;
using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics
@ -18,124 +16,124 @@ namespace Ryujinx.Graphics
ZetaBuffer
}
private NvGpu Gpu;
private NvGpu _gpu;
private HashSet<long>[] UploadedKeys;
private HashSet<long>[] _uploadedKeys;
private Dictionary<long, ImageType> ImageTypes;
private Dictionary<long, int> MirroredTextures;
private Dictionary<long, ImageType> _imageTypes;
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>();
MirroredTextures = new Dictionary<long, int>();
_imageTypes = new Dictionary<long, ImageType>();
_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.
if (Type != ImageType.Texture && Type != ImageType.TextureArrayLayer)
if (type != ImageType.Texture && type != ImageType.TextureArrayLayer)
{
LayerIndex = -1;
layerIndex = -1;
return false;
}
return true;
}
LayerIndex = -1;
layerIndex = -1;
return false;
}
public void SetTextureArrayLayer(long Position, int LayerIndex)
public void SetTextureArrayLayer(long position, int layerIndex)
{
ImageTypes[Position] = ImageType.TextureArrayLayer;
MirroredTextures[Position] = LayerIndex;
_imageTypes[position] = ImageType.TextureArrayLayer;
_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
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;
}
}
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;
}
@ -143,29 +141,29 @@ namespace Ryujinx.Graphics
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 Vmm.IsRegionModified(Position, Size, Type);
return vmm.IsRegionModified(position, size, type);
}
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();
}
}
}

View file

@ -6,6 +6,6 @@ namespace Ryujinx.Graphics.Graphics3d
{
int[] Registers { get; }
void CallMethod(NvGpuVmm Vmm, GpuMethodCall MethCall);
void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall);
}
}

View file

@ -42,78 +42,78 @@ namespace Ryujinx.Graphics.Graphics3d
BitwiseNotAnd = 12
}
private NvGpuFifo PFifo;
private INvGpuEngine Engine;
private NvGpuFifo _pFifo;
private INvGpuEngine _engine;
public Queue<int> Fifo { get; private set; }
private int[] Gprs;
private int[] _gprs;
private int MethAddr;
private int MethIncr;
private int _methAddr;
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;
this.Engine = Engine;
_pFifo = pFifo;
_engine = engine;
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();
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
//one more instruction before we actually exit.
Step(Vmm, Mme);
Step(vmm, mme);
}
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;
MethIncr = 0;
_methAddr = 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.
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.
case AssignmentOperation.IgnoreAndFetch:
@ -126,7 +126,7 @@ namespace Ryujinx.Graphics.Graphics3d
//Move result.
case AssignmentOperation.Move:
{
SetDstGpr(Result);
SetDstGpr(result);
break;
}
@ -134,9 +134,9 @@ namespace Ryujinx.Graphics.Graphics3d
//Move result and use as Method Address.
case AssignmentOperation.MoveAndSetMaddr:
{
SetDstGpr(Result);
SetDstGpr(result);
SetMethAddr(Result);
SetMethAddr(result);
break;
}
@ -146,7 +146,7 @@ namespace Ryujinx.Graphics.Graphics3d
{
SetDstGpr(FetchParam());
Send(Vmm, Result);
Send(vmm, result);
break;
}
@ -154,9 +154,9 @@ namespace Ryujinx.Graphics.Graphics3d
//Move and send result.
case AssignmentOperation.MoveAndSend:
{
SetDstGpr(Result);
SetDstGpr(result);
Send(Vmm, Result);
Send(vmm, result);
break;
}
@ -166,7 +166,7 @@ namespace Ryujinx.Graphics.Graphics3d
{
SetDstGpr(FetchParam());
SetMethAddr(Result);
SetMethAddr(result);
break;
}
@ -174,11 +174,11 @@ namespace Ryujinx.Graphics.Graphics3d
//Move result and use as Method Address, then fetch and send paramter.
case AssignmentOperation.MoveAndSetMaddrThenFetchAndSend:
{
SetDstGpr(Result);
SetDstGpr(result);
SetMethAddr(Result);
SetMethAddr(result);
Send(Vmm, FetchParam());
Send(vmm, FetchParam());
break;
}
@ -186,11 +186,11 @@ namespace Ryujinx.Graphics.Graphics3d
//Move result and use as Method Address, then send bits 17:12 of result.
case AssignmentOperation.MoveAndSetMaddrThenSendHigh:
{
SetDstGpr(Result);
SetDstGpr(result);
SetMethAddr(Result);
SetMethAddr(result);
Send(Vmm, (Result >> 12) & 0x3f);
Send(vmm, (result >> 12) & 0x3f);
break;
}
@ -199,50 +199,50 @@ namespace Ryujinx.Graphics.Graphics3d
else
{
//Branch.
bool OnNotZero = ((OpCode >> 4) & 1) != 0;
bool onNotZero = ((_opCode >> 4) & 1) != 0;
bool Taken = OnNotZero
bool taken = onNotZero
? 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;
}
}
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()
{
AluOperation Op = (AluOperation)(OpCode & 7);
AluOperation op = (AluOperation)(_opCode & 7);
switch (Op)
switch (op)
{
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:
@ -254,40 +254,40 @@ namespace Ryujinx.Graphics.Graphics3d
case AluOperation.BitfieldExtractLslImm:
case AluOperation.BitfieldExtractLslReg:
{
int BfSrcBit = (OpCode >> 17) & 0x1f;
int BfSize = (OpCode >> 22) & 0x1f;
int BfDstBit = (OpCode >> 27) & 0x1f;
int bfSrcBit = (_opCode >> 17) & 0x1f;
int bfSize = (_opCode >> 22) & 0x1f;
int bfDstBit = (_opCode >> 27) & 0x1f;
int BfMask = (1 << BfSize) - 1;
int bfMask = (1 << bfSize) - 1;
int Dst = GetGprA();
int Src = GetGprB();
int dst = GetGprA();
int src = GetGprB();
switch (Op)
switch (op)
{
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:
{
Src = (int)((uint)Src >> Dst) & BfMask;
src = (int)((uint)src >> dst) & bfMask;
return Src << BfDstBit;
return src << bfDstBit;
}
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:
{
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:
{
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:
{
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:
{
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.BitwiseOr: return A | B;
case AluRegOperation.BitwiseAnd: return A & B;
case AluRegOperation.BitwiseAndNot: return A & ~B;
case AluRegOperation.BitwiseNotAnd: return ~(A & B);
case AluRegOperation.BitwiseExclusiveOr: return a ^ b;
case AluRegOperation.BitwiseOr: return a | b;
case AluRegOperation.BitwiseAnd: return a & b;
case AluRegOperation.BitwiseAndNot: return a & ~b;
case AluRegOperation.BitwiseNotAnd: return ~(a & b);
}
throw new ArgumentOutOfRangeException(nameof(AluOp));
throw new ArgumentOutOfRangeException(nameof(aluOp));
}
private int GetImm()
{
//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;
MethIncr = (Value >> 12) & 0x3f;
_methAddr = (value >> 0) & 0xfff;
_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()
{
return GetGprValue((OpCode >> 11) & 7);
return GetGprValue((_opCode >> 11) & 7);
}
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()
{
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.");
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;
}
}
}

View file

@ -1,4 +1,3 @@
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gal;
using Ryujinx.Graphics.Memory;
using Ryujinx.Graphics.Texture;
@ -20,187 +19,187 @@ namespace Ryujinx.Graphics.Graphics3d
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];
}
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);
bool DstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0;
int DstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth);
int DstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight);
int DstDepth = ReadRegister(NvGpuEngine2dReg.DstDepth);
int DstLayer = ReadRegister(NvGpuEngine2dReg.DstLayer);
int DstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch);
int DstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions);
int dstFormat = ReadRegister(NvGpuEngine2dReg.DstFormat);
bool dstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0;
int dstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth);
int dstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight);
int dstDepth = ReadRegister(NvGpuEngine2dReg.DstDepth);
int dstLayer = ReadRegister(NvGpuEngine2dReg.DstLayer);
int dstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch);
int dstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions);
int SrcFormat = ReadRegister(NvGpuEngine2dReg.SrcFormat);
bool SrcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0;
int SrcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth);
int SrcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight);
int SrcDepth = ReadRegister(NvGpuEngine2dReg.SrcDepth);
int SrcLayer = ReadRegister(NvGpuEngine2dReg.SrcLayer);
int SrcPitch = ReadRegister(NvGpuEngine2dReg.SrcPitch);
int SrcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions);
int srcFormat = ReadRegister(NvGpuEngine2dReg.SrcFormat);
bool srcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0;
int srcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth);
int srcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight);
int srcDepth = ReadRegister(NvGpuEngine2dReg.SrcDepth);
int srcLayer = ReadRegister(NvGpuEngine2dReg.SrcLayer);
int srcPitch = ReadRegister(NvGpuEngine2dReg.SrcPitch);
int srcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions);
int DstBlitX = ReadRegister(NvGpuEngine2dReg.BlitDstX);
int DstBlitY = ReadRegister(NvGpuEngine2dReg.BlitDstY);
int DstBlitW = ReadRegister(NvGpuEngine2dReg.BlitDstW);
int DstBlitH = ReadRegister(NvGpuEngine2dReg.BlitDstH);
int dstBlitX = ReadRegister(NvGpuEngine2dReg.BlitDstX);
int dstBlitY = ReadRegister(NvGpuEngine2dReg.BlitDstY);
int dstBlitW = ReadRegister(NvGpuEngine2dReg.BlitDstW);
int dstBlitH = ReadRegister(NvGpuEngine2dReg.BlitDstH);
long BlitDuDx = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDuDxFract);
long BlitDvDy = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDvDyFract);
long blitDuDx = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDuDxFract);
long blitDvDy = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDvDyFract);
long SrcBlitX = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcXFract);
long SrcBlitY = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcYFract);
long srcBlitX = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcXFract);
long srcBlitY = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcYFract);
GalImageFormat SrcImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)SrcFormat);
GalImageFormat DstImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)DstFormat);
GalImageFormat srcImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)srcFormat);
GalImageFormat dstImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)dstFormat);
GalMemoryLayout SrcLayout = GetLayout(SrcLinear);
GalMemoryLayout DstLayout = GetLayout(DstLinear);
GalMemoryLayout srcLayout = GetLayout(srcLinear);
GalMemoryLayout dstLayout = GetLayout(dstLinear);
int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf);
int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
int srcBlockHeight = 1 << ((srcBlkDim >> 4) & 0xf);
int dstBlockHeight = 1 << ((dstBlkDim >> 4) & 0xf);
long SrcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress);
long DstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress);
long srcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress);
long dstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress);
long SrcKey = Vmm.GetPhysicalAddress(SrcAddress);
long DstKey = Vmm.GetPhysicalAddress(DstAddress);
long srcKey = vmm.GetPhysicalAddress(srcAddress);
long dstKey = vmm.GetPhysicalAddress(dstAddress);
bool IsSrcLayered = false;
bool IsDstLayered = false;
bool isSrcLayered = false;
bool isDstLayered = false;
GalTextureTarget SrcTarget = GalTextureTarget.TwoD;
GalTextureTarget srcTarget = GalTextureTarget.TwoD;
if (SrcDepth != 0)
if (srcDepth != 0)
{
SrcTarget = GalTextureTarget.TwoDArray;
SrcDepth++;
IsSrcLayered = true;
srcTarget = GalTextureTarget.TwoDArray;
srcDepth++;
isSrcLayered = true;
}
else
{
SrcDepth = 1;
srcDepth = 1;
}
GalTextureTarget DstTarget = GalTextureTarget.TwoD;
GalTextureTarget dstTarget = GalTextureTarget.TwoD;
if (DstDepth != 0)
if (dstDepth != 0)
{
DstTarget = GalTextureTarget.TwoDArray;
DstDepth++;
IsDstLayered = true;
dstTarget = GalTextureTarget.TwoDArray;
dstDepth++;
isDstLayered = true;
}
else
{
DstDepth = 1;
dstDepth = 1;
}
GalImage SrcTexture = new GalImage(
SrcWidth,
SrcHeight,
1, SrcDepth, 1,
SrcBlockHeight, 1,
SrcLayout,
SrcImgFormat,
SrcTarget);
GalImage srcTexture = new GalImage(
srcWidth,
srcHeight,
1, srcDepth, 1,
srcBlockHeight, 1,
srcLayout,
srcImgFormat,
srcTarget);
GalImage DstTexture = new GalImage(
DstWidth,
DstHeight,
1, DstDepth, 1,
DstBlockHeight, 1,
DstLayout,
DstImgFormat,
DstTarget);
GalImage dstTexture = new GalImage(
dstWidth,
dstHeight,
1, dstDepth, 1,
dstBlockHeight, 1,
dstLayout,
dstImgFormat,
dstTarget);
SrcTexture.Pitch = SrcPitch;
DstTexture.Pitch = DstPitch;
srcTexture.Pitch = srcPitch;
dstTexture.Pitch = dstPitch;
long GetLayerOffset(GalImage Image, int Layer)
long GetLayerOffset(GalImage image, int layer)
{
int TargetMipLevel = Image.MaxMipmapLevel <= 1 ? 1 : Image.MaxMipmapLevel - 1;
return ImageUtils.GetLayerOffset(Image, TargetMipLevel) * Layer;
int targetMipLevel = image.MaxMipmapLevel <= 1 ? 1 : image.MaxMipmapLevel - 1;
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, DstKey, DstTexture);
_gpu.ResourceManager.SendTexture(vmm, srcKey, srcTexture);
_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 SrcBlitY1 = (int)(SrcBlitY >> 32);
int srcBlitX1 = (int)(srcBlitX >> 32);
int srcBlitY1 = (int)(srcBlitY >> 32);
int SrcBlitX2 = (int)(SrcBlitX + DstBlitW * BlitDuDx >> 32);
int SrcBlitY2 = (int)(SrcBlitY + DstBlitH * BlitDvDy >> 32);
int srcBlitX2 = (int)(srcBlitX + dstBlitW * blitDuDx >> 32);
int srcBlitY2 = (int)(srcBlitY + dstBlitH * blitDvDy >> 32);
Gpu.Renderer.RenderTarget.Copy(
SrcTexture,
DstTexture,
SrcKey,
DstKey,
SrcLayerIndex,
DstLayerIndex,
SrcBlitX1,
SrcBlitY1,
SrcBlitX2,
SrcBlitY2,
DstBlitX,
DstBlitY,
DstBlitX + DstBlitW,
DstBlitY + DstBlitH);
_gpu.Renderer.RenderTarget.Copy(
srcTexture,
dstTexture,
srcKey,
dstKey,
srcLayerIndex,
dstLayerIndex,
srcBlitX1,
srcBlitY1,
srcBlitX2,
srcBlitY2,
dstBlitX,
dstBlitY,
dstBlitX + dstBlitW,
dstBlitY + dstBlitH);
//Do a guest side copy aswell. This is necessary when
//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)
ImageUtils.CopyTexture(
Vmm,
SrcTexture,
DstTexture,
SrcAddress,
DstAddress,
SrcBlitX1,
SrcBlitY1,
DstBlitX,
DstBlitY,
DstBlitW,
DstBlitH);
vmm,
srcTexture,
dstTexture,
srcAddress,
dstAddress,
srcBlitX1,
srcBlitY1,
dstBlitX,
dstBlitY,
dstBlitW,
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.BlockLinear;
}
private long MakeInt64From2xInt32(NvGpuEngine2dReg Reg)
private long MakeInt64From2xInt32(NvGpuEngine2dReg reg)
{
return
(long)Registers[(int)Reg + 0] << 32 |
(uint)Registers[(int)Reg + 1];
(long)Registers[(int)reg + 0] << 32 |
(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 High = (uint)ReadRegister(Reg + 1);
long low = (uint)ReadRegister(reg + 0);
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

View file

@ -32,13 +32,13 @@ namespace Ryujinx.Graphics.Graphics3d
StencilBackMask = 0x3d6,
StencilBackFuncMask = 0x3d7,
ColorMaskCommon = 0x3e4,
RTSeparateFragData = 0x3eb,
RtSeparateFragData = 0x3eb,
ZetaAddress = 0x3f8,
ZetaFormat = 0x3fa,
ZetaBlockDimensions = 0x3fb,
ZetaLayerStride = 0x3fc,
VertexAttribNFormat = 0x458,
RTControl = 0x487,
RtControl = 0x487,
ZetaHoriz = 0x48a,
ZetaVert = 0x48b,
ZetaArrayMode = 0x48c,

View file

@ -1,4 +1,3 @@
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Memory;
using Ryujinx.Graphics.Texture;
using System.Collections.Generic;
@ -9,188 +8,188 @@ namespace Ryujinx.Graphics.Graphics3d
{
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];
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);
}
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
{
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.
int Control = MethCall.Argument;
int control = methCall.Argument;
bool SrcLinear = ((Control >> 7) & 1) != 0;
bool DstLinear = ((Control >> 8) & 1) != 0;
bool Copy2d = ((Control >> 9) & 1) != 0;
bool srcLinear = ((control >> 7) & 1) != 0;
bool dstLinear = ((control >> 8) & 1) != 0;
bool copy2D = ((control >> 9) & 1) != 0;
long SrcAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.SrcAddress);
long DstAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.DstAddress);
long srcAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.SrcAddress);
long dstAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.DstAddress);
int SrcPitch = ReadRegister(NvGpuEngineM2mfReg.SrcPitch);
int DstPitch = ReadRegister(NvGpuEngineM2mfReg.DstPitch);
int srcPitch = ReadRegister(NvGpuEngineM2mfReg.SrcPitch);
int dstPitch = ReadRegister(NvGpuEngineM2mfReg.DstPitch);
int XCount = ReadRegister(NvGpuEngineM2mfReg.XCount);
int YCount = ReadRegister(NvGpuEngineM2mfReg.YCount);
int xCount = ReadRegister(NvGpuEngineM2mfReg.XCount);
int yCount = ReadRegister(NvGpuEngineM2mfReg.YCount);
int Swizzle = ReadRegister(NvGpuEngineM2mfReg.Swizzle);
int swizzle = ReadRegister(NvGpuEngineM2mfReg.Swizzle);
int DstBlkDim = ReadRegister(NvGpuEngineM2mfReg.DstBlkDim);
int DstSizeX = ReadRegister(NvGpuEngineM2mfReg.DstSizeX);
int DstSizeY = ReadRegister(NvGpuEngineM2mfReg.DstSizeY);
int DstSizeZ = ReadRegister(NvGpuEngineM2mfReg.DstSizeZ);
int DstPosXY = ReadRegister(NvGpuEngineM2mfReg.DstPosXY);
int DstPosZ = ReadRegister(NvGpuEngineM2mfReg.DstPosZ);
int dstBlkDim = ReadRegister(NvGpuEngineM2mfReg.DstBlkDim);
int dstSizeX = ReadRegister(NvGpuEngineM2mfReg.DstSizeX);
int dstSizeY = ReadRegister(NvGpuEngineM2mfReg.DstSizeY);
int dstSizeZ = ReadRegister(NvGpuEngineM2mfReg.DstSizeZ);
int dstPosXY = ReadRegister(NvGpuEngineM2mfReg.DstPosXY);
int dstPosZ = ReadRegister(NvGpuEngineM2mfReg.DstPosZ);
int SrcBlkDim = ReadRegister(NvGpuEngineM2mfReg.SrcBlkDim);
int SrcSizeX = ReadRegister(NvGpuEngineM2mfReg.SrcSizeX);
int SrcSizeY = ReadRegister(NvGpuEngineM2mfReg.SrcSizeY);
int SrcSizeZ = ReadRegister(NvGpuEngineM2mfReg.SrcSizeZ);
int SrcPosXY = ReadRegister(NvGpuEngineM2mfReg.SrcPosXY);
int SrcPosZ = ReadRegister(NvGpuEngineM2mfReg.SrcPosZ);
int srcBlkDim = ReadRegister(NvGpuEngineM2mfReg.SrcBlkDim);
int srcSizeX = ReadRegister(NvGpuEngineM2mfReg.SrcSizeX);
int srcSizeY = ReadRegister(NvGpuEngineM2mfReg.SrcSizeY);
int srcSizeZ = ReadRegister(NvGpuEngineM2mfReg.SrcSizeZ);
int srcPosXY = ReadRegister(NvGpuEngineM2mfReg.SrcPosXY);
int srcPosZ = ReadRegister(NvGpuEngineM2mfReg.SrcPosZ);
int SrcCpp = ((Swizzle >> 20) & 7) + 1;
int DstCpp = ((Swizzle >> 24) & 7) + 1;
int srcCpp = ((swizzle >> 20) & 7) + 1;
int dstCpp = ((swizzle >> 24) & 7) + 1;
int DstPosX = (DstPosXY >> 0) & 0xffff;
int DstPosY = (DstPosXY >> 16) & 0xffff;
int dstPosX = (dstPosXY >> 0) & 0xffff;
int dstPosY = (dstPosXY >> 16) & 0xffff;
int SrcPosX = (SrcPosXY >> 0) & 0xffff;
int SrcPosY = (SrcPosXY >> 16) & 0xffff;
int srcPosX = (srcPosXY >> 0) & 0xffff;
int srcPosY = (srcPosXY >> 16) & 0xffff;
int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf);
int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
int srcBlockHeight = 1 << ((srcBlkDim >> 4) & 0xf);
int dstBlockHeight = 1 << ((dstBlkDim >> 4) & 0xf);
long SrcPA = Vmm.GetPhysicalAddress(SrcAddress);
long DstPA = Vmm.GetPhysicalAddress(DstAddress);
long srcPa = vmm.GetPhysicalAddress(srcAddress);
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 DstOffset = (DstPosY + Y) * DstPitch + DstPosX * DstCpp;
int srcOffset = (srcPosY + y) * srcPitch + srcPosX * srcCpp;
int dstOffset = (dstPosY + y) * dstPitch + dstPosX * dstCpp;
long Src = SrcPA + (uint)SrcOffset;
long Dst = DstPA + (uint)DstOffset;
long src = srcPa + (uint)srcOffset;
long dst = dstPa + (uint)dstOffset;
Vmm.Memory.CopyBytes(Src, Dst, XCount * SrcCpp);
vmm.Memory.CopyBytes(src, dst, xCount * srcCpp);
}
}
else
{
ISwizzle SrcSwizzle;
ISwizzle srcSwizzle;
if (SrcLinear)
if (srcLinear)
{
SrcSwizzle = new LinearSwizzle(SrcPitch, SrcCpp, SrcSizeX, SrcSizeY);
srcSwizzle = new LinearSwizzle(srcPitch, srcCpp, srcSizeX, srcSizeY);
}
else
{
SrcSwizzle = new BlockLinearSwizzle(
SrcSizeX,
SrcSizeY, 1,
SrcBlockHeight, 1,
SrcCpp);
srcSwizzle = new BlockLinearSwizzle(
srcSizeX,
srcSizeY, 1,
srcBlockHeight, 1,
srcCpp);
}
ISwizzle DstSwizzle;
ISwizzle dstSwizzle;
if (DstLinear)
if (dstLinear)
{
DstSwizzle = new LinearSwizzle(DstPitch, DstCpp, SrcSizeX, SrcSizeY);
dstSwizzle = new LinearSwizzle(dstPitch, dstCpp, srcSizeX, srcSizeY);
}
else
{
DstSwizzle = new BlockLinearSwizzle(
DstSizeX,
DstSizeY, 1,
DstBlockHeight, 1,
DstCpp);
dstSwizzle = new BlockLinearSwizzle(
dstSizeX,
dstSizeY, 1,
dstBlockHeight, 1,
dstCpp);
}
for (int Y = 0; Y < YCount; Y++)
for (int X = 0; X < XCount; X++)
for (int y = 0; y < yCount; y++)
for (int x = 0; x < xCount; x++)
{
int SrcOffset = SrcSwizzle.GetSwizzleOffset(SrcPosX + X, SrcPosY + Y, 0);
int DstOffset = DstSwizzle.GetSwizzleOffset(DstPosX + X, DstPosY + Y, 0);
int srcOffset = srcSwizzle.GetSwizzleOffset(srcPosX + x, srcPosY + y, 0);
int dstOffset = dstSwizzle.GetSwizzleOffset(dstPosX + x, dstPosY + y, 0);
long Src = SrcPA + (uint)SrcOffset;
long Dst = DstPA + (uint)DstOffset;
long src = srcPa + (uint)srcOffset;
long dst = dstPa + (uint)dstOffset;
Vmm.Memory.CopyBytes(Src, Dst, SrcCpp);
vmm.Memory.CopyBytes(src, dst, srcCpp);
}
}
}
else
{
Vmm.Memory.CopyBytes(SrcPA, DstPA, XCount);
vmm.Memory.CopyBytes(srcPa, dstPa, xCount);
}
}
private long MakeInt64From2xInt32(NvGpuEngineM2mfReg Reg)
private long MakeInt64From2xInt32(NvGpuEngineM2mfReg reg)
{
return
(long)Registers[(int)Reg + 0] << 32 |
(uint)Registers[(int)Reg + 1];
(long)Registers[(int)reg + 0] << 32 |
(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;
}
}
}

View file

@ -1,4 +1,3 @@
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Memory;
using Ryujinx.Graphics.Texture;
using System.Collections.Generic;
@ -9,41 +8,41 @@ namespace Ryujinx.Graphics.Graphics3d
{
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 CopyStartY;
private int _copyStartX;
private int _copyStartY;
private int CopyWidth;
private int CopyHeight;
private int CopyGobBlockHeight;
private int _copyWidth;
private int _copyHeight;
private int _copyGobBlockHeight;
private long CopyAddress;
private long _copyAddress;
private int CopyOffset;
private int CopySize;
private int _copyOffset;
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];
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);
}
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
{
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.
int Control = MethCall.Argument;
int control = methCall.Argument;
long DstAddress = MakeInt64From2xInt32(NvGpuEngineP2mfReg.DstAddress);
long dstAddress = MakeInt64From2xInt32(NvGpuEngineP2mfReg.DstAddress);
int DstPitch = ReadRegister(NvGpuEngineP2mfReg.DstPitch);
int DstBlkDim = ReadRegister(NvGpuEngineP2mfReg.DstBlockDim);
int dstPitch = ReadRegister(NvGpuEngineP2mfReg.DstPitch);
int dstBlkDim = ReadRegister(NvGpuEngineP2mfReg.DstBlockDim);
int DstX = ReadRegister(NvGpuEngineP2mfReg.DstX);
int DstY = ReadRegister(NvGpuEngineP2mfReg.DstY);
int dstX = ReadRegister(NvGpuEngineP2mfReg.DstX);
int dstY = ReadRegister(NvGpuEngineP2mfReg.DstY);
int DstWidth = ReadRegister(NvGpuEngineP2mfReg.DstWidth);
int DstHeight = ReadRegister(NvGpuEngineP2mfReg.DstHeight);
int dstWidth = ReadRegister(NvGpuEngineP2mfReg.DstWidth);
int dstHeight = ReadRegister(NvGpuEngineP2mfReg.DstHeight);
int LineLengthIn = ReadRegister(NvGpuEngineP2mfReg.LineLengthIn);
int LineCount = ReadRegister(NvGpuEngineP2mfReg.LineCount);
int lineLengthIn = ReadRegister(NvGpuEngineP2mfReg.LineLengthIn);
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;
CopyStartY = DstY;
_copyStartX = dstX;
_copyStartY = dstY;
CopyWidth = DstWidth;
CopyHeight = DstHeight;
_copyWidth = dstWidth;
_copyHeight = dstHeight;
CopyAddress = DstAddress;
_copyAddress = dstAddress;
CopyOffset = 0;
CopySize = LineLengthIn * LineCount;
_copyOffset = 0;
_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;
}
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
{
BlockLinearSwizzle Swizzle = new BlockLinearSwizzle(
CopyWidth,
CopyHeight, 1,
CopyGobBlockHeight, 1, 1);
BlockLinearSwizzle swizzle = new BlockLinearSwizzle(
_copyWidth,
_copyHeight, 1,
_copyGobBlockHeight, 1, 1);
int SrcOffset = 0;
int srcOffset = 0;
for (int Y = CopyStartY; Y < CopyHeight && SrcOffset < CopySize; Y++)
for (int X = CopyStartX; X < CopyWidth && SrcOffset < CopySize; X++)
for (int y = _copyStartY; y < _copyHeight && srcOffset < _copySize; y++)
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
(long)Registers[(int)Reg + 0] << 32 |
(uint)Registers[(int)Reg + 1];
(long)Registers[(int)reg + 0] << 32 |
(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;
}
}
}

View file

@ -11,166 +11,166 @@ namespace Ryujinx.Graphics.Graphics3d
//a guess here and use 256kb as the size. Increase if needed.
private const int MmeWords = 256 * 256;
private NvGpu Gpu;
private NvGpu _gpu;
private NvGpuEngine[] SubChannels;
private NvGpuEngine[] _subChannels;
private struct CachedMacro
{
public int Position { get; private set; }
private bool ExecutionPending;
private int Argument;
private bool _executionPending;
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;
Argument = 0;
_executionPending = false;
_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 CurrMacroBindIndex;
private int _currMacroPosition;
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
{
switch (SubChannels[MethCall.SubChannel])
switch (_subChannels[methCall.SubChannel])
{
case NvGpuEngine._2d: Call2dMethod (Vmm, MethCall); break;
case NvGpuEngine._3d: Call3dMethod (Vmm, MethCall); break;
case NvGpuEngine.P2mf: CallP2mfMethod(Vmm, MethCall); break;
case NvGpuEngine.M2mf: CallM2mfMethod(Vmm, MethCall); break;
case NvGpuEngine._2d: Call2dMethod (vmm, methCall); break;
case NvGpuEngine._3d: Call3dMethod (vmm, methCall); break;
case NvGpuEngine.P2mf: CallP2mfMethod(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:
{
CurrMacroPosition = MethCall.Argument;
_currMacroPosition = methCall.Argument;
break;
}
case NvGpuFifoMeth.SendMacroCodeData:
{
Mme[CurrMacroPosition++] = MethCall.Argument;
_mme[_currMacroPosition++] = methCall.Argument;
break;
}
case NvGpuFifoMeth.SetMacroBindingIndex:
{
CurrMacroBindIndex = MethCall.Argument;
_currMacroBindIndex = methCall.Argument;
break;
}
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;
}
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
{
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
{
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);
}
}
}

View file

@ -2,5 +2,5 @@ using Ryujinx.Graphics.Memory;
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

View file

@ -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));
}
}
}

File diff suppressed because it is too large Load diff

View 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));
}
}
}

View file

@ -9,103 +9,103 @@ namespace Ryujinx.Graphics.Texture
public int Position { get; private set; }
public BitArrayStream(BitArray BitArray)
public BitArrayStream(BitArray bitArray)
{
BitsArray = BitArray;
BitsArray = bitArray;
Position = 0;
}
public short ReadBits(int Length)
public short ReadBits(int length)
{
int RetValue = 0;
for (int i = Position; i < Position + Length; i++)
int retValue = 0;
for (int i = Position; i < Position + length; i++)
{
if (BitsArray[i])
{
RetValue |= 1 << (i - Position);
retValue |= 1 << (i - Position);
}
}
Position += Length;
return (short)RetValue;
Position += length;
return (short)retValue;
}
public int ReadBits(int Start, int End)
public int ReadBits(int start, int end)
{
int RetValue = 0;
for (int i = Start; i <= End; i++)
int retValue = 0;
for (int i = start; i <= end; 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()
{
byte[] RetArray = new byte[(BitsArray.Length + 7) / 8];
BitsArray.CopyTo(RetArray, 0);
return RetArray;
byte[] retArray = new byte[(BitsArray.Length + 7) / 8];
BitsArray.CopyTo(retArray, 0);
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 (ToBit == 0) return 0;
if (numberBits == 0) return 0;
if (toBit == 0) return 0;
int TempValue = Value & ((1 << NumberBits) - 1);
int RetValue = TempValue;
int ResLength = NumberBits;
int tempValue = value & ((1 << numberBits) - 1);
int retValue = tempValue;
int resLength = numberBits;
while (ResLength < ToBit)
while (resLength < toBit)
{
int Comp = 0;
if (NumberBits > ToBit - ResLength)
int comp = 0;
if (numberBits > toBit - resLength)
{
int NewShift = ToBit - ResLength;
Comp = NumberBits - NewShift;
NumberBits = NewShift;
int newShift = toBit - resLength;
comp = numberBits - newShift;
numberBits = newShift;
}
RetValue <<= NumberBits;
RetValue |= TempValue >> Comp;
ResLength += NumberBits;
retValue <<= numberBits;
retValue |= tempValue >> comp;
resLength += numberBits;
}
return RetValue;
return retValue;
}
public static int PopCnt(int Number)
public static int PopCnt(int number)
{
int Counter;
for (Counter = 0; Number != 0; Counter++)
int 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)
{
T Temp = lhs;
T temp = lhs;
lhs = rhs;
rhs = Temp;
rhs = temp;
}
// Transfers a bit as described in C.2.14

View file

@ -10,98 +10,98 @@ namespace Ryujinx.Graphics.Texture
private const int GobSize = GobWidth * GobHeight;
private int TexWidth;
private int TexHeight;
private int TexDepth;
private int TexGobBlockHeight;
private int TexGobBlockDepth;
private int TexBpp;
private int _texWidth;
private int _texHeight;
private int _texDepth;
private int _texGobBlockHeight;
private int _texGobBlockDepth;
private int _texBpp;
private int BhMask;
private int BdMask;
private int _bhMask;
private int _bdMask;
private int BhShift;
private int BdShift;
private int BppShift;
private int _bhShift;
private int _bdShift;
private int _bppShift;
private int XShift;
private int _xShift;
private int RobSize;
private int SliceSize;
private int _robSize;
private int _sliceSize;
private int BaseOffset;
private int _baseOffset;
public BlockLinearSwizzle(
int Width,
int Height,
int Depth,
int GobBlockHeight,
int GobBlockDepth,
int Bpp)
int width,
int height,
int depth,
int gobBlockHeight,
int gobBlockDepth,
int bpp)
{
TexWidth = Width;
TexHeight = Height;
TexDepth = Depth;
TexGobBlockHeight = GobBlockHeight;
TexGobBlockDepth = GobBlockDepth;
TexBpp = Bpp;
_texWidth = width;
_texHeight = height;
_texDepth = depth;
_texGobBlockHeight = gobBlockHeight;
_texGobBlockDepth = gobBlockDepth;
_texBpp = bpp;
BppShift = BitUtils.CountTrailingZeros32(Bpp);
_bppShift = BitUtils.CountTrailingZeros32(bpp);
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 Height = Math.Max(1, TexHeight >> Level);
int Depth = Math.Max(1, TexDepth >> Level);
int width = Math.Max(1, _texWidth >> level);
int height = Math.Max(1, _texHeight >> level);
int depth = Math.Max(1, _texDepth >> level);
GobBlockSizes GbSizes = AdjustGobBlockSizes(Height, Depth);
GobBlockSizes gbSizes = AdjustGobBlockSizes(height, depth);
BhMask = GbSizes.Height - 1;
BdMask = GbSizes.Depth - 1;
_bhMask = gbSizes.Height - 1;
_bdMask = gbSizes.Depth - 1;
BhShift = BitUtils.CountTrailingZeros32(GbSizes.Height);
BdShift = BitUtils.CountTrailingZeros32(GbSizes.Depth);
_bhShift = BitUtils.CountTrailingZeros32(gbSizes.Height);
_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;
SliceSize = GsSizes.SliceSize;
_robSize = gsSizes.RobSize;
_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 Height = Math.Max(1, TexHeight >> Index);
int Depth = Math.Max(1, TexDepth >> Index);
int width = Math.Max(1, _texWidth >> index);
int height = Math.Max(1, _texHeight >> 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
@ -109,32 +109,32 @@ namespace Ryujinx.Graphics.Texture
public int Height;
public int Depth;
public GobBlockSizes(int GobBlockHeight, int GobBlockDepth)
public GobBlockSizes(int gobBlockHeight, int gobBlockDepth)
{
this.Height = GobBlockHeight;
this.Depth = GobBlockDepth;
Height = gobBlockHeight;
Depth = gobBlockDepth;
}
}
private GobBlockSizes AdjustGobBlockSizes(int Height, int Depth)
private GobBlockSizes AdjustGobBlockSizes(int height, int depth)
{
int GobBlockHeight = TexGobBlockHeight;
int GobBlockDepth = TexGobBlockDepth;
int gobBlockHeight = _texGobBlockHeight;
int gobBlockDepth = _texGobBlockDepth;
int Pow2Height = BitUtils.Pow2RoundUp(Height);
int Pow2Depth = BitUtils.Pow2RoundUp(Depth);
int pow2Height = BitUtils.Pow2RoundUp(height);
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
@ -142,45 +142,45 @@ namespace Ryujinx.Graphics.Texture
public int RobSize;
public int SliceSize;
public RobAndSliceSizes(int RobSize, int SliceSize)
public RobAndSliceSizes(int robSize, int sliceSize)
{
this.RobSize = RobSize;
this.SliceSize = SliceSize;
RobSize = robSize;
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 += ((Y & 0x07) >> 1) << 6;
Position += ((X & 0x1f) >> 4) << 5;
Position += ((Y & 0x01) >> 0) << 4;
Position += ((X & 0x0f) >> 0) << 0;
position += ((x & 0x3f) >> 5) << 8;
position += ((y & 0x07) >> 1) << 6;
position += ((x & 0x1f) >> 4) << 5;
position += ((y & 0x01) >> 0) << 4;
position += ((x & 0x0f) >> 0) << 0;
return BaseOffset + Position;
return _baseOffset + position;
}
}
}

View file

@ -2,12 +2,12 @@ namespace Ryujinx.Graphics.Texture
{
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);
}
}

View file

@ -1,6 +1,5 @@
using ChocolArm64.Memory;
using OpenTK.Graphics.OpenGL;
using Ryujinx.Common;
using Ryujinx.Graphics.Gal;
using Ryujinx.Graphics.Memory;
using System;
@ -29,13 +28,13 @@ namespace Ryujinx.Graphics.Texture
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;
this.BlockWidth = BlockWidth;
this.BlockHeight = BlockHeight;
this.BlockDepth = BlockDepth;
this.Target = Target;
BytesPerPixel = bytesPerPixel;
BlockWidth = blockWidth;
BlockHeight = blockHeight;
BlockDepth = blockDepth;
Target = target;
}
}
@ -46,26 +45,26 @@ namespace Ryujinx.Graphics.Texture
private const GalImageFormat Float = GalImageFormat.Float;
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>()
{
{ GalTextureFormat.RGBA32, GalImageFormat.RGBA32 | Sint | Uint | Float },
{ GalTextureFormat.RGBA16, GalImageFormat.RGBA16 | Snorm | Unorm | Sint | Uint | Float },
{ GalTextureFormat.RG32, GalImageFormat.RG32 | Sint | Uint | Float },
{ GalTextureFormat.RGBA8, GalImageFormat.RGBA8 | Snorm | Unorm | Sint | Uint | Srgb },
{ GalTextureFormat.RGB10A2, GalImageFormat.RGB10A2 | Snorm | Unorm | Sint | Uint },
{ GalTextureFormat.RG8, GalImageFormat.RG8 | Snorm | Unorm | Sint | Uint },
{ GalTextureFormat.Rgba32, GalImageFormat.Rgba32 | Sint | Uint | Float },
{ GalTextureFormat.Rgba16, GalImageFormat.Rgba16 | Snorm | Unorm | Sint | Uint | Float },
{ GalTextureFormat.Rg32, GalImageFormat.Rg32 | Sint | Uint | Float },
{ GalTextureFormat.Rgba8, GalImageFormat.Rgba8 | Snorm | Unorm | Sint | Uint | Srgb },
{ GalTextureFormat.Rgb10A2, GalImageFormat.Rgb10A2 | Snorm | Unorm | Sint | Uint },
{ GalTextureFormat.Rg8, GalImageFormat.Rg8 | Snorm | Unorm | Sint | Uint },
{ GalTextureFormat.R16, GalImageFormat.R16 | Snorm | Unorm | Sint | Uint | Float },
{ 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.RGBA4, GalImageFormat.RGBA4 | Unorm },
{ GalTextureFormat.RGB5A1, GalImageFormat.RGB5A1 | Unorm },
{ GalTextureFormat.RGB565, GalImageFormat.RGB565 | Unorm },
{ GalTextureFormat.Rgba4, GalImageFormat.Rgba4 | Unorm },
{ GalTextureFormat.Rgb5A1, GalImageFormat.Rgb5A1 | Unorm },
{ GalTextureFormat.Rgb565, GalImageFormat.Rgb565 | Unorm },
{ GalTextureFormat.R11G11B10F, GalImageFormat.R11G11B10 | Float },
{ GalTextureFormat.D24S8, GalImageFormat.D24S8 | Unorm | Uint },
{ GalTextureFormat.D32F, GalImageFormat.D32 | Float },
{ GalTextureFormat.D32FX24S8, GalImageFormat.D32S8 | Float },
{ GalTextureFormat.D32Fx24S8, GalImageFormat.D32S8 | Float },
{ GalTextureFormat.D16, GalImageFormat.D16 | Unorm },
//Compressed formats
@ -93,27 +92,27 @@ namespace Ryujinx.Graphics.Texture
{ 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>()
{
{ GalImageFormat.RGBA32, new ImageDescriptor(16, 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.RGBX8, 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.RGB10A2, new ImageDescriptor(4, 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.Rg32, new ImageDescriptor(8, 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.Bgra8, 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.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.BptcUfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
{ GalImageFormat.BGR5A1, 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.BGR565, 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.Rgb565, 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.RG16, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
{ GalImageFormat.RG8, new ImageDescriptor(2, 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.R16, new ImageDescriptor(2, 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) },
@ -145,77 +144,77 @@ namespace Ryujinx.Graphics.Texture
};
public static GalImageFormat ConvertTexture(
GalTextureFormat Format,
GalTextureType RType,
GalTextureType GType,
GalTextureType BType,
GalTextureType AType,
bool ConvSrgb)
GalTextureFormat format,
GalTextureType rType,
GalTextureType gType,
GalTextureType bType,
GalTextureType aType,
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.RGBA32Uint: return GalImageFormat.RGBA32 | Uint;
case GalSurfaceFormat.RGBA16Float: return GalImageFormat.RGBA16 | Float;
case GalSurfaceFormat.RGBA16Unorm: return GalImageFormat.RGBA16 | Unorm;
case GalSurfaceFormat.RG32Float: return GalImageFormat.RG32 | Float;
case GalSurfaceFormat.RG32Sint: return GalImageFormat.RG32 | Sint;
case GalSurfaceFormat.RG32Uint: return GalImageFormat.RG32 | Uint;
case GalSurfaceFormat.BGRA8Unorm: return GalImageFormat.BGRA8 | Unorm;
case GalSurfaceFormat.BGRA8Srgb: return GalImageFormat.BGRA8 | Srgb;
case GalSurfaceFormat.RGB10A2Unorm: return GalImageFormat.RGB10A2 | Unorm;
case GalSurfaceFormat.RGBA8Unorm: return GalImageFormat.RGBA8 | Unorm;
case GalSurfaceFormat.RGBA8Srgb: return GalImageFormat.RGBA8 | Srgb;
case GalSurfaceFormat.RGBA8Snorm: return GalImageFormat.RGBA8 | Snorm;
case GalSurfaceFormat.RG16Snorm: return GalImageFormat.RG16 | Snorm;
case GalSurfaceFormat.RG16Unorm: return GalImageFormat.RG16 | Unorm;
case GalSurfaceFormat.RG16Sint: return GalImageFormat.RG16 | Sint;
case GalSurfaceFormat.RG16Float: return GalImageFormat.RG16 | Float;
case GalSurfaceFormat.Rgba32Float: return GalImageFormat.Rgba32 | Float;
case GalSurfaceFormat.Rgba32Uint: return GalImageFormat.Rgba32 | Uint;
case GalSurfaceFormat.Rgba16Float: return GalImageFormat.Rgba16 | Float;
case GalSurfaceFormat.Rgba16Unorm: return GalImageFormat.Rgba16 | Unorm;
case GalSurfaceFormat.Rg32Float: return GalImageFormat.Rg32 | Float;
case GalSurfaceFormat.Rg32Sint: return GalImageFormat.Rg32 | Sint;
case GalSurfaceFormat.Rg32Uint: return GalImageFormat.Rg32 | Uint;
case GalSurfaceFormat.Bgra8Unorm: return GalImageFormat.Bgra8 | Unorm;
case GalSurfaceFormat.Bgra8Srgb: return GalImageFormat.Bgra8 | Srgb;
case GalSurfaceFormat.Rgb10A2Unorm: return GalImageFormat.Rgb10A2 | Unorm;
case GalSurfaceFormat.Rgba8Unorm: return GalImageFormat.Rgba8 | Unorm;
case GalSurfaceFormat.Rgba8Srgb: return GalImageFormat.Rgba8 | Srgb;
case GalSurfaceFormat.Rgba8Snorm: return GalImageFormat.Rgba8 | Snorm;
case GalSurfaceFormat.Rg16Snorm: return GalImageFormat.Rg16 | Snorm;
case GalSurfaceFormat.Rg16Unorm: return GalImageFormat.Rg16 | Unorm;
case GalSurfaceFormat.Rg16Sint: return GalImageFormat.Rg16 | Sint;
case GalSurfaceFormat.Rg16Float: return GalImageFormat.Rg16 | Float;
case GalSurfaceFormat.R11G11B10Float: return GalImageFormat.R11G11B10 | Float;
case GalSurfaceFormat.R32Float: return GalImageFormat.R32 | Float;
case GalSurfaceFormat.R32Uint: return GalImageFormat.R32 | Uint;
case GalSurfaceFormat.RG8Unorm: return GalImageFormat.RG8 | Unorm;
case GalSurfaceFormat.RG8Snorm: return GalImageFormat.RG8 | Snorm;
case GalSurfaceFormat.Rg8Unorm: return GalImageFormat.Rg8 | Unorm;
case GalSurfaceFormat.Rg8Snorm: return GalImageFormat.Rg8 | Snorm;
case GalSurfaceFormat.R16Float: return GalImageFormat.R16 | Float;
case GalSurfaceFormat.R16Unorm: return GalImageFormat.R16 | Unorm;
case GalSurfaceFormat.R16Uint: return GalImageFormat.R16 | Uint;
case GalSurfaceFormat.R8Unorm: return GalImageFormat.R8 | Unorm;
case GalSurfaceFormat.R8Uint: return GalImageFormat.R8 | Uint;
case GalSurfaceFormat.B5G6R5Unorm: return GalImageFormat.RGB565 | Unorm;
case GalSurfaceFormat.BGR5A1Unorm: return GalImageFormat.BGR5A1 | Unorm;
case GalSurfaceFormat.RGBX8Unorm: return GalImageFormat.RGBX8 | Unorm;
case GalSurfaceFormat.B5G6R5Unorm: return GalImageFormat.Rgb565 | Unorm;
case GalSurfaceFormat.Bgr5A1Unorm: return GalImageFormat.Bgr5A1 | 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.S8D24Unorm: return GalImageFormat.D24S8 | Unorm;
@ -225,268 +224,268 @@ namespace Ryujinx.Graphics.Texture
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
{
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.
int Pitch = (Width * BytesPerPixel + 3) & ~3;
int pitch = (width * bytesPerPixel + 3) & ~3;
int DataLayerSize = Height * Pitch * Depth;
byte[] Data = new byte[DataLayerSize * Image.LayerCount];
int dataLayerSize = height * pitch * depth;
byte[] data = new byte[dataLayerSize * image.LayerCount];
int TargetMipLevel = Image.MaxMipmapLevel <= 1 ? 1 : Image.MaxMipmapLevel - 1;
int LayerOffset = ImageUtils.GetLayerOffset(Image, TargetMipLevel);
int targetMipLevel = image.MaxMipmapLevel <= 1 ? 1 : image.MaxMipmapLevel - 1;
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 Y = 0; Y < Height; Y++)
for (int X = 0; X < Width; X++)
for (int z = 0; z < depth; z++)
for (int y = 0; y < height; y++)
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
public static bool CopyTexture(
NvGpuVmm Vmm,
GalImage SrcImage,
GalImage DstImage,
long SrcAddress,
long DstAddress,
int SrcX,
int SrcY,
int DstX,
int DstY,
int Width,
int Height)
NvGpuVmm vmm,
GalImage srcImage,
GalImage dstImage,
long srcAddress,
long dstAddress,
int srcX,
int srcY,
int dstX,
int dstY,
int width,
int height)
{
ISwizzle SrcSwizzle = TextureHelper.GetSwizzle(SrcImage);
ISwizzle DstSwizzle = TextureHelper.GetSwizzle(DstImage);
ISwizzle srcSwizzle = TextureHelper.GetSwizzle(srcImage);
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;
}
int BytesPerPixel = Desc.BytesPerPixel;
int bytesPerPixel = desc.BytesPerPixel;
for (int Y = 0; Y < Height; Y++)
for (int X = 0; X < Width; X++)
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
{
long SrcOffset = (uint)SrcSwizzle.GetSwizzleOffset(SrcX + X, SrcY + Y, 0);
long DstOffset = (uint)DstSwizzle.GetSwizzleOffset(DstX + X, DstY + Y, 0);
long srcOffset = (uint)srcSwizzle.GetSwizzleOffset(srcX + x, srcY + 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;
}
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))
ComponentCount--;
if (IsArray(image.TextureTarget))
componentCount--;
int Width = DivRoundUp(Image.Width, Desc.BlockWidth);
int Height = DivRoundUp(Image.Height, Desc.BlockHeight);
int Depth = DivRoundUp(Image.Depth, Desc.BlockDepth);
int width = DivRoundUp(image.Width, desc.BlockWidth);
int height = DivRoundUp(image.Height, desc.BlockHeight);
int depth = DivRoundUp(image.Depth, desc.BlockDepth);
switch (ComponentCount)
switch (componentCount)
{
case 1:
return Desc.BytesPerPixel * Width * Image.LayerCount;
return desc.BytesPerPixel * width * image.LayerCount;
case 2:
return Desc.BytesPerPixel * Width * Height * Image.LayerCount;
return desc.BytesPerPixel * width * height * image.LayerCount;
case 3:
return Desc.BytesPerPixel * Width * Height * Depth * Image.LayerCount;
return desc.BytesPerPixel * width * height * depth * image.LayerCount;
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
{
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),
DivRoundUp(Image.Height, Desc.BlockHeight),
DivRoundUp(Image.Depth, Desc.BlockDepth));
return (DivRoundUp(image.Width, desc.BlockWidth),
DivRoundUp(image.Height, desc.BlockHeight),
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.Unorm: return Unorm;
@ -494,13 +493,13 @@ namespace Ryujinx.Graphics.Texture
case GalTextureType.Uint: return Uint;
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:
return TextureTarget.Texture1D;
@ -520,13 +519,13 @@ namespace Ryujinx.Graphics.Texture
case GalTextureTarget.CubeArray:
return TextureTarget.TextureCubeMapArray;
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.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:
return 1;
@ -555,7 +554,7 @@ namespace Ryujinx.Graphics.Texture
case GalTextureTarget.CubeArray:
return 4;
default:
throw new NotImplementedException($"TextureTarget.{TextureTarget} not implemented yet.");
throw new NotImplementedException($"TextureTarget.{textureTarget} not implemented yet.");
}
}
}

View file

@ -12,81 +12,81 @@ namespace Ryujinx.Graphics.Texture
Trit
}
EIntegerEncoding Encoding;
EIntegerEncoding _encoding;
public int NumberBits { get; private set; }
public int BitValue { get; private set; }
public int TritValue { get; private set; }
public int QuintValue { get; private set; }
public IntegerEncoded(EIntegerEncoding _Encoding, int NumBits)
public IntegerEncoded(EIntegerEncoding encoding, int numBits)
{
Encoding = _Encoding;
NumberBits = NumBits;
_encoding = encoding;
NumberBits = numBits;
BitValue = 0;
TritValue = 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()
{
return Encoding;
return _encoding;
}
public int GetBitLength(int NumberVals)
public int GetBitLength(int numberVals)
{
int TotalBits = NumberBits * NumberVals;
if (Encoding == EIntegerEncoding.Trit)
int totalBits = NumberBits * numberVals;
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?
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?
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?
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...
// just iterate.
MaxVal--;
maxVal--;
}
return new IntegerEncoded(EIntegerEncoding.JustBits, 0);
}
public static void DecodeTritBlock(
BitArrayStream BitStream,
List<IntegerEncoded> ListIntegerEncoded,
int NumberBitsPerValue)
BitArrayStream bitStream,
List<IntegerEncoded> listIntegerEncoded,
int numberBitsPerValue)
{
// Implement the algorithm in section C.2.12
int[] m = new int[5];
@ -95,170 +95,170 @@ namespace Ryujinx.Graphics.Texture
// Read the trit encoded block according to
// table C.2.14
m[0] = BitStream.ReadBits(NumberBitsPerValue);
T = BitStream.ReadBits(2);
m[1] = BitStream.ReadBits(NumberBitsPerValue);
T |= BitStream.ReadBits(2) << 2;
m[2] = BitStream.ReadBits(NumberBitsPerValue);
T |= BitStream.ReadBits(1) << 4;
m[3] = BitStream.ReadBits(NumberBitsPerValue);
T |= BitStream.ReadBits(2) << 5;
m[4] = BitStream.ReadBits(NumberBitsPerValue);
T |= BitStream.ReadBits(1) << 7;
m[0] = bitStream.ReadBits(numberBitsPerValue);
T = bitStream.ReadBits(2);
m[1] = bitStream.ReadBits(numberBitsPerValue);
T |= bitStream.ReadBits(2) << 2;
m[2] = bitStream.ReadBits(numberBitsPerValue);
T |= bitStream.ReadBits(1) << 4;
m[3] = bitStream.ReadBits(numberBitsPerValue);
T |= bitStream.ReadBits(2) << 5;
m[4] = bitStream.ReadBits(numberBitsPerValue);
T |= bitStream.ReadBits(1) << 7;
int C = 0;
int c = 0;
BitArrayStream Tb = new BitArrayStream(new BitArray(new int[] { T }));
if (Tb.ReadBits(2, 4) == 7)
BitArrayStream tb = new BitArrayStream(new BitArray(new int[] { T }));
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;
}
else
{
C = Tb.ReadBits(0, 4);
if (Tb.ReadBits(5, 6) == 3)
c = tb.ReadBits(0, 4);
if (tb.ReadBits(5, 6) == 3)
{
t[4] = 2;
t[3] = Tb.ReadBit(7);
t[3] = tb.ReadBit(7);
}
else
{
t[4] = Tb.ReadBit(7);
t[3] = Tb.ReadBits(5, 6);
t[4] = tb.ReadBit(7);
t[3] = tb.ReadBits(5, 6);
}
}
BitArrayStream Cb = new BitArrayStream(new BitArray(new int[] { C }));
if (Cb.ReadBits(0, 1) == 3)
BitArrayStream cb = new BitArrayStream(new BitArray(new int[] { c }));
if (cb.ReadBits(0, 1) == 3)
{
t[2] = 2;
t[1] = Cb.ReadBit(4);
t[0] = (Cb.ReadBit(3) << 1) | (Cb.ReadBit(2) & ~Cb.ReadBit(3));
t[1] = cb.ReadBit(4);
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[1] = 2;
t[0] = Cb.ReadBits(0, 1);
t[0] = cb.ReadBits(0, 1);
}
else
{
t[2] = Cb.ReadBit(4);
t[1] = Cb.ReadBits(2, 3);
t[0] = (Cb.ReadBit(1) << 1) | (Cb.ReadBit(0) & ~Cb.ReadBit(1));
t[2] = cb.ReadBit(4);
t[1] = cb.ReadBits(2, 3);
t[0] = (cb.ReadBit(1) << 1) | (cb.ReadBit(0) & ~cb.ReadBit(1));
}
for (int i = 0; i < 5; i++)
{
IntegerEncoded IntEncoded = new IntegerEncoded(EIntegerEncoding.Trit, NumberBitsPerValue)
IntegerEncoded intEncoded = new IntegerEncoded(EIntegerEncoding.Trit, numberBitsPerValue)
{
BitValue = m[i],
TritValue = t[i]
};
ListIntegerEncoded.Add(IntEncoded);
listIntegerEncoded.Add(intEncoded);
}
}
public static void DecodeQuintBlock(
BitArrayStream BitStream,
List<IntegerEncoded> ListIntegerEncoded,
int NumberBitsPerValue)
BitArrayStream bitStream,
List<IntegerEncoded> listIntegerEncoded,
int numberBitsPerValue)
{
// Implement the algorithm in section C.2.12
int[] m = new int[3];
int[] q = new int[3];
int Q;
int[] qa = new int[3];
int q;
// Read the trit encoded block according to
// table C.2.15
m[0] = BitStream.ReadBits(NumberBitsPerValue);
Q = BitStream.ReadBits(3);
m[1] = BitStream.ReadBits(NumberBitsPerValue);
Q |= BitStream.ReadBits(2) << 3;
m[2] = BitStream.ReadBits(NumberBitsPerValue);
Q |= BitStream.ReadBits(2) << 5;
m[0] = bitStream.ReadBits(numberBitsPerValue);
q = bitStream.ReadBits(3);
m[1] = bitStream.ReadBits(numberBitsPerValue);
q |= bitStream.ReadBits(2) << 3;
m[2] = bitStream.ReadBits(numberBitsPerValue);
q |= bitStream.ReadBits(2) << 5;
BitArrayStream Qb = new BitArrayStream(new BitArray(new int[] { Q }));
if (Qb.ReadBits(1, 2) == 3 && Qb.ReadBits(5, 6) == 0)
BitArrayStream qb = new BitArrayStream(new BitArray(new int[] { q }));
if (qb.ReadBits(1, 2) == 3 && qb.ReadBits(5, 6) == 0)
{
q[0] = q[1] = 4;
q[2] = (Qb.ReadBit(0) << 2) | ((Qb.ReadBit(4) & ~Qb.ReadBit(0)) << 1) | (Qb.ReadBit(3) & ~Qb.ReadBit(0));
qa[0] = qa[1] = 4;
qa[2] = (qb.ReadBit(0) << 2) | ((qb.ReadBit(4) & ~qb.ReadBit(0)) << 1) | (qb.ReadBit(3) & ~qb.ReadBit(0));
}
else
{
int C = 0;
if (Qb.ReadBits(1, 2) == 3)
int c = 0;
if (qb.ReadBits(1, 2) == 3)
{
q[2] = 4;
C = (Qb.ReadBits(3, 4) << 3) | ((~Qb.ReadBits(5, 6) & 3) << 1) | Qb.ReadBit(0);
qa[2] = 4;
c = (qb.ReadBits(3, 4) << 3) | ((~qb.ReadBits(5, 6) & 3) << 1) | qb.ReadBit(0);
}
else
{
q[2] = Qb.ReadBits(5, 6);
C = Qb.ReadBits(0, 4);
qa[2] = qb.ReadBits(5, 6);
c = qb.ReadBits(0, 4);
}
BitArrayStream Cb = new BitArrayStream(new BitArray(new int[] { C }));
if (Cb.ReadBits(0, 2) == 5)
BitArrayStream cb = new BitArrayStream(new BitArray(new int[] { c }));
if (cb.ReadBits(0, 2) == 5)
{
q[1] = 4;
q[0] = Cb.ReadBits(3, 4);
qa[1] = 4;
qa[0] = cb.ReadBits(3, 4);
}
else
{
q[1] = Cb.ReadBits(3, 4);
q[0] = Cb.ReadBits(0, 2);
qa[1] = cb.ReadBits(3, 4);
qa[0] = cb.ReadBits(0, 2);
}
}
for (int i = 0; i < 3; i++)
{
IntegerEncoded IntEncoded = new IntegerEncoded(EIntegerEncoding.Quint, NumberBitsPerValue)
IntegerEncoded intEncoded = new IntegerEncoded(EIntegerEncoding.Quint, numberBitsPerValue)
{
BitValue = m[i],
QuintValue = q[i]
QuintValue = qa[i]
};
ListIntegerEncoded.Add(IntEncoded);
listIntegerEncoded.Add(intEncoded);
}
}
public static void DecodeIntegerSequence(
List<IntegerEncoded> DecodeIntegerSequence,
BitArrayStream BitStream,
int MaxRange,
int NumberValues)
List<IntegerEncoded> decodeIntegerSequence,
BitArrayStream bitStream,
int maxRange,
int numberValues)
{
// Determine encoding parameters
IntegerEncoded IntEncoded = CreateEncoding(MaxRange);
IntegerEncoded intEncoded = CreateEncoding(maxRange);
// Start decoding
int NumberValuesDecoded = 0;
while (NumberValuesDecoded < NumberValues)
int numberValuesDecoded = 0;
while (numberValuesDecoded < numberValues)
{
switch (IntEncoded.GetEncoding())
switch (intEncoded.GetEncoding())
{
case EIntegerEncoding.Quint:
{
DecodeQuintBlock(BitStream, DecodeIntegerSequence, IntEncoded.NumberBits);
NumberValuesDecoded += 3;
DecodeQuintBlock(bitStream, decodeIntegerSequence, intEncoded.NumberBits);
numberValuesDecoded += 3;
break;
}
case EIntegerEncoding.Trit:
{
DecodeTritBlock(BitStream, DecodeIntegerSequence, IntEncoded.NumberBits);
NumberValuesDecoded += 5;
DecodeTritBlock(bitStream, decodeIntegerSequence, intEncoded.NumberBits);
numberValuesDecoded += 5;
break;
}
case EIntegerEncoding.JustBits:
{
IntEncoded.BitValue = BitStream.ReadBits(IntEncoded.NumberBits);
DecodeIntegerSequence.Add(IntEncoded);
NumberValuesDecoded++;
intEncoded.BitValue = bitStream.ReadBits(intEncoded.NumberBits);
decodeIntegerSequence.Add(intEncoded);
numberValuesDecoded++;
break;
}

Some files were not shown because too many files have changed in this diff Show more