mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-07-24 15:37:10 +02: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
|
@ -1,12 +1,17 @@
|
|||
using Ryujinx.Graphics.Texture;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public struct GalImage
|
||||
{
|
||||
public int Width;
|
||||
public int Height;
|
||||
public int TileWidth;
|
||||
public int GobBlockHeight;
|
||||
public int Pitch;
|
||||
|
||||
public GalImageFormat Format;
|
||||
|
||||
public GalImageFormat Format;
|
||||
public GalMemoryLayout Layout;
|
||||
public GalTextureSource XSource;
|
||||
public GalTextureSource YSource;
|
||||
public GalTextureSource ZSource;
|
||||
|
@ -15,19 +20,44 @@ namespace Ryujinx.Graphics.Gal
|
|||
public GalImage(
|
||||
int Width,
|
||||
int Height,
|
||||
int TileWidth,
|
||||
int GobBlockHeight,
|
||||
GalMemoryLayout Layout,
|
||||
GalImageFormat Format,
|
||||
GalTextureSource XSource = GalTextureSource.Red,
|
||||
GalTextureSource YSource = GalTextureSource.Green,
|
||||
GalTextureSource ZSource = GalTextureSource.Blue,
|
||||
GalTextureSource WSource = GalTextureSource.Alpha)
|
||||
{
|
||||
this.Width = Width;
|
||||
this.Height = Height;
|
||||
this.Format = Format;
|
||||
this.XSource = XSource;
|
||||
this.YSource = YSource;
|
||||
this.ZSource = ZSource;
|
||||
this.WSource = WSource;
|
||||
this.Width = Width;
|
||||
this.Height = Height;
|
||||
this.TileWidth = TileWidth;
|
||||
this.GobBlockHeight = GobBlockHeight;
|
||||
this.Layout = Layout;
|
||||
this.Format = Format;
|
||||
this.XSource = XSource;
|
||||
this.YSource = YSource;
|
||||
this.ZSource = ZSource;
|
||||
this.WSource = WSource;
|
||||
|
||||
Pitch = ImageUtils.GetPitch(Format, Width);
|
||||
}
|
||||
|
||||
public bool SizeMatches(GalImage Image)
|
||||
{
|
||||
if (ImageUtils.GetBytesPerPixel(Format) !=
|
||||
ImageUtils.GetBytesPerPixel(Image.Format))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ImageUtils.GetAlignedWidth(this) !=
|
||||
ImageUtils.GetAlignedWidth(Image))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Height == Image.Height;
|
||||
}
|
||||
}
|
||||
}
|
8
Ryujinx.Graphics/Gal/GalMemoryLayout.cs
Normal file
8
Ryujinx.Graphics/Gal/GalMemoryLayout.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public enum GalMemoryLayout
|
||||
{
|
||||
BlockLinear = 0,
|
||||
Pitch = 1
|
||||
}
|
||||
}
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
public GalVertexBinding[] VertexBindings;
|
||||
|
||||
public bool FramebufferSrgb;
|
||||
|
||||
public float FlipX;
|
||||
public float FlipY;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace Ryujinx.Graphics.Gal
|
|||
R32G32 = 0x4,
|
||||
A8B8G8R8 = 0x8,
|
||||
A2B10G10R10 = 0x9,
|
||||
R16G16 = 0xc,
|
||||
R32 = 0xf,
|
||||
BC6H_SF16 = 0x10,
|
||||
BC6H_UF16 = 0x11,
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Gal
|
|||
|
||||
void SetIndexArray(int Size, GalIndexFormat Format);
|
||||
|
||||
void DrawArrays(int First, int PrimCount, GalPrimitiveType PrimType);
|
||||
void DrawArrays(int First, int Count, GalPrimitiveType PrimType);
|
||||
|
||||
void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType);
|
||||
}
|
||||
|
|
|
@ -1,23 +1,17 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public interface IGalRenderTarget
|
||||
{
|
||||
void BindColor(long Key, int Attachment);
|
||||
void BindColor(long Key, int Attachment, GalImage Image);
|
||||
|
||||
void UnbindColor(int Attachment);
|
||||
|
||||
void BindZeta(long Key);
|
||||
void BindZeta(long Key, GalImage Image);
|
||||
|
||||
void UnbindZeta();
|
||||
|
||||
void BindTexture(long Key, int Index);
|
||||
|
||||
void Set(long Key);
|
||||
|
||||
void Set(byte[] Data, int Width, int Height);
|
||||
|
||||
void SetMap(int[] Map);
|
||||
|
||||
void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom);
|
||||
|
@ -40,12 +34,8 @@ namespace Ryujinx.Graphics.Gal
|
|||
int DstX1,
|
||||
int DstY1);
|
||||
|
||||
void GetBufferData(long Key, Action<byte[]> Callback);
|
||||
void Reinterpret(long Key, GalImage NewImage);
|
||||
|
||||
void SetBufferData(
|
||||
long Key,
|
||||
int Width,
|
||||
int Height,
|
||||
byte[] Buffer);
|
||||
byte[] GetData(long Key);
|
||||
}
|
||||
}
|
|
@ -5,13 +5,13 @@ namespace Ryujinx.Graphics.Gal
|
|||
void LockCache();
|
||||
void UnlockCache();
|
||||
|
||||
void Create(long Key, int Size, GalImage Image);
|
||||
|
||||
void Create(long Key, byte[] Data, GalImage Image);
|
||||
|
||||
void CreateFb(long Key, long Size, GalImage Image);
|
||||
bool TryGetImage(long Key, out GalImage Image);
|
||||
|
||||
bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image);
|
||||
|
||||
void Bind(long Key, int Index);
|
||||
void Bind(long Key, int Index, GalImage Image);
|
||||
|
||||
void SetSampler(GalTextureSampler Sampler);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
using System;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
class ImageHandler
|
||||
{
|
||||
private static int CopyBuffer = 0;
|
||||
private static int CopyBufferSize = 0;
|
||||
|
||||
public GalImage Image { get; private set; }
|
||||
|
||||
public int Width => Image.Width;
|
||||
|
@ -16,144 +11,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public GalImageFormat Format => Image.Format;
|
||||
|
||||
public PixelInternalFormat InternalFormat { get; private set; }
|
||||
public PixelFormat PixelFormat { get; private set; }
|
||||
public PixelType PixelType { get; private set; }
|
||||
|
||||
public int Handle { get; private set; }
|
||||
|
||||
private bool Initialized;
|
||||
|
||||
public ImageHandler()
|
||||
{
|
||||
Handle = GL.GenTexture();
|
||||
}
|
||||
|
||||
public ImageHandler(int Handle, GalImage Image)
|
||||
{
|
||||
this.Handle = Handle;
|
||||
|
||||
this.Image = Image;
|
||||
}
|
||||
|
||||
public void EnsureSetup(GalImage NewImage)
|
||||
{
|
||||
if (Width == NewImage.Width &&
|
||||
Height == NewImage.Height &&
|
||||
Format == NewImage.Format &&
|
||||
Initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PixelInternalFormat InternalFmt;
|
||||
PixelFormat PixelFormat;
|
||||
PixelType PixelType;
|
||||
|
||||
if (ImageUtils.IsCompressed(NewImage.Format))
|
||||
{
|
||||
InternalFmt = (PixelInternalFormat)OGLEnumConverter.GetCompressedImageFormat(NewImage.Format);
|
||||
|
||||
PixelFormat = default(PixelFormat);
|
||||
PixelType = default(PixelType);
|
||||
}
|
||||
else
|
||||
{
|
||||
(InternalFmt, PixelFormat, PixelType) = OGLEnumConverter.GetImageFormat(NewImage.Format);
|
||||
}
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
|
||||
if (Initialized)
|
||||
{
|
||||
if (CopyBuffer == 0)
|
||||
{
|
||||
CopyBuffer = GL.GenBuffer();
|
||||
}
|
||||
|
||||
int CurrentSize = Math.Max(ImageUtils.GetSize(NewImage),
|
||||
ImageUtils.GetSize(Image));
|
||||
|
||||
GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyBuffer);
|
||||
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyBuffer);
|
||||
|
||||
if (CopyBufferSize < CurrentSize)
|
||||
{
|
||||
CopyBufferSize = CurrentSize;
|
||||
|
||||
GL.BufferData(BufferTarget.PixelPackBuffer, CurrentSize, IntPtr.Zero, BufferUsageHint.StreamCopy);
|
||||
}
|
||||
|
||||
if (ImageUtils.IsCompressed(Image.Format))
|
||||
{
|
||||
GL.GetCompressedTexImage(TextureTarget.Texture2D, 0, IntPtr.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.GetTexImage(TextureTarget.Texture2D, 0, this.PixelFormat, this.PixelType, IntPtr.Zero);
|
||||
}
|
||||
|
||||
GL.DeleteTexture(Handle);
|
||||
|
||||
Handle = GL.GenTexture();
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
}
|
||||
|
||||
const int MinFilter = (int)TextureMinFilter.Linear;
|
||||
const int MagFilter = (int)TextureMagFilter.Linear;
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
|
||||
|
||||
const int Level = 0;
|
||||
const int Border = 0;
|
||||
|
||||
if (ImageUtils.IsCompressed(NewImage.Format))
|
||||
{
|
||||
Console.WriteLine("Hit");
|
||||
|
||||
GL.CompressedTexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
(InternalFormat)InternalFmt,
|
||||
NewImage.Width,
|
||||
NewImage.Height,
|
||||
Border,
|
||||
ImageUtils.GetSize(NewImage),
|
||||
IntPtr.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
InternalFmt,
|
||||
NewImage.Width,
|
||||
NewImage.Height,
|
||||
Border,
|
||||
PixelFormat,
|
||||
PixelType,
|
||||
IntPtr.Zero);
|
||||
}
|
||||
|
||||
if (Initialized)
|
||||
{
|
||||
GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
|
||||
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0);
|
||||
}
|
||||
|
||||
Image = NewImage;
|
||||
|
||||
this.InternalFormat = InternalFmt;
|
||||
this.PixelFormat = PixelFormat;
|
||||
this.PixelType = PixelType;
|
||||
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
public bool HasColor => ImageUtils.HasColor(Image.Format);
|
||||
public bool HasDepth => ImageUtils.HasDepth(Image.Format);
|
||||
public bool HasStencil => ImageUtils.HasStencil(Image.Format);
|
||||
|
||||
public ImageHandler(int Handle, GalImage Image)
|
||||
{
|
||||
this.Handle = Handle;
|
||||
this.Image = Image;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public CacheBucket(T Value, long DataSize, LinkedListNode<long> Node)
|
||||
{
|
||||
this.Value = Value;
|
||||
this.DataSize = DataSize;
|
||||
this.Node = Node;
|
||||
this.Value = Value;
|
||||
this.DataSize = DataSize;
|
||||
this.Node = Node;
|
||||
|
||||
Timestamp = Environment.TickCount;
|
||||
}
|
||||
|
|
|
@ -149,8 +149,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
case GalImageFormat.R32 | GalImageFormat.Sfloat: return (PixelInternalFormat.R32f, PixelFormat.Red, PixelType.Float);
|
||||
case GalImageFormat.R32 | GalImageFormat.Sint: return (PixelInternalFormat.R32i, PixelFormat.Red, PixelType.Int);
|
||||
case GalImageFormat.R32 | GalImageFormat.Uint: return (PixelInternalFormat.R32ui, PixelFormat.Red, PixelType.UnsignedInt);
|
||||
case GalImageFormat.A1R5G5B5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551);
|
||||
case GalImageFormat.B5G6R5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565);
|
||||
case GalImageFormat.A1R5G5B5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed);
|
||||
case GalImageFormat.B5G6R5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565Reversed);
|
||||
case GalImageFormat.R16G16 | GalImageFormat.Sfloat: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat);
|
||||
case GalImageFormat.R16G16 | GalImageFormat.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short);
|
||||
case GalImageFormat.R16G16 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Byte);
|
||||
|
|
|
@ -126,6 +126,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
BindVertexLayout(New);
|
||||
|
||||
if (New.FramebufferSrgb != Old.FramebufferSrgb)
|
||||
{
|
||||
Enable(EnableCap.FramebufferSrgb, New.FramebufferSrgb);
|
||||
}
|
||||
|
||||
if (New.FlipX != Old.FlipX || New.FlipY != Old.FlipY || New.Instance != Old.Instance)
|
||||
{
|
||||
Shader.SetExtraData(New.FlipX, New.FlipY, New.Instance);
|
||||
|
@ -337,6 +342,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
foreach (GalVertexAttrib Attrib in Binding.Attribs)
|
||||
{
|
||||
//Skip uninitialized attributes.
|
||||
if (Attrib.Size == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GL.EnableVertexAttribArray(Attrib.Index);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
||||
|
|
|
@ -113,14 +113,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
IndexBuffer.ElemSizeLog2 = (int)Format;
|
||||
}
|
||||
|
||||
public void DrawArrays(int First, int PrimCount, GalPrimitiveType PrimType)
|
||||
public void DrawArrays(int First, int Count, GalPrimitiveType PrimType)
|
||||
{
|
||||
if (PrimCount == 0)
|
||||
if (Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, PrimCount);
|
||||
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, Count);
|
||||
}
|
||||
|
||||
public void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType)
|
||||
|
|
|
@ -15,9 +15,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public Rect(int X, int Y, int Width, int Height)
|
||||
{
|
||||
this.X = X;
|
||||
this.Y = Y;
|
||||
this.Width = Width;
|
||||
this.X = X;
|
||||
this.Y = Y;
|
||||
this.Width = Width;
|
||||
this.Height = Height;
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
private OGLTexture Texture;
|
||||
|
||||
private ImageHandler RawTex;
|
||||
private ImageHandler ReadTex;
|
||||
|
||||
private Rect Viewport;
|
||||
|
@ -64,13 +63,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
this.Texture = Texture;
|
||||
}
|
||||
|
||||
public void BindColor(long Key, int Attachment)
|
||||
public void BindColor(long Key, int Attachment, GalImage Image)
|
||||
{
|
||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||
if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
|
||||
{
|
||||
EnsureFrameBuffer();
|
||||
|
||||
Attach(ref ColorAttachments[Attachment], Tex.Handle, FramebufferAttachment.ColorAttachment0 + Attachment);
|
||||
Attach(ref ColorAttachments[Attachment], CachedImage.Handle, FramebufferAttachment.ColorAttachment0 + Attachment);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -84,40 +83,39 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
Attach(ref ColorAttachments[Attachment], 0, FramebufferAttachment.ColorAttachment0 + Attachment);
|
||||
}
|
||||
|
||||
public void BindZeta(long Key)
|
||||
|
||||
public void BindZeta(long Key, GalImage Image)
|
||||
{
|
||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||
if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
|
||||
{
|
||||
EnsureFrameBuffer();
|
||||
|
||||
if (Tex.HasDepth && Tex.HasStencil)
|
||||
if (CachedImage.HasDepth && CachedImage.HasStencil)
|
||||
{
|
||||
if (DepthAttachment != Tex.Handle ||
|
||||
StencilAttachment != Tex.Handle)
|
||||
if (DepthAttachment != CachedImage.Handle ||
|
||||
StencilAttachment != CachedImage.Handle)
|
||||
{
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
FramebufferAttachment.DepthStencilAttachment,
|
||||
Tex.Handle,
|
||||
CachedImage.Handle,
|
||||
0);
|
||||
|
||||
DepthAttachment = Tex.Handle;
|
||||
|
||||
StencilAttachment = Tex.Handle;
|
||||
DepthAttachment = CachedImage.Handle;
|
||||
StencilAttachment = CachedImage.Handle;
|
||||
}
|
||||
}
|
||||
else if (Tex.HasDepth)
|
||||
else if (CachedImage.HasDepth)
|
||||
{
|
||||
Attach(ref DepthAttachment, Tex.Handle, FramebufferAttachment.DepthAttachment);
|
||||
Attach(ref DepthAttachment, CachedImage.Handle, FramebufferAttachment.DepthAttachment);
|
||||
|
||||
Attach(ref StencilAttachment, 0, FramebufferAttachment.StencilAttachment);
|
||||
}
|
||||
else if (Tex.HasStencil)
|
||||
else if (CachedImage.HasStencil)
|
||||
{
|
||||
Attach(ref DepthAttachment, 0, FramebufferAttachment.DepthAttachment);
|
||||
|
||||
Attach(ref StencilAttachment, Tex.Handle, FramebufferAttachment.StencilAttachment);
|
||||
Attach(ref StencilAttachment, CachedImage.Handle, FramebufferAttachment.StencilAttachment);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -130,12 +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()
|
||||
{
|
||||
EnsureFrameBuffer();
|
||||
|
||||
if (DepthAttachment != 0 ||
|
||||
StencilAttachment != 0)
|
||||
if (DepthAttachment != 0 || StencilAttachment != 0)
|
||||
{
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
|
@ -143,44 +154,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
0,
|
||||
0);
|
||||
|
||||
DepthAttachment = 0;
|
||||
|
||||
DepthAttachment = 0;
|
||||
StencilAttachment = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void BindTexture(long Key, int Index)
|
||||
{
|
||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||
{
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(long Key)
|
||||
{
|
||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||
{
|
||||
ReadTex = Tex;
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(byte[] Data, int Width, int Height)
|
||||
{
|
||||
if (RawTex == null)
|
||||
{
|
||||
RawTex = new ImageHandler();
|
||||
}
|
||||
|
||||
RawTex.EnsureSetup(new GalImage(Width, Height, RawFormat));
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, RawTex.Handle);
|
||||
|
||||
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, RawTex.PixelFormat, RawTex.PixelType, Data);
|
||||
|
||||
ReadTex = RawTex;
|
||||
Texture.TryGetImageHandler(Key, out ReadTex);
|
||||
}
|
||||
|
||||
public void SetMap(int[] Map)
|
||||
|
@ -280,13 +261,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
|
||||
int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
|
||||
|
||||
if (SrcFb == 0) SrcFb = GL.GenFramebuffer();
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
|
||||
|
||||
GL.Viewport(0, 0, Window.Width, Window.Height);
|
||||
|
||||
if (SrcFb == 0)
|
||||
{
|
||||
SrcFb = GL.GenFramebuffer();
|
||||
}
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
|
||||
|
||||
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, ReadTex.Handle, 0);
|
||||
|
||||
|
@ -298,7 +281,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.BlitFramebuffer(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear);
|
||||
ClearBufferMask.ColorBufferBit,
|
||||
BlitFramebufferFilter.Linear);
|
||||
|
||||
EnsureFrameBuffer();
|
||||
}
|
||||
|
@ -315,110 +299,135 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
int DstX1,
|
||||
int DstY1)
|
||||
{
|
||||
if (Texture.TryGetImage(SrcKey, out ImageHandler SrcTex) &&
|
||||
Texture.TryGetImage(DstKey, out ImageHandler DstTex))
|
||||
if (Texture.TryGetImageHandler(SrcKey, out ImageHandler SrcTex) &&
|
||||
Texture.TryGetImageHandler(DstKey, out ImageHandler DstTex))
|
||||
{
|
||||
if (SrcTex.HasColor != DstTex.HasColor ||
|
||||
SrcTex.HasDepth != DstTex.HasDepth ||
|
||||
if (SrcTex.HasColor != DstTex.HasColor ||
|
||||
SrcTex.HasDepth != DstTex.HasDepth ||
|
||||
SrcTex.HasStencil != DstTex.HasStencil)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
if (SrcFb == 0)
|
||||
{
|
||||
SrcFb = GL.GenFramebuffer();
|
||||
}
|
||||
|
||||
if (DstFb == 0)
|
||||
{
|
||||
DstFb = GL.GenFramebuffer();
|
||||
}
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb);
|
||||
|
||||
FramebufferAttachment Attachment = GetAttachment(SrcTex);
|
||||
|
||||
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0);
|
||||
GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0);
|
||||
|
||||
BlitFramebufferFilter Filter = BlitFramebufferFilter.Nearest;
|
||||
|
||||
if (SrcTex.HasColor)
|
||||
{
|
||||
CopyTextures(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
SrcTex.Handle,
|
||||
DstTex.Handle,
|
||||
FramebufferAttachment.ColorAttachment0,
|
||||
ClearBufferMask.ColorBufferBit,
|
||||
true);
|
||||
}
|
||||
else if (SrcTex.HasDepth && SrcTex.HasStencil)
|
||||
{
|
||||
CopyTextures(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
SrcTex.Handle,
|
||||
DstTex.Handle,
|
||||
FramebufferAttachment.DepthStencilAttachment,
|
||||
ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit,
|
||||
false);
|
||||
}
|
||||
else if (SrcTex.HasDepth)
|
||||
{
|
||||
CopyTextures(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
SrcTex.Handle,
|
||||
DstTex.Handle,
|
||||
FramebufferAttachment.DepthAttachment,
|
||||
ClearBufferMask.DepthBufferBit,
|
||||
false);
|
||||
}
|
||||
else if (SrcTex.HasStencil)
|
||||
{
|
||||
CopyTextures(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
SrcTex.Handle,
|
||||
DstTex.Handle,
|
||||
FramebufferAttachment.StencilAttachment,
|
||||
ClearBufferMask.StencilBufferBit,
|
||||
false);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||
|
||||
Filter = BlitFramebufferFilter.Linear;
|
||||
}
|
||||
|
||||
ClearBufferMask Mask = GetClearMask(SrcTex);
|
||||
|
||||
GL.Clear(Mask);
|
||||
|
||||
GL.BlitFramebuffer(SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, Mask, Filter);
|
||||
|
||||
EnsureFrameBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
public void GetBufferData(long Key, Action<byte[]> Callback)
|
||||
public void Reinterpret(long Key, GalImage NewImage)
|
||||
{
|
||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||
if (!Texture.TryGetImage(Key, out GalImage OldImage))
|
||||
{
|
||||
byte[] Data = new byte[ImageUtils.GetSize(Tex.Image)];
|
||||
return;
|
||||
}
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
|
||||
if (NewImage.Format == OldImage.Format)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GL.GetTexImage(
|
||||
TextureTarget.Texture2D,
|
||||
0,
|
||||
Tex.PixelFormat,
|
||||
Tex.PixelType,
|
||||
Data);
|
||||
byte[] Data = GetData(Key);
|
||||
|
||||
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(
|
||||
long Key,
|
||||
int Width,
|
||||
int Height,
|
||||
byte[] Buffer)
|
||||
private static ClearBufferMask GetClearMask(ImageHandler CachedImage)
|
||||
{
|
||||
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
|
||||
|
||||
const int Level = 0;
|
||||
const int Border = 0;
|
||||
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
Tex.InternalFormat,
|
||||
Width,
|
||||
Height,
|
||||
Border,
|
||||
Tex.PixelFormat,
|
||||
Tex.PixelType,
|
||||
Buffer);
|
||||
}
|
||||
return (CachedImage.HasColor ? ClearBufferMask.ColorBufferBit : 0) |
|
||||
(CachedImage.HasDepth ? ClearBufferMask.DepthBufferBit : 0) |
|
||||
(CachedImage.HasStencil ? ClearBufferMask.StencilBufferBit : 0);
|
||||
}
|
||||
|
||||
private void EnsureFrameBuffer()
|
||||
|
@ -430,68 +439,5 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
|
||||
}
|
||||
|
||||
private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment)
|
||||
{
|
||||
if (OldHandle != NewHandle)
|
||||
{
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
FbAttachment,
|
||||
NewHandle,
|
||||
0);
|
||||
|
||||
OldHandle = NewHandle;
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyTextures(
|
||||
int SrcX0,
|
||||
int SrcY0,
|
||||
int SrcX1,
|
||||
int SrcY1,
|
||||
int DstX0,
|
||||
int DstY0,
|
||||
int DstX1,
|
||||
int DstY1,
|
||||
int SrcTexture,
|
||||
int DstTexture,
|
||||
FramebufferAttachment Attachment,
|
||||
ClearBufferMask Mask,
|
||||
bool Color)
|
||||
{
|
||||
if (SrcFb == 0) SrcFb = GL.GenFramebuffer();
|
||||
if (DstFb == 0) DstFb = GL.GenFramebuffer();
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb);
|
||||
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.ReadFramebuffer,
|
||||
Attachment,
|
||||
SrcTexture,
|
||||
0);
|
||||
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
Attachment,
|
||||
DstTexture,
|
||||
0);
|
||||
|
||||
if (Color)
|
||||
{
|
||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||
}
|
||||
|
||||
GL.Clear(Mask);
|
||||
|
||||
GL.BlitFramebuffer(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
Mask,
|
||||
Color ? BlitFramebufferFilter.Linear : BlitFramebufferFilter.Nearest);
|
||||
|
||||
EnsureFrameBuffer();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,17 +28,65 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.DeleteTexture(CachedImage.Handle);
|
||||
}
|
||||
|
||||
public void Create(long Key, byte[] Data, GalImage Image)
|
||||
public void Create(long Key, int Size, GalImage Image)
|
||||
{
|
||||
int Handle = GL.GenTexture();
|
||||
|
||||
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
|
||||
const int Level = 0; //TODO: Support mipmap textures.
|
||||
const int Border = 0;
|
||||
|
||||
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Size);
|
||||
|
||||
GalImageFormat TypeLess = Image.Format & GalImageFormat.FormatMask;
|
||||
|
||||
bool IsASTC = TypeLess >= GalImageFormat.ASTC_BEGIN && TypeLess <= GalImageFormat.ASTC_END;
|
||||
|
||||
if (ImageUtils.IsCompressed(Image.Format) && !IsASTC)
|
||||
{
|
||||
InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format);
|
||||
|
||||
GL.CompressedTexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
InternalFmt,
|
||||
Image.Width,
|
||||
Image.Height,
|
||||
Border,
|
||||
Size,
|
||||
IntPtr.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
(PixelInternalFormat InternalFmt,
|
||||
PixelFormat Format,
|
||||
PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
|
||||
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
InternalFmt,
|
||||
Image.Width,
|
||||
Image.Height,
|
||||
Border,
|
||||
Format,
|
||||
Type,
|
||||
IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
public void Create(long Key, byte[] Data, GalImage Image)
|
||||
{
|
||||
int Handle = GL.GenTexture();
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
|
||||
const int Level = 0; //TODO: Support mipmap textures.
|
||||
const int Border = 0;
|
||||
|
||||
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length);
|
||||
|
||||
GalImageFormat TypeLess = Image.Format & GalImageFormat.FormatMask;
|
||||
|
||||
bool IsASTC = TypeLess >= GalImageFormat.ASTC_BEGIN && TypeLess <= GalImageFormat.ASTC_END;
|
||||
|
@ -62,8 +110,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
//TODO: Use KHR_texture_compression_astc_hdr when available
|
||||
if (IsASTC)
|
||||
{
|
||||
int TextureBlockWidth = GetAstcBlockWidth(Image.Format);
|
||||
int TextureBlockHeight = GetAstcBlockHeight(Image.Format);
|
||||
int TextureBlockWidth = ImageUtils.GetBlockWidth(Image.Format);
|
||||
int TextureBlockHeight = ImageUtils.GetBlockHeight(Image.Format);
|
||||
|
||||
Data = ASTCDecoder.DecodeToRGBA8888(
|
||||
Data,
|
||||
|
@ -85,12 +133,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
Image.Format = GalImageFormat.R8G8 | (Image.Format & GalImageFormat.TypeMask);
|
||||
}
|
||||
|
||||
(PixelInternalFormat InternalFormat, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
|
||||
(PixelInternalFormat InternalFmt,
|
||||
PixelFormat Format,
|
||||
PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
|
||||
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
InternalFormat,
|
||||
InternalFmt,
|
||||
Image.Width,
|
||||
Image.Height,
|
||||
Border,
|
||||
|
@ -98,31 +148,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
Type,
|
||||
Data);
|
||||
}
|
||||
|
||||
int SwizzleR = (int)OGLEnumConverter.GetTextureSwizzle(Image.XSource);
|
||||
int SwizzleG = (int)OGLEnumConverter.GetTextureSwizzle(Image.YSource);
|
||||
int SwizzleB = (int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource);
|
||||
int SwizzleA = (int)OGLEnumConverter.GetTextureSwizzle(Image.WSource);
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, SwizzleR);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, SwizzleG);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleB, SwizzleB);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA);
|
||||
}
|
||||
|
||||
public void CreateFb(long Key, long Size, GalImage Image)
|
||||
public bool TryGetImage(long Key, out GalImage Image)
|
||||
{
|
||||
if (!TryGetImage(Key, out ImageHandler CachedImage))
|
||||
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
|
||||
{
|
||||
CachedImage = new ImageHandler();
|
||||
Image = CachedImage.Image;
|
||||
|
||||
TextureCache.AddOrUpdate(Key, CachedImage, Size);
|
||||
return true;
|
||||
}
|
||||
|
||||
CachedImage.EnsureSetup(Image);
|
||||
Image = default(GalImage);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetImage(long Key, out ImageHandler CachedImage)
|
||||
public bool TryGetImageHandler(long Key, out ImageHandler CachedImage)
|
||||
{
|
||||
if (TextureCache.TryGetValue(Key, out CachedImage))
|
||||
{
|
||||
|
@ -134,76 +176,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
return false;
|
||||
}
|
||||
|
||||
private static int GetAstcBlockWidth(GalImageFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalImageFormat.ASTC_4x4 | GalImageFormat.Unorm: return 4;
|
||||
case GalImageFormat.ASTC_5x5 | GalImageFormat.Unorm: return 5;
|
||||
case GalImageFormat.ASTC_6x6 | GalImageFormat.Unorm: return 6;
|
||||
case GalImageFormat.ASTC_8x8 | GalImageFormat.Unorm: return 8;
|
||||
case GalImageFormat.ASTC_10x10 | GalImageFormat.Unorm: return 10;
|
||||
case GalImageFormat.ASTC_12x12 | GalImageFormat.Unorm: return 12;
|
||||
case GalImageFormat.ASTC_5x4 | GalImageFormat.Unorm: return 5;
|
||||
case GalImageFormat.ASTC_6x5 | GalImageFormat.Unorm: return 6;
|
||||
case GalImageFormat.ASTC_8x6 | GalImageFormat.Unorm: return 8;
|
||||
case GalImageFormat.ASTC_10x8 | GalImageFormat.Unorm: return 10;
|
||||
case GalImageFormat.ASTC_12x10 | GalImageFormat.Unorm: return 12;
|
||||
case GalImageFormat.ASTC_8x5 | GalImageFormat.Unorm: return 8;
|
||||
case GalImageFormat.ASTC_10x5 | GalImageFormat.Unorm: return 10;
|
||||
case GalImageFormat.ASTC_10x6 | GalImageFormat.Unorm: return 10;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Format));
|
||||
}
|
||||
|
||||
private static int GetAstcBlockHeight(GalImageFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalImageFormat.ASTC_4x4 | GalImageFormat.Unorm: return 4;
|
||||
case GalImageFormat.ASTC_5x5 | GalImageFormat.Unorm: return 5;
|
||||
case GalImageFormat.ASTC_6x6 | GalImageFormat.Unorm: return 6;
|
||||
case GalImageFormat.ASTC_8x8 | GalImageFormat.Unorm: return 8;
|
||||
case GalImageFormat.ASTC_10x10 | GalImageFormat.Unorm: return 10;
|
||||
case GalImageFormat.ASTC_12x12 | GalImageFormat.Unorm: return 12;
|
||||
case GalImageFormat.ASTC_5x4 | GalImageFormat.Unorm: return 4;
|
||||
case GalImageFormat.ASTC_6x5 | GalImageFormat.Unorm: return 5;
|
||||
case GalImageFormat.ASTC_8x6 | GalImageFormat.Unorm: return 6;
|
||||
case GalImageFormat.ASTC_10x8 | GalImageFormat.Unorm: return 8;
|
||||
case GalImageFormat.ASTC_12x10 | GalImageFormat.Unorm: return 10;
|
||||
case GalImageFormat.ASTC_8x5 | GalImageFormat.Unorm: return 5;
|
||||
case GalImageFormat.ASTC_10x5 | GalImageFormat.Unorm: return 5;
|
||||
case GalImageFormat.ASTC_10x6 | GalImageFormat.Unorm: return 6;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Format));
|
||||
}
|
||||
|
||||
public bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image)
|
||||
{
|
||||
if (TextureCache.TryGetSize(Key, out long Size) && Size == DataSize)
|
||||
{
|
||||
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
|
||||
{
|
||||
Image = CachedImage.Image;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Image = default(GalImage);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Bind(long Key, int Index)
|
||||
public void Bind(long Key, int Index, GalImage Image)
|
||||
{
|
||||
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
|
||||
{
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle);
|
||||
|
||||
int[] SwizzleRgba = new int[]
|
||||
{
|
||||
(int)OGLEnumConverter.GetTextureSwizzle(Image.XSource),
|
||||
(int)OGLEnumConverter.GetTextureSwizzle(Image.YSource),
|
||||
(int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource),
|
||||
(int)OGLEnumConverter.GetTextureSwizzle(Image.WSource)
|
||||
};
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleRgba, SwizzleRgba);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -641,6 +641,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
default:
|
||||
SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,32 +6,32 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
static partial class ShaderDecode
|
||||
{
|
||||
public static void Bfe_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Bfe_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitBfe(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Bfe_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Bfe_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitBfe(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Bfe_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Bfe_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitBfe(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Fadd_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fadd_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFadd(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Fadd_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fadd_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFadd(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Fadd_I32(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fadd_I32(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode OperA = OpCode.Gpr8();
|
||||
ShaderIrNode OperB = OpCode.Immf32_20();
|
||||
|
@ -49,47 +49,47 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||
}
|
||||
|
||||
public static void Fadd_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fadd_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFadd(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Ffma_CR(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ffma_CR(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFfma(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Ffma_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ffma_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFfma(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Ffma_RC(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ffma_RC(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFfma(Block, OpCode, ShaderOper.RC);
|
||||
}
|
||||
|
||||
public static void Ffma_RR(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ffma_RR(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFfma(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Fmnmx_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fmnmx_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFmnmx(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Fmnmx_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fmnmx_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFmnmx(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Fmnmx_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fmnmx_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFmnmx(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Fmul_I32(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fmul_I32(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode OperA = OpCode.Gpr8();
|
||||
ShaderIrNode OperB = OpCode.Immf32_20();
|
||||
|
@ -99,62 +99,62 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||
}
|
||||
|
||||
public static void Fmul_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fmul_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFmul(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Fmul_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fmul_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFmul(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Fmul_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fmul_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFmul(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Fset_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fset_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFset(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Fset_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fset_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFset(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Fset_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fset_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFset(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Fsetp_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fsetp_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFsetp(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Fsetp_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fsetp_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFsetp(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Fsetp_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Fsetp_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitFsetp(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Iadd_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iadd_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIadd(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Iadd_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iadd_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIadd(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Iadd_I32(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iadd_I32(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode OperA = OpCode.Gpr8();
|
||||
ShaderIrNode OperB = OpCode.Imm32_20();
|
||||
|
@ -168,42 +168,42 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||
}
|
||||
|
||||
public static void Iadd_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iadd_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIadd(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Iadd3_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iadd3_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIadd3(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Iadd3_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iadd3_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIadd3(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Iadd3_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iadd3_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIadd3(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Imnmx_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Imnmx_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitImnmx(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Imnmx_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Imnmx_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitImnmx(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Imnmx_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Imnmx_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitImnmx(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Ipa(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ipa(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode OperA = OpCode.Abuf28();
|
||||
ShaderIrNode OperB = OpCode.Gpr20();
|
||||
|
@ -217,52 +217,52 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||
}
|
||||
|
||||
public static void Iscadd_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iscadd_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIscadd(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Iscadd_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iscadd_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIscadd(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Iscadd_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iscadd_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIscadd(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Iset_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iset_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIset(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Iset_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iset_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIset(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Iset_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Iset_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIset(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Isetp_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Isetp_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIsetp(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Isetp_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Isetp_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIsetp(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Isetp_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Isetp_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitIsetp(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Lop_I32(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Lop_I32(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
int SubOp = OpCode.Read(53, 3);
|
||||
|
||||
|
@ -296,22 +296,22 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
public static void Lop_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Lop_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitLop(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Lop_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Lop_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitLop(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Lop_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Lop_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitLop(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Mufu(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Mufu(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
int SubOp = OpCode.Read(20, 0xf);
|
||||
|
||||
|
@ -340,7 +340,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||
}
|
||||
|
||||
public static void Psetp(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Psetp(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
bool NegA = OpCode.Read(15);
|
||||
bool NegB = OpCode.Read(32);
|
||||
|
@ -394,47 +394,47 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
|
||||
}
|
||||
|
||||
public static void Rro_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Rro_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitRro(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Rro_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Rro_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitRro(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void Rro_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Rro_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitRro(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Shl_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Shl_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Lsl);
|
||||
}
|
||||
|
||||
public static void Shl_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Shl_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Lsl);
|
||||
}
|
||||
|
||||
public static void Shl_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Shl_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Lsl);
|
||||
}
|
||||
|
||||
public static void Shr_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Shr_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode));
|
||||
}
|
||||
|
||||
public static void Shr_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Shr_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.Imm, GetShrInst(OpCode));
|
||||
}
|
||||
|
||||
public static void Shr_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Shr_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitAluBinary(Block, OpCode, ShaderOper.RR, GetShrInst(OpCode));
|
||||
}
|
||||
|
@ -446,7 +446,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
return Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
||||
}
|
||||
|
||||
public static void Vmad(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Vmad(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode OperA = OpCode.Gpr8();
|
||||
|
||||
|
@ -481,22 +481,22 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Final)));
|
||||
}
|
||||
|
||||
public static void Xmad_CR(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Xmad_CR(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitXmad(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Xmad_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Xmad_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitXmad(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Xmad_RC(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Xmad_RC(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitXmad(Block, OpCode, ShaderOper.RC);
|
||||
}
|
||||
|
||||
public static void Xmad_RR(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Xmad_RR(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitXmad(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
using System;
|
||||
|
||||
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
static partial class ShaderDecode
|
||||
{
|
||||
public static void Bra(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Bra(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
if ((OpCode & 0x20) != 0)
|
||||
{
|
||||
|
@ -15,14 +13,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
int Target = OpCode.Branch();
|
||||
|
||||
ShaderIrOperImm Imm = new ShaderIrOperImm(Target);
|
||||
ShaderIrOperImm Imm = new ShaderIrOperImm(Position + OpCode.Branch());
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Bra, Imm)));
|
||||
}
|
||||
|
||||
public static void Exit(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Exit(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
int CCode = (int)OpCode & 0x1f;
|
||||
|
||||
|
@ -31,15 +27,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Exit)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void Kil(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Kil(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Kil)));
|
||||
}
|
||||
|
||||
public static void Ssy(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ssy(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
if ((OpCode & 0x20) != 0)
|
||||
{
|
||||
|
@ -48,19 +43,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
int Offset = OpCode.Branch();
|
||||
|
||||
int Target = (int)(Position + Offset);
|
||||
|
||||
ShaderIrOperImm Imm = new ShaderIrOperImm(Target);
|
||||
ShaderIrOperImm Imm = new ShaderIrOperImm(Position + OpCode.Branch());
|
||||
|
||||
Block.AddNode(new ShaderIrOp(ShaderIrInst.Ssy, Imm));
|
||||
}
|
||||
|
||||
public static void Sync(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Sync(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
//TODO: Implement Sync condition codes
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Sync)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode, long Position);
|
||||
delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode, int Position);
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
static class ShaderDecodeHelper
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{ RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
|
||||
};
|
||||
|
||||
public static void Ld_A(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ld_A(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode[] Opers = OpCode.Abuf20();
|
||||
|
||||
|
@ -50,7 +50,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
public static void Ld_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Ld_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
int CbufPos = OpCode.Read(22, 0x3fff);
|
||||
int CbufIndex = OpCode.Read(36, 0x1f);
|
||||
|
@ -97,7 +97,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
public static void St_A(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void St_A(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode[] Opers = OpCode.Abuf20();
|
||||
|
||||
|
@ -113,7 +113,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
public static void Texq(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Texq(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode OperD = OpCode.Gpr0();
|
||||
ShaderIrNode OperA = OpCode.Gpr8();
|
||||
|
@ -132,12 +132,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperA, Op1))); //Is this right?
|
||||
}
|
||||
|
||||
public static void Tex(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Tex(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTex(Block, OpCode, GprHandle: false);
|
||||
}
|
||||
|
||||
public static void Tex_B(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Tex_B(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTex(Block, OpCode, GprHandle: true);
|
||||
}
|
||||
|
@ -202,12 +202,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
public static void Texs(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Texs(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTexs(Block, OpCode, ShaderIrInst.Texs);
|
||||
}
|
||||
|
||||
public static void Tlds(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Tlds(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTexs(Block, OpCode, ShaderIrInst.Txlf);
|
||||
}
|
||||
|
|
|
@ -25,67 +25,67 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
F64 = 3
|
||||
}
|
||||
|
||||
public static void F2f_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void F2f_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitF2f(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void F2f_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void F2f_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitF2f(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void F2f_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void F2f_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitF2f(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void F2i_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void F2i_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitF2i(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void F2i_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void F2i_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitF2i(Block, OpCode, ShaderOper.Immf);
|
||||
}
|
||||
|
||||
public static void F2i_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void F2i_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitF2i(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void I2f_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void I2f_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitI2f(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void I2f_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void I2f_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitI2f(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void I2f_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void I2f_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitI2f(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void I2i_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void I2i_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitI2i(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void I2i_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void I2i_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitI2i(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void I2i_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void I2i_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitI2i(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Isberd(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Isberd(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
//This instruction seems to be used to translate from an address to a vertex index in a GS
|
||||
//Stub it as such
|
||||
|
@ -95,50 +95,50 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OpCode.Gpr8())));
|
||||
}
|
||||
|
||||
public static void Mov_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Mov_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrOperCbuf Cbuf = OpCode.Cbuf34();
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Cbuf)));
|
||||
}
|
||||
|
||||
public static void Mov_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Mov_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrOperImm Imm = OpCode.Imm19_20();
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Imm)));
|
||||
}
|
||||
|
||||
public static void Mov_I32(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Mov_I32(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrOperImm Imm = OpCode.Imm32_20();
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Imm)));
|
||||
}
|
||||
|
||||
public static void Mov_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Mov_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrOperGpr Gpr = OpCode.Gpr20();
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Gpr)));
|
||||
}
|
||||
|
||||
public static void Sel_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Sel_C(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitSel(Block, OpCode, ShaderOper.CR);
|
||||
}
|
||||
|
||||
public static void Sel_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Sel_I(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitSel(Block, OpCode, ShaderOper.Imm);
|
||||
}
|
||||
|
||||
public static void Sel_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Sel_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitSel(Block, OpCode, ShaderOper.RR);
|
||||
}
|
||||
|
||||
public static void Mov_S(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Mov_S(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
Block.AddNode(new ShaderIrCmnt("Stubbed."));
|
||||
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
static partial class ShaderDecode
|
||||
{
|
||||
public static void Out_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||
public static void Out_R(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
//TODO: Those registers have to be used for something
|
||||
ShaderIrOperGpr Gpr0 = OpCode.Gpr0();
|
||||
|
|
|
@ -10,12 +10,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public static ShaderIrBlock[] Decode(IGalMemory Memory, long Start)
|
||||
{
|
||||
Dictionary<long, ShaderIrBlock> Visited = new Dictionary<long, ShaderIrBlock>();
|
||||
Dictionary<long, ShaderIrBlock> VisitedEnd = new Dictionary<long, ShaderIrBlock>();
|
||||
Dictionary<int, ShaderIrBlock> Visited = new Dictionary<int, ShaderIrBlock>();
|
||||
Dictionary<int, ShaderIrBlock> VisitedEnd = new Dictionary<int, ShaderIrBlock>();
|
||||
|
||||
Queue<ShaderIrBlock> Blocks = new Queue<ShaderIrBlock>();
|
||||
|
||||
ShaderIrBlock Enqueue(long Position, ShaderIrBlock Source = null)
|
||||
long Beginning = Start + HeaderSize;
|
||||
|
||||
ShaderIrBlock Enqueue(int Position, ShaderIrBlock Source = null)
|
||||
{
|
||||
if (!Visited.TryGetValue(Position, out ShaderIrBlock Output))
|
||||
{
|
||||
|
@ -34,13 +36,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
return Output;
|
||||
}
|
||||
|
||||
ShaderIrBlock Entry = Enqueue(Start + HeaderSize);
|
||||
ShaderIrBlock Entry = Enqueue(0);
|
||||
|
||||
while (Blocks.Count > 0)
|
||||
{
|
||||
ShaderIrBlock Current = Blocks.Dequeue();
|
||||
|
||||
FillBlock(Memory, Current, Start + HeaderSize);
|
||||
FillBlock(Memory, Current, Beginning);
|
||||
|
||||
//Set child blocks. "Branch" is the block the branch instruction
|
||||
//points to (when taken), "Next" is the block at the next address,
|
||||
|
@ -54,20 +56,18 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
if (InnerOp?.Inst == ShaderIrInst.Bra)
|
||||
{
|
||||
int Offset = ((ShaderIrOperImm)InnerOp.OperandA).Value;
|
||||
|
||||
long Target = Current.EndPosition + Offset;
|
||||
int Target = ((ShaderIrOperImm)InnerOp.OperandA).Value;
|
||||
|
||||
Current.Branch = Enqueue(Target, Current);
|
||||
}
|
||||
|
||||
foreach (ShaderIrNode Node in Current.Nodes)
|
||||
{
|
||||
if (Node is ShaderIrOp CurrOp && CurrOp.Inst == ShaderIrInst.Ssy)
|
||||
{
|
||||
int Offset = ((ShaderIrOperImm)CurrOp.OperandA).Value;
|
||||
InnerOp = GetInnermostOp(Node);
|
||||
|
||||
long Target = Offset;
|
||||
if (InnerOp is ShaderIrOp CurrOp && CurrOp.Inst == ShaderIrInst.Ssy)
|
||||
{
|
||||
int Target = ((ShaderIrOperImm)CurrOp.OperandA).Value;
|
||||
|
||||
Current.Branch = Enqueue(Target, Current);
|
||||
}
|
||||
|
@ -112,15 +112,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
while (Visited.Count > 0)
|
||||
{
|
||||
ulong FirstPos = ulong.MaxValue;
|
||||
uint FirstPos = uint.MaxValue;
|
||||
|
||||
foreach (ShaderIrBlock Block in Visited.Values)
|
||||
{
|
||||
if (FirstPos > (ulong)Block.Position)
|
||||
FirstPos = (ulong)Block.Position;
|
||||
if (FirstPos > (uint)Block.Position)
|
||||
FirstPos = (uint)Block.Position;
|
||||
}
|
||||
|
||||
ShaderIrBlock Current = Visited[(long)FirstPos];
|
||||
ShaderIrBlock Current = Visited[(int)FirstPos];
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -138,20 +138,20 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private static void FillBlock(IGalMemory Memory, ShaderIrBlock Block, long Beginning)
|
||||
{
|
||||
long Position = Block.Position;
|
||||
int Position = Block.Position;
|
||||
|
||||
do
|
||||
{
|
||||
//Ignore scheduling instructions, which are written every 32 bytes.
|
||||
if (((Position - Beginning) & 0x1f) == 0)
|
||||
if ((Position & 0x1f) == 0)
|
||||
{
|
||||
Position += 8;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
uint Word0 = (uint)Memory.ReadInt32(Position + 0);
|
||||
uint Word1 = (uint)Memory.ReadInt32(Position + 4);
|
||||
uint Word0 = (uint)Memory.ReadInt32(Position + Beginning + 0);
|
||||
uint Word1 = (uint)Memory.ReadInt32(Position + Beginning + 4);
|
||||
|
||||
Position += 8;
|
||||
|
||||
|
@ -161,7 +161,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
if (AddDbgComments)
|
||||
{
|
||||
string DbgOpCode = $"0x{(Position - Beginning - 8):x16}: 0x{OpCode:x16} ";
|
||||
string DbgOpCode = $"0x{(Position - 8):x16}: 0x{OpCode:x16} ";
|
||||
|
||||
DbgOpCode += (Decode?.Method.Name ?? "???");
|
||||
|
||||
|
@ -169,7 +169,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
int Offset = ((int)(OpCode >> 20) << 8) >> 8;
|
||||
|
||||
long Target = Position + Offset - Beginning;
|
||||
long Target = Position + Offset;
|
||||
|
||||
DbgOpCode += " (0x" + Target.ToString("x16") + ")";
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
class ShaderIrBlock
|
||||
{
|
||||
public long Position { get; set; }
|
||||
public long EndPosition { get; set; }
|
||||
public int Position { get; set; }
|
||||
public int EndPosition { get; set; }
|
||||
|
||||
public ShaderIrBlock Next { get; set; }
|
||||
public ShaderIrBlock Branch { get; set; }
|
||||
|
@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public List<ShaderIrNode> Nodes { get; private set; }
|
||||
|
||||
public ShaderIrBlock(long Position)
|
||||
public ShaderIrBlock(int Position)
|
||||
{
|
||||
this.Position = Position;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue