Use textures for framebuffers and split color and zeta framebuffers
This commit is contained in:
parent
a11293b793
commit
b723bd5e4a
10 changed files with 557 additions and 218 deletions
|
@ -19,7 +19,7 @@
|
|||
RG32Sint = 0xcc,
|
||||
RG32Uint = 0xcd,
|
||||
RGBX16Float = 0xce,
|
||||
BGRA8Unorm = 0x0cf,
|
||||
BGRA8Unorm = 0xcf,
|
||||
BGRA8Srgb = 0xd0,
|
||||
RGB10A2Unorm = 0xd1,
|
||||
RGB10A2Uint = 0xd2,
|
||||
|
|
|
@ -4,9 +4,17 @@ namespace Ryujinx.Graphics.Gal
|
|||
{
|
||||
public interface IGalFrameBuffer
|
||||
{
|
||||
void Create(long Key, int Width, int Height);
|
||||
void CreateColor(long Key, int Width, int Height, GalFrameBufferFormat Format);
|
||||
|
||||
void Bind(long Key);
|
||||
void BindColor(long Key, int Attachment);
|
||||
|
||||
void UnbindColor(int Attachment);
|
||||
|
||||
void CreateZeta(long Key, int Width, int Height, GalZetaFormat Format);
|
||||
|
||||
void BindZeta(long Key);
|
||||
|
||||
void UnbindZeta();
|
||||
|
||||
void BindTexture(long Key, int Index);
|
||||
|
||||
|
@ -40,7 +48,6 @@ namespace Ryujinx.Graphics.Gal
|
|||
long Key,
|
||||
int Width,
|
||||
int Height,
|
||||
GalTextureFormat Format,
|
||||
byte[] Buffer);
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.Gal
|
|||
|
||||
void ClearBuffers(
|
||||
GalClearBufferFlags Flags,
|
||||
int Attachment,
|
||||
float Red, float Green, float Blue, float Alpha,
|
||||
float Depth,
|
||||
int Stencil);
|
||||
|
|
48
Ryujinx.Graphics/Gal/OpenGL/OGLBlend.cs
Normal file
48
Ryujinx.Graphics/Gal/OpenGL/OGLBlend.cs
Normal file
|
@ -0,0 +1,48 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
public class OGLBlend : IGalBlend
|
||||
{
|
||||
public void Enable()
|
||||
{
|
||||
GL.Enable(EnableCap.Blend);
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
{
|
||||
GL.Disable(EnableCap.Blend);
|
||||
}
|
||||
|
||||
public void Set(
|
||||
GalBlendEquation Equation,
|
||||
GalBlendFactor FuncSrc,
|
||||
GalBlendFactor FuncDst)
|
||||
{
|
||||
GL.BlendEquation(OGLEnumConverter.GetBlendEquation(Equation));
|
||||
|
||||
GL.BlendFunc(
|
||||
OGLEnumConverter.GetBlendFactor(FuncSrc),
|
||||
OGLEnumConverter.GetBlendFactor(FuncDst));
|
||||
}
|
||||
|
||||
public void SetSeparate(
|
||||
GalBlendEquation EquationRgb,
|
||||
GalBlendEquation EquationAlpha,
|
||||
GalBlendFactor FuncSrcRgb,
|
||||
GalBlendFactor FuncDstRgb,
|
||||
GalBlendFactor FuncSrcAlpha,
|
||||
GalBlendFactor FuncDstAlpha)
|
||||
{
|
||||
GL.BlendEquationSeparate(
|
||||
OGLEnumConverter.GetBlendEquation(EquationRgb),
|
||||
OGLEnumConverter.GetBlendEquation(EquationAlpha));
|
||||
|
||||
GL.BlendFuncSeparate(
|
||||
(BlendingFactorSrc)OGLEnumConverter.GetBlendFactor(FuncSrcRgb),
|
||||
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(FuncDstRgb),
|
||||
(BlendingFactorSrc)OGLEnumConverter.GetBlendFactor(FuncSrcAlpha),
|
||||
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(FuncDstAlpha));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -125,6 +125,75 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
throw new ArgumentException(nameof(Type));
|
||||
}
|
||||
|
||||
public static PixelInternalFormat GetFrameBufferInternalFormat(GalFrameBufferFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
//Sometimes it's not set, use a safe format
|
||||
case 0: return PixelInternalFormat.Rgba8;
|
||||
|
||||
case GalFrameBufferFormat.RGBA32Float: return PixelInternalFormat.Rgba32f;
|
||||
case GalFrameBufferFormat.RGBA32Sint: return PixelInternalFormat.Rgba32i;
|
||||
case GalFrameBufferFormat.RGBA32Uint: return PixelInternalFormat.Rgba32ui;
|
||||
case GalFrameBufferFormat.RGBA16Unorm: return PixelInternalFormat.Rgba16;
|
||||
case GalFrameBufferFormat.RGBA16Snorm: return PixelInternalFormat.Rgba16Snorm;
|
||||
case GalFrameBufferFormat.RGBA16Sint: return PixelInternalFormat.Rgba16i;
|
||||
case GalFrameBufferFormat.RGBA16Uint: return PixelInternalFormat.Rgba16ui;
|
||||
case GalFrameBufferFormat.RGBA16Float: return PixelInternalFormat.Rgba16f;
|
||||
case GalFrameBufferFormat.RG32Float: return PixelInternalFormat.Rg32f;
|
||||
case GalFrameBufferFormat.RG32Sint: return PixelInternalFormat.Rg32i;
|
||||
case GalFrameBufferFormat.RG32Uint: return PixelInternalFormat.Rg32ui;
|
||||
case GalFrameBufferFormat.RGB10A2Unorm: return PixelInternalFormat.Rgb10A2;
|
||||
case GalFrameBufferFormat.RGB10A2Uint: return PixelInternalFormat.Rgb10A2ui;
|
||||
case GalFrameBufferFormat.RGBA8Unorm: return PixelInternalFormat.Rgba8;
|
||||
case GalFrameBufferFormat.RGBA8Srgb: return PixelInternalFormat.Srgb8;
|
||||
case GalFrameBufferFormat.RG16Snorm: return PixelInternalFormat.Rg16Snorm;
|
||||
case GalFrameBufferFormat.R11G11B10Float: return PixelInternalFormat.R11fG11fB10f;
|
||||
case GalFrameBufferFormat.R32Float: return PixelInternalFormat.R32f;
|
||||
case GalFrameBufferFormat.R16Float: return PixelInternalFormat.R16f;
|
||||
case GalFrameBufferFormat.R8Unorm: return PixelInternalFormat.R8;
|
||||
case GalFrameBufferFormat.R8Snorm: return PixelInternalFormat.R8Snorm;
|
||||
case GalFrameBufferFormat.R8Sint: return PixelInternalFormat.R8i;
|
||||
case GalFrameBufferFormat.R8Uint: return PixelInternalFormat.R8ui;
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Format.ToString());
|
||||
}
|
||||
|
||||
public static (PixelFormat Format, PixelType Type) GetFrameBufferFormat(GalFrameBufferFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case 0: return (PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||
|
||||
case GalFrameBufferFormat.RGBA32Float: return (PixelFormat.Rgba, PixelType.Float);
|
||||
case GalFrameBufferFormat.RGBA32Sint: return (PixelFormat.Rgba, PixelType.Int);
|
||||
case GalFrameBufferFormat.RGBA32Uint: return (PixelFormat.Rgba, PixelType.UnsignedInt);
|
||||
case GalFrameBufferFormat.RGBA16Unorm: return (PixelFormat.Rgba, PixelType.UnsignedShort);
|
||||
case GalFrameBufferFormat.RGBA16Snorm: return (PixelFormat.Rgba, PixelType.Short);
|
||||
case GalFrameBufferFormat.RGBA16Sint: return (PixelFormat.Rgba, PixelType.Short);
|
||||
case GalFrameBufferFormat.RGBA16Uint: return (PixelFormat.Rgba, PixelType.UnsignedShort);
|
||||
case GalFrameBufferFormat.RGBA16Float: return (PixelFormat.Rgba, PixelType.HalfFloat);
|
||||
case GalFrameBufferFormat.RG32Float: return (PixelFormat.Rg, PixelType.Float);
|
||||
case GalFrameBufferFormat.RG32Sint: return (PixelFormat.Rg, PixelType.Int);
|
||||
case GalFrameBufferFormat.RG32Uint: return (PixelFormat.Rg, PixelType.UnsignedInt);
|
||||
case GalFrameBufferFormat.RGB10A2Unorm: return (PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed);
|
||||
case GalFrameBufferFormat.RGB10A2Uint: return (PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed);
|
||||
case GalFrameBufferFormat.RGBA8Unorm: return (PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||
case GalFrameBufferFormat.RGBA8Srgb: return (PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||
case GalFrameBufferFormat.RG16Snorm: return (PixelFormat.Rg, PixelType.Short);
|
||||
case GalFrameBufferFormat.R11G11B10Float: return (PixelFormat.Rgb, PixelType.UnsignedInt10F11F11FRev);
|
||||
case GalFrameBufferFormat.R32Float: return (PixelFormat.Red, PixelType.Float);
|
||||
case GalFrameBufferFormat.R16Float: return (PixelFormat.Red, PixelType.HalfFloat);
|
||||
case GalFrameBufferFormat.R8Unorm: return (PixelFormat.Red, PixelType.UnsignedByte);
|
||||
case GalFrameBufferFormat.R8Snorm: return (PixelFormat.Red, PixelType.Byte);
|
||||
case GalFrameBufferFormat.R8Sint: return (PixelFormat.Red, PixelType.Byte);
|
||||
case GalFrameBufferFormat.R8Uint: return (PixelFormat.Red, PixelType.UnsignedByte);
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Format.ToString());
|
||||
}
|
||||
|
||||
public static (PixelFormat, PixelType) GetTextureFormat(GalTextureFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
|
|
|
@ -16,50 +16,163 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
private class FrameBuffer
|
||||
private class Texture
|
||||
{
|
||||
public int Width { get; set; }
|
||||
public int Height { get; set; }
|
||||
public int Width { get; private set; }
|
||||
public int Height { get; private set; }
|
||||
|
||||
public int Handle { get; private set; }
|
||||
public int RbHandle { get; private set; }
|
||||
public int TexHandle { get; private set; }
|
||||
public PixelInternalFormat InternalFormat { get; private set; }
|
||||
public PixelFormat Format { get; private set; }
|
||||
public PixelType Type { get; private set; }
|
||||
|
||||
public FrameBuffer(int Width, int Height, bool HasRenderBuffer)
|
||||
public int Handle { get; private set; }
|
||||
|
||||
private bool Initialized;
|
||||
|
||||
public Texture()
|
||||
{
|
||||
this.Width = Width;
|
||||
this.Height = Height;
|
||||
Handle = GL.GenTexture();
|
||||
}
|
||||
|
||||
Handle = GL.GenFramebuffer();
|
||||
TexHandle = GL.GenTexture();
|
||||
|
||||
if (HasRenderBuffer)
|
||||
public void EnsureSetup(
|
||||
int Width,
|
||||
int Height,
|
||||
PixelInternalFormat InternalFormat,
|
||||
PixelFormat Format,
|
||||
PixelType Type)
|
||||
{
|
||||
if (!Initialized ||
|
||||
this.Width != Width ||
|
||||
this.Height != Height ||
|
||||
this.InternalFormat != InternalFormat)
|
||||
{
|
||||
RbHandle = GL.GenRenderbuffer();
|
||||
int CopyBuffer = 0;
|
||||
|
||||
bool ChangingFormat = Initialized && this.InternalFormat != InternalFormat;
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
|
||||
if (ChangingFormat)
|
||||
{
|
||||
CopyBuffer = GL.GenBuffer();
|
||||
|
||||
GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyBuffer);
|
||||
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyBuffer);
|
||||
|
||||
int MaxWidth = Math.Max(Width, this.Width);
|
||||
int MaxHeight = Math.Max(Height, this.Height);
|
||||
|
||||
//TODO: Dehardcode size number
|
||||
GL.BufferData(BufferTarget.PixelPackBuffer, MaxWidth * MaxHeight * MaxBpp, IntPtr.Zero, BufferUsageHint.StaticCopy);
|
||||
|
||||
GL.GetTexImage(TextureTarget.Texture2D, 0, this.Format, this.Type, 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;
|
||||
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
InternalFormat,
|
||||
Width,
|
||||
Height,
|
||||
Border,
|
||||
Format,
|
||||
Type,
|
||||
IntPtr.Zero);
|
||||
|
||||
if (ChangingFormat)
|
||||
{
|
||||
GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
|
||||
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0);
|
||||
|
||||
GL.DeleteBuffer(CopyBuffer);
|
||||
}
|
||||
|
||||
this.Width = Width;
|
||||
this.Height = Height;
|
||||
this.InternalFormat = InternalFormat;
|
||||
this.Format = Format;
|
||||
this.Type = Type;
|
||||
|
||||
Initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void EnsureSetup(int Width, int Height, GalFrameBufferFormat Format)
|
||||
{
|
||||
//TODO: Convert color format
|
||||
|
||||
EnsureSetup(
|
||||
Width,
|
||||
Height,
|
||||
PixelInternalFormat.Rgba8,
|
||||
PixelFormat.Rgba,
|
||||
PixelType.UnsignedByte);
|
||||
}
|
||||
|
||||
public void EnsureSetup(int Width, int Height, GalZetaFormat Format)
|
||||
{
|
||||
//TODO: Convert zeta format
|
||||
|
||||
EnsureSetup(
|
||||
Width,
|
||||
Height,
|
||||
PixelInternalFormat.Depth24Stencil8,
|
||||
PixelFormat.DepthStencil,
|
||||
PixelType.UnsignedInt248);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly DrawBuffersEnum[] DrawBuffers = new DrawBuffersEnum[]
|
||||
{
|
||||
DrawBuffersEnum.ColorAttachment0,
|
||||
DrawBuffersEnum.ColorAttachment1,
|
||||
DrawBuffersEnum.ColorAttachment2,
|
||||
DrawBuffersEnum.ColorAttachment3,
|
||||
DrawBuffersEnum.ColorAttachment4,
|
||||
DrawBuffersEnum.ColorAttachment5,
|
||||
DrawBuffersEnum.ColorAttachment6,
|
||||
DrawBuffersEnum.ColorAttachment7,
|
||||
};
|
||||
|
||||
private const int NativeWidth = 1280;
|
||||
private const int NativeHeight = 720;
|
||||
|
||||
private Dictionary<long, FrameBuffer> Fbs;
|
||||
//TODO: Use a variable value here
|
||||
private const int MaxBpp = 16;
|
||||
|
||||
private const GalTextureFormat RawFormat = GalTextureFormat.A8B8G8R8;
|
||||
|
||||
private Dictionary<long, Texture> ColorTextures;
|
||||
private Dictionary<long, Texture> ZetaTextures;
|
||||
|
||||
private Texture RawTex;
|
||||
private Texture ReadTex;
|
||||
|
||||
private Rect Viewport;
|
||||
private Rect Window;
|
||||
|
||||
private FrameBuffer CurrFb;
|
||||
private FrameBuffer CurrReadFb;
|
||||
|
||||
private FrameBuffer RawFb;
|
||||
|
||||
private bool FlipX;
|
||||
private bool FlipY;
|
||||
|
||||
|
@ -68,111 +181,137 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
private int CropRight;
|
||||
private int CropBottom;
|
||||
|
||||
private int DummyFrameBuffer;
|
||||
|
||||
private int SrcFb;
|
||||
private int DstFb;
|
||||
|
||||
public OGLFrameBuffer()
|
||||
{
|
||||
Fbs = new Dictionary<long, FrameBuffer>();
|
||||
ColorTextures = new Dictionary<long, Texture>();
|
||||
|
||||
ZetaTextures = new Dictionary<long, Texture>();
|
||||
}
|
||||
|
||||
public void Create(long Key, int Width, int Height)
|
||||
public void CreateColor(long Key, int Width, int Height, GalFrameBufferFormat Format)
|
||||
{
|
||||
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
||||
if (!ColorTextures.TryGetValue(Key, out Texture Tex))
|
||||
{
|
||||
if (Fb.Width != Width ||
|
||||
Fb.Height != Height)
|
||||
{
|
||||
SetupTexture(Fb.TexHandle, Width, Height);
|
||||
Tex = new Texture();
|
||||
|
||||
Fb.Width = Width;
|
||||
Fb.Height = Height;
|
||||
}
|
||||
|
||||
return;
|
||||
ColorTextures.Add(Key, Tex);
|
||||
}
|
||||
|
||||
Fb = new FrameBuffer(Width, Height, true);
|
||||
Tex.EnsureSetup(Width, Height, Format);
|
||||
}
|
||||
|
||||
SetupTexture(Fb.TexHandle, Width, Height);
|
||||
public void BindColor(long Key, int Attachment)
|
||||
{
|
||||
if (ColorTextures.TryGetValue(Key, out Texture Tex))
|
||||
{
|
||||
EnsureFrameBuffer();
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.Framebuffer,
|
||||
FramebufferAttachment.ColorAttachment0 + Attachment,
|
||||
Tex.Handle,
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnbindColor(Attachment);
|
||||
}
|
||||
}
|
||||
|
||||
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, Fb.RbHandle);
|
||||
|
||||
GL.RenderbufferStorage(
|
||||
RenderbufferTarget.Renderbuffer,
|
||||
RenderbufferStorage.Depth24Stencil8,
|
||||
Width,
|
||||
Height);
|
||||
|
||||
GL.FramebufferRenderbuffer(
|
||||
FramebufferTarget.Framebuffer,
|
||||
FramebufferAttachment.DepthStencilAttachment,
|
||||
RenderbufferTarget.Renderbuffer,
|
||||
Fb.RbHandle);
|
||||
public void UnbindColor(int Attachment)
|
||||
{
|
||||
EnsureFrameBuffer();
|
||||
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.Framebuffer,
|
||||
FramebufferAttachment.ColorAttachment0,
|
||||
Fb.TexHandle,
|
||||
FramebufferAttachment.ColorAttachment0 + Attachment,
|
||||
0,
|
||||
0);
|
||||
|
||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||
|
||||
Fbs.Add(Key, Fb);
|
||||
}
|
||||
|
||||
public void Bind(long Key)
|
||||
public void CreateZeta(long Key, int Width, int Height, GalZetaFormat Format)
|
||||
{
|
||||
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
||||
if (!ZetaTextures.TryGetValue(Key, out Texture Tex))
|
||||
{
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
|
||||
Tex = new Texture();
|
||||
|
||||
CurrFb = Fb;
|
||||
ZetaTextures.Add(Key, Tex);
|
||||
}
|
||||
|
||||
Tex.EnsureSetup(Width, Height, Format);
|
||||
}
|
||||
|
||||
public void BindZeta(long Key)
|
||||
{
|
||||
if (ZetaTextures.TryGetValue(Key, out Texture Tex))
|
||||
{
|
||||
EnsureFrameBuffer();
|
||||
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.Framebuffer,
|
||||
FramebufferAttachment.DepthStencilAttachment,
|
||||
Tex.Handle,
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnbindZeta();
|
||||
}
|
||||
}
|
||||
|
||||
public void UnbindZeta()
|
||||
{
|
||||
EnsureFrameBuffer();
|
||||
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.Framebuffer,
|
||||
FramebufferAttachment.DepthStencilAttachment,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
|
||||
public void BindTexture(long Key, int Index)
|
||||
{
|
||||
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
||||
Texture Tex;
|
||||
|
||||
if (ColorTextures.TryGetValue(Key, out Tex) ||
|
||||
ZetaTextures.TryGetValue(Key, out Tex))
|
||||
{
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Fb.TexHandle);
|
||||
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(long Key)
|
||||
{
|
||||
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
||||
if (ColorTextures.TryGetValue(Key, out Texture Tex))
|
||||
{
|
||||
CurrReadFb = Fb;
|
||||
ReadTex = Tex;
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(byte[] Data, int Width, int Height)
|
||||
{
|
||||
if (RawFb == null)
|
||||
if (RawTex == null)
|
||||
{
|
||||
CreateRawFb(Width, Height);
|
||||
RawTex = new Texture();
|
||||
}
|
||||
|
||||
if (RawFb.Width != Width ||
|
||||
RawFb.Height != Height)
|
||||
{
|
||||
SetupTexture(RawFb.TexHandle, Width, Height);
|
||||
RawTex.EnsureSetup(Width, Height, PixelInternalFormat.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||
|
||||
RawFb.Width = Width;
|
||||
RawFb.Height = Height;
|
||||
}
|
||||
GL.BindTexture(TextureTarget.Texture2D, RawTex.Handle);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, RawFb.TexHandle);
|
||||
|
||||
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
|
||||
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(RawFormat);
|
||||
|
||||
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, Format, Type, Data);
|
||||
|
||||
CurrReadFb = RawFb;
|
||||
ReadTex = RawTex;
|
||||
}
|
||||
|
||||
public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom)
|
||||
|
@ -209,60 +348,71 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public void Render()
|
||||
{
|
||||
if (CurrReadFb != null)
|
||||
if (ReadTex == null)
|
||||
{
|
||||
int SrcX0, SrcX1, SrcY0, SrcY1;
|
||||
|
||||
if (CropLeft == 0 && CropRight == 0)
|
||||
{
|
||||
SrcX0 = 0;
|
||||
SrcX1 = CurrReadFb.Width;
|
||||
}
|
||||
else
|
||||
{
|
||||
SrcX0 = CropLeft;
|
||||
SrcX1 = CropRight;
|
||||
}
|
||||
|
||||
if (CropTop == 0 && CropBottom == 0)
|
||||
{
|
||||
SrcY0 = 0;
|
||||
SrcY1 = CurrReadFb.Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
SrcY0 = CropTop;
|
||||
SrcY1 = CropBottom;
|
||||
}
|
||||
|
||||
float RatioX = MathF.Min(1f, (Window.Height * (float)NativeWidth) / ((float)NativeHeight * Window.Width));
|
||||
float RatioY = MathF.Min(1f, (Window.Width * (float)NativeHeight) / ((float)NativeWidth * Window.Height));
|
||||
|
||||
int DstWidth = (int)(Window.Width * RatioX);
|
||||
int DstHeight = (int)(Window.Height * RatioY);
|
||||
|
||||
int DstPaddingX = (Window.Width - DstWidth) / 2;
|
||||
int DstPaddingY = (Window.Height - DstHeight) / 2;
|
||||
|
||||
int DstX0 = FlipX ? Window.Width - DstPaddingX : DstPaddingX;
|
||||
int DstX1 = FlipX ? DstPaddingX : Window.Width - DstPaddingX;
|
||||
|
||||
int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
|
||||
int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
||||
|
||||
GL.Viewport(0, 0, Window.Width, Window.Height);
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, CurrReadFb.Handle);
|
||||
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
|
||||
|
||||
GL.BlitFramebuffer(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear);
|
||||
return;
|
||||
}
|
||||
|
||||
int SrcX0, SrcX1, SrcY0, SrcY1;
|
||||
|
||||
if (CropLeft == 0 && CropRight == 0)
|
||||
{
|
||||
SrcX0 = 0;
|
||||
SrcX1 = ReadTex.Width;
|
||||
}
|
||||
else
|
||||
{
|
||||
SrcX0 = CropLeft;
|
||||
SrcX1 = CropRight;
|
||||
}
|
||||
|
||||
if (CropTop == 0 && CropBottom == 0)
|
||||
{
|
||||
SrcY0 = 0;
|
||||
SrcY1 = ReadTex.Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
SrcY0 = CropTop;
|
||||
SrcY1 = CropBottom;
|
||||
}
|
||||
|
||||
float RatioX = MathF.Min(1f, (Window.Height * (float)NativeWidth) / ((float)NativeHeight * Window.Width));
|
||||
float RatioY = MathF.Min(1f, (Window.Width * (float)NativeHeight) / ((float)NativeWidth * Window.Height));
|
||||
|
||||
int DstWidth = (int)(Window.Width * RatioX);
|
||||
int DstHeight = (int)(Window.Height * RatioY);
|
||||
|
||||
int DstPaddingX = (Window.Width - DstWidth) / 2;
|
||||
int DstPaddingY = (Window.Height - DstHeight) / 2;
|
||||
|
||||
int DstX0 = FlipX ? Window.Width - DstPaddingX : DstPaddingX;
|
||||
int DstX1 = FlipX ? DstPaddingX : Window.Width - DstPaddingX;
|
||||
|
||||
int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
|
||||
int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
|
||||
|
||||
if (SrcFb == 0) SrcFb = GL.GenFramebuffer();
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
|
||||
|
||||
GL.Viewport(0, 0, Window.Width, Window.Height);
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
|
||||
|
||||
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, ReadTex.Handle, 0);
|
||||
|
||||
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
|
||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
|
||||
GL.BlitFramebuffer(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear);
|
||||
|
||||
EnsureFrameBuffer();
|
||||
}
|
||||
|
||||
public void Copy(
|
||||
|
@ -277,39 +427,61 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
int DstX1,
|
||||
int DstY1)
|
||||
{
|
||||
if (Fbs.TryGetValue(SrcKey, out FrameBuffer SrcFb) &&
|
||||
Fbs.TryGetValue(DstKey, out FrameBuffer DstFb))
|
||||
bool Found = false;
|
||||
|
||||
if (ColorTextures.TryGetValue(SrcKey, out Texture SrcTex) &&
|
||||
ColorTextures.TryGetValue(DstKey, out Texture DstTex))
|
||||
{
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb.Handle);
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb.Handle);
|
||||
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
|
||||
GL.BlitFramebuffer(
|
||||
CopyTextures(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
SrcTex.Handle,
|
||||
DstTex.Handle,
|
||||
FramebufferAttachment.ColorAttachment0,
|
||||
ClearBufferMask.ColorBufferBit,
|
||||
BlitFramebufferFilter.Linear);
|
||||
true);
|
||||
|
||||
Found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ZetaTextures.TryGetValue(SrcKey, out Texture ZetaSrcTex) &&
|
||||
ZetaTextures.TryGetValue(DstKey, out Texture ZetaDstTex))
|
||||
{
|
||||
CopyTextures(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
ZetaSrcTex.Handle,
|
||||
ZetaDstTex.Handle,
|
||||
FramebufferAttachment.DepthStencilAttachment,
|
||||
ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit,
|
||||
false);
|
||||
|
||||
Found = true;
|
||||
}
|
||||
|
||||
if (Found)
|
||||
{
|
||||
EnsureFrameBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
public void GetBufferData(long Key, Action<byte[]> Callback)
|
||||
{
|
||||
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
||||
Texture Tex;
|
||||
|
||||
if (ColorTextures.TryGetValue(Key, out Tex) ||
|
||||
ZetaTextures.TryGetValue(Key, out Tex))
|
||||
{
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, Fb.Handle);
|
||||
//Note: Change this value when framebuffer sizes are dehardcoded
|
||||
byte[] Data = new byte[Tex.Width * Tex.Height * MaxBpp];
|
||||
|
||||
byte[] Data = new byte[Fb.Width * Fb.Height * 4];
|
||||
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
|
||||
|
||||
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
|
||||
|
||||
GL.ReadPixels(
|
||||
GL.GetTexImage(
|
||||
TextureTarget.Texture2D,
|
||||
0,
|
||||
0,
|
||||
Fb.Width,
|
||||
Fb.Height,
|
||||
Format,
|
||||
Type,
|
||||
Tex.Format,
|
||||
Tex.Type,
|
||||
Data);
|
||||
|
||||
Callback(Data);
|
||||
|
@ -320,83 +492,88 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
long Key,
|
||||
int Width,
|
||||
int Height,
|
||||
GalTextureFormat Format,
|
||||
byte[] Buffer)
|
||||
{
|
||||
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
||||
Texture Tex;
|
||||
|
||||
if (ColorTextures.TryGetValue(Key, out Tex) ||
|
||||
ZetaTextures.TryGetValue(Key, out Tex))
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, Fb.TexHandle);
|
||||
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
|
||||
|
||||
const int Level = 0;
|
||||
const int Border = 0;
|
||||
|
||||
const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
|
||||
|
||||
(PixelFormat GlFormat, PixelType Type) = OGLEnumConverter.GetTextureFormat(Format);
|
||||
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
InternalFmt,
|
||||
Tex.InternalFormat,
|
||||
Width,
|
||||
Height,
|
||||
Border,
|
||||
GlFormat,
|
||||
Type,
|
||||
Tex.Format,
|
||||
Tex.Type,
|
||||
Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateRawFb(int Width, int Height)
|
||||
private void EnsureFrameBuffer()
|
||||
{
|
||||
if (RawFb == null)
|
||||
if (DummyFrameBuffer == 0)
|
||||
{
|
||||
RawFb = new FrameBuffer(Width, Height, false);
|
||||
|
||||
SetupTexture(RawFb.TexHandle, Width, Height);
|
||||
|
||||
RawFb.Width = Width;
|
||||
RawFb.Height = Height;
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, RawFb.Handle);
|
||||
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.Framebuffer,
|
||||
FramebufferAttachment.ColorAttachment0,
|
||||
RawFb.TexHandle,
|
||||
0);
|
||||
|
||||
GL.Viewport(0, 0, Width, Height);
|
||||
DummyFrameBuffer = GL.GenFramebuffer();
|
||||
}
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, DummyFrameBuffer);
|
||||
|
||||
GL.DrawBuffers(8, DrawBuffers);
|
||||
}
|
||||
|
||||
private void SetupTexture(int Handle, int Width, int Height)
|
||||
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)
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
if (SrcFb == 0) SrcFb = GL.GenFramebuffer();
|
||||
if (DstFb == 0) DstFb = GL.GenFramebuffer();
|
||||
|
||||
const int MinFilter = (int)TextureMinFilter.Linear;
|
||||
const int MagFilter = (int)TextureMagFilter.Linear;
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb);
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.ReadFramebuffer,
|
||||
Attachment,
|
||||
SrcTexture,
|
||||
0);
|
||||
|
||||
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
Attachment,
|
||||
DstTexture,
|
||||
0);
|
||||
|
||||
const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
|
||||
if (Color)
|
||||
{
|
||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||
}
|
||||
|
||||
const int Level = 0;
|
||||
const int Border = 0;
|
||||
GL.Clear(Mask);
|
||||
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
InternalFmt,
|
||||
Width,
|
||||
Height,
|
||||
Border,
|
||||
Format,
|
||||
Type,
|
||||
IntPtr.Zero);
|
||||
GL.BlitFramebuffer(
|
||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||
DstX0, DstY0, DstX1, DstY1,
|
||||
Mask,
|
||||
Color ? BlitFramebufferFilter.Linear : BlitFramebufferFilter.Nearest);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,17 +45,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public void ClearBuffers(
|
||||
GalClearBufferFlags Flags,
|
||||
int Attachment,
|
||||
float Red, float Green, float Blue, float Alpha,
|
||||
float Depth,
|
||||
int Stencil)
|
||||
{
|
||||
ClearBufferMask Mask = ClearBufferMask.ColorBufferBit;
|
||||
//TODO: Handle attachment
|
||||
|
||||
GL.ColorMask(
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorRed),
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorGreen),
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorBlue),
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorAlpha));
|
||||
ClearBufferMask Mask = ClearBufferMask.ColorBufferBit;
|
||||
|
||||
if (Flags.HasFlag(GalClearBufferFlags.Depth))
|
||||
{
|
||||
|
@ -67,6 +64,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
Mask |= ClearBufferMask.StencilBufferBit;
|
||||
}
|
||||
|
||||
GL.ColorMask(
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorRed),
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorGreen),
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorBlue),
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorAlpha));
|
||||
|
||||
GL.ClearColor(Red, Green, Blue, Alpha);
|
||||
|
||||
GL.ClearDepth(Depth);
|
||||
|
|
|
@ -154,16 +154,12 @@ namespace Ryujinx.HLE.Gpu.Engines
|
|||
}
|
||||
else if (IsDstFb)
|
||||
{
|
||||
//Texture -> Frame Buffer copy.
|
||||
const GalTextureFormat Format = GalTextureFormat.A8B8G8R8;
|
||||
|
||||
byte[] Buffer = TextureReader.Read(Vmm, SrcTexture());
|
||||
|
||||
Gpu.Renderer.FrameBuffer.SetBufferData(
|
||||
DstKey,
|
||||
DstWidth,
|
||||
DstHeight,
|
||||
Format,
|
||||
Buffer);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -104,6 +104,8 @@ namespace Ryujinx.HLE.Gpu.Engines
|
|||
|
||||
SetFrameBuffer(Vmm, 0);
|
||||
|
||||
SetZeta(Vmm);
|
||||
|
||||
long[] Keys = UploadShaders(Vmm);
|
||||
|
||||
Gpu.Renderer.Shader.BindProgram();
|
||||
|
@ -152,6 +154,7 @@ namespace Ryujinx.HLE.Gpu.Engines
|
|||
|
||||
Gpu.Renderer.Rasterizer.ClearBuffers(
|
||||
Flags,
|
||||
FbIndex,
|
||||
Red, Green, Blue, Alpha,
|
||||
Depth,
|
||||
Stencil);
|
||||
|
@ -161,13 +164,22 @@ namespace Ryujinx.HLE.Gpu.Engines
|
|||
{
|
||||
long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10);
|
||||
|
||||
int Format = ReadRegister(NvGpuEngine3dReg.FrameBufferNFormat + FbIndex * 0x10);
|
||||
|
||||
if (VA == 0 || Format == 0)
|
||||
{
|
||||
Gpu.Renderer.FrameBuffer.UnbindColor(FbIndex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
long Key = Vmm.GetPhysicalAddress(VA);
|
||||
|
||||
FrameBuffers.Add(Key);
|
||||
|
||||
int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10);
|
||||
int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10);
|
||||
|
||||
|
||||
float TX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateX + FbIndex * 4);
|
||||
float TY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateY + FbIndex * 4);
|
||||
|
||||
|
@ -180,12 +192,37 @@ namespace Ryujinx.HLE.Gpu.Engines
|
|||
int VpW = (int)(TX + MathF.Abs(SX)) - VpX;
|
||||
int VpH = (int)(TY + MathF.Abs(SY)) - VpY;
|
||||
|
||||
Gpu.Renderer.FrameBuffer.Create(Key, Width, Height);
|
||||
Gpu.Renderer.FrameBuffer.Bind(Key);
|
||||
Gpu.Renderer.FrameBuffer.CreateColor(Key, Width, Height, (GalFrameBufferFormat)Format);
|
||||
Gpu.Renderer.FrameBuffer.BindColor(Key, FbIndex);
|
||||
|
||||
Gpu.Renderer.FrameBuffer.SetViewport(VpX, VpY, VpW, VpH);
|
||||
}
|
||||
|
||||
private void SetZeta(NvGpuVmm Vmm)
|
||||
{
|
||||
long ZA = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress);
|
||||
|
||||
int Format = ReadRegister(NvGpuEngine3dReg.ZetaFormat);
|
||||
|
||||
bool ZetaEnable = (ReadRegister(NvGpuEngine3dReg.ZetaEnable) & 1) != 0;
|
||||
|
||||
if (ZA == 0 || Format == 0 || !ZetaEnable)
|
||||
{
|
||||
Gpu.Renderer.FrameBuffer.UnbindZeta();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
long Key = Vmm.GetPhysicalAddress(ZA);
|
||||
|
||||
int Width = ReadRegister(NvGpuEngine3dReg.ZetaHoriz);
|
||||
int Height = ReadRegister(NvGpuEngine3dReg.ZetaVert);
|
||||
|
||||
Gpu.Renderer.FrameBuffer.CreateZeta(Key, Width, Height, (GalZetaFormat)Format);
|
||||
|
||||
Gpu.Renderer.FrameBuffer.BindZeta(Key);
|
||||
}
|
||||
|
||||
private long[] UploadShaders(NvGpuVmm Vmm)
|
||||
{
|
||||
long[] Keys = new long[5];
|
||||
|
|
|
@ -51,6 +51,7 @@ namespace Ryujinx.HLE.Gpu.Engines
|
|||
StencilFrontFuncMask = 0x4e6,
|
||||
StencilFrontMask = 0x4e7,
|
||||
VertexArrayElemBase = 0x50d,
|
||||
ZetaEnable = 0x54e,
|
||||
TexHeaderPoolOffset = 0x55d,
|
||||
TexSamplerPoolOffset = 0x557,
|
||||
StencilTwoSideEnable = 0x565,
|
||||
|
|
Loading…
Add table
Reference in a new issue