mirror of
https://github.com/ryujinx-mirror/ryujinx.git
synced 2024-11-26 03:55:15 +00:00
Allow "reinterpretation" of framebuffer/zeta formats (#418)
* (Re)Implement format reinterpretation, other changes * Implement writeback to guest memory, some refactoring * More refactoring, implement reinterpretation the old way again * Clean up * Some fixes on M2MF (old Dma engine), added partial support for P2MF, fix conditional ssy, add Z24S8 zeta format, other fixes * nit: Formatting * Address PR feedback
This commit is contained in:
parent
bec95cacc1
commit
d4187aaa9d
52 changed files with 1594 additions and 1979 deletions
|
@ -287,6 +287,14 @@ namespace ChocolArm64.Memory
|
||||||
return Data;
|
return Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ReadBytes(long Position, byte[] Data, int StartIndex, int Size)
|
||||||
|
{
|
||||||
|
//Note: This will be moved later.
|
||||||
|
EnsureRangeIsValid(Position, (uint)Size);
|
||||||
|
|
||||||
|
Marshal.Copy((IntPtr)Translate(Position), Data, StartIndex, Size);
|
||||||
|
}
|
||||||
|
|
||||||
public void WriteSByte(long Position, sbyte Value)
|
public void WriteSByte(long Position, sbyte Value)
|
||||||
{
|
{
|
||||||
WriteByte(Position, (byte)Value);
|
WriteByte(Position, (byte)Value);
|
||||||
|
@ -403,6 +411,27 @@ namespace ChocolArm64.Memory
|
||||||
Marshal.Copy(Data, 0, (IntPtr)TranslateWrite(Position), Data.Length);
|
Marshal.Copy(Data, 0, (IntPtr)TranslateWrite(Position), Data.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteBytes(long Position, byte[] Data, int StartIndex, int Size)
|
||||||
|
{
|
||||||
|
//Note: This will be moved later.
|
||||||
|
//Using Translate instead of TranslateWrite is on purpose.
|
||||||
|
EnsureRangeIsValid(Position, (uint)Size);
|
||||||
|
|
||||||
|
Marshal.Copy(Data, StartIndex, (IntPtr)Translate(Position), Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyBytes(long Src, long Dst, long Size)
|
||||||
|
{
|
||||||
|
//Note: This will be moved later.
|
||||||
|
EnsureRangeIsValid(Src, Size);
|
||||||
|
EnsureRangeIsValid(Dst, Size);
|
||||||
|
|
||||||
|
byte* SrcPtr = Translate(Src);
|
||||||
|
byte* DstPtr = TranslateWrite(Dst);
|
||||||
|
|
||||||
|
Buffer.MemoryCopy(SrcPtr, DstPtr, Size, Size);
|
||||||
|
}
|
||||||
|
|
||||||
public void Map(long VA, long PA, long Size)
|
public void Map(long VA, long PA, long Size)
|
||||||
{
|
{
|
||||||
SetPTEntries(VA, RamPtr + PA, Size);
|
SetPTEntries(VA, RamPtr + PA, Size);
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
|
using Ryujinx.Graphics.Texture;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal
|
namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
public struct GalImage
|
public struct GalImage
|
||||||
{
|
{
|
||||||
public int Width;
|
public int Width;
|
||||||
public int Height;
|
public int Height;
|
||||||
|
public int TileWidth;
|
||||||
|
public int GobBlockHeight;
|
||||||
|
public int Pitch;
|
||||||
|
|
||||||
public GalImageFormat Format;
|
public GalImageFormat Format;
|
||||||
|
public GalMemoryLayout Layout;
|
||||||
public GalTextureSource XSource;
|
public GalTextureSource XSource;
|
||||||
public GalTextureSource YSource;
|
public GalTextureSource YSource;
|
||||||
public GalTextureSource ZSource;
|
public GalTextureSource ZSource;
|
||||||
|
@ -15,19 +20,44 @@ namespace Ryujinx.Graphics.Gal
|
||||||
public GalImage(
|
public GalImage(
|
||||||
int Width,
|
int Width,
|
||||||
int Height,
|
int Height,
|
||||||
|
int TileWidth,
|
||||||
|
int GobBlockHeight,
|
||||||
|
GalMemoryLayout Layout,
|
||||||
GalImageFormat Format,
|
GalImageFormat Format,
|
||||||
GalTextureSource XSource = GalTextureSource.Red,
|
GalTextureSource XSource = GalTextureSource.Red,
|
||||||
GalTextureSource YSource = GalTextureSource.Green,
|
GalTextureSource YSource = GalTextureSource.Green,
|
||||||
GalTextureSource ZSource = GalTextureSource.Blue,
|
GalTextureSource ZSource = GalTextureSource.Blue,
|
||||||
GalTextureSource WSource = GalTextureSource.Alpha)
|
GalTextureSource WSource = GalTextureSource.Alpha)
|
||||||
{
|
{
|
||||||
this.Width = Width;
|
this.Width = Width;
|
||||||
this.Height = Height;
|
this.Height = Height;
|
||||||
this.Format = Format;
|
this.TileWidth = TileWidth;
|
||||||
this.XSource = XSource;
|
this.GobBlockHeight = GobBlockHeight;
|
||||||
this.YSource = YSource;
|
this.Layout = Layout;
|
||||||
this.ZSource = ZSource;
|
this.Format = Format;
|
||||||
this.WSource = WSource;
|
this.XSource = XSource;
|
||||||
|
this.YSource = YSource;
|
||||||
|
this.ZSource = ZSource;
|
||||||
|
this.WSource = WSource;
|
||||||
|
|
||||||
|
Pitch = ImageUtils.GetPitch(Format, Width);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SizeMatches(GalImage Image)
|
||||||
|
{
|
||||||
|
if (ImageUtils.GetBytesPerPixel(Format) !=
|
||||||
|
ImageUtils.GetBytesPerPixel(Image.Format))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImageUtils.GetAlignedWidth(this) !=
|
||||||
|
ImageUtils.GetAlignedWidth(Image))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Height == Image.Height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
8
Ryujinx.Graphics/Gal/GalMemoryLayout.cs
Normal file
8
Ryujinx.Graphics/Gal/GalMemoryLayout.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public enum GalMemoryLayout
|
||||||
|
{
|
||||||
|
BlockLinear = 0,
|
||||||
|
Pitch = 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,8 @@
|
||||||
|
|
||||||
public GalVertexBinding[] VertexBindings;
|
public GalVertexBinding[] VertexBindings;
|
||||||
|
|
||||||
|
public bool FramebufferSrgb;
|
||||||
|
|
||||||
public float FlipX;
|
public float FlipX;
|
||||||
public float FlipY;
|
public float FlipY;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ namespace Ryujinx.Graphics.Gal
|
||||||
R32G32 = 0x4,
|
R32G32 = 0x4,
|
||||||
A8B8G8R8 = 0x8,
|
A8B8G8R8 = 0x8,
|
||||||
A2B10G10R10 = 0x9,
|
A2B10G10R10 = 0x9,
|
||||||
|
R16G16 = 0xc,
|
||||||
R32 = 0xf,
|
R32 = 0xf,
|
||||||
BC6H_SF16 = 0x10,
|
BC6H_SF16 = 0x10,
|
||||||
BC6H_UF16 = 0x11,
|
BC6H_UF16 = 0x11,
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Gal
|
||||||
|
|
||||||
void SetIndexArray(int Size, GalIndexFormat Format);
|
void SetIndexArray(int Size, GalIndexFormat Format);
|
||||||
|
|
||||||
void DrawArrays(int First, int PrimCount, GalPrimitiveType PrimType);
|
void DrawArrays(int First, int Count, GalPrimitiveType PrimType);
|
||||||
|
|
||||||
void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType);
|
void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,17 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal
|
namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
public interface IGalRenderTarget
|
public interface IGalRenderTarget
|
||||||
{
|
{
|
||||||
void BindColor(long Key, int Attachment);
|
void BindColor(long Key, int Attachment, GalImage Image);
|
||||||
|
|
||||||
void UnbindColor(int Attachment);
|
void UnbindColor(int Attachment);
|
||||||
|
|
||||||
void BindZeta(long Key);
|
void BindZeta(long Key, GalImage Image);
|
||||||
|
|
||||||
void UnbindZeta();
|
void UnbindZeta();
|
||||||
|
|
||||||
void BindTexture(long Key, int Index);
|
|
||||||
|
|
||||||
void Set(long Key);
|
void Set(long Key);
|
||||||
|
|
||||||
void Set(byte[] Data, int Width, int Height);
|
|
||||||
|
|
||||||
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);
|
||||||
|
@ -40,12 +34,8 @@ namespace Ryujinx.Graphics.Gal
|
||||||
int DstX1,
|
int DstX1,
|
||||||
int DstY1);
|
int DstY1);
|
||||||
|
|
||||||
void GetBufferData(long Key, Action<byte[]> Callback);
|
void Reinterpret(long Key, GalImage NewImage);
|
||||||
|
|
||||||
void SetBufferData(
|
byte[] GetData(long Key);
|
||||||
long Key,
|
|
||||||
int Width,
|
|
||||||
int Height,
|
|
||||||
byte[] Buffer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.Graphics.Gal
|
||||||
void LockCache();
|
void LockCache();
|
||||||
void UnlockCache();
|
void UnlockCache();
|
||||||
|
|
||||||
|
void Create(long Key, int Size, GalImage Image);
|
||||||
|
|
||||||
void Create(long Key, byte[] Data, GalImage Image);
|
void Create(long Key, byte[] Data, GalImage Image);
|
||||||
|
|
||||||
void CreateFb(long Key, long Size, GalImage Image);
|
bool TryGetImage(long Key, out GalImage Image);
|
||||||
|
|
||||||
bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image);
|
void Bind(long Key, int Index, GalImage Image);
|
||||||
|
|
||||||
void Bind(long Key, int Index);
|
|
||||||
|
|
||||||
void SetSampler(GalTextureSampler Sampler);
|
void SetSampler(GalTextureSampler Sampler);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,9 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
using Ryujinx.Graphics.Texture;
|
||||||
using Ryujinx.Graphics.Texture;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
class ImageHandler
|
class ImageHandler
|
||||||
{
|
{
|
||||||
private static int CopyBuffer = 0;
|
|
||||||
private static int CopyBufferSize = 0;
|
|
||||||
|
|
||||||
public GalImage Image { get; private set; }
|
public GalImage Image { get; private set; }
|
||||||
|
|
||||||
public int Width => Image.Width;
|
public int Width => Image.Width;
|
||||||
|
@ -16,144 +11,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public GalImageFormat Format => Image.Format;
|
public GalImageFormat Format => Image.Format;
|
||||||
|
|
||||||
public PixelInternalFormat InternalFormat { get; private set; }
|
|
||||||
public PixelFormat PixelFormat { get; private set; }
|
|
||||||
public PixelType PixelType { get; private set; }
|
|
||||||
|
|
||||||
public int Handle { get; private set; }
|
public int Handle { get; private set; }
|
||||||
|
|
||||||
private bool Initialized;
|
|
||||||
|
|
||||||
public ImageHandler()
|
|
||||||
{
|
|
||||||
Handle = GL.GenTexture();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageHandler(int Handle, GalImage Image)
|
|
||||||
{
|
|
||||||
this.Handle = Handle;
|
|
||||||
|
|
||||||
this.Image = Image;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EnsureSetup(GalImage NewImage)
|
|
||||||
{
|
|
||||||
if (Width == NewImage.Width &&
|
|
||||||
Height == NewImage.Height &&
|
|
||||||
Format == NewImage.Format &&
|
|
||||||
Initialized)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PixelInternalFormat InternalFmt;
|
|
||||||
PixelFormat PixelFormat;
|
|
||||||
PixelType PixelType;
|
|
||||||
|
|
||||||
if (ImageUtils.IsCompressed(NewImage.Format))
|
|
||||||
{
|
|
||||||
InternalFmt = (PixelInternalFormat)OGLEnumConverter.GetCompressedImageFormat(NewImage.Format);
|
|
||||||
|
|
||||||
PixelFormat = default(PixelFormat);
|
|
||||||
PixelType = default(PixelType);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
(InternalFmt, PixelFormat, PixelType) = OGLEnumConverter.GetImageFormat(NewImage.Format);
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
|
||||||
|
|
||||||
if (Initialized)
|
|
||||||
{
|
|
||||||
if (CopyBuffer == 0)
|
|
||||||
{
|
|
||||||
CopyBuffer = GL.GenBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
int CurrentSize = Math.Max(ImageUtils.GetSize(NewImage),
|
|
||||||
ImageUtils.GetSize(Image));
|
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyBuffer);
|
|
||||||
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyBuffer);
|
|
||||||
|
|
||||||
if (CopyBufferSize < CurrentSize)
|
|
||||||
{
|
|
||||||
CopyBufferSize = CurrentSize;
|
|
||||||
|
|
||||||
GL.BufferData(BufferTarget.PixelPackBuffer, CurrentSize, IntPtr.Zero, BufferUsageHint.StreamCopy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImageUtils.IsCompressed(Image.Format))
|
|
||||||
{
|
|
||||||
GL.GetCompressedTexImage(TextureTarget.Texture2D, 0, IntPtr.Zero);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GL.GetTexImage(TextureTarget.Texture2D, 0, this.PixelFormat, this.PixelType, IntPtr.Zero);
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.DeleteTexture(Handle);
|
|
||||||
|
|
||||||
Handle = GL.GenTexture();
|
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int MinFilter = (int)TextureMinFilter.Linear;
|
|
||||||
const int MagFilter = (int)TextureMagFilter.Linear;
|
|
||||||
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
|
|
||||||
|
|
||||||
const int Level = 0;
|
|
||||||
const int Border = 0;
|
|
||||||
|
|
||||||
if (ImageUtils.IsCompressed(NewImage.Format))
|
|
||||||
{
|
|
||||||
Console.WriteLine("Hit");
|
|
||||||
|
|
||||||
GL.CompressedTexImage2D(
|
|
||||||
TextureTarget.Texture2D,
|
|
||||||
Level,
|
|
||||||
(InternalFormat)InternalFmt,
|
|
||||||
NewImage.Width,
|
|
||||||
NewImage.Height,
|
|
||||||
Border,
|
|
||||||
ImageUtils.GetSize(NewImage),
|
|
||||||
IntPtr.Zero);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GL.TexImage2D(
|
|
||||||
TextureTarget.Texture2D,
|
|
||||||
Level,
|
|
||||||
InternalFmt,
|
|
||||||
NewImage.Width,
|
|
||||||
NewImage.Height,
|
|
||||||
Border,
|
|
||||||
PixelFormat,
|
|
||||||
PixelType,
|
|
||||||
IntPtr.Zero);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Initialized)
|
|
||||||
{
|
|
||||||
GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
|
|
||||||
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Image = NewImage;
|
|
||||||
|
|
||||||
this.InternalFormat = InternalFmt;
|
|
||||||
this.PixelFormat = PixelFormat;
|
|
||||||
this.PixelType = PixelType;
|
|
||||||
|
|
||||||
Initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasColor => ImageUtils.HasColor(Image.Format);
|
public bool HasColor => ImageUtils.HasColor(Image.Format);
|
||||||
public bool HasDepth => ImageUtils.HasDepth(Image.Format);
|
public bool HasDepth => ImageUtils.HasDepth(Image.Format);
|
||||||
public bool HasStencil => ImageUtils.HasStencil(Image.Format);
|
public bool HasStencil => ImageUtils.HasStencil(Image.Format);
|
||||||
|
|
||||||
|
public ImageHandler(int Handle, GalImage Image)
|
||||||
|
{
|
||||||
|
this.Handle = Handle;
|
||||||
|
this.Image = Image;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public CacheBucket(T Value, long DataSize, LinkedListNode<long> Node)
|
public CacheBucket(T Value, long DataSize, LinkedListNode<long> Node)
|
||||||
{
|
{
|
||||||
this.Value = Value;
|
this.Value = Value;
|
||||||
this.DataSize = DataSize;
|
this.DataSize = DataSize;
|
||||||
this.Node = Node;
|
this.Node = Node;
|
||||||
|
|
||||||
Timestamp = Environment.TickCount;
|
Timestamp = Environment.TickCount;
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,8 +149,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalImageFormat.R32 | GalImageFormat.Sfloat: return (PixelInternalFormat.R32f, PixelFormat.Red, PixelType.Float);
|
case GalImageFormat.R32 | GalImageFormat.Sfloat: return (PixelInternalFormat.R32f, PixelFormat.Red, PixelType.Float);
|
||||||
case GalImageFormat.R32 | GalImageFormat.Sint: return (PixelInternalFormat.R32i, PixelFormat.Red, PixelType.Int);
|
case GalImageFormat.R32 | GalImageFormat.Sint: return (PixelInternalFormat.R32i, PixelFormat.Red, PixelType.Int);
|
||||||
case GalImageFormat.R32 | GalImageFormat.Uint: return (PixelInternalFormat.R32ui, PixelFormat.Red, PixelType.UnsignedInt);
|
case GalImageFormat.R32 | GalImageFormat.Uint: return (PixelInternalFormat.R32ui, PixelFormat.Red, PixelType.UnsignedInt);
|
||||||
case GalImageFormat.A1R5G5B5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551);
|
case GalImageFormat.A1R5G5B5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed);
|
||||||
case GalImageFormat.B5G6R5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565);
|
case GalImageFormat.B5G6R5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565Reversed);
|
||||||
case GalImageFormat.R16G16 | GalImageFormat.Sfloat: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat);
|
case GalImageFormat.R16G16 | GalImageFormat.Sfloat: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat);
|
||||||
case GalImageFormat.R16G16 | GalImageFormat.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short);
|
case GalImageFormat.R16G16 | GalImageFormat.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short);
|
||||||
case GalImageFormat.R16G16 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Byte);
|
case GalImageFormat.R16G16 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Byte);
|
||||||
|
|
|
@ -126,6 +126,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
BindVertexLayout(New);
|
BindVertexLayout(New);
|
||||||
|
|
||||||
|
if (New.FramebufferSrgb != Old.FramebufferSrgb)
|
||||||
|
{
|
||||||
|
Enable(EnableCap.FramebufferSrgb, New.FramebufferSrgb);
|
||||||
|
}
|
||||||
|
|
||||||
if (New.FlipX != Old.FlipX || New.FlipY != Old.FlipY || New.Instance != Old.Instance)
|
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);
|
||||||
|
@ -337,6 +342,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
foreach (GalVertexAttrib Attrib in Binding.Attribs)
|
foreach (GalVertexAttrib Attrib in Binding.Attribs)
|
||||||
{
|
{
|
||||||
|
//Skip uninitialized attributes.
|
||||||
|
if (Attrib.Size == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
GL.EnableVertexAttribArray(Attrib.Index);
|
GL.EnableVertexAttribArray(Attrib.Index);
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
||||||
|
|
|
@ -113,14 +113,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
IndexBuffer.ElemSizeLog2 = (int)Format;
|
IndexBuffer.ElemSizeLog2 = (int)Format;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawArrays(int First, int PrimCount, GalPrimitiveType PrimType)
|
public void DrawArrays(int First, int Count, GalPrimitiveType PrimType)
|
||||||
{
|
{
|
||||||
if (PrimCount == 0)
|
if (Count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, PrimCount);
|
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType)
|
public void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType)
|
||||||
|
|
|
@ -15,9 +15,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public Rect(int X, int Y, int Width, int Height)
|
public Rect(int X, int Y, int Width, int Height)
|
||||||
{
|
{
|
||||||
this.X = X;
|
this.X = X;
|
||||||
this.Y = Y;
|
this.Y = Y;
|
||||||
this.Width = Width;
|
this.Width = Width;
|
||||||
this.Height = Height;
|
this.Height = Height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
private OGLTexture Texture;
|
private OGLTexture Texture;
|
||||||
|
|
||||||
private ImageHandler RawTex;
|
|
||||||
private ImageHandler ReadTex;
|
private ImageHandler ReadTex;
|
||||||
|
|
||||||
private Rect Viewport;
|
private Rect Viewport;
|
||||||
|
@ -64,13 +63,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
this.Texture = Texture;
|
this.Texture = Texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BindColor(long Key, int Attachment)
|
public void BindColor(long Key, int Attachment, GalImage Image)
|
||||||
{
|
{
|
||||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
|
||||||
{
|
{
|
||||||
EnsureFrameBuffer();
|
EnsureFrameBuffer();
|
||||||
|
|
||||||
Attach(ref ColorAttachments[Attachment], Tex.Handle, FramebufferAttachment.ColorAttachment0 + Attachment);
|
Attach(ref ColorAttachments[Attachment], CachedImage.Handle, FramebufferAttachment.ColorAttachment0 + Attachment);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -85,39 +84,38 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Attach(ref ColorAttachments[Attachment], 0, FramebufferAttachment.ColorAttachment0 + Attachment);
|
Attach(ref ColorAttachments[Attachment], 0, FramebufferAttachment.ColorAttachment0 + Attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BindZeta(long Key)
|
public void BindZeta(long Key, GalImage Image)
|
||||||
{
|
{
|
||||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
|
||||||
{
|
{
|
||||||
EnsureFrameBuffer();
|
EnsureFrameBuffer();
|
||||||
|
|
||||||
if (Tex.HasDepth && Tex.HasStencil)
|
if (CachedImage.HasDepth && CachedImage.HasStencil)
|
||||||
{
|
{
|
||||||
if (DepthAttachment != Tex.Handle ||
|
if (DepthAttachment != CachedImage.Handle ||
|
||||||
StencilAttachment != Tex.Handle)
|
StencilAttachment != CachedImage.Handle)
|
||||||
{
|
{
|
||||||
GL.FramebufferTexture(
|
GL.FramebufferTexture(
|
||||||
FramebufferTarget.DrawFramebuffer,
|
FramebufferTarget.DrawFramebuffer,
|
||||||
FramebufferAttachment.DepthStencilAttachment,
|
FramebufferAttachment.DepthStencilAttachment,
|
||||||
Tex.Handle,
|
CachedImage.Handle,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
DepthAttachment = Tex.Handle;
|
DepthAttachment = CachedImage.Handle;
|
||||||
|
StencilAttachment = CachedImage.Handle;
|
||||||
StencilAttachment = Tex.Handle;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Tex.HasDepth)
|
else if (CachedImage.HasDepth)
|
||||||
{
|
{
|
||||||
Attach(ref DepthAttachment, Tex.Handle, FramebufferAttachment.DepthAttachment);
|
Attach(ref DepthAttachment, CachedImage.Handle, FramebufferAttachment.DepthAttachment);
|
||||||
|
|
||||||
Attach(ref StencilAttachment, 0, FramebufferAttachment.StencilAttachment);
|
Attach(ref StencilAttachment, 0, FramebufferAttachment.StencilAttachment);
|
||||||
}
|
}
|
||||||
else if (Tex.HasStencil)
|
else if (CachedImage.HasStencil)
|
||||||
{
|
{
|
||||||
Attach(ref DepthAttachment, 0, FramebufferAttachment.DepthAttachment);
|
Attach(ref DepthAttachment, 0, FramebufferAttachment.DepthAttachment);
|
||||||
|
|
||||||
Attach(ref StencilAttachment, Tex.Handle, FramebufferAttachment.StencilAttachment);
|
Attach(ref StencilAttachment, CachedImage.Handle, FramebufferAttachment.StencilAttachment);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -130,12 +128,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment)
|
||||||
|
{
|
||||||
|
if (OldHandle != NewHandle)
|
||||||
|
{
|
||||||
|
GL.FramebufferTexture(
|
||||||
|
FramebufferTarget.DrawFramebuffer,
|
||||||
|
FbAttachment,
|
||||||
|
NewHandle,
|
||||||
|
0);
|
||||||
|
|
||||||
|
OldHandle = NewHandle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void UnbindZeta()
|
public void UnbindZeta()
|
||||||
{
|
{
|
||||||
EnsureFrameBuffer();
|
EnsureFrameBuffer();
|
||||||
|
|
||||||
if (DepthAttachment != 0 ||
|
if (DepthAttachment != 0 || StencilAttachment != 0)
|
||||||
StencilAttachment != 0)
|
|
||||||
{
|
{
|
||||||
GL.FramebufferTexture(
|
GL.FramebufferTexture(
|
||||||
FramebufferTarget.DrawFramebuffer,
|
FramebufferTarget.DrawFramebuffer,
|
||||||
|
@ -143,44 +154,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
0,
|
0,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
DepthAttachment = 0;
|
DepthAttachment = 0;
|
||||||
|
|
||||||
StencilAttachment = 0;
|
StencilAttachment = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BindTexture(long Key, int Index)
|
|
||||||
{
|
|
||||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
|
||||||
{
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Set(long Key)
|
public void Set(long Key)
|
||||||
{
|
{
|
||||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
Texture.TryGetImageHandler(Key, out ReadTex);
|
||||||
{
|
|
||||||
ReadTex = Tex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Set(byte[] Data, int Width, int Height)
|
|
||||||
{
|
|
||||||
if (RawTex == null)
|
|
||||||
{
|
|
||||||
RawTex = new ImageHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
RawTex.EnsureSetup(new GalImage(Width, Height, RawFormat));
|
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, RawTex.Handle);
|
|
||||||
|
|
||||||
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, RawTex.PixelFormat, RawTex.PixelType, Data);
|
|
||||||
|
|
||||||
ReadTex = RawTex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetMap(int[] Map)
|
public void SetMap(int[] Map)
|
||||||
|
@ -280,13 +261,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
|
int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
|
||||||
int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
|
int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
|
||||||
|
|
||||||
if (SrcFb == 0) SrcFb = GL.GenFramebuffer();
|
|
||||||
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
|
|
||||||
|
|
||||||
GL.Viewport(0, 0, Window.Width, Window.Height);
|
GL.Viewport(0, 0, Window.Width, Window.Height);
|
||||||
|
|
||||||
|
if (SrcFb == 0)
|
||||||
|
{
|
||||||
|
SrcFb = GL.GenFramebuffer();
|
||||||
|
}
|
||||||
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
|
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
|
||||||
|
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
|
||||||
|
|
||||||
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, ReadTex.Handle, 0);
|
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, ReadTex.Handle, 0);
|
||||||
|
|
||||||
|
@ -298,7 +281,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
GL.BlitFramebuffer(
|
GL.BlitFramebuffer(
|
||||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||||
DstX0, DstY0, DstX1, DstY1,
|
DstX0, DstY0, DstX1, DstY1,
|
||||||
ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear);
|
ClearBufferMask.ColorBufferBit,
|
||||||
|
BlitFramebufferFilter.Linear);
|
||||||
|
|
||||||
EnsureFrameBuffer();
|
EnsureFrameBuffer();
|
||||||
}
|
}
|
||||||
|
@ -315,110 +299,135 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
int DstX1,
|
int DstX1,
|
||||||
int DstY1)
|
int DstY1)
|
||||||
{
|
{
|
||||||
if (Texture.TryGetImage(SrcKey, out ImageHandler SrcTex) &&
|
if (Texture.TryGetImageHandler(SrcKey, out ImageHandler SrcTex) &&
|
||||||
Texture.TryGetImage(DstKey, out ImageHandler DstTex))
|
Texture.TryGetImageHandler(DstKey, out ImageHandler DstTex))
|
||||||
{
|
{
|
||||||
if (SrcTex.HasColor != DstTex.HasColor ||
|
if (SrcTex.HasColor != DstTex.HasColor ||
|
||||||
SrcTex.HasDepth != DstTex.HasDepth ||
|
SrcTex.HasDepth != DstTex.HasDepth ||
|
||||||
SrcTex.HasStencil != DstTex.HasStencil)
|
SrcTex.HasStencil != DstTex.HasStencil)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SrcFb == 0)
|
||||||
|
{
|
||||||
|
SrcFb = GL.GenFramebuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DstFb == 0)
|
||||||
|
{
|
||||||
|
DstFb = GL.GenFramebuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
|
||||||
|
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb);
|
||||||
|
|
||||||
|
FramebufferAttachment Attachment = GetAttachment(SrcTex);
|
||||||
|
|
||||||
|
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0);
|
||||||
|
GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0);
|
||||||
|
|
||||||
|
BlitFramebufferFilter Filter = BlitFramebufferFilter.Nearest;
|
||||||
|
|
||||||
if (SrcTex.HasColor)
|
if (SrcTex.HasColor)
|
||||||
{
|
{
|
||||||
CopyTextures(
|
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
|
||||||
DstX0, DstY0, DstX1, DstY1,
|
Filter = BlitFramebufferFilter.Linear;
|
||||||
SrcTex.Handle,
|
|
||||||
DstTex.Handle,
|
|
||||||
FramebufferAttachment.ColorAttachment0,
|
|
||||||
ClearBufferMask.ColorBufferBit,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
else if (SrcTex.HasDepth && SrcTex.HasStencil)
|
|
||||||
{
|
|
||||||
CopyTextures(
|
|
||||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
|
||||||
DstX0, DstY0, DstX1, DstY1,
|
|
||||||
SrcTex.Handle,
|
|
||||||
DstTex.Handle,
|
|
||||||
FramebufferAttachment.DepthStencilAttachment,
|
|
||||||
ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit,
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
else if (SrcTex.HasDepth)
|
|
||||||
{
|
|
||||||
CopyTextures(
|
|
||||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
|
||||||
DstX0, DstY0, DstX1, DstY1,
|
|
||||||
SrcTex.Handle,
|
|
||||||
DstTex.Handle,
|
|
||||||
FramebufferAttachment.DepthAttachment,
|
|
||||||
ClearBufferMask.DepthBufferBit,
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
else if (SrcTex.HasStencil)
|
|
||||||
{
|
|
||||||
CopyTextures(
|
|
||||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
|
||||||
DstX0, DstY0, DstX1, DstY1,
|
|
||||||
SrcTex.Handle,
|
|
||||||
DstTex.Handle,
|
|
||||||
FramebufferAttachment.StencilAttachment,
|
|
||||||
ClearBufferMask.StencilBufferBit,
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClearBufferMask Mask = GetClearMask(SrcTex);
|
||||||
|
|
||||||
|
GL.Clear(Mask);
|
||||||
|
|
||||||
|
GL.BlitFramebuffer(SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, Mask, Filter);
|
||||||
|
|
||||||
|
EnsureFrameBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetBufferData(long Key, Action<byte[]> Callback)
|
public void Reinterpret(long Key, GalImage NewImage)
|
||||||
{
|
{
|
||||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
if (!Texture.TryGetImage(Key, out GalImage OldImage))
|
||||||
{
|
{
|
||||||
byte[] Data = new byte[ImageUtils.GetSize(Tex.Image)];
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
|
if (NewImage.Format == OldImage.Format)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GL.GetTexImage(
|
byte[] Data = GetData(Key);
|
||||||
TextureTarget.Texture2D,
|
|
||||||
0,
|
|
||||||
Tex.PixelFormat,
|
|
||||||
Tex.PixelType,
|
|
||||||
Data);
|
|
||||||
|
|
||||||
Callback(Data);
|
GL.PixelStore(PixelStoreParameter.UnpackRowLength, OldImage.Width);
|
||||||
|
|
||||||
|
Texture.Create(Key, Data, NewImage);
|
||||||
|
|
||||||
|
GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetData(long Key)
|
||||||
|
{
|
||||||
|
if (!Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SrcFb == 0)
|
||||||
|
{
|
||||||
|
SrcFb = GL.GenFramebuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
|
||||||
|
|
||||||
|
FramebufferAttachment Attachment = GetAttachment(CachedImage);
|
||||||
|
|
||||||
|
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, CachedImage.Handle, 0);
|
||||||
|
|
||||||
|
int Size = ImageUtils.GetSize(CachedImage.Image);
|
||||||
|
|
||||||
|
byte[] Data = new byte[Size];
|
||||||
|
|
||||||
|
int Width = CachedImage.Width;
|
||||||
|
int Height = CachedImage.Height;
|
||||||
|
|
||||||
|
(_, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(CachedImage.Format);
|
||||||
|
|
||||||
|
GL.ReadPixels(0, 0, Width, Height, Format, Type, Data);
|
||||||
|
|
||||||
|
return Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FramebufferAttachment GetAttachment(ImageHandler CachedImage)
|
||||||
|
{
|
||||||
|
if (CachedImage.HasColor)
|
||||||
|
{
|
||||||
|
return FramebufferAttachment.ColorAttachment0;
|
||||||
|
}
|
||||||
|
else if (CachedImage.HasDepth && CachedImage.HasStencil)
|
||||||
|
{
|
||||||
|
return FramebufferAttachment.DepthStencilAttachment;
|
||||||
|
}
|
||||||
|
else if (CachedImage.HasDepth)
|
||||||
|
{
|
||||||
|
return FramebufferAttachment.DepthAttachment;
|
||||||
|
}
|
||||||
|
else if (CachedImage.HasStencil)
|
||||||
|
{
|
||||||
|
return FramebufferAttachment.StencilAttachment;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetBufferData(
|
private static ClearBufferMask GetClearMask(ImageHandler CachedImage)
|
||||||
long Key,
|
|
||||||
int Width,
|
|
||||||
int Height,
|
|
||||||
byte[] Buffer)
|
|
||||||
{
|
{
|
||||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
return (CachedImage.HasColor ? ClearBufferMask.ColorBufferBit : 0) |
|
||||||
{
|
(CachedImage.HasDepth ? ClearBufferMask.DepthBufferBit : 0) |
|
||||||
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
|
(CachedImage.HasStencil ? ClearBufferMask.StencilBufferBit : 0);
|
||||||
|
|
||||||
const int Level = 0;
|
|
||||||
const int Border = 0;
|
|
||||||
|
|
||||||
GL.TexImage2D(
|
|
||||||
TextureTarget.Texture2D,
|
|
||||||
Level,
|
|
||||||
Tex.InternalFormat,
|
|
||||||
Width,
|
|
||||||
Height,
|
|
||||||
Border,
|
|
||||||
Tex.PixelFormat,
|
|
||||||
Tex.PixelType,
|
|
||||||
Buffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnsureFrameBuffer()
|
private void EnsureFrameBuffer()
|
||||||
|
@ -430,68 +439,5 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
|
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment)
|
|
||||||
{
|
|
||||||
if (OldHandle != NewHandle)
|
|
||||||
{
|
|
||||||
GL.FramebufferTexture(
|
|
||||||
FramebufferTarget.DrawFramebuffer,
|
|
||||||
FbAttachment,
|
|
||||||
NewHandle,
|
|
||||||
0);
|
|
||||||
|
|
||||||
OldHandle = NewHandle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CopyTextures(
|
|
||||||
int SrcX0,
|
|
||||||
int SrcY0,
|
|
||||||
int SrcX1,
|
|
||||||
int SrcY1,
|
|
||||||
int DstX0,
|
|
||||||
int DstY0,
|
|
||||||
int DstX1,
|
|
||||||
int DstY1,
|
|
||||||
int SrcTexture,
|
|
||||||
int DstTexture,
|
|
||||||
FramebufferAttachment Attachment,
|
|
||||||
ClearBufferMask Mask,
|
|
||||||
bool Color)
|
|
||||||
{
|
|
||||||
if (SrcFb == 0) SrcFb = GL.GenFramebuffer();
|
|
||||||
if (DstFb == 0) DstFb = GL.GenFramebuffer();
|
|
||||||
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb);
|
|
||||||
|
|
||||||
GL.FramebufferTexture(
|
|
||||||
FramebufferTarget.ReadFramebuffer,
|
|
||||||
Attachment,
|
|
||||||
SrcTexture,
|
|
||||||
0);
|
|
||||||
|
|
||||||
GL.FramebufferTexture(
|
|
||||||
FramebufferTarget.DrawFramebuffer,
|
|
||||||
Attachment,
|
|
||||||
DstTexture,
|
|
||||||
0);
|
|
||||||
|
|
||||||
if (Color)
|
|
||||||
{
|
|
||||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.Clear(Mask);
|
|
||||||
|
|
||||||
GL.BlitFramebuffer(
|
|
||||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
|
||||||
DstX0, DstY0, DstX1, DstY1,
|
|
||||||
Mask,
|
|
||||||
Color ? BlitFramebufferFilter.Linear : BlitFramebufferFilter.Nearest);
|
|
||||||
|
|
||||||
EnsureFrameBuffer();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -28,17 +28,65 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
GL.DeleteTexture(CachedImage.Handle);
|
GL.DeleteTexture(CachedImage.Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Create(long Key, byte[] Data, GalImage Image)
|
public void Create(long Key, int Size, GalImage Image)
|
||||||
{
|
{
|
||||||
int Handle = GL.GenTexture();
|
int Handle = GL.GenTexture();
|
||||||
|
|
||||||
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length);
|
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||||
|
|
||||||
const int Level = 0; //TODO: Support mipmap textures.
|
const int Level = 0; //TODO: Support mipmap textures.
|
||||||
const int Border = 0;
|
const int Border = 0;
|
||||||
|
|
||||||
|
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Size);
|
||||||
|
|
||||||
|
GalImageFormat TypeLess = Image.Format & GalImageFormat.FormatMask;
|
||||||
|
|
||||||
|
bool IsASTC = TypeLess >= GalImageFormat.ASTC_BEGIN && TypeLess <= GalImageFormat.ASTC_END;
|
||||||
|
|
||||||
|
if (ImageUtils.IsCompressed(Image.Format) && !IsASTC)
|
||||||
|
{
|
||||||
|
InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format);
|
||||||
|
|
||||||
|
GL.CompressedTexImage2D(
|
||||||
|
TextureTarget.Texture2D,
|
||||||
|
Level,
|
||||||
|
InternalFmt,
|
||||||
|
Image.Width,
|
||||||
|
Image.Height,
|
||||||
|
Border,
|
||||||
|
Size,
|
||||||
|
IntPtr.Zero);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(PixelInternalFormat InternalFmt,
|
||||||
|
PixelFormat Format,
|
||||||
|
PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
|
||||||
|
|
||||||
|
GL.TexImage2D(
|
||||||
|
TextureTarget.Texture2D,
|
||||||
|
Level,
|
||||||
|
InternalFmt,
|
||||||
|
Image.Width,
|
||||||
|
Image.Height,
|
||||||
|
Border,
|
||||||
|
Format,
|
||||||
|
Type,
|
||||||
|
IntPtr.Zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Create(long Key, byte[] Data, GalImage Image)
|
||||||
|
{
|
||||||
|
int Handle = GL.GenTexture();
|
||||||
|
|
||||||
|
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||||
|
|
||||||
|
const int Level = 0; //TODO: Support mipmap textures.
|
||||||
|
const int Border = 0;
|
||||||
|
|
||||||
|
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length);
|
||||||
|
|
||||||
GalImageFormat TypeLess = Image.Format & GalImageFormat.FormatMask;
|
GalImageFormat TypeLess = Image.Format & GalImageFormat.FormatMask;
|
||||||
|
|
||||||
bool IsASTC = TypeLess >= GalImageFormat.ASTC_BEGIN && TypeLess <= GalImageFormat.ASTC_END;
|
bool IsASTC = TypeLess >= GalImageFormat.ASTC_BEGIN && TypeLess <= GalImageFormat.ASTC_END;
|
||||||
|
@ -62,8 +110,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
//TODO: Use KHR_texture_compression_astc_hdr when available
|
//TODO: Use KHR_texture_compression_astc_hdr when available
|
||||||
if (IsASTC)
|
if (IsASTC)
|
||||||
{
|
{
|
||||||
int TextureBlockWidth = GetAstcBlockWidth(Image.Format);
|
int TextureBlockWidth = ImageUtils.GetBlockWidth(Image.Format);
|
||||||
int TextureBlockHeight = GetAstcBlockHeight(Image.Format);
|
int TextureBlockHeight = ImageUtils.GetBlockHeight(Image.Format);
|
||||||
|
|
||||||
Data = ASTCDecoder.DecodeToRGBA8888(
|
Data = ASTCDecoder.DecodeToRGBA8888(
|
||||||
Data,
|
Data,
|
||||||
|
@ -85,12 +133,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Image.Format = GalImageFormat.R8G8 | (Image.Format & GalImageFormat.TypeMask);
|
Image.Format = GalImageFormat.R8G8 | (Image.Format & GalImageFormat.TypeMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
(PixelInternalFormat InternalFormat, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
|
(PixelInternalFormat InternalFmt,
|
||||||
|
PixelFormat Format,
|
||||||
|
PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
|
||||||
|
|
||||||
GL.TexImage2D(
|
GL.TexImage2D(
|
||||||
TextureTarget.Texture2D,
|
TextureTarget.Texture2D,
|
||||||
Level,
|
Level,
|
||||||
InternalFormat,
|
InternalFmt,
|
||||||
Image.Width,
|
Image.Width,
|
||||||
Image.Height,
|
Image.Height,
|
||||||
Border,
|
Border,
|
||||||
|
@ -98,31 +148,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Type,
|
Type,
|
||||||
Data);
|
Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SwizzleR = (int)OGLEnumConverter.GetTextureSwizzle(Image.XSource);
|
|
||||||
int SwizzleG = (int)OGLEnumConverter.GetTextureSwizzle(Image.YSource);
|
|
||||||
int SwizzleB = (int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource);
|
|
||||||
int SwizzleA = (int)OGLEnumConverter.GetTextureSwizzle(Image.WSource);
|
|
||||||
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, SwizzleR);
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, SwizzleG);
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleB, SwizzleB);
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateFb(long Key, long Size, GalImage Image)
|
public bool TryGetImage(long Key, out GalImage Image)
|
||||||
{
|
{
|
||||||
if (!TryGetImage(Key, out ImageHandler CachedImage))
|
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
|
||||||
{
|
{
|
||||||
CachedImage = new ImageHandler();
|
Image = CachedImage.Image;
|
||||||
|
|
||||||
TextureCache.AddOrUpdate(Key, CachedImage, Size);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedImage.EnsureSetup(Image);
|
Image = default(GalImage);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetImage(long Key, out ImageHandler CachedImage)
|
public bool TryGetImageHandler(long Key, out ImageHandler CachedImage)
|
||||||
{
|
{
|
||||||
if (TextureCache.TryGetValue(Key, out CachedImage))
|
if (TextureCache.TryGetValue(Key, out CachedImage))
|
||||||
{
|
{
|
||||||
|
@ -134,76 +176,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetAstcBlockWidth(GalImageFormat Format)
|
public void Bind(long Key, int Index, GalImage Image)
|
||||||
{
|
|
||||||
switch (Format)
|
|
||||||
{
|
|
||||||
case GalImageFormat.ASTC_4x4 | GalImageFormat.Unorm: return 4;
|
|
||||||
case GalImageFormat.ASTC_5x5 | GalImageFormat.Unorm: return 5;
|
|
||||||
case GalImageFormat.ASTC_6x6 | GalImageFormat.Unorm: return 6;
|
|
||||||
case GalImageFormat.ASTC_8x8 | GalImageFormat.Unorm: return 8;
|
|
||||||
case GalImageFormat.ASTC_10x10 | GalImageFormat.Unorm: return 10;
|
|
||||||
case GalImageFormat.ASTC_12x12 | GalImageFormat.Unorm: return 12;
|
|
||||||
case GalImageFormat.ASTC_5x4 | GalImageFormat.Unorm: return 5;
|
|
||||||
case GalImageFormat.ASTC_6x5 | GalImageFormat.Unorm: return 6;
|
|
||||||
case GalImageFormat.ASTC_8x6 | GalImageFormat.Unorm: return 8;
|
|
||||||
case GalImageFormat.ASTC_10x8 | GalImageFormat.Unorm: return 10;
|
|
||||||
case GalImageFormat.ASTC_12x10 | GalImageFormat.Unorm: return 12;
|
|
||||||
case GalImageFormat.ASTC_8x5 | GalImageFormat.Unorm: return 8;
|
|
||||||
case GalImageFormat.ASTC_10x5 | GalImageFormat.Unorm: return 10;
|
|
||||||
case GalImageFormat.ASTC_10x6 | GalImageFormat.Unorm: return 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Format));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int GetAstcBlockHeight(GalImageFormat Format)
|
|
||||||
{
|
|
||||||
switch (Format)
|
|
||||||
{
|
|
||||||
case GalImageFormat.ASTC_4x4 | GalImageFormat.Unorm: return 4;
|
|
||||||
case GalImageFormat.ASTC_5x5 | GalImageFormat.Unorm: return 5;
|
|
||||||
case GalImageFormat.ASTC_6x6 | GalImageFormat.Unorm: return 6;
|
|
||||||
case GalImageFormat.ASTC_8x8 | GalImageFormat.Unorm: return 8;
|
|
||||||
case GalImageFormat.ASTC_10x10 | GalImageFormat.Unorm: return 10;
|
|
||||||
case GalImageFormat.ASTC_12x12 | GalImageFormat.Unorm: return 12;
|
|
||||||
case GalImageFormat.ASTC_5x4 | GalImageFormat.Unorm: return 4;
|
|
||||||
case GalImageFormat.ASTC_6x5 | GalImageFormat.Unorm: return 5;
|
|
||||||
case GalImageFormat.ASTC_8x6 | GalImageFormat.Unorm: return 6;
|
|
||||||
case GalImageFormat.ASTC_10x8 | GalImageFormat.Unorm: return 8;
|
|
||||||
case GalImageFormat.ASTC_12x10 | GalImageFormat.Unorm: return 10;
|
|
||||||
case GalImageFormat.ASTC_8x5 | GalImageFormat.Unorm: return 5;
|
|
||||||
case GalImageFormat.ASTC_10x5 | GalImageFormat.Unorm: return 5;
|
|
||||||
case GalImageFormat.ASTC_10x6 | GalImageFormat.Unorm: return 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Format));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image)
|
|
||||||
{
|
|
||||||
if (TextureCache.TryGetSize(Key, out long Size) && Size == DataSize)
|
|
||||||
{
|
|
||||||
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
|
|
||||||
{
|
|
||||||
Image = CachedImage.Image;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Image = default(GalImage);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Bind(long Key, int Index)
|
|
||||||
{
|
{
|
||||||
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
|
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
|
||||||
{
|
{
|
||||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle);
|
GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle);
|
||||||
|
|
||||||
|
int[] SwizzleRgba = new int[]
|
||||||
|
{
|
||||||
|
(int)OGLEnumConverter.GetTextureSwizzle(Image.XSource),
|
||||||
|
(int)OGLEnumConverter.GetTextureSwizzle(Image.YSource),
|
||||||
|
(int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource),
|
||||||
|
(int)OGLEnumConverter.GetTextureSwizzle(Image.WSource)
|
||||||
|
};
|
||||||
|
|
||||||
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleRgba, SwizzleRgba);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -641,6 +641,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
default:
|
default:
|
||||||
SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
|
SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,32 +6,32 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static partial class ShaderDecode
|
static partial class ShaderDecode
|
||||||
{
|
{
|
||||||
public static void Bfe_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Bfe_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitBfe(Block, OpCode, ShaderOper.CR);
|
EmitBfe(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Bfe_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Bfe_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitBfe(Block, OpCode, ShaderOper.Imm);
|
EmitBfe(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Bfe_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Bfe_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitBfe(Block, OpCode, ShaderOper.RR);
|
EmitBfe(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fadd_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fadd_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFadd(Block, OpCode, ShaderOper.CR);
|
EmitFadd(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fadd_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fadd_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFadd(Block, OpCode, ShaderOper.Immf);
|
EmitFadd(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fadd_I32(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fadd_I32(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode OperA = OpCode.Gpr8();
|
ShaderIrNode OperA = OpCode.Gpr8();
|
||||||
ShaderIrNode OperB = OpCode.Immf32_20();
|
ShaderIrNode OperB = OpCode.Immf32_20();
|
||||||
|
@ -49,47 +49,47 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fadd_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fadd_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFadd(Block, OpCode, ShaderOper.RR);
|
EmitFadd(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ffma_CR(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Ffma_CR(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFfma(Block, OpCode, ShaderOper.CR);
|
EmitFfma(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ffma_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Ffma_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFfma(Block, OpCode, ShaderOper.Immf);
|
EmitFfma(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ffma_RC(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Ffma_RC(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFfma(Block, OpCode, ShaderOper.RC);
|
EmitFfma(Block, OpCode, ShaderOper.RC);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ffma_RR(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Ffma_RR(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFfma(Block, OpCode, ShaderOper.RR);
|
EmitFfma(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fmnmx_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fmnmx_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFmnmx(Block, OpCode, ShaderOper.CR);
|
EmitFmnmx(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fmnmx_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fmnmx_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFmnmx(Block, OpCode, ShaderOper.Immf);
|
EmitFmnmx(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fmnmx_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fmnmx_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFmnmx(Block, OpCode, ShaderOper.RR);
|
EmitFmnmx(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fmul_I32(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fmul_I32(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode OperA = OpCode.Gpr8();
|
ShaderIrNode OperA = OpCode.Gpr8();
|
||||||
ShaderIrNode OperB = OpCode.Immf32_20();
|
ShaderIrNode OperB = OpCode.Immf32_20();
|
||||||
|
@ -99,62 +99,62 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fmul_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fmul_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFmul(Block, OpCode, ShaderOper.CR);
|
EmitFmul(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fmul_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fmul_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFmul(Block, OpCode, ShaderOper.Immf);
|
EmitFmul(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fmul_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fmul_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFmul(Block, OpCode, ShaderOper.RR);
|
EmitFmul(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fset_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fset_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFset(Block, OpCode, ShaderOper.CR);
|
EmitFset(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fset_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fset_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFset(Block, OpCode, ShaderOper.Immf);
|
EmitFset(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fset_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fset_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFset(Block, OpCode, ShaderOper.RR);
|
EmitFset(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fsetp_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fsetp_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFsetp(Block, OpCode, ShaderOper.CR);
|
EmitFsetp(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fsetp_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fsetp_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFsetp(Block, OpCode, ShaderOper.Immf);
|
EmitFsetp(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fsetp_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Fsetp_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitFsetp(Block, OpCode, ShaderOper.RR);
|
EmitFsetp(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iadd_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Iadd_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitIadd(Block, OpCode, ShaderOper.CR);
|
EmitIadd(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iadd_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Iadd_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitIadd(Block, OpCode, ShaderOper.Imm);
|
EmitIadd(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iadd_I32(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Iadd_I32(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode OperA = OpCode.Gpr8();
|
ShaderIrNode OperA = OpCode.Gpr8();
|
||||||
ShaderIrNode OperB = OpCode.Imm32_20();
|
ShaderIrNode OperB = OpCode.Imm32_20();
|
||||||
|
@ -168,42 +168,42 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iadd_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Iadd_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitIadd(Block, OpCode, ShaderOper.RR);
|
EmitIadd(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iadd3_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Iadd3_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitIadd3(Block, OpCode, ShaderOper.CR);
|
EmitIadd3(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iadd3_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Iadd3_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitIadd3(Block, OpCode, ShaderOper.Imm);
|
EmitIadd3(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iadd3_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Iadd3_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitIadd3(Block, OpCode, ShaderOper.RR);
|
EmitIadd3(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Imnmx_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Imnmx_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitImnmx(Block, OpCode, ShaderOper.CR);
|
EmitImnmx(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Imnmx_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Imnmx_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitImnmx(Block, OpCode, ShaderOper.Imm);
|
EmitImnmx(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Imnmx_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Imnmx_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitImnmx(Block, OpCode, ShaderOper.RR);
|
EmitImnmx(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ipa(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Ipa(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode OperA = OpCode.Abuf28();
|
ShaderIrNode OperA = OpCode.Abuf28();
|
||||||
ShaderIrNode OperB = OpCode.Gpr20();
|
ShaderIrNode OperB = OpCode.Gpr20();
|
||||||
|
@ -217,52 +217,52 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iscadd_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Iscadd_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitIscadd(Block, OpCode, ShaderOper.CR);
|
EmitIscadd(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iscadd_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Iscadd_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitIscadd(Block, OpCode, ShaderOper.Imm);
|
EmitIscadd(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iscadd_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Iscadd_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitIscadd(Block, OpCode, ShaderOper.RR);
|
EmitIscadd(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iset_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Iset_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitIset(Block, OpCode, ShaderOper.CR);
|
EmitIset(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iset_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Iset_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitIset(Block, OpCode, ShaderOper.Imm);
|
EmitIset(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iset_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Iset_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitIset(Block, OpCode, ShaderOper.RR);
|
EmitIset(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Isetp_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Isetp_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitIsetp(Block, OpCode, ShaderOper.CR);
|
EmitIsetp(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Isetp_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Isetp_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitIsetp(Block, OpCode, ShaderOper.Imm);
|
EmitIsetp(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Isetp_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Isetp_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitIsetp(Block, OpCode, ShaderOper.RR);
|
EmitIsetp(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Lop_I32(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Lop_I32(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
int SubOp = OpCode.Read(53, 3);
|
int SubOp = OpCode.Read(53, 3);
|
||||||
|
|
||||||
|
@ -296,22 +296,22 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Lop_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Lop_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitLop(Block, OpCode, ShaderOper.CR);
|
EmitLop(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Lop_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Lop_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitLop(Block, OpCode, ShaderOper.Imm);
|
EmitLop(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Lop_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Lop_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitLop(Block, OpCode, ShaderOper.RR);
|
EmitLop(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mufu(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Mufu(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
int SubOp = OpCode.Read(20, 0xf);
|
int SubOp = OpCode.Read(20, 0xf);
|
||||||
|
|
||||||
|
@ -340,7 +340,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Psetp(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Psetp(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
bool NegA = OpCode.Read(15);
|
bool NegA = OpCode.Read(15);
|
||||||
bool NegB = OpCode.Read(32);
|
bool NegB = OpCode.Read(32);
|
||||||
|
@ -394,47 +394,47 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
|
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Rro_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Rro_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitRro(Block, OpCode, ShaderOper.CR);
|
EmitRro(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Rro_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Rro_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitRro(Block, OpCode, ShaderOper.Immf);
|
EmitRro(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Rro_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Rro_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitRro(Block, OpCode, ShaderOper.RR);
|
EmitRro(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shl_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Shl_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Lsl);
|
EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Lsl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shl_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Shl_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Lsl);
|
EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Lsl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shl_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Shl_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Lsl);
|
EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Lsl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shr_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Shr_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode));
|
EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shr_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Shr_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.Imm, GetShrInst(OpCode));
|
EmitAluBinary(Block, OpCode, ShaderOper.Imm, GetShrInst(OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shr_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Shr_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.RR, GetShrInst(OpCode));
|
EmitAluBinary(Block, OpCode, ShaderOper.RR, GetShrInst(OpCode));
|
||||||
}
|
}
|
||||||
|
@ -446,7 +446,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
return Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Vmad(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Vmad(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode OperA = OpCode.Gpr8();
|
ShaderIrNode OperA = OpCode.Gpr8();
|
||||||
|
|
||||||
|
@ -481,22 +481,22 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Final)));
|
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Final)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Xmad_CR(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Xmad_CR(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitXmad(Block, OpCode, ShaderOper.CR);
|
EmitXmad(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Xmad_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Xmad_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitXmad(Block, OpCode, ShaderOper.Imm);
|
EmitXmad(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Xmad_RC(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Xmad_RC(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitXmad(Block, OpCode, ShaderOper.RC);
|
EmitXmad(Block, OpCode, ShaderOper.RC);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Xmad_RR(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Xmad_RR(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitXmad(Block, OpCode, ShaderOper.RR);
|
EmitXmad(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static partial class ShaderDecode
|
static partial class ShaderDecode
|
||||||
{
|
{
|
||||||
public static void Bra(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Bra(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
if ((OpCode & 0x20) != 0)
|
if ((OpCode & 0x20) != 0)
|
||||||
{
|
{
|
||||||
|
@ -15,14 +13,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Target = OpCode.Branch();
|
ShaderIrOperImm Imm = new ShaderIrOperImm(Position + OpCode.Branch());
|
||||||
|
|
||||||
ShaderIrOperImm Imm = new ShaderIrOperImm(Target);
|
|
||||||
|
|
||||||
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, long Position)
|
public static void Exit(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
int CCode = (int)OpCode & 0x1f;
|
int CCode = (int)OpCode & 0x1f;
|
||||||
|
|
||||||
|
@ -31,15 +27,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Exit)));
|
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Exit)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Kil(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Kil(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Kil)));
|
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Kil)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ssy(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Ssy(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
if ((OpCode & 0x20) != 0)
|
if ((OpCode & 0x20) != 0)
|
||||||
{
|
{
|
||||||
|
@ -48,19 +43,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Offset = OpCode.Branch();
|
ShaderIrOperImm Imm = new ShaderIrOperImm(Position + OpCode.Branch());
|
||||||
|
|
||||||
int Target = (int)(Position + Offset);
|
|
||||||
|
|
||||||
ShaderIrOperImm Imm = new ShaderIrOperImm(Target);
|
|
||||||
|
|
||||||
Block.AddNode(new ShaderIrOp(ShaderIrInst.Ssy, Imm));
|
Block.AddNode(new ShaderIrOp(ShaderIrInst.Ssy, Imm));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sync(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Sync(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
//TODO: Implement Sync condition codes
|
//TODO: Implement Sync condition codes
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Sync)));
|
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Sync)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode, long Position);
|
delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode, int Position);
|
||||||
}
|
}
|
|
@ -1,5 +1,3 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static class ShaderDecodeHelper
|
static class ShaderDecodeHelper
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{ RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
|
{ RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static void Ld_A(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Ld_A(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode[] Opers = OpCode.Abuf20();
|
ShaderIrNode[] Opers = OpCode.Abuf20();
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ld_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Ld_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
int CbufPos = OpCode.Read(22, 0x3fff);
|
int CbufPos = OpCode.Read(22, 0x3fff);
|
||||||
int CbufIndex = OpCode.Read(36, 0x1f);
|
int CbufIndex = OpCode.Read(36, 0x1f);
|
||||||
|
@ -97,7 +97,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void St_A(ShaderIrBlock Block, long OpCode, long Position)
|
public static void St_A(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode[] Opers = OpCode.Abuf20();
|
ShaderIrNode[] Opers = OpCode.Abuf20();
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Texq(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Texq(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode OperD = OpCode.Gpr0();
|
ShaderIrNode OperD = OpCode.Gpr0();
|
||||||
ShaderIrNode OperA = OpCode.Gpr8();
|
ShaderIrNode OperA = OpCode.Gpr8();
|
||||||
|
@ -132,12 +132,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperA, Op1))); //Is this right?
|
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperA, Op1))); //Is this right?
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Tex(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Tex(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitTex(Block, OpCode, GprHandle: false);
|
EmitTex(Block, OpCode, GprHandle: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Tex_B(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Tex_B(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitTex(Block, OpCode, GprHandle: true);
|
EmitTex(Block, OpCode, GprHandle: true);
|
||||||
}
|
}
|
||||||
|
@ -202,12 +202,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Texs(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Texs(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitTexs(Block, OpCode, ShaderIrInst.Texs);
|
EmitTexs(Block, OpCode, ShaderIrInst.Texs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Tlds(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Tlds(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitTexs(Block, OpCode, ShaderIrInst.Txlf);
|
EmitTexs(Block, OpCode, ShaderIrInst.Txlf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,67 +25,67 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
F64 = 3
|
F64 = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2f_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void F2f_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitF2f(Block, OpCode, ShaderOper.CR);
|
EmitF2f(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2f_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void F2f_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitF2f(Block, OpCode, ShaderOper.Immf);
|
EmitF2f(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2f_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void F2f_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitF2f(Block, OpCode, ShaderOper.RR);
|
EmitF2f(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2i_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void F2i_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitF2i(Block, OpCode, ShaderOper.CR);
|
EmitF2i(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2i_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void F2i_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitF2i(Block, OpCode, ShaderOper.Immf);
|
EmitF2i(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2i_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void F2i_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitF2i(Block, OpCode, ShaderOper.RR);
|
EmitF2i(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2f_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void I2f_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitI2f(Block, OpCode, ShaderOper.CR);
|
EmitI2f(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2f_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void I2f_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitI2f(Block, OpCode, ShaderOper.Imm);
|
EmitI2f(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2f_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void I2f_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitI2f(Block, OpCode, ShaderOper.RR);
|
EmitI2f(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2i_C(ShaderIrBlock Block, long OpCode, long Position)
|
public static void I2i_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitI2i(Block, OpCode, ShaderOper.CR);
|
EmitI2i(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2i_I(ShaderIrBlock Block, long OpCode, long Position)
|
public static void I2i_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitI2i(Block, OpCode, ShaderOper.Imm);
|
EmitI2i(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2i_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void I2i_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
EmitI2i(Block, OpCode, ShaderOper.RR);
|
EmitI2i(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Isberd(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Isberd(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
//This instruction seems to be used to translate from an address to a vertex index in a GS
|
//This instruction seems to be used to translate from an address to a vertex index in a GS
|
||||||
//Stub it as such
|
//Stub it as such
|
||||||
|
@ -95,50 +95,50 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
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, long 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, long 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, long 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, long 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, long 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, long 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, long 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, long Position)
|
public static void Mov_S(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
Block.AddNode(new ShaderIrCmnt("Stubbed."));
|
Block.AddNode(new ShaderIrCmnt("Stubbed."));
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
|
||||||
{
|
{
|
||||||
static partial class ShaderDecode
|
static partial class ShaderDecode
|
||||||
{
|
{
|
||||||
public static void Out_R(ShaderIrBlock Block, long OpCode, long Position)
|
public static void Out_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||||
{
|
{
|
||||||
//TODO: Those registers have to be used for something
|
//TODO: Those registers have to be used for something
|
||||||
ShaderIrOperGpr Gpr0 = OpCode.Gpr0();
|
ShaderIrOperGpr Gpr0 = OpCode.Gpr0();
|
||||||
|
|
|
@ -10,12 +10,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public static ShaderIrBlock[] Decode(IGalMemory Memory, long Start)
|
public static ShaderIrBlock[] Decode(IGalMemory Memory, long Start)
|
||||||
{
|
{
|
||||||
Dictionary<long, ShaderIrBlock> Visited = new Dictionary<long, ShaderIrBlock>();
|
Dictionary<int, ShaderIrBlock> Visited = new Dictionary<int, ShaderIrBlock>();
|
||||||
Dictionary<long, ShaderIrBlock> VisitedEnd = new Dictionary<long, ShaderIrBlock>();
|
Dictionary<int, ShaderIrBlock> VisitedEnd = new Dictionary<int, ShaderIrBlock>();
|
||||||
|
|
||||||
Queue<ShaderIrBlock> Blocks = new Queue<ShaderIrBlock>();
|
Queue<ShaderIrBlock> Blocks = new Queue<ShaderIrBlock>();
|
||||||
|
|
||||||
ShaderIrBlock Enqueue(long Position, ShaderIrBlock Source = null)
|
long Beginning = Start + HeaderSize;
|
||||||
|
|
||||||
|
ShaderIrBlock Enqueue(int Position, ShaderIrBlock Source = null)
|
||||||
{
|
{
|
||||||
if (!Visited.TryGetValue(Position, out ShaderIrBlock Output))
|
if (!Visited.TryGetValue(Position, out ShaderIrBlock Output))
|
||||||
{
|
{
|
||||||
|
@ -34,13 +36,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return Output;
|
return Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrBlock Entry = Enqueue(Start + HeaderSize);
|
ShaderIrBlock Entry = Enqueue(0);
|
||||||
|
|
||||||
while (Blocks.Count > 0)
|
while (Blocks.Count > 0)
|
||||||
{
|
{
|
||||||
ShaderIrBlock Current = Blocks.Dequeue();
|
ShaderIrBlock Current = Blocks.Dequeue();
|
||||||
|
|
||||||
FillBlock(Memory, Current, Start + HeaderSize);
|
FillBlock(Memory, Current, Beginning);
|
||||||
|
|
||||||
//Set child blocks. "Branch" is the block the branch instruction
|
//Set child blocks. "Branch" is the block the branch instruction
|
||||||
//points to (when taken), "Next" is the block at the next address,
|
//points to (when taken), "Next" is the block at the next address,
|
||||||
|
@ -54,20 +56,18 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
if (InnerOp?.Inst == ShaderIrInst.Bra)
|
if (InnerOp?.Inst == ShaderIrInst.Bra)
|
||||||
{
|
{
|
||||||
int Offset = ((ShaderIrOperImm)InnerOp.OperandA).Value;
|
int Target = ((ShaderIrOperImm)InnerOp.OperandA).Value;
|
||||||
|
|
||||||
long Target = Current.EndPosition + Offset;
|
|
||||||
|
|
||||||
Current.Branch = Enqueue(Target, Current);
|
Current.Branch = Enqueue(Target, Current);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ShaderIrNode Node in Current.Nodes)
|
foreach (ShaderIrNode Node in Current.Nodes)
|
||||||
{
|
{
|
||||||
if (Node is ShaderIrOp CurrOp && CurrOp.Inst == ShaderIrInst.Ssy)
|
InnerOp = GetInnermostOp(Node);
|
||||||
{
|
|
||||||
int Offset = ((ShaderIrOperImm)CurrOp.OperandA).Value;
|
|
||||||
|
|
||||||
long Target = Offset;
|
if (InnerOp is ShaderIrOp CurrOp && CurrOp.Inst == ShaderIrInst.Ssy)
|
||||||
|
{
|
||||||
|
int Target = ((ShaderIrOperImm)CurrOp.OperandA).Value;
|
||||||
|
|
||||||
Current.Branch = Enqueue(Target, Current);
|
Current.Branch = Enqueue(Target, Current);
|
||||||
}
|
}
|
||||||
|
@ -112,15 +112,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
while (Visited.Count > 0)
|
while (Visited.Count > 0)
|
||||||
{
|
{
|
||||||
ulong FirstPos = ulong.MaxValue;
|
uint FirstPos = uint.MaxValue;
|
||||||
|
|
||||||
foreach (ShaderIrBlock Block in Visited.Values)
|
foreach (ShaderIrBlock Block in Visited.Values)
|
||||||
{
|
{
|
||||||
if (FirstPos > (ulong)Block.Position)
|
if (FirstPos > (uint)Block.Position)
|
||||||
FirstPos = (ulong)Block.Position;
|
FirstPos = (uint)Block.Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrBlock Current = Visited[(long)FirstPos];
|
ShaderIrBlock Current = Visited[(int)FirstPos];
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -138,20 +138,20 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private static void FillBlock(IGalMemory Memory, ShaderIrBlock Block, long Beginning)
|
private static void FillBlock(IGalMemory Memory, ShaderIrBlock Block, long Beginning)
|
||||||
{
|
{
|
||||||
long Position = Block.Position;
|
int Position = Block.Position;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
//Ignore scheduling instructions, which are written every 32 bytes.
|
//Ignore scheduling instructions, which are written every 32 bytes.
|
||||||
if (((Position - Beginning) & 0x1f) == 0)
|
if ((Position & 0x1f) == 0)
|
||||||
{
|
{
|
||||||
Position += 8;
|
Position += 8;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint Word0 = (uint)Memory.ReadInt32(Position + 0);
|
uint Word0 = (uint)Memory.ReadInt32(Position + Beginning + 0);
|
||||||
uint Word1 = (uint)Memory.ReadInt32(Position + 4);
|
uint Word1 = (uint)Memory.ReadInt32(Position + Beginning + 4);
|
||||||
|
|
||||||
Position += 8;
|
Position += 8;
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
if (AddDbgComments)
|
if (AddDbgComments)
|
||||||
{
|
{
|
||||||
string DbgOpCode = $"0x{(Position - Beginning - 8):x16}: 0x{OpCode:x16} ";
|
string DbgOpCode = $"0x{(Position - 8):x16}: 0x{OpCode:x16} ";
|
||||||
|
|
||||||
DbgOpCode += (Decode?.Method.Name ?? "???");
|
DbgOpCode += (Decode?.Method.Name ?? "???");
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
int Offset = ((int)(OpCode >> 20) << 8) >> 8;
|
int Offset = ((int)(OpCode >> 20) << 8) >> 8;
|
||||||
|
|
||||||
long Target = Position + Offset - Beginning;
|
long Target = Position + Offset;
|
||||||
|
|
||||||
DbgOpCode += " (0x" + Target.ToString("x16") + ")";
|
DbgOpCode += " (0x" + Target.ToString("x16") + ")";
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
class ShaderIrBlock
|
class ShaderIrBlock
|
||||||
{
|
{
|
||||||
public long Position { get; set; }
|
public int Position { get; set; }
|
||||||
public long EndPosition { get; set; }
|
public int EndPosition { get; set; }
|
||||||
|
|
||||||
public ShaderIrBlock Next { get; set; }
|
public ShaderIrBlock Next { get; set; }
|
||||||
public ShaderIrBlock Branch { get; set; }
|
public ShaderIrBlock Branch { get; set; }
|
||||||
|
@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public List<ShaderIrNode> Nodes { get; private set; }
|
public List<ShaderIrNode> Nodes { get; private set; }
|
||||||
|
|
||||||
public ShaderIrBlock(long Position)
|
public ShaderIrBlock(int Position)
|
||||||
{
|
{
|
||||||
this.Position = Position;
|
this.Position = Position;
|
||||||
|
|
||||||
|
|
122
Ryujinx.Graphics/GpuResourceManager.cs
Normal file
122
Ryujinx.Graphics/GpuResourceManager.cs
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
using Ryujinx.Graphics.Gal;
|
||||||
|
using Ryujinx.Graphics.Memory;
|
||||||
|
using Ryujinx.Graphics.Texture;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics
|
||||||
|
{
|
||||||
|
public class GpuResourceManager
|
||||||
|
{
|
||||||
|
private NvGpu Gpu;
|
||||||
|
|
||||||
|
private HashSet<long>[] UploadedKeys;
|
||||||
|
|
||||||
|
public GpuResourceManager(NvGpu Gpu)
|
||||||
|
{
|
||||||
|
this.Gpu = Gpu;
|
||||||
|
|
||||||
|
UploadedKeys = new HashSet<long>[(int)NvGpuBufferType.Count];
|
||||||
|
|
||||||
|
for (int Index = 0; Index < UploadedKeys.Length; Index++)
|
||||||
|
{
|
||||||
|
UploadedKeys[Index] = new HashSet<long>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendColorBuffer(NvGpuVmm Vmm, long Position, int Attachment, GalImage NewImage)
|
||||||
|
{
|
||||||
|
long Size = (uint)ImageUtils.GetSize(NewImage);
|
||||||
|
|
||||||
|
MarkAsCached(Vmm, Position, Size, NvGpuBufferType.Texture);
|
||||||
|
|
||||||
|
bool IsCached = Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage);
|
||||||
|
|
||||||
|
if (IsCached && CachedImage.SizeMatches(NewImage))
|
||||||
|
{
|
||||||
|
Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage);
|
||||||
|
Gpu.Renderer.RenderTarget.BindColor(Position, Attachment, NewImage);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage);
|
||||||
|
|
||||||
|
Gpu.Renderer.RenderTarget.BindColor(Position, Attachment, NewImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendZetaBuffer(NvGpuVmm Vmm, long Position, GalImage NewImage)
|
||||||
|
{
|
||||||
|
long Size = (uint)ImageUtils.GetSize(NewImage);
|
||||||
|
|
||||||
|
MarkAsCached(Vmm, Position, Size, NvGpuBufferType.Texture);
|
||||||
|
|
||||||
|
bool IsCached = Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage);
|
||||||
|
|
||||||
|
if (IsCached && CachedImage.SizeMatches(NewImage))
|
||||||
|
{
|
||||||
|
Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage);
|
||||||
|
Gpu.Renderer.RenderTarget.BindZeta(Position, NewImage);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage);
|
||||||
|
|
||||||
|
Gpu.Renderer.RenderTarget.BindZeta(Position, NewImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage, int TexIndex = -1)
|
||||||
|
{
|
||||||
|
long Size = (uint)ImageUtils.GetSize(NewImage);
|
||||||
|
|
||||||
|
if (!MemoryRegionModified(Vmm, Position, Size, NvGpuBufferType.Texture))
|
||||||
|
{
|
||||||
|
if (Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage) && CachedImage.SizeMatches(NewImage))
|
||||||
|
{
|
||||||
|
Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage);
|
||||||
|
|
||||||
|
if (TexIndex >= 0)
|
||||||
|
{
|
||||||
|
Gpu.Renderer.Texture.Bind(Position, TexIndex, NewImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] Data = ImageUtils.ReadTexture(Vmm, NewImage, Position);
|
||||||
|
|
||||||
|
Gpu.Renderer.Texture.Create(Position, Data, NewImage);
|
||||||
|
|
||||||
|
if (TexIndex >= 0)
|
||||||
|
{
|
||||||
|
Gpu.Renderer.Texture.Bind(Position, TexIndex, NewImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MarkAsCached(NvGpuVmm Vmm, long Position, long Size, NvGpuBufferType Type)
|
||||||
|
{
|
||||||
|
Vmm.IsRegionModified(Position, Size, Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool MemoryRegionModified(NvGpuVmm Vmm, long Position, long Size, NvGpuBufferType Type)
|
||||||
|
{
|
||||||
|
HashSet<long> Uploaded = UploadedKeys[(int)Type];
|
||||||
|
|
||||||
|
if (!Uploaded.Add(Position))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Vmm.IsRegionModified(Position, Size, Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearPbCache()
|
||||||
|
{
|
||||||
|
for (int Index = 0; Index < UploadedKeys.Length; Index++)
|
||||||
|
{
|
||||||
|
UploadedKeys[Index].Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,309 +1,82 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Memory
|
namespace Ryujinx.Graphics.Memory
|
||||||
{
|
{
|
||||||
class NvGpuVmmCache
|
class NvGpuVmmCache
|
||||||
{
|
{
|
||||||
private const long RamSize = 4L * 1024 * 1024 * 1024;
|
private ValueRangeSet<int> CachedRanges;
|
||||||
|
|
||||||
private const int MaxCpCount = 10000;
|
|
||||||
private const int MaxCpTimeDelta = 60000;
|
|
||||||
|
|
||||||
private class CachedPage
|
|
||||||
{
|
|
||||||
private struct Range
|
|
||||||
{
|
|
||||||
public long Start;
|
|
||||||
public long End;
|
|
||||||
|
|
||||||
public Range(long Start, long End)
|
|
||||||
{
|
|
||||||
this.Start = Start;
|
|
||||||
this.End = End;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Range>[] Regions;
|
|
||||||
|
|
||||||
private HashSet<long> ResidencyKeys;
|
|
||||||
|
|
||||||
public LinkedListNode<long> Node { get; set; }
|
|
||||||
|
|
||||||
public int Timestamp { get; private set; }
|
|
||||||
|
|
||||||
public CachedPage()
|
|
||||||
{
|
|
||||||
Regions = new List<Range>[(int)NvGpuBufferType.Count];
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Regions.Length; Index++)
|
|
||||||
{
|
|
||||||
Regions[Index] = new List<Range>();
|
|
||||||
}
|
|
||||||
|
|
||||||
ResidencyKeys = new HashSet<long>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddResidency(long Key)
|
|
||||||
{
|
|
||||||
ResidencyKeys.Add(Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveResidency(HashSet<long>[] Residency, long PageSize)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < (int)NvGpuBufferType.Count; i++)
|
|
||||||
{
|
|
||||||
foreach (Range Region in Regions[i])
|
|
||||||
{
|
|
||||||
foreach (long Key in ResidencyKeys)
|
|
||||||
{
|
|
||||||
Residency[Region.Start / PageSize].Remove(Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AddRange(long Start, long End, NvGpuBufferType BufferType)
|
|
||||||
{
|
|
||||||
List<Range> BtRegions = Regions[(int)BufferType];
|
|
||||||
|
|
||||||
for (int Index = 0; Index < BtRegions.Count; Index++)
|
|
||||||
{
|
|
||||||
Range Rg = BtRegions[Index];
|
|
||||||
|
|
||||||
if (Start >= Rg.Start && End <= Rg.End)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Start <= Rg.End && Rg.Start <= End)
|
|
||||||
{
|
|
||||||
long MinStart = Math.Min(Rg.Start, Start);
|
|
||||||
long MaxEnd = Math.Max(Rg.End, End);
|
|
||||||
|
|
||||||
BtRegions[Index] = new Range(MinStart, MaxEnd);
|
|
||||||
|
|
||||||
Timestamp = Environment.TickCount;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BtRegions.Add(new Range(Start, End));
|
|
||||||
|
|
||||||
Timestamp = Environment.TickCount;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetTotalCount()
|
|
||||||
{
|
|
||||||
int Count = 0;
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Regions.Length; Index++)
|
|
||||||
{
|
|
||||||
Count += Regions[Index].Count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<long, CachedPage> Cache;
|
|
||||||
|
|
||||||
private LinkedList<long> SortedCache;
|
|
||||||
|
|
||||||
private HashSet<long>[] Residency;
|
|
||||||
|
|
||||||
private long ResidencyPageSize;
|
|
||||||
|
|
||||||
private int CpCount;
|
|
||||||
|
|
||||||
public NvGpuVmmCache()
|
public NvGpuVmmCache()
|
||||||
{
|
{
|
||||||
Cache = new Dictionary<long, CachedPage>();
|
CachedRanges = new ValueRangeSet<int>();
|
||||||
|
|
||||||
SortedCache = new LinkedList<long>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsRegionModified(AMemory Memory, NvGpuBufferType BufferType, long PA, long Size)
|
public bool IsRegionModified(AMemory Memory, NvGpuBufferType BufferType, long PA, long Size)
|
||||||
{
|
{
|
||||||
(bool[] Modified, long ModifiedCount) = Memory.IsRegionModified(PA, Size);
|
(bool[] Modified, long ModifiedCount) = Memory.IsRegionModified(PA, Size);
|
||||||
|
|
||||||
PA = Memory.GetPhysicalAddress(PA);
|
//Remove all modified ranges.
|
||||||
|
|
||||||
ClearCachedPagesIfNeeded();
|
|
||||||
|
|
||||||
long PageSize = AMemory.PageSize;
|
|
||||||
|
|
||||||
EnsureResidencyInitialized(PageSize);
|
|
||||||
|
|
||||||
bool HasResidents = AddResidency(PA, Size);
|
|
||||||
|
|
||||||
if (!HasResidents && ModifiedCount == 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
long Mask = PageSize - 1;
|
|
||||||
|
|
||||||
long ResidencyKey = PA;
|
|
||||||
|
|
||||||
long PAEnd = PA + Size;
|
|
||||||
|
|
||||||
bool RegMod = false;
|
|
||||||
|
|
||||||
int Index = 0;
|
int Index = 0;
|
||||||
|
|
||||||
while (PA < PAEnd)
|
long Position = PA & ~NvGpuVmm.PageMask;
|
||||||
|
|
||||||
|
while (ModifiedCount > 0)
|
||||||
{
|
{
|
||||||
long Key = PA & ~AMemory.PageMask;
|
if (Modified[Index++])
|
||||||
|
|
||||||
long PAPgEnd = Math.Min((PA + AMemory.PageSize) & ~AMemory.PageMask, PAEnd);
|
|
||||||
|
|
||||||
bool IsCached = Cache.TryGetValue(Key, out CachedPage Cp);
|
|
||||||
|
|
||||||
if (IsCached)
|
|
||||||
{
|
{
|
||||||
CpCount -= Cp.GetTotalCount();
|
CachedRanges.Remove(new ValueRange<int>(Position, Position + NvGpuVmm.PageSize));
|
||||||
|
|
||||||
SortedCache.Remove(Cp.Node);
|
ModifiedCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
Position += NvGpuVmm.PageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Mask has the bit set for the current resource type.
|
||||||
|
//If the region is not yet present on the list, then a new ValueRange
|
||||||
|
//is directly added with the current resource type as the only bit set.
|
||||||
|
//Otherwise, it just sets the bit for this new resource type on the current mask.
|
||||||
|
int Mask = 1 << (int)BufferType;
|
||||||
|
|
||||||
|
ValueRange<int> NewCached = new ValueRange<int>(PA, PA + Size);
|
||||||
|
|
||||||
|
ValueRange<int>[] Ranges = CachedRanges.GetAllIntersections(NewCached);
|
||||||
|
|
||||||
|
long LastEnd = NewCached.Start;
|
||||||
|
|
||||||
|
long Coverage = 0;
|
||||||
|
|
||||||
|
for (Index = 0; Index < Ranges.Length; Index++)
|
||||||
|
{
|
||||||
|
ValueRange<int> Current = Ranges[Index];
|
||||||
|
|
||||||
|
long RgStart = Math.Max(Current.Start, NewCached.Start);
|
||||||
|
long RgEnd = Math.Min(Current.End, NewCached.End);
|
||||||
|
|
||||||
|
if ((Current.Value & Mask) == 0)
|
||||||
|
{
|
||||||
|
CachedRanges.Add(new ValueRange<int>(RgStart, RgEnd, Current.Value | Mask));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Cp = new CachedPage();
|
Coverage += RgEnd - RgStart;
|
||||||
|
|
||||||
Cache.Add(Key, Cp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Modified[Index++] && IsCached)
|
if (RgStart > LastEnd)
|
||||||
{
|
{
|
||||||
Cp = new CachedPage();
|
CachedRanges.Add(new ValueRange<int>(LastEnd, RgStart, Mask));
|
||||||
|
|
||||||
Cache[Key] = Cp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Cp.AddResidency(ResidencyKey);
|
LastEnd = RgEnd;
|
||||||
|
|
||||||
Cp.Node = SortedCache.AddLast(Key);
|
|
||||||
|
|
||||||
RegMod |= Cp.AddRange(PA, PAPgEnd, BufferType);
|
|
||||||
|
|
||||||
CpCount += Cp.GetTotalCount();
|
|
||||||
|
|
||||||
PA = PAPgEnd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return RegMod;
|
if (LastEnd < NewCached.End)
|
||||||
}
|
|
||||||
|
|
||||||
private bool AddResidency(long PA, long Size)
|
|
||||||
{
|
|
||||||
long PageSize = ResidencyPageSize;
|
|
||||||
|
|
||||||
long Mask = PageSize - 1;
|
|
||||||
|
|
||||||
long Key = PA;
|
|
||||||
|
|
||||||
bool ResidentFound = false;
|
|
||||||
|
|
||||||
for (long Cursor = PA & ~Mask; Cursor < ((PA + Size + PageSize - 1) & ~Mask); Cursor += PageSize)
|
|
||||||
{
|
{
|
||||||
long PageIndex = Cursor / PageSize;
|
CachedRanges.Add(new ValueRange<int>(LastEnd, NewCached.End, Mask));
|
||||||
|
|
||||||
Residency[PageIndex].Add(Key);
|
|
||||||
|
|
||||||
if (Residency[PageIndex].Count > 1)
|
|
||||||
{
|
|
||||||
ResidentFound = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResidentFound;
|
return Coverage != Size;
|
||||||
}
|
|
||||||
|
|
||||||
private void EnsureResidencyInitialized(long PageSize)
|
|
||||||
{
|
|
||||||
if (Residency == null)
|
|
||||||
{
|
|
||||||
Residency = new HashSet<long>[RamSize / PageSize];
|
|
||||||
|
|
||||||
for (int i = 0; i < Residency.Length; i++)
|
|
||||||
{
|
|
||||||
Residency[i] = new HashSet<long>();
|
|
||||||
}
|
|
||||||
|
|
||||||
ResidencyPageSize = PageSize;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (ResidencyPageSize != PageSize)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Tried to change residency page size");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ClearCachedPagesIfNeeded()
|
|
||||||
{
|
|
||||||
if (CpCount <= MaxCpCount)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Timestamp = Environment.TickCount;
|
|
||||||
|
|
||||||
int TimeDelta;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (!TryPopOldestCachedPageKey(Timestamp, out long Key))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CachedPage Cp = Cache[Key];
|
|
||||||
|
|
||||||
Cp.RemoveResidency(Residency, ResidencyPageSize);
|
|
||||||
|
|
||||||
Cache.Remove(Key);
|
|
||||||
|
|
||||||
CpCount -= Cp.GetTotalCount();
|
|
||||||
|
|
||||||
TimeDelta = RingDelta(Cp.Timestamp, Timestamp);
|
|
||||||
}
|
|
||||||
while (CpCount > (MaxCpCount >> 1) || (uint)TimeDelta > (uint)MaxCpTimeDelta);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryPopOldestCachedPageKey(int Timestamp, out long Key)
|
|
||||||
{
|
|
||||||
LinkedListNode<long> Node = SortedCache.First;
|
|
||||||
|
|
||||||
if (Node == null)
|
|
||||||
{
|
|
||||||
Key = 0;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SortedCache.Remove(Node);
|
|
||||||
|
|
||||||
Key = Node.Value;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int RingDelta(int Old, int New)
|
|
||||||
{
|
|
||||||
if ((uint)New < (uint)Old)
|
|
||||||
{
|
|
||||||
return New + (~Old + 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return New - Old;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using Ryujinx.Graphics;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics
|
namespace Ryujinx.Graphics
|
||||||
{
|
{
|
||||||
|
@ -7,21 +6,27 @@ namespace Ryujinx.Graphics
|
||||||
{
|
{
|
||||||
public IGalRenderer Renderer { get; private set; }
|
public IGalRenderer Renderer { get; private set; }
|
||||||
|
|
||||||
|
public GpuResourceManager ResourceManager { get; private set; }
|
||||||
|
|
||||||
public NvGpuFifo Fifo { get; private set; }
|
public NvGpuFifo Fifo { get; private set; }
|
||||||
|
|
||||||
public NvGpuEngine2d Engine2d { get; private set; }
|
internal NvGpuEngine2d Engine2d { get; private set; }
|
||||||
public NvGpuEngine3d Engine3d { get; private set; }
|
internal NvGpuEngine3d Engine3d { get; private set; }
|
||||||
public NvGpuEngineDma EngineDma { get; private set; }
|
internal NvGpuEngineM2mf EngineM2mf { get; private set; }
|
||||||
|
internal NvGpuEngineP2mf EngineP2mf { get; private set; }
|
||||||
|
|
||||||
public NvGpu(IGalRenderer Renderer)
|
public NvGpu(IGalRenderer Renderer)
|
||||||
{
|
{
|
||||||
this.Renderer = Renderer;
|
this.Renderer = Renderer;
|
||||||
|
|
||||||
|
ResourceManager = new GpuResourceManager(this);
|
||||||
|
|
||||||
Fifo = new NvGpuFifo(this);
|
Fifo = new NvGpuFifo(this);
|
||||||
|
|
||||||
Engine2d = new NvGpuEngine2d(this);
|
Engine2d = new NvGpuEngine2d(this);
|
||||||
Engine3d = new NvGpuEngine3d(this);
|
Engine3d = new NvGpuEngine3d(this);
|
||||||
EngineDma = new NvGpuEngineDma(this);
|
EngineM2mf = new NvGpuEngineM2mf(this);
|
||||||
|
EngineP2mf = new NvGpuEngineP2mf(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.Graphics.Memory
|
namespace Ryujinx.Graphics
|
||||||
{
|
{
|
||||||
public enum NvGpuBufferType
|
public enum NvGpuBufferType
|
||||||
{
|
{
|
|
@ -5,7 +5,7 @@ namespace Ryujinx.Graphics
|
||||||
_2d = 0x902d,
|
_2d = 0x902d,
|
||||||
_3d = 0xb197,
|
_3d = 0xb197,
|
||||||
Compute = 0xb1c0,
|
Compute = 0xb1c0,
|
||||||
Kepler = 0xa140,
|
P2mf = 0xa140,
|
||||||
Dma = 0xb0b5
|
M2mf = 0xb0b5
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using Ryujinx.Graphics.Memory;
|
using Ryujinx.Graphics.Memory;
|
||||||
using Ryujinx.Graphics.Texture;
|
using Ryujinx.Graphics.Texture;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics
|
namespace Ryujinx.Graphics
|
||||||
|
@ -62,25 +61,25 @@ namespace Ryujinx.Graphics
|
||||||
{
|
{
|
||||||
CopyOperation Operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation);
|
CopyOperation Operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation);
|
||||||
|
|
||||||
|
int SrcFormat = ReadRegister(NvGpuEngine2dReg.SrcFormat);
|
||||||
bool SrcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0;
|
bool SrcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0;
|
||||||
int SrcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth);
|
int SrcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth);
|
||||||
int SrcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight);
|
int SrcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight);
|
||||||
int SrcPitch = ReadRegister(NvGpuEngine2dReg.SrcPitch);
|
int SrcPitch = ReadRegister(NvGpuEngine2dReg.SrcPitch);
|
||||||
int SrcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions);
|
int SrcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions);
|
||||||
|
|
||||||
|
int DstFormat = ReadRegister(NvGpuEngine2dReg.DstFormat);
|
||||||
bool DstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0;
|
bool DstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0;
|
||||||
int DstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth);
|
int DstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth);
|
||||||
int DstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight);
|
int DstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight);
|
||||||
int DstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch);
|
int DstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch);
|
||||||
int DstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions);
|
int DstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions);
|
||||||
|
|
||||||
TextureSwizzle SrcSwizzle = SrcLinear
|
GalImageFormat SrcImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)SrcFormat);
|
||||||
? TextureSwizzle.Pitch
|
GalImageFormat DstImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)DstFormat);
|
||||||
: TextureSwizzle.BlockLinear;
|
|
||||||
|
|
||||||
TextureSwizzle DstSwizzle = DstLinear
|
GalMemoryLayout SrcLayout = GetLayout(SrcLinear);
|
||||||
? TextureSwizzle.Pitch
|
GalMemoryLayout DstLayout = GetLayout(DstLinear);
|
||||||
: TextureSwizzle.BlockLinear;
|
|
||||||
|
|
||||||
int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf);
|
int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf);
|
||||||
int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
|
int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
|
||||||
|
@ -91,91 +90,41 @@ namespace Ryujinx.Graphics
|
||||||
long SrcKey = Vmm.GetPhysicalAddress(SrcAddress);
|
long SrcKey = Vmm.GetPhysicalAddress(SrcAddress);
|
||||||
long DstKey = Vmm.GetPhysicalAddress(DstAddress);
|
long DstKey = Vmm.GetPhysicalAddress(DstAddress);
|
||||||
|
|
||||||
bool IsSrcFb = Gpu.Engine3d.IsFrameBufferPosition(SrcKey);
|
GalImage SrcTexture = new GalImage(
|
||||||
bool IsDstFb = Gpu.Engine3d.IsFrameBufferPosition(DstKey);
|
SrcWidth,
|
||||||
|
SrcHeight, 1,
|
||||||
|
SrcBlockHeight,
|
||||||
|
SrcLayout,
|
||||||
|
SrcImgFormat);
|
||||||
|
|
||||||
TextureInfo SrcTexture()
|
GalImage DstTexture = new GalImage(
|
||||||
{
|
DstWidth,
|
||||||
return new TextureInfo(
|
DstHeight, 1,
|
||||||
SrcAddress,
|
DstBlockHeight,
|
||||||
SrcWidth,
|
DstLayout,
|
||||||
SrcHeight,
|
DstImgFormat);
|
||||||
SrcPitch,
|
|
||||||
SrcBlockHeight, 1,
|
|
||||||
SrcSwizzle,
|
|
||||||
GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureInfo DstTexture()
|
Gpu.ResourceManager.SendTexture(Vmm, SrcKey, SrcTexture);
|
||||||
{
|
Gpu.ResourceManager.SendTexture(Vmm, DstKey, DstTexture);
|
||||||
return new TextureInfo(
|
|
||||||
DstAddress,
|
|
||||||
DstWidth,
|
|
||||||
DstHeight,
|
|
||||||
DstPitch,
|
|
||||||
DstBlockHeight, 1,
|
|
||||||
DstSwizzle,
|
|
||||||
GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: fb -> fb copies, tex -> fb copies, formats other than RGBA8,
|
Gpu.Renderer.RenderTarget.Copy(
|
||||||
//make it throw for unimpl stuff (like the copy mode)...
|
SrcKey,
|
||||||
if (IsSrcFb && IsDstFb)
|
DstKey,
|
||||||
{
|
0,
|
||||||
//Frame Buffer -> Frame Buffer copy.
|
0,
|
||||||
Gpu.Renderer.RenderTarget.Copy(
|
SrcWidth,
|
||||||
SrcKey,
|
SrcHeight,
|
||||||
DstKey,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
DstWidth,
|
||||||
SrcWidth,
|
DstHeight);
|
||||||
SrcHeight,
|
}
|
||||||
0,
|
|
||||||
0,
|
|
||||||
DstWidth,
|
|
||||||
DstHeight);
|
|
||||||
}
|
|
||||||
if (IsSrcFb)
|
|
||||||
{
|
|
||||||
//Frame Buffer -> Texture copy.
|
|
||||||
Gpu.Renderer.RenderTarget.GetBufferData(SrcKey, (byte[] Buffer) =>
|
|
||||||
{
|
|
||||||
TextureInfo Src = SrcTexture();
|
|
||||||
TextureInfo Dst = DstTexture();
|
|
||||||
|
|
||||||
if (Src.Width != Dst.Width ||
|
private static GalMemoryLayout GetLayout(bool Linear)
|
||||||
Src.Height != Dst.Height)
|
{
|
||||||
{
|
return Linear
|
||||||
throw new NotImplementedException("Texture resizing is not supported");
|
? GalMemoryLayout.Pitch
|
||||||
}
|
: GalMemoryLayout.BlockLinear;
|
||||||
|
|
||||||
TextureWriter.Write(Vmm, Dst, Buffer);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (IsDstFb)
|
|
||||||
{
|
|
||||||
byte[] Buffer = TextureReader.Read(Vmm, SrcTexture());
|
|
||||||
|
|
||||||
Gpu.Renderer.RenderTarget.SetBufferData(
|
|
||||||
DstKey,
|
|
||||||
DstWidth,
|
|
||||||
DstHeight,
|
|
||||||
Buffer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Texture -> Texture copy.
|
|
||||||
TextureInfo Src = SrcTexture();
|
|
||||||
TextureInfo Dst = DstTexture();
|
|
||||||
|
|
||||||
if (Src.Width != Dst.Width ||
|
|
||||||
Src.Height != Dst.Height)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException("Texture resizing is not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureWriter.Write(Vmm, Dst, TextureReader.Read(Vmm, Src));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private long MakeInt64From2xInt32(NvGpuEngine2dReg Reg)
|
private long MakeInt64From2xInt32(NvGpuEngine2dReg Reg)
|
||||||
|
|
|
@ -23,8 +23,6 @@ namespace Ryujinx.Graphics
|
||||||
|
|
||||||
private ConstBuffer[][] ConstBuffers;
|
private ConstBuffer[][] ConstBuffers;
|
||||||
|
|
||||||
private HashSet<long> FrameBuffers;
|
|
||||||
|
|
||||||
private List<long>[] UploadedKeys;
|
private List<long>[] UploadedKeys;
|
||||||
|
|
||||||
private int CurrentInstance = 0;
|
private int CurrentInstance = 0;
|
||||||
|
@ -60,8 +58,6 @@ namespace Ryujinx.Graphics
|
||||||
ConstBuffers[Index] = new ConstBuffer[18];
|
ConstBuffers[Index] = new ConstBuffer[18];
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameBuffers = new HashSet<long>();
|
|
||||||
|
|
||||||
UploadedKeys = new List<long>[(int)NvGpuBufferType.Count];
|
UploadedKeys = new List<long>[(int)NvGpuBufferType.Count];
|
||||||
|
|
||||||
for (int i = 0; i < UploadedKeys.Length; i++)
|
for (int i = 0; i < UploadedKeys.Length; i++)
|
||||||
|
@ -96,7 +92,7 @@ namespace Ryujinx.Graphics
|
||||||
|
|
||||||
GalPipelineState State = new GalPipelineState();
|
GalPipelineState State = new GalPipelineState();
|
||||||
|
|
||||||
SetFlip(State);
|
SetFrameBuffer(State);
|
||||||
SetFrontFace(State);
|
SetFrontFace(State);
|
||||||
SetCullFace(State);
|
SetCullFace(State);
|
||||||
SetDepth(State);
|
SetDepth(State);
|
||||||
|
@ -104,10 +100,7 @@ namespace Ryujinx.Graphics
|
||||||
SetAlphaBlending(State);
|
SetAlphaBlending(State);
|
||||||
SetPrimitiveRestart(State);
|
SetPrimitiveRestart(State);
|
||||||
|
|
||||||
for (int FbIndex = 0; FbIndex < 8; FbIndex++)
|
SetFrameBuffer(Vmm, 0);
|
||||||
{
|
|
||||||
SetFrameBuffer(Vmm, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
SetZeta(Vmm);
|
SetZeta(Vmm);
|
||||||
|
|
||||||
|
@ -173,9 +166,9 @@ namespace Ryujinx.Graphics
|
||||||
{
|
{
|
||||||
long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10);
|
long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10);
|
||||||
|
|
||||||
int Format = ReadRegister(NvGpuEngine3dReg.FrameBufferNFormat + FbIndex * 0x10);
|
int SurfFormat = ReadRegister(NvGpuEngine3dReg.FrameBufferNFormat + FbIndex * 0x10);
|
||||||
|
|
||||||
if (VA == 0 || Format == 0)
|
if (VA == 0 || SurfFormat == 0)
|
||||||
{
|
{
|
||||||
Gpu.Renderer.RenderTarget.UnbindColor(FbIndex);
|
Gpu.Renderer.RenderTarget.UnbindColor(FbIndex);
|
||||||
|
|
||||||
|
@ -184,11 +177,15 @@ namespace Ryujinx.Graphics
|
||||||
|
|
||||||
long Key = Vmm.GetPhysicalAddress(VA);
|
long Key = Vmm.GetPhysicalAddress(VA);
|
||||||
|
|
||||||
FrameBuffers.Add(Key);
|
|
||||||
|
|
||||||
int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10);
|
int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10);
|
||||||
int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10);
|
int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10);
|
||||||
|
|
||||||
|
int BlockDim = ReadRegister(NvGpuEngine3dReg.FrameBufferNBlockDim + FbIndex * 0x10);
|
||||||
|
|
||||||
|
int GobBlockHeight = 1 << ((BlockDim >> 4) & 7);
|
||||||
|
|
||||||
|
GalMemoryLayout Layout = (GalMemoryLayout)((BlockDim >> 12) & 1);
|
||||||
|
|
||||||
float TX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateX + FbIndex * 8);
|
float TX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateX + FbIndex * 8);
|
||||||
float TY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateY + FbIndex * 8);
|
float TY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateY + FbIndex * 8);
|
||||||
|
|
||||||
|
@ -201,48 +198,54 @@ namespace Ryujinx.Graphics
|
||||||
int VpW = (int)(TX + MathF.Abs(SX)) - VpX;
|
int VpW = (int)(TX + MathF.Abs(SX)) - VpX;
|
||||||
int VpH = (int)(TY + MathF.Abs(SY)) - VpY;
|
int VpH = (int)(TY + MathF.Abs(SY)) - VpY;
|
||||||
|
|
||||||
GalImageFormat ImageFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)Format);
|
GalImageFormat Format = ImageUtils.ConvertSurface((GalSurfaceFormat)SurfFormat);
|
||||||
|
|
||||||
GalImage Image = new GalImage(Width, Height, ImageFormat);
|
GalImage Image = new GalImage(Width, Height, 1, GobBlockHeight, Layout, Format);
|
||||||
|
|
||||||
long Size = ImageUtils.GetSize(Image);
|
Gpu.ResourceManager.SendColorBuffer(Vmm, Key, FbIndex, Image);
|
||||||
|
|
||||||
Gpu.Renderer.Texture.CreateFb(Key, Size, Image);
|
|
||||||
|
|
||||||
Gpu.Renderer.RenderTarget.BindColor(Key, FbIndex);
|
|
||||||
|
|
||||||
Gpu.Renderer.RenderTarget.SetViewport(VpX, VpY, VpW, VpH);
|
Gpu.Renderer.RenderTarget.SetViewport(VpX, VpY, VpW, VpH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetFrameBuffer(GalPipelineState State)
|
||||||
|
{
|
||||||
|
State.FramebufferSrgb = (ReadRegister(NvGpuEngine3dReg.FrameBufferSrgb) & 1) != 0;
|
||||||
|
|
||||||
|
State.FlipX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX);
|
||||||
|
State.FlipY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY);
|
||||||
|
}
|
||||||
|
|
||||||
private void SetZeta(NvGpuVmm Vmm)
|
private void SetZeta(NvGpuVmm Vmm)
|
||||||
{
|
{
|
||||||
long ZA = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress);
|
long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress);
|
||||||
|
|
||||||
int Format = ReadRegister(NvGpuEngine3dReg.ZetaFormat);
|
int ZetaFormat = ReadRegister(NvGpuEngine3dReg.ZetaFormat);
|
||||||
|
|
||||||
|
int BlockDim = ReadRegister(NvGpuEngine3dReg.ZetaBlockDimensions);
|
||||||
|
|
||||||
|
int GobBlockHeight = 1 << ((BlockDim >> 4) & 7);
|
||||||
|
|
||||||
|
GalMemoryLayout Layout = (GalMemoryLayout)((BlockDim >> 12) & 1); //?
|
||||||
|
|
||||||
bool ZetaEnable = (ReadRegister(NvGpuEngine3dReg.ZetaEnable) & 1) != 0;
|
bool ZetaEnable = (ReadRegister(NvGpuEngine3dReg.ZetaEnable) & 1) != 0;
|
||||||
|
|
||||||
if (ZA == 0 || Format == 0 || !ZetaEnable)
|
if (VA == 0 || ZetaFormat == 0 || !ZetaEnable)
|
||||||
{
|
{
|
||||||
Gpu.Renderer.RenderTarget.UnbindZeta();
|
Gpu.Renderer.RenderTarget.UnbindZeta();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long Key = Vmm.GetPhysicalAddress(ZA);
|
long Key = Vmm.GetPhysicalAddress(VA);
|
||||||
|
|
||||||
int Width = ReadRegister(NvGpuEngine3dReg.ZetaHoriz);
|
int Width = ReadRegister(NvGpuEngine3dReg.ZetaHoriz);
|
||||||
int Height = ReadRegister(NvGpuEngine3dReg.ZetaVert);
|
int Height = ReadRegister(NvGpuEngine3dReg.ZetaVert);
|
||||||
|
|
||||||
GalImageFormat ImageFormat = ImageUtils.ConvertZeta((GalZetaFormat)Format);
|
GalImageFormat Format = ImageUtils.ConvertZeta((GalZetaFormat)ZetaFormat);
|
||||||
|
|
||||||
GalImage Image = new GalImage(Width, Height, ImageFormat);
|
GalImage Image = new GalImage(Width, Height, 1, GobBlockHeight, Layout, Format);
|
||||||
|
|
||||||
long Size = ImageUtils.GetSize(Image);
|
Gpu.ResourceManager.SendZetaBuffer(Vmm, Key, Image);
|
||||||
|
|
||||||
Gpu.Renderer.Texture.CreateFb(Key, Size, Image);
|
|
||||||
|
|
||||||
Gpu.Renderer.RenderTarget.BindZeta(Key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private long[] UploadShaders(NvGpuVmm Vmm)
|
private long[] UploadShaders(NvGpuVmm Vmm)
|
||||||
|
@ -322,12 +325,6 @@ namespace Ryujinx.Graphics
|
||||||
throw new ArgumentOutOfRangeException(nameof(Program));
|
throw new ArgumentOutOfRangeException(nameof(Program));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetFlip(GalPipelineState State)
|
|
||||||
{
|
|
||||||
State.FlipX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX);
|
|
||||||
State.FlipY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetFrontFace(GalPipelineState State)
|
private void SetFrontFace(GalPipelineState State)
|
||||||
{
|
{
|
||||||
float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX);
|
float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX);
|
||||||
|
@ -504,53 +501,30 @@ namespace Ryujinx.Graphics
|
||||||
TicPosition += TicIndex * 0x20;
|
TicPosition += TicIndex * 0x20;
|
||||||
TscPosition += TscIndex * 0x20;
|
TscPosition += TscIndex * 0x20;
|
||||||
|
|
||||||
|
GalImage Image = TextureFactory.MakeTexture(Vmm, TicPosition);
|
||||||
|
|
||||||
GalTextureSampler Sampler = TextureFactory.MakeSampler(Gpu, Vmm, TscPosition);
|
GalTextureSampler Sampler = TextureFactory.MakeSampler(Gpu, Vmm, TscPosition);
|
||||||
|
|
||||||
long Key = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff;
|
long Key = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff;
|
||||||
|
|
||||||
|
if (Image.Layout == GalMemoryLayout.BlockLinear)
|
||||||
|
{
|
||||||
|
Key &= ~0x1ffL;
|
||||||
|
}
|
||||||
|
else if (Image.Layout == GalMemoryLayout.Pitch)
|
||||||
|
{
|
||||||
|
Key &= ~0x1fL;
|
||||||
|
}
|
||||||
|
|
||||||
Key = Vmm.GetPhysicalAddress(Key);
|
Key = Vmm.GetPhysicalAddress(Key);
|
||||||
|
|
||||||
if (Key == -1)
|
if (Key == -1)
|
||||||
{
|
{
|
||||||
//FIXME: Should'nt ignore invalid addresses.
|
//FIXME: Shouldn't ignore invalid addresses.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsFrameBufferPosition(Key))
|
Gpu.ResourceManager.SendTexture(Vmm, Key, Image, TexIndex);
|
||||||
{
|
|
||||||
//This texture is a frame buffer texture,
|
|
||||||
//we shouldn't read anything from memory and bind
|
|
||||||
//the frame buffer texture instead, since we're not
|
|
||||||
//really writing anything to memory.
|
|
||||||
Gpu.Renderer.RenderTarget.BindTexture(Key, TexIndex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GalImage NewImage = TextureFactory.MakeTexture(Vmm, TicPosition);
|
|
||||||
|
|
||||||
long Size = (uint)ImageUtils.GetSize(NewImage);
|
|
||||||
|
|
||||||
bool HasCachedTexture = false;
|
|
||||||
|
|
||||||
if (Gpu.Renderer.Texture.TryGetCachedTexture(Key, Size, out GalImage Image))
|
|
||||||
{
|
|
||||||
if (NewImage.Equals(Image) && !QueryKeyUpload(Vmm, Key, Size, NvGpuBufferType.Texture))
|
|
||||||
{
|
|
||||||
Gpu.Renderer.Texture.Bind(Key, TexIndex);
|
|
||||||
|
|
||||||
HasCachedTexture = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!HasCachedTexture)
|
|
||||||
{
|
|
||||||
byte[] Data = TextureFactory.GetTextureData(Vmm, TicPosition);
|
|
||||||
|
|
||||||
Gpu.Renderer.Texture.Create(Key, Data, NewImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
Gpu.Renderer.Texture.Bind(Key, TexIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
Gpu.Renderer.Texture.SetSampler(Sampler);
|
Gpu.Renderer.Texture.SetSampler(Sampler);
|
||||||
}
|
}
|
||||||
|
@ -876,11 +850,6 @@ namespace Ryujinx.Graphics
|
||||||
Registers[(int)Reg] = Value;
|
Registers[(int)Reg] = Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsFrameBufferPosition(long Position)
|
|
||||||
{
|
|
||||||
return FrameBuffers.Contains(Position);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool QueryKeyUpload(NvGpuVmm Vmm, long Key, long Size, NvGpuBufferType Type)
|
private bool QueryKeyUpload(NvGpuVmm Vmm, long Key, long Size, NvGpuBufferType Type)
|
||||||
{
|
{
|
||||||
List<long> Uploaded = UploadedKeys[(int)Type];
|
List<long> Uploaded = UploadedKeys[(int)Type];
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace Ryujinx.Graphics
|
||||||
FrameBufferNWidth = 0x202,
|
FrameBufferNWidth = 0x202,
|
||||||
FrameBufferNHeight = 0x203,
|
FrameBufferNHeight = 0x203,
|
||||||
FrameBufferNFormat = 0x204,
|
FrameBufferNFormat = 0x204,
|
||||||
|
FrameBufferNBlockDim = 0x205,
|
||||||
ViewportNScaleX = 0x280,
|
ViewportNScaleX = 0x280,
|
||||||
ViewportNScaleY = 0x281,
|
ViewportNScaleY = 0x281,
|
||||||
ViewportNScaleZ = 0x282,
|
ViewportNScaleZ = 0x282,
|
||||||
|
@ -62,6 +63,7 @@ namespace Ryujinx.Graphics
|
||||||
StencilBackOpZFail = 0x567,
|
StencilBackOpZFail = 0x567,
|
||||||
StencilBackOpZPass = 0x568,
|
StencilBackOpZPass = 0x568,
|
||||||
StencilBackFuncFunc = 0x569,
|
StencilBackFuncFunc = 0x569,
|
||||||
|
FrameBufferSrgb = 0x56e,
|
||||||
ShaderAddress = 0x582,
|
ShaderAddress = 0x582,
|
||||||
VertexBeginGl = 0x586,
|
VertexBeginGl = 0x586,
|
||||||
PrimRestartEnable = 0x591,
|
PrimRestartEnable = 0x591,
|
||||||
|
|
|
@ -1,143 +0,0 @@
|
||||||
using Ryujinx.Graphics.Memory;
|
|
||||||
using Ryujinx.Graphics.Texture;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics
|
|
||||||
{
|
|
||||||
public class NvGpuEngineDma : INvGpuEngine
|
|
||||||
{
|
|
||||||
public int[] Registers { get; private set; }
|
|
||||||
|
|
||||||
private NvGpu Gpu;
|
|
||||||
|
|
||||||
private Dictionary<int, NvGpuMethod> Methods;
|
|
||||||
|
|
||||||
public NvGpuEngineDma(NvGpu Gpu)
|
|
||||||
{
|
|
||||||
this.Gpu = Gpu;
|
|
||||||
|
|
||||||
Registers = new int[0x1d6];
|
|
||||||
|
|
||||||
Methods = new Dictionary<int, NvGpuMethod>();
|
|
||||||
|
|
||||||
void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method)
|
|
||||||
{
|
|
||||||
while (Count-- > 0)
|
|
||||||
{
|
|
||||||
Methods.Add(Meth, Method);
|
|
||||||
|
|
||||||
Meth += Stride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AddMethod(0xc0, 1, 1, Execute);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
|
||||||
{
|
|
||||||
if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method))
|
|
||||||
{
|
|
||||||
Method(Vmm, PBEntry);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteRegister(PBEntry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Execute(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
|
||||||
{
|
|
||||||
int Control = PBEntry.Arguments[0];
|
|
||||||
|
|
||||||
bool SrcLinear = ((Control >> 7) & 1) != 0;
|
|
||||||
bool DstLinear = ((Control >> 8) & 1) != 0;
|
|
||||||
|
|
||||||
long SrcAddress = MakeInt64From2xInt32(NvGpuEngineDmaReg.SrcAddress);
|
|
||||||
long DstAddress = MakeInt64From2xInt32(NvGpuEngineDmaReg.DstAddress);
|
|
||||||
|
|
||||||
int SrcPitch = ReadRegister(NvGpuEngineDmaReg.SrcPitch);
|
|
||||||
int DstPitch = ReadRegister(NvGpuEngineDmaReg.DstPitch);
|
|
||||||
|
|
||||||
int DstBlkDim = ReadRegister(NvGpuEngineDmaReg.DstBlkDim);
|
|
||||||
int DstSizeX = ReadRegister(NvGpuEngineDmaReg.DstSizeX);
|
|
||||||
int DstSizeY = ReadRegister(NvGpuEngineDmaReg.DstSizeY);
|
|
||||||
int DstSizeZ = ReadRegister(NvGpuEngineDmaReg.DstSizeZ);
|
|
||||||
int DstPosXY = ReadRegister(NvGpuEngineDmaReg.DstPosXY);
|
|
||||||
int DstPosZ = ReadRegister(NvGpuEngineDmaReg.DstPosZ);
|
|
||||||
|
|
||||||
int SrcBlkDim = ReadRegister(NvGpuEngineDmaReg.SrcBlkDim);
|
|
||||||
int SrcSizeX = ReadRegister(NvGpuEngineDmaReg.SrcSizeX);
|
|
||||||
int SrcSizeY = ReadRegister(NvGpuEngineDmaReg.SrcSizeY);
|
|
||||||
int SrcSizeZ = ReadRegister(NvGpuEngineDmaReg.SrcSizeZ);
|
|
||||||
int SrcPosXY = ReadRegister(NvGpuEngineDmaReg.SrcPosXY);
|
|
||||||
int SrcPosZ = ReadRegister(NvGpuEngineDmaReg.SrcPosZ);
|
|
||||||
|
|
||||||
int DstPosX = (DstPosXY >> 0) & 0xffff;
|
|
||||||
int DstPosY = (DstPosXY >> 16) & 0xffff;
|
|
||||||
|
|
||||||
int SrcPosX = (SrcPosXY >> 0) & 0xffff;
|
|
||||||
int SrcPosY = (SrcPosXY >> 16) & 0xffff;
|
|
||||||
|
|
||||||
int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf);
|
|
||||||
int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
|
|
||||||
|
|
||||||
ISwizzle SrcSwizzle;
|
|
||||||
|
|
||||||
if (SrcLinear)
|
|
||||||
{
|
|
||||||
SrcSwizzle = new LinearSwizzle(SrcPitch, 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SrcSwizzle = new BlockLinearSwizzle(SrcSizeX, 1, SrcBlockHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
ISwizzle DstSwizzle;
|
|
||||||
|
|
||||||
if (DstLinear)
|
|
||||||
{
|
|
||||||
DstSwizzle = new LinearSwizzle(DstPitch, 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DstSwizzle = new BlockLinearSwizzle(DstSizeX, 1, DstBlockHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int Y = 0; Y < DstSizeY; Y++)
|
|
||||||
for (int X = 0; X < DstSizeX; X++)
|
|
||||||
{
|
|
||||||
long SrcOffset = SrcAddress + (uint)SrcSwizzle.GetSwizzleOffset(X, Y);
|
|
||||||
long DstOffset = DstAddress + (uint)DstSwizzle.GetSwizzleOffset(X, Y);
|
|
||||||
|
|
||||||
Vmm.WriteByte(DstOffset, Vmm.ReadByte(SrcOffset));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private long MakeInt64From2xInt32(NvGpuEngineDmaReg Reg)
|
|
||||||
{
|
|
||||||
return
|
|
||||||
(long)Registers[(int)Reg + 0] << 32 |
|
|
||||||
(uint)Registers[(int)Reg + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteRegister(NvGpuPBEntry PBEntry)
|
|
||||||
{
|
|
||||||
int ArgsCount = PBEntry.Arguments.Count;
|
|
||||||
|
|
||||||
if (ArgsCount > 0)
|
|
||||||
{
|
|
||||||
Registers[PBEntry.Method] = PBEntry.Arguments[ArgsCount - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int ReadRegister(NvGpuEngineDmaReg Reg)
|
|
||||||
{
|
|
||||||
return Registers[(int)Reg];
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteRegister(NvGpuEngineDmaReg Reg, int Value)
|
|
||||||
{
|
|
||||||
Registers[(int)Reg] = Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
192
Ryujinx.Graphics/NvGpuEngineM2mf.cs
Normal file
192
Ryujinx.Graphics/NvGpuEngineM2mf.cs
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
using Ryujinx.Graphics.Memory;
|
||||||
|
using Ryujinx.Graphics.Texture;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics
|
||||||
|
{
|
||||||
|
public class NvGpuEngineM2mf : INvGpuEngine
|
||||||
|
{
|
||||||
|
public int[] Registers { get; private set; }
|
||||||
|
|
||||||
|
private NvGpu Gpu;
|
||||||
|
|
||||||
|
private Dictionary<int, NvGpuMethod> Methods;
|
||||||
|
|
||||||
|
public NvGpuEngineM2mf(NvGpu Gpu)
|
||||||
|
{
|
||||||
|
this.Gpu = Gpu;
|
||||||
|
|
||||||
|
Registers = new int[0x1d6];
|
||||||
|
|
||||||
|
Methods = new Dictionary<int, NvGpuMethod>();
|
||||||
|
|
||||||
|
void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method)
|
||||||
|
{
|
||||||
|
while (Count-- > 0)
|
||||||
|
{
|
||||||
|
Methods.Add(Meth, Method);
|
||||||
|
|
||||||
|
Meth += Stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddMethod(0xc0, 1, 1, Execute);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||||
|
{
|
||||||
|
if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method))
|
||||||
|
{
|
||||||
|
Method(Vmm, PBEntry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteRegister(PBEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Execute(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||||
|
{
|
||||||
|
//TODO: Some registers and copy modes are still not implemented.
|
||||||
|
int Control = PBEntry.Arguments[0];
|
||||||
|
|
||||||
|
bool SrcLinear = ((Control >> 7) & 1) != 0;
|
||||||
|
bool DstLinear = ((Control >> 8) & 1) != 0;
|
||||||
|
bool Copy2d = ((Control >> 9) & 1) != 0;
|
||||||
|
|
||||||
|
long SrcAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.SrcAddress);
|
||||||
|
long DstAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.DstAddress);
|
||||||
|
|
||||||
|
int SrcPitch = ReadRegister(NvGpuEngineM2mfReg.SrcPitch);
|
||||||
|
int DstPitch = ReadRegister(NvGpuEngineM2mfReg.DstPitch);
|
||||||
|
|
||||||
|
int XCount = ReadRegister(NvGpuEngineM2mfReg.XCount);
|
||||||
|
int YCount = ReadRegister(NvGpuEngineM2mfReg.YCount);
|
||||||
|
|
||||||
|
int Swizzle = ReadRegister(NvGpuEngineM2mfReg.Swizzle);
|
||||||
|
|
||||||
|
int DstBlkDim = ReadRegister(NvGpuEngineM2mfReg.DstBlkDim);
|
||||||
|
int DstSizeX = ReadRegister(NvGpuEngineM2mfReg.DstSizeX);
|
||||||
|
int DstSizeY = ReadRegister(NvGpuEngineM2mfReg.DstSizeY);
|
||||||
|
int DstSizeZ = ReadRegister(NvGpuEngineM2mfReg.DstSizeZ);
|
||||||
|
int DstPosXY = ReadRegister(NvGpuEngineM2mfReg.DstPosXY);
|
||||||
|
int DstPosZ = ReadRegister(NvGpuEngineM2mfReg.DstPosZ);
|
||||||
|
|
||||||
|
int SrcBlkDim = ReadRegister(NvGpuEngineM2mfReg.SrcBlkDim);
|
||||||
|
int SrcSizeX = ReadRegister(NvGpuEngineM2mfReg.SrcSizeX);
|
||||||
|
int SrcSizeY = ReadRegister(NvGpuEngineM2mfReg.SrcSizeY);
|
||||||
|
int SrcSizeZ = ReadRegister(NvGpuEngineM2mfReg.SrcSizeZ);
|
||||||
|
int SrcPosXY = ReadRegister(NvGpuEngineM2mfReg.SrcPosXY);
|
||||||
|
int SrcPosZ = ReadRegister(NvGpuEngineM2mfReg.SrcPosZ);
|
||||||
|
|
||||||
|
int SrcCpp = ((Swizzle >> 20) & 7) + 1;
|
||||||
|
int DstCpp = ((Swizzle >> 24) & 7) + 1;
|
||||||
|
|
||||||
|
int DstPosX = (DstPosXY >> 0) & 0xffff;
|
||||||
|
int DstPosY = (DstPosXY >> 16) & 0xffff;
|
||||||
|
|
||||||
|
int SrcPosX = (SrcPosXY >> 0) & 0xffff;
|
||||||
|
int SrcPosY = (SrcPosXY >> 16) & 0xffff;
|
||||||
|
|
||||||
|
int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf);
|
||||||
|
int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
|
||||||
|
|
||||||
|
long SrcPA = Vmm.GetPhysicalAddress(SrcAddress);
|
||||||
|
long DstPA = Vmm.GetPhysicalAddress(DstAddress);
|
||||||
|
|
||||||
|
if (Copy2d)
|
||||||
|
{
|
||||||
|
if (SrcLinear)
|
||||||
|
{
|
||||||
|
SrcPosX = SrcPosY = SrcPosZ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DstLinear)
|
||||||
|
{
|
||||||
|
DstPosX = DstPosY = DstPosZ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SrcLinear && DstLinear)
|
||||||
|
{
|
||||||
|
for (int Y = 0; Y < YCount; Y++)
|
||||||
|
{
|
||||||
|
int SrcOffset = (SrcPosY + Y) * SrcPitch + SrcPosX * SrcCpp;
|
||||||
|
int DstOffset = (DstPosY + Y) * DstPitch + DstPosX * DstCpp;
|
||||||
|
|
||||||
|
long Src = SrcPA + (uint)SrcOffset;
|
||||||
|
long Dst = DstPA + (uint)DstOffset;
|
||||||
|
|
||||||
|
Vmm.Memory.CopyBytes(Src, Dst, XCount * SrcCpp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ISwizzle SrcSwizzle;
|
||||||
|
|
||||||
|
if (SrcLinear)
|
||||||
|
{
|
||||||
|
SrcSwizzle = new LinearSwizzle(SrcPitch, SrcCpp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SrcSwizzle = new BlockLinearSwizzle(SrcSizeX, SrcCpp, SrcBlockHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
ISwizzle DstSwizzle;
|
||||||
|
|
||||||
|
if (DstLinear)
|
||||||
|
{
|
||||||
|
DstSwizzle = new LinearSwizzle(DstPitch, DstCpp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DstSwizzle = new BlockLinearSwizzle(DstSizeX, DstCpp, DstBlockHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int Y = 0; Y < YCount; Y++)
|
||||||
|
for (int X = 0; X < XCount; X++)
|
||||||
|
{
|
||||||
|
int SrcOffset = SrcSwizzle.GetSwizzleOffset(SrcPosX + X, SrcPosY + Y);
|
||||||
|
int DstOffset = DstSwizzle.GetSwizzleOffset(DstPosX + X, DstPosY + Y);
|
||||||
|
|
||||||
|
long Src = SrcPA + (uint)SrcOffset;
|
||||||
|
long Dst = DstPA + (uint)DstOffset;
|
||||||
|
|
||||||
|
Vmm.Memory.CopyBytes(Src, Dst, SrcCpp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vmm.Memory.CopyBytes(SrcPA, DstPA, XCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private long MakeInt64From2xInt32(NvGpuEngineM2mfReg Reg)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(long)Registers[(int)Reg + 0] << 32 |
|
||||||
|
(uint)Registers[(int)Reg + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteRegister(NvGpuPBEntry PBEntry)
|
||||||
|
{
|
||||||
|
int ArgsCount = PBEntry.Arguments.Count;
|
||||||
|
|
||||||
|
if (ArgsCount > 0)
|
||||||
|
{
|
||||||
|
Registers[PBEntry.Method] = PBEntry.Arguments[ArgsCount - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ReadRegister(NvGpuEngineM2mfReg Reg)
|
||||||
|
{
|
||||||
|
return Registers[(int)Reg];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteRegister(NvGpuEngineM2mfReg Reg, int Value)
|
||||||
|
{
|
||||||
|
Registers[(int)Reg] = Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,14 @@
|
||||||
namespace Ryujinx.Graphics
|
namespace Ryujinx.Graphics
|
||||||
{
|
{
|
||||||
enum NvGpuEngineDmaReg
|
enum NvGpuEngineM2mfReg
|
||||||
{
|
{
|
||||||
SrcAddress = 0x100,
|
SrcAddress = 0x100,
|
||||||
DstAddress = 0x102,
|
DstAddress = 0x102,
|
||||||
SrcPitch = 0x104,
|
SrcPitch = 0x104,
|
||||||
DstPitch = 0x105,
|
DstPitch = 0x105,
|
||||||
|
XCount = 0x106,
|
||||||
|
YCount = 0x107,
|
||||||
|
Swizzle = 0x1c2,
|
||||||
DstBlkDim = 0x1c3,
|
DstBlkDim = 0x1c3,
|
||||||
DstSizeX = 0x1c4,
|
DstSizeX = 0x1c4,
|
||||||
DstSizeY = 0x1c5,
|
DstSizeY = 0x1c5,
|
102
Ryujinx.Graphics/NvGpuEngineP2mf.cs
Normal file
102
Ryujinx.Graphics/NvGpuEngineP2mf.cs
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
using Ryujinx.Graphics.Memory;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics
|
||||||
|
{
|
||||||
|
public class NvGpuEngineP2mf : INvGpuEngine
|
||||||
|
{
|
||||||
|
public int[] Registers { get; private set; }
|
||||||
|
|
||||||
|
private NvGpu Gpu;
|
||||||
|
|
||||||
|
private Dictionary<int, NvGpuMethod> Methods;
|
||||||
|
|
||||||
|
private ReadOnlyCollection<int> DataBuffer;
|
||||||
|
|
||||||
|
public NvGpuEngineP2mf(NvGpu Gpu)
|
||||||
|
{
|
||||||
|
this.Gpu = Gpu;
|
||||||
|
|
||||||
|
Registers = new int[0x80];
|
||||||
|
|
||||||
|
Methods = new Dictionary<int, NvGpuMethod>();
|
||||||
|
|
||||||
|
void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method)
|
||||||
|
{
|
||||||
|
while (Count-- > 0)
|
||||||
|
{
|
||||||
|
Methods.Add(Meth, Method);
|
||||||
|
|
||||||
|
Meth += Stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddMethod(0x6c, 1, 1, Execute);
|
||||||
|
AddMethod(0x6d, 1, 1, PushData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||||
|
{
|
||||||
|
if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method))
|
||||||
|
{
|
||||||
|
Method(Vmm, PBEntry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteRegister(PBEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Execute(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||||
|
{
|
||||||
|
//TODO: Some registers and copy modes are still not implemented.
|
||||||
|
int Control = PBEntry.Arguments[0];
|
||||||
|
|
||||||
|
long DstAddress = MakeInt64From2xInt32(NvGpuEngineP2mfReg.DstAddress);
|
||||||
|
|
||||||
|
int LineLengthIn = ReadRegister(NvGpuEngineP2mfReg.LineLengthIn);
|
||||||
|
|
||||||
|
DataBuffer = null;
|
||||||
|
|
||||||
|
Gpu.Fifo.Step();
|
||||||
|
|
||||||
|
for (int Offset = 0; Offset < LineLengthIn; Offset += 4)
|
||||||
|
{
|
||||||
|
Vmm.WriteInt32(DstAddress + Offset, DataBuffer[Offset >> 2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PushData(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||||
|
{
|
||||||
|
DataBuffer = PBEntry.Arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long MakeInt64From2xInt32(NvGpuEngineP2mfReg Reg)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(long)Registers[(int)Reg + 0] << 32 |
|
||||||
|
(uint)Registers[(int)Reg + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteRegister(NvGpuPBEntry PBEntry)
|
||||||
|
{
|
||||||
|
int ArgsCount = PBEntry.Arguments.Count;
|
||||||
|
|
||||||
|
if (ArgsCount > 0)
|
||||||
|
{
|
||||||
|
Registers[PBEntry.Method] = PBEntry.Arguments[ArgsCount - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ReadRegister(NvGpuEngineP2mfReg Reg)
|
||||||
|
{
|
||||||
|
return Registers[(int)Reg];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteRegister(NvGpuEngineP2mfReg Reg, int Value)
|
||||||
|
{
|
||||||
|
Registers[(int)Reg] = Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
Ryujinx.Graphics/NvGpuEngineP2mfReg.cs
Normal file
17
Ryujinx.Graphics/NvGpuEngineP2mfReg.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
namespace Ryujinx.Graphics
|
||||||
|
{
|
||||||
|
enum NvGpuEngineP2mfReg
|
||||||
|
{
|
||||||
|
LineLengthIn = 0x60,
|
||||||
|
LineCount = 0x61,
|
||||||
|
DstAddress = 0x62,
|
||||||
|
DstPitch = 0x64,
|
||||||
|
DstBlockDim = 0x65,
|
||||||
|
DstWidth = 0x66,
|
||||||
|
DstHeight = 0x67,
|
||||||
|
DstDepth = 0x68,
|
||||||
|
DstZ = 0x69,
|
||||||
|
DstX = 0x6a,
|
||||||
|
DstY = 0x6b
|
||||||
|
}
|
||||||
|
}
|
|
@ -94,6 +94,8 @@ namespace Ryujinx.Graphics
|
||||||
|
|
||||||
Gpu.Engine3d.ResetCache();
|
Gpu.Engine3d.ResetCache();
|
||||||
|
|
||||||
|
Gpu.ResourceManager.ClearPbCache();
|
||||||
|
|
||||||
CurrPbEntryIndex = 0;
|
CurrPbEntryIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,20 +105,36 @@ namespace Ryujinx.Graphics
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
private void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||||
|
{
|
||||||
|
if ((NvGpuFifoMeth)PBEntry.Method == NvGpuFifoMeth.BindChannel)
|
||||||
|
{
|
||||||
|
NvGpuEngine Engine = (NvGpuEngine)PBEntry.Arguments[0];
|
||||||
|
|
||||||
|
SubChannels[PBEntry.SubChannel] = Engine;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (SubChannels[PBEntry.SubChannel])
|
||||||
|
{
|
||||||
|
case NvGpuEngine._2d: Call2dMethod (Vmm, PBEntry); break;
|
||||||
|
case NvGpuEngine._3d: Call3dMethod (Vmm, PBEntry); break;
|
||||||
|
case NvGpuEngine.P2mf: CallP2mfMethod(Vmm, PBEntry); break;
|
||||||
|
case NvGpuEngine.M2mf: CallM2mfMethod(Vmm, PBEntry); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Call2dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||||
|
{
|
||||||
|
Gpu.Engine2d.CallMethod(Vmm, PBEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Call3dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||||
{
|
{
|
||||||
if (PBEntry.Method < 0x80)
|
if (PBEntry.Method < 0x80)
|
||||||
{
|
{
|
||||||
switch ((NvGpuFifoMeth)PBEntry.Method)
|
switch ((NvGpuFifoMeth)PBEntry.Method)
|
||||||
{
|
{
|
||||||
case NvGpuFifoMeth.BindChannel:
|
|
||||||
{
|
|
||||||
NvGpuEngine Engine = (NvGpuEngine)PBEntry.Arguments[0];
|
|
||||||
|
|
||||||
SubChannels[PBEntry.SubChannel] = Engine;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case NvGpuFifoMeth.SetMacroUploadAddress:
|
case NvGpuFifoMeth.SetMacroUploadAddress:
|
||||||
{
|
{
|
||||||
CurrMacroPosition = PBEntry.Arguments[0];
|
CurrMacroPosition = PBEntry.Arguments[0];
|
||||||
|
@ -150,25 +168,7 @@ namespace Ryujinx.Graphics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (PBEntry.Method < 0xe00)
|
||||||
{
|
|
||||||
switch (SubChannels[PBEntry.SubChannel])
|
|
||||||
{
|
|
||||||
case NvGpuEngine._2d: Call2dMethod (Vmm, PBEntry); break;
|
|
||||||
case NvGpuEngine._3d: Call3dMethod (Vmm, PBEntry); break;
|
|
||||||
case NvGpuEngine.Dma: CallDmaMethod(Vmm, PBEntry); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Call2dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
|
||||||
{
|
|
||||||
Gpu.Engine2d.CallMethod(Vmm, PBEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Call3dMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
|
||||||
{
|
|
||||||
if (PBEntry.Method < 0xe00)
|
|
||||||
{
|
{
|
||||||
Gpu.Engine3d.CallMethod(Vmm, PBEntry);
|
Gpu.Engine3d.CallMethod(Vmm, PBEntry);
|
||||||
}
|
}
|
||||||
|
@ -190,9 +190,14 @@ namespace Ryujinx.Graphics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CallDmaMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
private void CallP2mfMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||||
{
|
{
|
||||||
Gpu.EngineDma.CallMethod(Vmm, PBEntry);
|
Gpu.EngineP2mf.CallMethod(Vmm, PBEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CallM2mfMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||||
|
{
|
||||||
|
Gpu.EngineM2mf.CallMethod(Vmm, PBEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,33 +1,37 @@
|
||||||
using Ryujinx.Graphics.Gal;
|
using ChocolArm64.Memory;
|
||||||
|
using Ryujinx.Graphics.Gal;
|
||||||
|
using Ryujinx.Graphics.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Texture
|
namespace Ryujinx.Graphics.Texture
|
||||||
{
|
{
|
||||||
static class ImageUtils
|
public static class ImageUtils
|
||||||
{
|
{
|
||||||
struct ImageDescriptor
|
[Flags]
|
||||||
|
private enum TargetBuffer
|
||||||
{
|
{
|
||||||
public TextureReaderDelegate Reader;
|
Color = 1 << 0,
|
||||||
|
Depth = 1 << 1,
|
||||||
|
Stencil = 1 << 2,
|
||||||
|
|
||||||
public bool HasColor;
|
DepthStencil = Depth | Stencil
|
||||||
public bool HasDepth;
|
}
|
||||||
public bool HasStencil;
|
|
||||||
|
|
||||||
public bool Compressed;
|
private struct ImageDescriptor
|
||||||
|
{
|
||||||
|
public int BytesPerPixel { get; private set; }
|
||||||
|
public int BlockWidth { get; private set; }
|
||||||
|
public int BlockHeight { get; private set; }
|
||||||
|
|
||||||
public ImageDescriptor(
|
public TargetBuffer Target { get; private set; }
|
||||||
TextureReaderDelegate Reader,
|
|
||||||
bool HasColor,
|
public ImageDescriptor(int BytesPerPixel, int BlockWidth, int BlockHeight, TargetBuffer Target)
|
||||||
bool HasDepth,
|
|
||||||
bool HasStencil,
|
|
||||||
bool Compressed)
|
|
||||||
{
|
{
|
||||||
this.Reader = Reader;
|
this.BytesPerPixel = BytesPerPixel;
|
||||||
this.HasColor = HasColor;
|
this.BlockWidth = BlockWidth;
|
||||||
this.HasDepth = HasDepth;
|
this.BlockHeight = BlockHeight;
|
||||||
this.HasStencil = HasStencil;
|
this.Target = Target;
|
||||||
this.Compressed = Compressed;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +52,7 @@ namespace Ryujinx.Graphics.Texture
|
||||||
{ GalTextureFormat.G8R8, GalImageFormat.G8R8 | Snorm | Unorm | Sint | Uint },
|
{ GalTextureFormat.G8R8, GalImageFormat.G8R8 | Snorm | Unorm | Sint | Uint },
|
||||||
{ GalTextureFormat.R16, GalImageFormat.R16 | Snorm | Unorm | Sint | Uint | Sfloat },
|
{ GalTextureFormat.R16, GalImageFormat.R16 | Snorm | Unorm | Sint | Uint | Sfloat },
|
||||||
{ GalTextureFormat.R8, GalImageFormat.R8 | Snorm | Unorm | Sint | Uint },
|
{ GalTextureFormat.R8, GalImageFormat.R8 | Snorm | Unorm | Sint | Uint },
|
||||||
|
{ GalTextureFormat.R16G16, GalImageFormat.R16G16 | Snorm },
|
||||||
{ GalTextureFormat.R32, GalImageFormat.R32 | Sint | Uint | Sfloat },
|
{ GalTextureFormat.R32, GalImageFormat.R32 | Sint | Uint | Sfloat },
|
||||||
{ GalTextureFormat.A4B4G4R4, GalImageFormat.A4B4G4R4 | Unorm },
|
{ GalTextureFormat.A4B4G4R4, GalImageFormat.A4B4G4R4 | Unorm },
|
||||||
{ GalTextureFormat.A1B5G5R5, GalImageFormat.A1R5G5B5 | Unorm },
|
{ GalTextureFormat.A1B5G5R5, GalImageFormat.A1R5G5B5 | Unorm },
|
||||||
|
@ -85,58 +90,58 @@ namespace Ryujinx.Graphics.Texture
|
||||||
|
|
||||||
private static readonly Dictionary<GalImageFormat, ImageDescriptor> s_ImageTable =
|
private static readonly Dictionary<GalImageFormat, ImageDescriptor> s_ImageTable =
|
||||||
new Dictionary<GalImageFormat, ImageDescriptor>()
|
new Dictionary<GalImageFormat, ImageDescriptor>()
|
||||||
{
|
{
|
||||||
{ GalImageFormat.R32G32B32A32, new ImageDescriptor(TextureReader.Read16Bpp, true, false, false, false) },
|
{ GalImageFormat.R32G32B32A32, new ImageDescriptor(16, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.R16G16B16A16, new ImageDescriptor(TextureReader.Read8Bpp, true, false, false, false) },
|
{ GalImageFormat.R16G16B16A16, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.R32G32, new ImageDescriptor(TextureReader.Read8Bpp, true, false, false, false) },
|
{ GalImageFormat.R32G32, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.A8B8G8R8, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
{ GalImageFormat.A8B8G8R8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.A2B10G10R10, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
{ GalImageFormat.A2B10G10R10, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.R32, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
{ GalImageFormat.R32, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.A4B4G4R4, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
|
{ GalImageFormat.A4B4G4R4, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.BC6H_SF16, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
{ GalImageFormat.BC6H_SF16, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.BC6H_UF16, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
{ GalImageFormat.BC6H_UF16, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.A1R5G5B5, new ImageDescriptor(TextureReader.Read5551, true, false, false, false) },
|
{ GalImageFormat.A1R5G5B5, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.B5G6R5, new ImageDescriptor(TextureReader.Read565, true, false, false, false) },
|
{ GalImageFormat.B5G6R5, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.BC7, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
{ GalImageFormat.BC7, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.R16G16, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
{ GalImageFormat.R16G16, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.R8G8, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
|
{ GalImageFormat.R8G8, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.G8R8, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
|
{ GalImageFormat.G8R8, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.R16, new ImageDescriptor(TextureReader.Read2Bpp, true, false, false, false) },
|
{ GalImageFormat.R16, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.R8, new ImageDescriptor(TextureReader.Read1Bpp, true, false, false, false) },
|
{ GalImageFormat.R8, new ImageDescriptor(1, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.B10G11R11, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
{ GalImageFormat.B10G11R11, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.A8B8G8R8_SRGB, new ImageDescriptor(TextureReader.Read4Bpp, true, false, false, false) },
|
{ GalImageFormat.A8B8G8R8_SRGB, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.BC1_RGBA, new ImageDescriptor(TextureReader.Read8Bpt4x4, true, false, false, true) },
|
{ GalImageFormat.BC1_RGBA, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.BC2, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
{ GalImageFormat.BC2, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.BC3, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
{ GalImageFormat.BC3, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.BC4, new ImageDescriptor(TextureReader.Read8Bpt4x4, true, false, false, true) },
|
{ GalImageFormat.BC4, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.BC5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
{ GalImageFormat.BC5, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.ASTC_4x4, new ImageDescriptor(TextureReader.Read16BptCompressedTexture4x4, true, false, false, true) },
|
{ GalImageFormat.ASTC_4x4, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.ASTC_5x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture5x5, true, false, false, true) },
|
{ GalImageFormat.ASTC_5x5, new ImageDescriptor(16, 5, 5, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.ASTC_6x6, new ImageDescriptor(TextureReader.Read16BptCompressedTexture6x6, true, false, false, true) },
|
{ GalImageFormat.ASTC_6x6, new ImageDescriptor(16, 6, 6, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.ASTC_8x8, new ImageDescriptor(TextureReader.Read16BptCompressedTexture8x8, true, false, false, true) },
|
{ GalImageFormat.ASTC_8x8, new ImageDescriptor(16, 8, 8, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.ASTC_10x10, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x10, true, false, false, true) },
|
{ GalImageFormat.ASTC_10x10, new ImageDescriptor(16, 10, 10, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.ASTC_12x12, new ImageDescriptor(TextureReader.Read16BptCompressedTexture12x12, true, false, false, true) },
|
{ GalImageFormat.ASTC_12x12, new ImageDescriptor(16, 12, 12, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.ASTC_5x4, new ImageDescriptor(TextureReader.Read16BptCompressedTexture5x4, true, false, false, true) },
|
{ GalImageFormat.ASTC_5x4, new ImageDescriptor(16, 5, 4, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.ASTC_6x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture6x5, true, false, false, true) },
|
{ GalImageFormat.ASTC_6x5, new ImageDescriptor(16, 6, 5, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.ASTC_8x6, new ImageDescriptor(TextureReader.Read16BptCompressedTexture8x6, true, false, false, true) },
|
{ GalImageFormat.ASTC_8x6, new ImageDescriptor(16, 8, 6, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.ASTC_10x8, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x8, true, false, false, true) },
|
{ GalImageFormat.ASTC_10x8, new ImageDescriptor(16, 10, 8, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.ASTC_12x10, new ImageDescriptor(TextureReader.Read16BptCompressedTexture12x10, true, false, false, true) },
|
{ GalImageFormat.ASTC_12x10, new ImageDescriptor(16, 12, 10, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.ASTC_8x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture8x5, true, false, false, true) },
|
{ GalImageFormat.ASTC_8x5, new ImageDescriptor(16, 8, 5, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.ASTC_10x5, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x5, true, false, false, true) },
|
{ GalImageFormat.ASTC_10x5, new ImageDescriptor(16, 10, 5, TargetBuffer.Color) },
|
||||||
{ GalImageFormat.ASTC_10x6, new ImageDescriptor(TextureReader.Read16BptCompressedTexture10x6, true, false, false, true) },
|
{ GalImageFormat.ASTC_10x6, new ImageDescriptor(16, 10, 6, TargetBuffer.Color) },
|
||||||
|
|
||||||
{ GalImageFormat.D24_S8, new ImageDescriptor(TextureReader.Read4Bpp, false, true, true, false) },
|
{ GalImageFormat.D24_S8, new ImageDescriptor(4, 1, 1, TargetBuffer.DepthStencil) },
|
||||||
{ GalImageFormat.D32, new ImageDescriptor(TextureReader.Read4Bpp, false, true, false, false) },
|
{ GalImageFormat.D32, new ImageDescriptor(4, 1, 1, TargetBuffer.Depth) },
|
||||||
{ GalImageFormat.D16, new ImageDescriptor(TextureReader.Read2Bpp, false, true, false, false) },
|
{ GalImageFormat.D16, new ImageDescriptor(2, 1, 1, TargetBuffer.Depth) },
|
||||||
{ GalImageFormat.D32_S8, new ImageDescriptor(TextureReader.Read8Bpp, false, true, true, false) },
|
{ GalImageFormat.D32_S8, new ImageDescriptor(8, 1, 1, TargetBuffer.DepthStencil) },
|
||||||
};
|
};
|
||||||
|
|
||||||
public static GalImageFormat ConvertTexture(
|
public static GalImageFormat ConvertTexture(
|
||||||
GalTextureFormat Format,
|
GalTextureFormat Format,
|
||||||
GalTextureType RType,
|
GalTextureType RType,
|
||||||
GalTextureType GType,
|
GalTextureType GType,
|
||||||
GalTextureType BType,
|
GalTextureType BType,
|
||||||
GalTextureType AType)
|
GalTextureType AType)
|
||||||
{
|
{
|
||||||
if (RType != GType || RType != BType || RType != AType)
|
if (RType != GType || RType != BType || RType != AType)
|
||||||
{
|
{
|
||||||
|
@ -202,128 +207,157 @@ namespace Ryujinx.Graphics.Texture
|
||||||
case GalZetaFormat.Z32Float: return GalImageFormat.D32 | Sfloat;
|
case GalZetaFormat.Z32Float: return GalImageFormat.D32 | Sfloat;
|
||||||
case GalZetaFormat.S8Z24Unorm: return GalImageFormat.D24_S8 | Unorm;
|
case GalZetaFormat.S8Z24Unorm: return GalImageFormat.D24_S8 | Unorm;
|
||||||
case GalZetaFormat.Z16Unorm: return GalImageFormat.D16 | Unorm;
|
case GalZetaFormat.Z16Unorm: return GalImageFormat.D16 | Unorm;
|
||||||
//This one might not be Uint, change when a texture uses this format
|
case GalZetaFormat.Z24S8Unorm: return GalImageFormat.D24_S8 | Unorm;
|
||||||
case GalZetaFormat.Z32S8X24Float: return GalImageFormat.D32_S8 | Uint;
|
case GalZetaFormat.Z32S8X24Float: return GalImageFormat.D32_S8 | Sfloat;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException(Format.ToString());
|
throw new NotImplementedException(Format.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextureReaderDelegate GetReader(GalImageFormat Format)
|
public static byte[] ReadTexture(IAMemory Memory, GalImage Image, long Position)
|
||||||
{
|
{
|
||||||
return GetImageDescriptor(Format).Reader;
|
AMemory CpuMemory;
|
||||||
|
|
||||||
|
if (Memory is NvGpuVmm Vmm)
|
||||||
|
{
|
||||||
|
CpuMemory = Vmm.Memory;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CpuMemory = (AMemory)Memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISwizzle Swizzle = TextureHelper.GetSwizzle(Image);
|
||||||
|
|
||||||
|
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
||||||
|
|
||||||
|
(int Width, int Height) = GetImageSizeInBlocks(Image);
|
||||||
|
|
||||||
|
int BytesPerPixel = Desc.BytesPerPixel;
|
||||||
|
|
||||||
|
int OutOffs = 0;
|
||||||
|
|
||||||
|
byte[] Data = new byte[Width * Height * BytesPerPixel];
|
||||||
|
|
||||||
|
for (int Y = 0; Y < Height; Y++)
|
||||||
|
for (int X = 0; X < Width; X++)
|
||||||
|
{
|
||||||
|
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||||
|
|
||||||
|
CpuMemory.ReadBytes(Position + Offset, Data, OutOffs, BytesPerPixel);
|
||||||
|
|
||||||
|
OutOffs += BytesPerPixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteTexture(NvGpuVmm Vmm, GalImage Image, long Position, byte[] Data)
|
||||||
|
{
|
||||||
|
ISwizzle Swizzle = TextureHelper.GetSwizzle(Image);
|
||||||
|
|
||||||
|
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
||||||
|
|
||||||
|
(int Width, int Height) = ImageUtils.GetImageSizeInBlocks(Image);
|
||||||
|
|
||||||
|
int BytesPerPixel = Desc.BytesPerPixel;
|
||||||
|
|
||||||
|
int InOffs = 0;
|
||||||
|
|
||||||
|
for (int Y = 0; Y < Height; Y++)
|
||||||
|
for (int X = 0; X < Width; X++)
|
||||||
|
{
|
||||||
|
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||||
|
|
||||||
|
Vmm.Memory.WriteBytes(Position + Offset, Data, InOffs, BytesPerPixel);
|
||||||
|
|
||||||
|
InOffs += BytesPerPixel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetSize(GalImage Image)
|
public static int GetSize(GalImage Image)
|
||||||
{
|
{
|
||||||
switch (Image.Format & GalImageFormat.FormatMask)
|
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
||||||
|
|
||||||
|
int Width = DivRoundUp(Image.Width, Desc.BlockWidth);
|
||||||
|
int Height = DivRoundUp(Image.Height, Desc.BlockHeight);
|
||||||
|
|
||||||
|
return Desc.BytesPerPixel * Width * Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetPitch(GalImageFormat Format, int Width)
|
||||||
|
{
|
||||||
|
ImageDescriptor Desc = GetImageDescriptor(Format);
|
||||||
|
|
||||||
|
return Desc.BytesPerPixel * DivRoundUp(Width, Desc.BlockWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetBlockWidth(GalImageFormat Format)
|
||||||
|
{
|
||||||
|
return GetImageDescriptor(Format).BlockWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetBlockHeight(GalImageFormat Format)
|
||||||
|
{
|
||||||
|
return GetImageDescriptor(Format).BlockHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetAlignedWidth(GalImage Image)
|
||||||
|
{
|
||||||
|
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
||||||
|
|
||||||
|
int AlignMask;
|
||||||
|
|
||||||
|
if (Image.Layout == GalMemoryLayout.BlockLinear)
|
||||||
{
|
{
|
||||||
case GalImageFormat.R32G32B32A32:
|
AlignMask = Image.TileWidth * (64 / Desc.BytesPerPixel) - 1;
|
||||||
return Image.Width * Image.Height * 16;
|
}
|
||||||
|
else
|
||||||
case GalImageFormat.R16G16B16A16:
|
{
|
||||||
case GalImageFormat.D32_S8:
|
AlignMask = (32 / Desc.BytesPerPixel) - 1;
|
||||||
case GalImageFormat.R32G32:
|
|
||||||
return Image.Width * Image.Height * 8;
|
|
||||||
|
|
||||||
case GalImageFormat.A8B8G8R8:
|
|
||||||
case GalImageFormat.A8B8G8R8_SRGB:
|
|
||||||
case GalImageFormat.A2B10G10R10:
|
|
||||||
case GalImageFormat.R16G16:
|
|
||||||
case GalImageFormat.R32:
|
|
||||||
case GalImageFormat.D32:
|
|
||||||
case GalImageFormat.B10G11R11:
|
|
||||||
case GalImageFormat.D24_S8:
|
|
||||||
return Image.Width * Image.Height * 4;
|
|
||||||
|
|
||||||
case GalImageFormat.B4G4R4A4:
|
|
||||||
case GalImageFormat.A1R5G5B5:
|
|
||||||
case GalImageFormat.B5G6R5:
|
|
||||||
case GalImageFormat.R8G8:
|
|
||||||
case GalImageFormat.G8R8:
|
|
||||||
case GalImageFormat.R16:
|
|
||||||
case GalImageFormat.D16:
|
|
||||||
return Image.Width * Image.Height * 2;
|
|
||||||
|
|
||||||
case GalImageFormat.R8:
|
|
||||||
return Image.Width * Image.Height;
|
|
||||||
|
|
||||||
case GalImageFormat.BC1_RGBA:
|
|
||||||
case GalImageFormat.BC4:
|
|
||||||
{
|
|
||||||
return CompressedTextureSize(Image.Width, Image.Height, 4, 4, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
case GalImageFormat.BC6H_SF16:
|
|
||||||
case GalImageFormat.BC6H_UF16:
|
|
||||||
case GalImageFormat.BC7:
|
|
||||||
case GalImageFormat.BC2:
|
|
||||||
case GalImageFormat.BC3:
|
|
||||||
case GalImageFormat.BC5:
|
|
||||||
case GalImageFormat.ASTC_4x4:
|
|
||||||
return CompressedTextureSize(Image.Width, Image.Height, 4, 4, 16);
|
|
||||||
|
|
||||||
case GalImageFormat.ASTC_5x5:
|
|
||||||
return CompressedTextureSize(Image.Width, Image.Height, 5, 5, 16);
|
|
||||||
|
|
||||||
case GalImageFormat.ASTC_6x6:
|
|
||||||
return CompressedTextureSize(Image.Width, Image.Height, 6, 6, 16);
|
|
||||||
|
|
||||||
case GalImageFormat.ASTC_8x8:
|
|
||||||
return CompressedTextureSize(Image.Width, Image.Height, 8, 8, 16);
|
|
||||||
|
|
||||||
case GalImageFormat.ASTC_10x10:
|
|
||||||
return CompressedTextureSize(Image.Width, Image.Height, 10, 10, 16);
|
|
||||||
|
|
||||||
case GalImageFormat.ASTC_12x12:
|
|
||||||
return CompressedTextureSize(Image.Width, Image.Height, 12, 12, 16);
|
|
||||||
|
|
||||||
case GalImageFormat.ASTC_5x4:
|
|
||||||
return CompressedTextureSize(Image.Width, Image.Height, 5, 4, 16);
|
|
||||||
|
|
||||||
case GalImageFormat.ASTC_6x5:
|
|
||||||
return CompressedTextureSize(Image.Width, Image.Height, 6, 5, 16);
|
|
||||||
|
|
||||||
case GalImageFormat.ASTC_8x6:
|
|
||||||
return CompressedTextureSize(Image.Width, Image.Height, 8, 6, 16);
|
|
||||||
|
|
||||||
case GalImageFormat.ASTC_10x8:
|
|
||||||
return CompressedTextureSize(Image.Width, Image.Height, 10, 8, 16);
|
|
||||||
|
|
||||||
case GalImageFormat.ASTC_12x10:
|
|
||||||
return CompressedTextureSize(Image.Width, Image.Height, 12, 10, 16);
|
|
||||||
|
|
||||||
case GalImageFormat.ASTC_8x5:
|
|
||||||
return CompressedTextureSize(Image.Width, Image.Height, 8, 5, 16);
|
|
||||||
|
|
||||||
case GalImageFormat.ASTC_10x5:
|
|
||||||
return CompressedTextureSize(Image.Width, Image.Height, 10, 5, 16);
|
|
||||||
|
|
||||||
case GalImageFormat.ASTC_10x6:
|
|
||||||
return CompressedTextureSize(Image.Width, Image.Height, 10, 6, 16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException((Image.Format & GalImageFormat.FormatMask).ToString());
|
return (Image.Width + AlignMask) & ~AlignMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (int Width, int Height) GetImageSizeInBlocks(GalImage Image)
|
||||||
|
{
|
||||||
|
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
|
||||||
|
|
||||||
|
return (DivRoundUp(Image.Width, Desc.BlockWidth),
|
||||||
|
DivRoundUp(Image.Height, Desc.BlockHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetBytesPerPixel(GalImageFormat Format)
|
||||||
|
{
|
||||||
|
return GetImageDescriptor(Format).BytesPerPixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int DivRoundUp(int LHS, int RHS)
|
||||||
|
{
|
||||||
|
return (LHS + (RHS - 1)) / RHS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool HasColor(GalImageFormat Format)
|
public static bool HasColor(GalImageFormat Format)
|
||||||
{
|
{
|
||||||
return GetImageDescriptor(Format).HasColor;
|
return (GetImageDescriptor(Format).Target & TargetBuffer.Color) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool HasDepth(GalImageFormat Format)
|
public static bool HasDepth(GalImageFormat Format)
|
||||||
{
|
{
|
||||||
return GetImageDescriptor(Format).HasDepth;
|
return (GetImageDescriptor(Format).Target & TargetBuffer.Depth) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool HasStencil(GalImageFormat Format)
|
public static bool HasStencil(GalImageFormat Format)
|
||||||
{
|
{
|
||||||
return GetImageDescriptor(Format).HasStencil;
|
return (GetImageDescriptor(Format).Target & TargetBuffer.Stencil) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsCompressed(GalImageFormat Format)
|
public static bool IsCompressed(GalImageFormat Format)
|
||||||
{
|
{
|
||||||
return GetImageDescriptor(Format).Compressed;
|
ImageDescriptor Desc = GetImageDescriptor(Format);
|
||||||
|
|
||||||
|
return (Desc.BlockWidth | Desc.BlockHeight) != 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ImageDescriptor GetImageDescriptor(GalImageFormat Format)
|
private static ImageDescriptor GetImageDescriptor(GalImageFormat Format)
|
||||||
|
@ -351,13 +385,5 @@ namespace Ryujinx.Graphics.Texture
|
||||||
default: throw new NotImplementedException(((int)Type).ToString());
|
default: throw new NotImplementedException(((int)Type).ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int CompressedTextureSize(int TextureWidth, int TextureHeight, int BlockWidth, int BlockHeight, int Bpb)
|
|
||||||
{
|
|
||||||
int W = (TextureWidth + (BlockWidth - 1)) / BlockWidth;
|
|
||||||
int H = (TextureHeight + (BlockHeight - 1)) / BlockHeight;
|
|
||||||
|
|
||||||
return W * H * Bpb;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,44 +17,20 @@ namespace Ryujinx.Graphics.Texture
|
||||||
GalTextureSource ZSource = (GalTextureSource)((Tic[0] >> 25) & 7);
|
GalTextureSource ZSource = (GalTextureSource)((Tic[0] >> 25) & 7);
|
||||||
GalTextureSource WSource = (GalTextureSource)((Tic[0] >> 28) & 7);
|
GalTextureSource WSource = (GalTextureSource)((Tic[0] >> 28) & 7);
|
||||||
|
|
||||||
int Width = (Tic[4] & 0xffff) + 1;
|
|
||||||
int Height = (Tic[5] & 0xffff) + 1;
|
|
||||||
|
|
||||||
return new GalImage(
|
|
||||||
Width,
|
|
||||||
Height,
|
|
||||||
Format,
|
|
||||||
XSource,
|
|
||||||
YSource,
|
|
||||||
ZSource,
|
|
||||||
WSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] GetTextureData(NvGpuVmm Vmm, long TicPosition)
|
|
||||||
{
|
|
||||||
int[] Tic = ReadWords(Vmm, TicPosition, 8);
|
|
||||||
|
|
||||||
GalImageFormat Format = GetImageFormat(Tic);
|
|
||||||
|
|
||||||
long TextureAddress = (uint)Tic[1];
|
|
||||||
|
|
||||||
TextureAddress |= (long)((ushort)Tic[2]) << 32;
|
|
||||||
|
|
||||||
TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7);
|
TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7);
|
||||||
|
|
||||||
|
GalMemoryLayout Layout;
|
||||||
|
|
||||||
if (Swizzle == TextureSwizzle.BlockLinear ||
|
if (Swizzle == TextureSwizzle.BlockLinear ||
|
||||||
Swizzle == TextureSwizzle.BlockLinearColorKey)
|
Swizzle == TextureSwizzle.BlockLinearColorKey)
|
||||||
{
|
{
|
||||||
TextureAddress &= ~0x1ffL;
|
Layout = GalMemoryLayout.BlockLinear;
|
||||||
}
|
}
|
||||||
else if (Swizzle == TextureSwizzle.Pitch ||
|
else
|
||||||
Swizzle == TextureSwizzle.PitchColorKey)
|
|
||||||
{
|
{
|
||||||
TextureAddress &= ~0x1fL;
|
Layout = GalMemoryLayout.Pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Pitch = (Tic[3] & 0xffff) << 5;
|
|
||||||
|
|
||||||
int BlockHeightLog2 = (Tic[3] >> 3) & 7;
|
int BlockHeightLog2 = (Tic[3] >> 3) & 7;
|
||||||
int TileWidthLog2 = (Tic[3] >> 10) & 7;
|
int TileWidthLog2 = (Tic[3] >> 10) & 7;
|
||||||
|
|
||||||
|
@ -64,17 +40,17 @@ namespace Ryujinx.Graphics.Texture
|
||||||
int Width = (Tic[4] & 0xffff) + 1;
|
int Width = (Tic[4] & 0xffff) + 1;
|
||||||
int Height = (Tic[5] & 0xffff) + 1;
|
int Height = (Tic[5] & 0xffff) + 1;
|
||||||
|
|
||||||
TextureInfo Texture = new TextureInfo(
|
return new GalImage(
|
||||||
TextureAddress,
|
|
||||||
Width,
|
Width,
|
||||||
Height,
|
Height,
|
||||||
Pitch,
|
|
||||||
BlockHeight,
|
|
||||||
TileWidth,
|
TileWidth,
|
||||||
Swizzle,
|
BlockHeight,
|
||||||
Format);
|
Layout,
|
||||||
|
Format,
|
||||||
return TextureReader.Read(Vmm, Texture);
|
XSource,
|
||||||
|
YSource,
|
||||||
|
ZSource,
|
||||||
|
WSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GalTextureSampler MakeSampler(NvGpu Gpu, NvGpuVmm Vmm, long TscPosition)
|
public static GalTextureSampler MakeSampler(NvGpu Gpu, NvGpuVmm Vmm, long TscPosition)
|
||||||
|
@ -107,7 +83,7 @@ namespace Ryujinx.Graphics.Texture
|
||||||
|
|
||||||
private static GalImageFormat GetImageFormat(int[] Tic)
|
private static GalImageFormat GetImageFormat(int[] Tic)
|
||||||
{
|
{
|
||||||
GalTextureType RType = (GalTextureType)((Tic[0] >> 7) & 7);
|
GalTextureType RType = (GalTextureType)((Tic[0] >> 7) & 7);
|
||||||
GalTextureType GType = (GalTextureType)((Tic[0] >> 10) & 7);
|
GalTextureType GType = (GalTextureType)((Tic[0] >> 10) & 7);
|
||||||
GalTextureType BType = (GalTextureType)((Tic[0] >> 13) & 7);
|
GalTextureType BType = (GalTextureType)((Tic[0] >> 13) & 7);
|
||||||
GalTextureType AType = (GalTextureType)((Tic[0] >> 16) & 7);
|
GalTextureType AType = (GalTextureType)((Tic[0] >> 16) & 7);
|
||||||
|
|
|
@ -1,33 +1,30 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using Ryujinx.Graphics.Memory;
|
using Ryujinx.Graphics.Memory;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Texture
|
namespace Ryujinx.Graphics.Texture
|
||||||
{
|
{
|
||||||
static class TextureHelper
|
static class TextureHelper
|
||||||
{
|
{
|
||||||
public static ISwizzle GetSwizzle(TextureInfo Texture, int BlockWidth, int Bpp)
|
public static ISwizzle GetSwizzle(GalImage Image)
|
||||||
{
|
{
|
||||||
int Width = (Texture.Width + (BlockWidth - 1)) / BlockWidth;
|
int BlockWidth = ImageUtils.GetBlockWidth (Image.Format);
|
||||||
|
int BytesPerPixel = ImageUtils.GetBytesPerPixel(Image.Format);
|
||||||
|
|
||||||
int AlignMask = Texture.TileWidth * (64 / Bpp) - 1;
|
int Width = (Image.Width + (BlockWidth - 1)) / BlockWidth;
|
||||||
|
|
||||||
Width = (Width + AlignMask) & ~AlignMask;
|
if (Image.Layout == GalMemoryLayout.BlockLinear)
|
||||||
|
|
||||||
switch (Texture.Swizzle)
|
|
||||||
{
|
{
|
||||||
case TextureSwizzle._1dBuffer:
|
int AlignMask = Image.TileWidth * (64 / BytesPerPixel) - 1;
|
||||||
case TextureSwizzle.Pitch:
|
|
||||||
case TextureSwizzle.PitchColorKey:
|
|
||||||
return new LinearSwizzle(Texture.Pitch, Bpp);
|
|
||||||
|
|
||||||
case TextureSwizzle.BlockLinear:
|
Width = (Width + AlignMask) & ~AlignMask;
|
||||||
case TextureSwizzle.BlockLinearColorKey:
|
|
||||||
return new BlockLinearSwizzle(Width, Bpp, Texture.BlockHeight);
|
return new BlockLinearSwizzle(Width, BytesPerPixel, Image.GobBlockHeight);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new LinearSwizzle(Image.Pitch, BytesPerPixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException(Texture.Swizzle.ToString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (AMemory Memory, long Position) GetMemoryAndPosition(
|
public static (AMemory Memory, long Position) GetMemoryAndPosition(
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
using Ryujinx.Graphics.Gal;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Texture
|
|
||||||
{
|
|
||||||
public struct TextureInfo
|
|
||||||
{
|
|
||||||
public long Position { get; private set; }
|
|
||||||
|
|
||||||
public int Width { get; private set; }
|
|
||||||
public int Height { get; private set; }
|
|
||||||
public int Pitch { get; private set; }
|
|
||||||
|
|
||||||
public int BlockHeight { get; private set; }
|
|
||||||
public int TileWidth { get; private set; }
|
|
||||||
|
|
||||||
public TextureSwizzle Swizzle { get; private set; }
|
|
||||||
|
|
||||||
public GalImageFormat Format { get; private set; }
|
|
||||||
|
|
||||||
public TextureInfo(
|
|
||||||
long Position,
|
|
||||||
int Width,
|
|
||||||
int Height)
|
|
||||||
{
|
|
||||||
this.Position = Position;
|
|
||||||
this.Width = Width;
|
|
||||||
this.Height = Height;
|
|
||||||
|
|
||||||
Pitch = 0;
|
|
||||||
|
|
||||||
BlockHeight = 16;
|
|
||||||
|
|
||||||
TileWidth = 1;
|
|
||||||
|
|
||||||
Swizzle = TextureSwizzle.BlockLinear;
|
|
||||||
|
|
||||||
Format = GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextureInfo(
|
|
||||||
long Position,
|
|
||||||
int Width,
|
|
||||||
int Height,
|
|
||||||
int Pitch,
|
|
||||||
int BlockHeight,
|
|
||||||
int TileWidth,
|
|
||||||
TextureSwizzle Swizzle,
|
|
||||||
GalImageFormat Format)
|
|
||||||
{
|
|
||||||
this.Position = Position;
|
|
||||||
this.Width = Width;
|
|
||||||
this.Height = Height;
|
|
||||||
this.Pitch = Pitch;
|
|
||||||
this.BlockHeight = BlockHeight;
|
|
||||||
this.TileWidth = TileWidth;
|
|
||||||
this.Swizzle = Swizzle;
|
|
||||||
this.Format = Format;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,398 +0,0 @@
|
||||||
using ChocolArm64.Memory;
|
|
||||||
using Ryujinx.Graphics.Gal;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Texture
|
|
||||||
{
|
|
||||||
delegate byte[] TextureReaderDelegate(IAMemory Memory, TextureInfo Texture);
|
|
||||||
|
|
||||||
public static class TextureReader
|
|
||||||
{
|
|
||||||
public static byte[] Read(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
TextureReaderDelegate Reader = ImageUtils.GetReader(Texture.Format);
|
|
||||||
|
|
||||||
return Reader(Memory, Texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal unsafe static byte[] Read1Bpp(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
int Width = Texture.Width;
|
|
||||||
int Height = Texture.Height;
|
|
||||||
|
|
||||||
byte[] Output = new byte[Width * Height];
|
|
||||||
|
|
||||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 1);
|
|
||||||
|
|
||||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
|
||||||
Memory,
|
|
||||||
Texture.Position);
|
|
||||||
|
|
||||||
fixed (byte* BuffPtr = Output)
|
|
||||||
{
|
|
||||||
long OutOffs = 0;
|
|
||||||
|
|
||||||
for (int Y = 0; Y < Height; Y++)
|
|
||||||
for (int X = 0; X < Width; X++)
|
|
||||||
{
|
|
||||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
|
||||||
|
|
||||||
byte Pixel = CpuMem.ReadByte(Position + Offset);
|
|
||||||
|
|
||||||
*(BuffPtr + OutOffs) = Pixel;
|
|
||||||
|
|
||||||
OutOffs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal unsafe static byte[] Read5551(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
int Width = Texture.Width;
|
|
||||||
int Height = Texture.Height;
|
|
||||||
|
|
||||||
byte[] Output = new byte[Width * Height * 2];
|
|
||||||
|
|
||||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 2);
|
|
||||||
|
|
||||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
|
||||||
Memory,
|
|
||||||
Texture.Position);
|
|
||||||
|
|
||||||
fixed (byte* BuffPtr = Output)
|
|
||||||
{
|
|
||||||
long OutOffs = 0;
|
|
||||||
|
|
||||||
for (int Y = 0; Y < Height; Y++)
|
|
||||||
for (int X = 0; X < Width; X++)
|
|
||||||
{
|
|
||||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
|
||||||
|
|
||||||
uint Pixel = (uint)CpuMem.ReadInt16(Position + Offset);
|
|
||||||
|
|
||||||
Pixel = (Pixel & 0x001f) << 11 |
|
|
||||||
(Pixel & 0x03e0) << 1 |
|
|
||||||
(Pixel & 0x7c00) >> 9 |
|
|
||||||
(Pixel & 0x8000) >> 15;
|
|
||||||
|
|
||||||
*(short*)(BuffPtr + OutOffs) = (short)Pixel;
|
|
||||||
|
|
||||||
OutOffs += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal unsafe static byte[] Read565(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
int Width = Texture.Width;
|
|
||||||
int Height = Texture.Height;
|
|
||||||
|
|
||||||
byte[] Output = new byte[Width * Height * 2];
|
|
||||||
|
|
||||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 2);
|
|
||||||
|
|
||||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
|
||||||
Memory,
|
|
||||||
Texture.Position);
|
|
||||||
|
|
||||||
fixed (byte* BuffPtr = Output)
|
|
||||||
{
|
|
||||||
long OutOffs = 0;
|
|
||||||
|
|
||||||
for (int Y = 0; Y < Height; Y++)
|
|
||||||
for (int X = 0; X < Width; X++)
|
|
||||||
{
|
|
||||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
|
||||||
|
|
||||||
uint Pixel = (uint)CpuMem.ReadInt16(Position + Offset);
|
|
||||||
|
|
||||||
Pixel = (Pixel & 0x001f) << 11 |
|
|
||||||
(Pixel & 0x07e0) |
|
|
||||||
(Pixel & 0xf800) >> 11;
|
|
||||||
|
|
||||||
*(short*)(BuffPtr + OutOffs) = (short)Pixel;
|
|
||||||
|
|
||||||
OutOffs += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal unsafe static byte[] Read2Bpp(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
int Width = Texture.Width;
|
|
||||||
int Height = Texture.Height;
|
|
||||||
|
|
||||||
byte[] Output = new byte[Width * Height * 2];
|
|
||||||
|
|
||||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 2);
|
|
||||||
|
|
||||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
|
||||||
Memory,
|
|
||||||
Texture.Position);
|
|
||||||
|
|
||||||
fixed (byte* BuffPtr = Output)
|
|
||||||
{
|
|
||||||
long OutOffs = 0;
|
|
||||||
|
|
||||||
for (int Y = 0; Y < Height; Y++)
|
|
||||||
for (int X = 0; X < Width; X++)
|
|
||||||
{
|
|
||||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
|
||||||
|
|
||||||
short Pixel = CpuMem.ReadInt16(Position + Offset);
|
|
||||||
|
|
||||||
*(short*)(BuffPtr + OutOffs) = Pixel;
|
|
||||||
|
|
||||||
OutOffs += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal unsafe static byte[] Read4Bpp(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
int Width = Texture.Width;
|
|
||||||
int Height = Texture.Height;
|
|
||||||
|
|
||||||
byte[] Output = new byte[Width * Height * 4];
|
|
||||||
|
|
||||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 4);
|
|
||||||
|
|
||||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
|
||||||
Memory,
|
|
||||||
Texture.Position);
|
|
||||||
|
|
||||||
fixed (byte* BuffPtr = Output)
|
|
||||||
{
|
|
||||||
long OutOffs = 0;
|
|
||||||
|
|
||||||
for (int Y = 0; Y < Height; Y++)
|
|
||||||
for (int X = 0; X < Width; X++)
|
|
||||||
{
|
|
||||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
|
||||||
|
|
||||||
int Pixel = CpuMem.ReadInt32(Position + Offset);
|
|
||||||
|
|
||||||
*(int*)(BuffPtr + OutOffs) = Pixel;
|
|
||||||
|
|
||||||
OutOffs += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal unsafe static byte[] Read8Bpp(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
int Width = Texture.Width;
|
|
||||||
int Height = Texture.Height;
|
|
||||||
|
|
||||||
byte[] Output = new byte[Width * Height * 8];
|
|
||||||
|
|
||||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 8);
|
|
||||||
|
|
||||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
|
||||||
Memory,
|
|
||||||
Texture.Position);
|
|
||||||
|
|
||||||
fixed (byte* BuffPtr = Output)
|
|
||||||
{
|
|
||||||
long OutOffs = 0;
|
|
||||||
|
|
||||||
for (int Y = 0; Y < Height; Y++)
|
|
||||||
for (int X = 0; X < Width; X++)
|
|
||||||
{
|
|
||||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
|
||||||
|
|
||||||
long Pixel = CpuMem.ReadInt64(Position + Offset);
|
|
||||||
|
|
||||||
*(long*)(BuffPtr + OutOffs) = Pixel;
|
|
||||||
|
|
||||||
OutOffs += 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal unsafe static byte[] Read16Bpp(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
int Width = Texture.Width;
|
|
||||||
int Height = Texture.Height;
|
|
||||||
|
|
||||||
byte[] Output = new byte[Width * Height * 16];
|
|
||||||
|
|
||||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 16);
|
|
||||||
|
|
||||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
|
||||||
Memory,
|
|
||||||
Texture.Position);
|
|
||||||
|
|
||||||
fixed (byte* BuffPtr = Output)
|
|
||||||
{
|
|
||||||
long OutOffs = 0;
|
|
||||||
|
|
||||||
for (int Y = 0; Y < Height; Y++)
|
|
||||||
for (int X = 0; X < Width; X++)
|
|
||||||
{
|
|
||||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
|
||||||
|
|
||||||
long PxLow = CpuMem.ReadInt64(Position + Offset + 0);
|
|
||||||
long PxHigh = CpuMem.ReadInt64(Position + Offset + 8);
|
|
||||||
|
|
||||||
*(long*)(BuffPtr + OutOffs + 0) = PxLow;
|
|
||||||
*(long*)(BuffPtr + OutOffs + 8) = PxHigh;
|
|
||||||
|
|
||||||
OutOffs += 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal unsafe static byte[] Read8Bpt4x4(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
int Width = (Texture.Width + 3) / 4;
|
|
||||||
int Height = (Texture.Height + 3) / 4;
|
|
||||||
|
|
||||||
byte[] Output = new byte[Width * Height * 8];
|
|
||||||
|
|
||||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 4, 8);
|
|
||||||
|
|
||||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
|
||||||
Memory,
|
|
||||||
Texture.Position);
|
|
||||||
|
|
||||||
fixed (byte* BuffPtr = Output)
|
|
||||||
{
|
|
||||||
long OutOffs = 0;
|
|
||||||
|
|
||||||
for (int Y = 0; Y < Height; Y++)
|
|
||||||
for (int X = 0; X < Width; X++)
|
|
||||||
{
|
|
||||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
|
||||||
|
|
||||||
long Tile = CpuMem.ReadInt64(Position + Offset);
|
|
||||||
|
|
||||||
*(long*)(BuffPtr + OutOffs) = Tile;
|
|
||||||
|
|
||||||
OutOffs += 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal unsafe static byte[] Read16BptCompressedTexture(IAMemory Memory, TextureInfo Texture, int BlockWidth, int BlockHeight)
|
|
||||||
{
|
|
||||||
int Width = (Texture.Width + (BlockWidth - 1)) / BlockWidth;
|
|
||||||
int Height = (Texture.Height + (BlockHeight - 1)) / BlockHeight;
|
|
||||||
|
|
||||||
byte[] Output = new byte[Width * Height * 16];
|
|
||||||
|
|
||||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, BlockWidth, 16);
|
|
||||||
|
|
||||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
|
||||||
Memory,
|
|
||||||
Texture.Position);
|
|
||||||
|
|
||||||
fixed (byte* BuffPtr = Output)
|
|
||||||
{
|
|
||||||
long OutOffs = 0;
|
|
||||||
|
|
||||||
for (int Y = 0; Y < Height; Y++)
|
|
||||||
for (int X = 0; X < Width; X++)
|
|
||||||
{
|
|
||||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
|
||||||
|
|
||||||
long Tile0 = CpuMem.ReadInt64(Position + Offset + 0);
|
|
||||||
long Tile1 = CpuMem.ReadInt64(Position + Offset + 8);
|
|
||||||
|
|
||||||
*(long*)(BuffPtr + OutOffs + 0) = Tile0;
|
|
||||||
*(long*)(BuffPtr + OutOffs + 8) = Tile1;
|
|
||||||
|
|
||||||
OutOffs += 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] Read16BptCompressedTexture4x4(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
return Read16BptCompressedTexture(Memory, Texture, 4, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] Read16BptCompressedTexture5x5(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
return Read16BptCompressedTexture(Memory, Texture, 5, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] Read16BptCompressedTexture6x6(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
return Read16BptCompressedTexture(Memory, Texture, 6, 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] Read16BptCompressedTexture8x8(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
return Read16BptCompressedTexture(Memory, Texture, 8, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] Read16BptCompressedTexture10x10(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
return Read16BptCompressedTexture(Memory, Texture, 10, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] Read16BptCompressedTexture12x12(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
return Read16BptCompressedTexture(Memory, Texture, 12, 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] Read16BptCompressedTexture5x4(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
return Read16BptCompressedTexture(Memory, Texture, 5, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] Read16BptCompressedTexture6x5(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
return Read16BptCompressedTexture(Memory, Texture, 6, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] Read16BptCompressedTexture8x6(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
return Read16BptCompressedTexture(Memory, Texture, 8, 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] Read16BptCompressedTexture10x8(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
return Read16BptCompressedTexture(Memory, Texture, 10, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] Read16BptCompressedTexture12x10(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
return Read16BptCompressedTexture(Memory, Texture, 12, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] Read16BptCompressedTexture8x5(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
return Read16BptCompressedTexture(Memory, Texture, 5, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] Read16BptCompressedTexture10x5(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
return Read16BptCompressedTexture(Memory, Texture, 10, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] Read16BptCompressedTexture10x6(IAMemory Memory, TextureInfo Texture)
|
|
||||||
{
|
|
||||||
return Read16BptCompressedTexture(Memory, Texture, 10, 6);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
using ChocolArm64.Memory;
|
|
||||||
using Ryujinx.Graphics.Gal;
|
|
||||||
using Ryujinx.Graphics.Memory;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Texture
|
|
||||||
{
|
|
||||||
static class TextureWriter
|
|
||||||
{
|
|
||||||
public unsafe static void Write(IAMemory Memory, TextureInfo Texture, byte[] Data)
|
|
||||||
{
|
|
||||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, 1, 4);
|
|
||||||
|
|
||||||
(AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
|
|
||||||
Memory,
|
|
||||||
Texture.Position);
|
|
||||||
|
|
||||||
fixed (byte* BuffPtr = Data)
|
|
||||||
{
|
|
||||||
long InOffs = 0;
|
|
||||||
|
|
||||||
for (int Y = 0; Y < Texture.Height; Y++)
|
|
||||||
for (int X = 0; X < Texture.Width; X++)
|
|
||||||
{
|
|
||||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
|
||||||
|
|
||||||
int Pixel = *(int*)(BuffPtr + InOffs);
|
|
||||||
|
|
||||||
CpuMem.WriteInt32(Position + Offset, Pixel);
|
|
||||||
|
|
||||||
InOffs += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
17
Ryujinx.Graphics/ValueRange.cs
Normal file
17
Ryujinx.Graphics/ValueRange.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
namespace Ryujinx.Graphics
|
||||||
|
{
|
||||||
|
struct ValueRange<T>
|
||||||
|
{
|
||||||
|
public long Start { get; private set; }
|
||||||
|
public long End { get; private set; }
|
||||||
|
|
||||||
|
public T Value { get; set; }
|
||||||
|
|
||||||
|
public ValueRange(long Start, long End, T Value = default(T))
|
||||||
|
{
|
||||||
|
this.Start = Start;
|
||||||
|
this.End = End;
|
||||||
|
this.Value = Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
234
Ryujinx.Graphics/ValueRangeSet.cs
Normal file
234
Ryujinx.Graphics/ValueRangeSet.cs
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics
|
||||||
|
{
|
||||||
|
class ValueRangeSet<T>
|
||||||
|
{
|
||||||
|
private List<ValueRange<T>> Ranges;
|
||||||
|
|
||||||
|
public ValueRangeSet()
|
||||||
|
{
|
||||||
|
Ranges = new List<ValueRange<T>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(ValueRange<T> Range)
|
||||||
|
{
|
||||||
|
if (Range.End <= Range.Start)
|
||||||
|
{
|
||||||
|
//Empty or invalid range, do nothing.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int First = BinarySearchFirstIntersection(Range);
|
||||||
|
|
||||||
|
if (First == -1)
|
||||||
|
{
|
||||||
|
//No intersections case.
|
||||||
|
//Find first greater than range (after the current one).
|
||||||
|
//If found, add before, otherwise add to the end of the list.
|
||||||
|
int GtIndex = BinarySearchGt(Range);
|
||||||
|
|
||||||
|
if (GtIndex != -1)
|
||||||
|
{
|
||||||
|
Ranges.Insert(GtIndex, Range);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Ranges.Add(Range);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(int Start, int End) = GetAllIntersectionRanges(Range, First);
|
||||||
|
|
||||||
|
ValueRange<T> Prev = Ranges[Start];
|
||||||
|
ValueRange<T> Next = Ranges[End];
|
||||||
|
|
||||||
|
Ranges.RemoveRange(Start, (End - Start) + 1);
|
||||||
|
|
||||||
|
InsertNextNeighbour(Start, Range, Next);
|
||||||
|
|
||||||
|
int NewIndex = Start;
|
||||||
|
|
||||||
|
Ranges.Insert(Start, Range);
|
||||||
|
|
||||||
|
InsertPrevNeighbour(Start, Range, Prev);
|
||||||
|
|
||||||
|
//Try merging neighbours if the value is equal.
|
||||||
|
if (NewIndex > 0)
|
||||||
|
{
|
||||||
|
Prev = Ranges[NewIndex - 1];
|
||||||
|
|
||||||
|
if (Prev.End == Range.Start && CompareValues(Prev, Range))
|
||||||
|
{
|
||||||
|
Ranges.RemoveAt(--NewIndex);
|
||||||
|
|
||||||
|
Ranges[NewIndex] = new ValueRange<T>(Prev.Start, Range.End, Range.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NewIndex < Ranges.Count - 1)
|
||||||
|
{
|
||||||
|
Next = Ranges[NewIndex + 1];
|
||||||
|
|
||||||
|
if (Next.Start == Range.End && CompareValues(Next, Range))
|
||||||
|
{
|
||||||
|
Ranges.RemoveAt(NewIndex + 1);
|
||||||
|
|
||||||
|
Ranges[NewIndex] = new ValueRange<T>(Range.Start, Next.End, Range.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CompareValues(ValueRange<T> LHS, ValueRange<T> RHS)
|
||||||
|
{
|
||||||
|
return LHS.Value?.Equals(RHS.Value) ?? RHS.Value == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(ValueRange<T> Range)
|
||||||
|
{
|
||||||
|
int First = BinarySearchFirstIntersection(Range);
|
||||||
|
|
||||||
|
if (First == -1)
|
||||||
|
{
|
||||||
|
//Nothing to remove.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(int Start, int End) = GetAllIntersectionRanges(Range, First);
|
||||||
|
|
||||||
|
ValueRange<T> Prev = Ranges[Start];
|
||||||
|
ValueRange<T> Next = Ranges[End];
|
||||||
|
|
||||||
|
Ranges.RemoveRange(Start, (End - Start) + 1);
|
||||||
|
|
||||||
|
InsertNextNeighbour(Start, Range, Next);
|
||||||
|
InsertPrevNeighbour(Start, Range, Prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InsertNextNeighbour(int Index, ValueRange<T> Range, ValueRange<T> Next)
|
||||||
|
{
|
||||||
|
//Split last intersection (ordered by Start) if necessary.
|
||||||
|
if (Range.End < Next.End)
|
||||||
|
{
|
||||||
|
InsertNewRange(Index, Range.End, Next.End, Next.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InsertPrevNeighbour(int Index, ValueRange<T> Range, ValueRange<T> Prev)
|
||||||
|
{
|
||||||
|
//Split first intersection (ordered by Start) if necessary.
|
||||||
|
if (Range.Start > Prev.Start)
|
||||||
|
{
|
||||||
|
InsertNewRange(Index, Prev.Start, Range.Start, Prev.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InsertNewRange(int Index, long Start, long End, T Value)
|
||||||
|
{
|
||||||
|
Ranges.Insert(Index, new ValueRange<T>(Start, End, Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueRange<T>[] GetAllIntersections(ValueRange<T> Range)
|
||||||
|
{
|
||||||
|
int First = BinarySearchFirstIntersection(Range);
|
||||||
|
|
||||||
|
if (First == -1)
|
||||||
|
{
|
||||||
|
return new ValueRange<T>[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
(int Start, int End) = GetAllIntersectionRanges(Range, First);
|
||||||
|
|
||||||
|
return Ranges.GetRange(Start, (End - Start) + 1).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private (int Start, int End) GetAllIntersectionRanges(ValueRange<T> Range, int BaseIndex)
|
||||||
|
{
|
||||||
|
int Start = BaseIndex;
|
||||||
|
int End = BaseIndex;
|
||||||
|
|
||||||
|
while (Start > 0 && Intersects(Range, Ranges[Start - 1]))
|
||||||
|
{
|
||||||
|
Start--;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (End < Ranges.Count - 1 && Intersects(Range, Ranges[End + 1]))
|
||||||
|
{
|
||||||
|
End++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Start, End);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int BinarySearchFirstIntersection(ValueRange<T> Range)
|
||||||
|
{
|
||||||
|
int Left = 0;
|
||||||
|
int Right = Ranges.Count - 1;
|
||||||
|
|
||||||
|
while (Left <= Right)
|
||||||
|
{
|
||||||
|
int Size = Right - Left;
|
||||||
|
|
||||||
|
int Middle = Left + (Size >> 1);
|
||||||
|
|
||||||
|
ValueRange<T> Current = Ranges[Middle];
|
||||||
|
|
||||||
|
if (Intersects(Range, Current))
|
||||||
|
{
|
||||||
|
return Middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Range.Start < Current.Start)
|
||||||
|
{
|
||||||
|
Right = Middle - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Left = Middle + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int BinarySearchGt(ValueRange<T> Range)
|
||||||
|
{
|
||||||
|
int GtIndex = -1;
|
||||||
|
|
||||||
|
int Left = 0;
|
||||||
|
int Right = Ranges.Count - 1;
|
||||||
|
|
||||||
|
while (Left <= Right)
|
||||||
|
{
|
||||||
|
int Size = Right - Left;
|
||||||
|
|
||||||
|
int Middle = Left + (Size >> 1);
|
||||||
|
|
||||||
|
ValueRange<T> Current = Ranges[Middle];
|
||||||
|
|
||||||
|
if (Range.Start < Current.Start)
|
||||||
|
{
|
||||||
|
Right = Middle - 1;
|
||||||
|
|
||||||
|
if (GtIndex == -1 || Current.Start < Ranges[GtIndex].Start)
|
||||||
|
{
|
||||||
|
GtIndex = Middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Left = Middle + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GtIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Intersects(ValueRange<T> LHS, ValueRange<T> RHS)
|
||||||
|
{
|
||||||
|
return LHS.Start < RHS.End && RHS.Start < LHS.End;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -288,7 +288,8 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
//Fail for info not available on older Kernel versions.
|
//Fail for info not available on older Kernel versions.
|
||||||
if (InfoType == 18 ||
|
if (InfoType == 18 ||
|
||||||
InfoType == 19 ||
|
InfoType == 19 ||
|
||||||
InfoType == 20)
|
InfoType == 20 ||
|
||||||
|
InfoType == 21)
|
||||||
{
|
{
|
||||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue);
|
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue);
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ using Ryujinx.HLE.HOS.Ipc;
|
||||||
using Ryujinx.HLE.HOS.SystemState;
|
using Ryujinx.HLE.HOS.SystemState;
|
||||||
using Ryujinx.HLE.Logging;
|
using Ryujinx.HLE.Logging;
|
||||||
using Ryujinx.HLE.Utilities;
|
using Ryujinx.HLE.Utilities;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
|
||||||
|
|
||||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||||
|
|
||||||
private KEvent ReleaseEvent;
|
private KEvent BinderEvent;
|
||||||
|
|
||||||
private NvFlinger Flinger;
|
private NvFlinger Flinger;
|
||||||
|
|
||||||
|
@ -27,9 +27,11 @@ namespace Ryujinx.HLE.HOS.Services.Vi
|
||||||
{ 3, TransactParcelAuto }
|
{ 3, TransactParcelAuto }
|
||||||
};
|
};
|
||||||
|
|
||||||
ReleaseEvent = new KEvent();
|
BinderEvent = new KEvent();
|
||||||
|
|
||||||
Flinger = new NvFlinger(Renderer, ReleaseEvent);
|
BinderEvent.WaitEvent.Set();
|
||||||
|
|
||||||
|
Flinger = new NvFlinger(Renderer, BinderEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long TransactParcel(ServiceCtx Context)
|
public long TransactParcel(ServiceCtx Context)
|
||||||
|
@ -75,7 +77,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
|
||||||
int Id = Context.RequestData.ReadInt32();
|
int Id = Context.RequestData.ReadInt32();
|
||||||
uint Unk = Context.RequestData.ReadUInt32();
|
uint Unk = Context.RequestData.ReadUInt32();
|
||||||
|
|
||||||
int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent);
|
int Handle = Context.Process.HandleTable.OpenHandle(BinderEvent);
|
||||||
|
|
||||||
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
|
Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
|
||||||
|
|
||||||
|
@ -91,7 +93,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi
|
||||||
{
|
{
|
||||||
if (Disposing)
|
if (Disposing)
|
||||||
{
|
{
|
||||||
ReleaseEvent.Dispose();
|
BinderEvent.Dispose();
|
||||||
|
|
||||||
Flinger.Dispose();
|
Flinger.Dispose();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using Ryujinx.Graphics.Texture;
|
using Ryujinx.Graphics.Memory;
|
||||||
using Ryujinx.HLE.HOS.Kernel;
|
using Ryujinx.HLE.HOS.Kernel;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Nv.NvGpuAS;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.NvMap;
|
using Ryujinx.HLE.HOS.Services.Nv.NvMap;
|
||||||
using Ryujinx.HLE.Logging;
|
using Ryujinx.HLE.Logging;
|
||||||
using System;
|
using System;
|
||||||
|
@ -19,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Android
|
||||||
|
|
||||||
private Dictionary<(string, int), ServiceProcessParcel> Commands;
|
private Dictionary<(string, int), ServiceProcessParcel> Commands;
|
||||||
|
|
||||||
private KEvent ReleaseEvent;
|
private KEvent BinderEvent;
|
||||||
|
|
||||||
private IGalRenderer Renderer;
|
private IGalRenderer Renderer;
|
||||||
|
|
||||||
|
@ -67,7 +68,7 @@ namespace Ryujinx.HLE.HOS.Services.Android
|
||||||
|
|
||||||
private bool Disposed;
|
private bool Disposed;
|
||||||
|
|
||||||
public NvFlinger(IGalRenderer Renderer, KEvent ReleaseEvent)
|
public NvFlinger(IGalRenderer Renderer, KEvent BinderEvent)
|
||||||
{
|
{
|
||||||
Commands = new Dictionary<(string, int), ServiceProcessParcel>()
|
Commands = new Dictionary<(string, int), ServiceProcessParcel>()
|
||||||
{
|
{
|
||||||
|
@ -82,8 +83,8 @@ namespace Ryujinx.HLE.HOS.Services.Android
|
||||||
{ ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer }
|
{ ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer }
|
||||||
};
|
};
|
||||||
|
|
||||||
this.Renderer = Renderer;
|
this.Renderer = Renderer;
|
||||||
this.ReleaseEvent = ReleaseEvent;
|
this.BinderEvent = BinderEvent;
|
||||||
|
|
||||||
BufferQueue = new BufferEntry[0x40];
|
BufferQueue = new BufferEntry[0x40];
|
||||||
|
|
||||||
|
@ -301,42 +302,41 @@ namespace Ryujinx.HLE.HOS.Services.Android
|
||||||
bool FlipX = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipX);
|
bool FlipX = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipX);
|
||||||
bool FlipY = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipY);
|
bool FlipY = BufferQueue[Slot].Transform.HasFlag(HalTransform.FlipY);
|
||||||
|
|
||||||
//Rotation is being ignored
|
//Note: Rotation is being ignored.
|
||||||
|
|
||||||
int Top = Crop.Top;
|
int Top = Crop.Top;
|
||||||
int Left = Crop.Left;
|
int Left = Crop.Left;
|
||||||
int Right = Crop.Right;
|
int Right = Crop.Right;
|
||||||
int Bottom = Crop.Bottom;
|
int Bottom = Crop.Bottom;
|
||||||
|
|
||||||
Renderer.QueueAction(() => Renderer.RenderTarget.SetTransform(FlipX, FlipY, Top, Left, Right, Bottom));
|
NvGpuVmm Vmm = NvGpuASIoctl.GetASCtx(Context).Vmm;
|
||||||
|
|
||||||
//TODO: Support double buffering here aswell, it is broken for GPU
|
Renderer.QueueAction(() =>
|
||||||
//frame buffers because it seems to be completely out of sync.
|
|
||||||
if (Context.Device.Gpu.Engine3d.IsFrameBufferPosition(FbAddr))
|
|
||||||
{
|
{
|
||||||
//Frame buffer is rendered to by the GPU, we can just
|
if (!Renderer.Texture.TryGetImage(FbAddr, out GalImage Image))
|
||||||
//bind the frame buffer texture, it's not necessary to read anything.
|
{
|
||||||
Renderer.QueueAction(() => Renderer.RenderTarget.Set(FbAddr));
|
Image = new GalImage(
|
||||||
}
|
FbWidth,
|
||||||
else
|
FbHeight, 1, 16,
|
||||||
{
|
GalMemoryLayout.BlockLinear,
|
||||||
//Frame buffer is not set on the GPU registers, in this case
|
GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm);
|
||||||
//assume that the app is manually writing to it.
|
}
|
||||||
TextureInfo Texture = new TextureInfo(FbAddr, FbWidth, FbHeight);
|
|
||||||
|
|
||||||
byte[] Data = TextureReader.Read(Context.Memory, Texture);
|
Context.Device.Gpu.ResourceManager.ClearPbCache();
|
||||||
|
Context.Device.Gpu.ResourceManager.SendTexture(Vmm, FbAddr, Image);
|
||||||
|
|
||||||
Renderer.QueueAction(() => Renderer.RenderTarget.Set(Data, FbWidth, FbHeight));
|
Renderer.RenderTarget.SetTransform(FlipX, FlipY, Top, Left, Right, Bottom);
|
||||||
}
|
Renderer.RenderTarget.Set(FbAddr);
|
||||||
|
|
||||||
Context.Device.Gpu.Renderer.QueueAction(() => ReleaseBuffer(Slot));
|
ReleaseBuffer(Slot);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReleaseBuffer(int Slot)
|
private void ReleaseBuffer(int Slot)
|
||||||
{
|
{
|
||||||
BufferQueue[Slot].State = BufferState.Free;
|
BufferQueue[Slot].State = BufferState.Free;
|
||||||
|
|
||||||
ReleaseEvent.WaitEvent.Set();
|
BinderEvent.WaitEvent.Set();
|
||||||
|
|
||||||
lock (WaitBufferFree)
|
lock (WaitBufferFree)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue