Use textures for framebuffers and split color and zeta framebuffers

This commit is contained in:
ReinUsesLisp 2018-08-05 20:30:25 -03:00
commit b723bd5e4a
10 changed files with 557 additions and 218 deletions

View file

@ -19,7 +19,7 @@
RG32Sint = 0xcc,
RG32Uint = 0xcd,
RGBX16Float = 0xce,
BGRA8Unorm = 0x0cf,
BGRA8Unorm = 0xcf,
BGRA8Srgb = 0xd0,
RGB10A2Unorm = 0xd1,
RGB10A2Uint = 0xd2,

View file

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

View file

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

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

View file

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

View file

@ -23,43 +23,156 @@ namespace Ryujinx.Graphics.Gal.OpenGL
}
}
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 PixelInternalFormat InternalFormat { get; private set; }
public PixelFormat Format { get; private set; }
public PixelType Type { get; private set; }
public int Handle { get; private set; }
public int RbHandle { get; private set; }
public int TexHandle { get; private set; }
public FrameBuffer(int Width, int Height, bool HasRenderBuffer)
private bool Initialized;
public Texture()
{
Handle = GL.GenTexture();
}
public void EnsureSetup(
int Width,
int Height,
PixelInternalFormat InternalFormat,
PixelFormat Format,
PixelType Type)
{
if (!Initialized ||
this.Width != Width ||
this.Height != Height ||
this.InternalFormat != InternalFormat)
{
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;
Handle = GL.GenFramebuffer();
TexHandle = GL.GenTexture();
Initialized = true;
}
}
if (HasRenderBuffer)
public void EnsureSetup(int Width, int Height, GalFrameBufferFormat Format)
{
RbHandle = GL.GenRenderbuffer();
}
//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;
ColorTextures.Add(Key, Tex);
}
return;
Tex.EnsureSetup(Width, Height, Format);
}
Fb = new FrameBuffer(Width, Height, true);
SetupTexture(Fb.TexHandle, Width, Height);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
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 BindColor(long Key, int Attachment)
{
if (ColorTextures.TryGetValue(Key, out Texture Tex))
{
EnsureFrameBuffer();
GL.FramebufferTexture(
FramebufferTarget.Framebuffer,
FramebufferAttachment.ColorAttachment0,
Fb.TexHandle,
FramebufferAttachment.ColorAttachment0 + Attachment,
Tex.Handle,
0);
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
Fbs.Add(Key, Fb);
}
else
{
UnbindColor(Attachment);
}
}
public void Bind(long Key)
public void UnbindColor(int Attachment)
{
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
EnsureFrameBuffer();
CurrFb = Fb;
GL.FramebufferTexture(
FramebufferTarget.Framebuffer,
FramebufferAttachment.ColorAttachment0 + Attachment,
0,
0);
}
public void CreateZeta(long Key, int Width, int Height, GalZetaFormat Format)
{
if (!ZetaTextures.TryGetValue(Key, out Texture Tex))
{
Tex = new Texture();
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,14 +348,17 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public void Render()
{
if (CurrReadFb != null)
if (ReadTex == null)
{
return;
}
int SrcX0, SrcX1, SrcY0, SrcY1;
if (CropLeft == 0 && CropRight == 0)
{
SrcX0 = 0;
SrcX1 = CurrReadFb.Width;
SrcX1 = ReadTex.Width;
}
else
{
@ -227,7 +369,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
if (CropTop == 0 && CropBottom == 0)
{
SrcY0 = 0;
SrcY1 = CurrReadFb.Height;
SrcY1 = ReadTex.Height;
}
else
{
@ -250,19 +392,27 @@ namespace Ryujinx.Graphics.Gal.OpenGL
int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
if (SrcFb == 0) SrcFb = GL.GenFramebuffer();
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
GL.Viewport(0, 0, Window.Width, Window.Height);
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, CurrReadFb.Handle);
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
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);
DummyFrameBuffer = GL.GenFramebuffer();
}
SetupTexture(RawFb.TexHandle, Width, Height);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, DummyFrameBuffer);
RawFb.Width = Width;
RawFb.Height = Height;
GL.DrawBuffers(8, DrawBuffers);
}
GL.BindFramebuffer(FramebufferTarget.Framebuffer, RawFb.Handle);
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.Framebuffer,
FramebufferAttachment.ColorAttachment0,
RawFb.TexHandle,
FramebufferTarget.ReadFramebuffer,
Attachment,
SrcTexture,
0);
GL.Viewport(0, 0, Width, Height);
}
}
GL.FramebufferTexture(
FramebufferTarget.DrawFramebuffer,
Attachment,
DstTexture,
0);
private void SetupTexture(int Handle, int Width, int Height)
if (Color)
{
GL.BindTexture(TextureTarget.Texture2D, Handle);
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
}
const int MinFilter = (int)TextureMinFilter.Linear;
const int MagFilter = (int)TextureMagFilter.Linear;
GL.Clear(Mask);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
const int Level = 0;
const int Border = 0;
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);
}
}
}

View file

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

View file

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

View file

@ -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,6 +164,15 @@ 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);
@ -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];

View file

@ -51,6 +51,7 @@ namespace Ryujinx.HLE.Gpu.Engines
StencilFrontFuncMask = 0x4e6,
StencilFrontMask = 0x4e7,
VertexArrayElemBase = 0x50d,
ZetaEnable = 0x54e,
TexHeaderPoolOffset = 0x55d,
TexSamplerPoolOffset = 0x557,
StencilTwoSideEnable = 0x565,