| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- using OpenTK;
- using OpenTK.Graphics.OpenGL;
- using System;
- using System.Collections.Generic;
- namespace Ryujinx.Graphics.Gal.OpenGL
- {
- public class OGLFrameBuffer : IGalFrameBuffer
- {
- private struct Rect
- {
- public int X { get; private set; }
- public int Y { get; private set; }
- public int Width { get; private set; }
- public int Height { get; private set; }
- public Rect(int X, int Y, int Width, int Height)
- {
- this.X = X;
- this.Y = Y;
- this.Width = Width;
- this.Height = Height;
- }
- }
- private class FrameBuffer
- {
- public int Width { get; set; }
- public int Height { get; 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)
- {
- this.Width = Width;
- this.Height = Height;
- Handle = GL.GenFramebuffer();
- RbHandle = GL.GenRenderbuffer();
- TexHandle = GL.GenTexture();
- }
- }
- private struct ShaderProgram
- {
- public int Handle;
- public int VpHandle;
- public int FpHandle;
- }
- private Dictionary<long, FrameBuffer> Fbs;
- private ShaderProgram Shader;
- private Rect Viewport;
- private Rect Window;
- private bool IsInitialized;
- private int RawFbTexWidth;
- private int RawFbTexHeight;
- private int RawFbTexHandle;
- private int CurrFbHandle;
- private int CurrTexHandle;
- private int VaoHandle;
- private int VboHandle;
- public OGLFrameBuffer()
- {
- Fbs = new Dictionary<long, FrameBuffer>();
- Shader = new ShaderProgram();
- }
- public void Create(long Key, int Width, int Height)
- {
- //TODO: We should either use the original frame buffer size,
- //or just remove the Width/Height arguments.
- Width = Window.Width;
- Height = Window.Height;
- if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
- {
- if (Fb.Width != Width ||
- Fb.Height != Height)
- {
- SetupTexture(Fb.TexHandle, Width, Height);
- Fb.Width = Width;
- Fb.Height = Height;
- }
- return;
- }
- Fb = new FrameBuffer(Width, Height);
- 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);
- GL.FramebufferTexture(
- FramebufferTarget.Framebuffer,
- FramebufferAttachment.ColorAttachment0,
- Fb.TexHandle,
- 0);
- GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
- GL.Viewport(0, 0, Width, Height);
- Fbs.Add(Key, Fb);
- }
- public void Bind(long Key)
- {
- if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
- {
- GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
- CurrFbHandle = Fb.Handle;
- }
- }
- public void BindTexture(long Key, int Index)
- {
- if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
- {
- GL.ActiveTexture(TextureUnit.Texture0 + Index);
- GL.BindTexture(TextureTarget.Texture2D, Fb.TexHandle);
- }
- }
- public void Set(long Key)
- {
- if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
- {
- CurrTexHandle = Fb.TexHandle;
- }
- }
- public void Set(byte[] Data, int Width, int Height)
- {
- if (RawFbTexHandle == 0)
- {
- RawFbTexHandle = GL.GenTexture();
- }
- if (RawFbTexWidth != Width ||
- RawFbTexHeight != Height)
- {
- SetupTexture(RawFbTexHandle, Width, Height);
- RawFbTexWidth = Width;
- RawFbTexHeight = Height;
- }
- GL.ActiveTexture(TextureUnit.Texture0);
- GL.BindTexture(TextureTarget.Texture2D, RawFbTexHandle);
- (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
- GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, Format, Type, Data);
- CurrTexHandle = RawFbTexHandle;
- }
- public void SetTransform(float SX, float SY, float Rotate, float TX, float TY)
- {
- EnsureInitialized();
- Matrix2 Transform;
- Transform = Matrix2.CreateScale(SX, SY);
- Transform *= Matrix2.CreateRotation(Rotate);
- Vector2 Offs = new Vector2(TX, TY);
- int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram);
- GL.UseProgram(Shader.Handle);
- int TransformUniformLocation = GL.GetUniformLocation(Shader.Handle, "transform");
- GL.UniformMatrix2(TransformUniformLocation, false, ref Transform);
- int OffsetUniformLocation = GL.GetUniformLocation(Shader.Handle, "offset");
- GL.Uniform2(OffsetUniformLocation, ref Offs);
- GL.UseProgram(CurrentProgram);
- }
- public void SetWindowSize(int Width, int Height)
- {
- int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram);
- GL.UseProgram(Shader.Handle);
- int WindowSizeUniformLocation = GL.GetUniformLocation(Shader.Handle, "window_size");
- GL.Uniform2(WindowSizeUniformLocation, new Vector2(Width, Height));
- GL.UseProgram(CurrentProgram);
- Window = new Rect(0, 0, Width, Height);
- }
- public void SetViewport(int X, int Y, int Width, int Height)
- {
- Viewport = new Rect(X, Y, Width, Height);
- //TODO
- }
- public void Render()
- {
- if (CurrTexHandle != 0)
- {
- EnsureInitialized();
- //bool CullFaceEnable = GL.IsEnabled(EnableCap.CullFace);
- bool DepthTestEnable = GL.IsEnabled(EnableCap.DepthTest);
- bool StencilTestEnable = GL.IsEnabled(EnableCap.StencilTest);
- bool AlphaBlendEnable = GL.IsEnabled(EnableCap.Blend);
- //GL.Disable(EnableCap.CullFace);
- GL.Disable(EnableCap.DepthTest);
- GL.Disable(EnableCap.StencilTest);
- GL.Disable(EnableCap.Blend);
- GL.ActiveTexture(TextureUnit.Texture0);
- GL.BindTexture(TextureTarget.Texture2D, CurrTexHandle);
- int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram);
- GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
- SetViewport(Window);
- GL.Clear(
- ClearBufferMask.ColorBufferBit |
- ClearBufferMask.DepthBufferBit);
- GL.BindVertexArray(VaoHandle);
- GL.UseProgram(Shader.Handle);
- GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
- //Restore the original state.
- GL.BindFramebuffer(FramebufferTarget.Framebuffer, CurrFbHandle);
- GL.UseProgram(CurrentProgram);
- //if (CullFaceEnable)
- //{
- // GL.Enable(EnableCap.CullFace);
- //}
- if (DepthTestEnable)
- {
- GL.Enable(EnableCap.DepthTest);
- }
- if (StencilTestEnable)
- {
- GL.Enable(EnableCap.StencilTest);
- }
- if (AlphaBlendEnable)
- {
- GL.Enable(EnableCap.Blend);
- }
- //GL.Viewport(0, 0, 1280, 720);
- }
- }
- public void GetBufferData(long Key, Action<byte[]> Callback)
- {
- if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
- {
- GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, Fb.Handle);
- byte[] Data = new byte[Fb.Width * Fb.Height * 4];
- (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
- GL.ReadPixels(
- 0,
- 0,
- Fb.Width,
- Fb.Height,
- Format,
- Type,
- Data);
- Callback(Data);
- GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, CurrFbHandle);
- }
- }
- private void SetViewport(Rect Viewport)
- {
- GL.Viewport(
- Viewport.X,
- Viewport.Y,
- Viewport.Width,
- Viewport.Height);
- }
- private void EnsureInitialized()
- {
- if (!IsInitialized)
- {
- IsInitialized = true;
- SetupShader();
- SetupVertex();
- }
- }
- private void SetupShader()
- {
- Shader.VpHandle = GL.CreateShader(ShaderType.VertexShader);
- Shader.FpHandle = GL.CreateShader(ShaderType.FragmentShader);
- string VpSource = EmbeddedResource.GetString("GlFbVtxShader");
- string FpSource = EmbeddedResource.GetString("GlFbFragShader");
- GL.ShaderSource(Shader.VpHandle, VpSource);
- GL.ShaderSource(Shader.FpHandle, FpSource);
- GL.CompileShader(Shader.VpHandle);
- GL.CompileShader(Shader.FpHandle);
- Shader.Handle = GL.CreateProgram();
- GL.AttachShader(Shader.Handle, Shader.VpHandle);
- GL.AttachShader(Shader.Handle, Shader.FpHandle);
- GL.LinkProgram(Shader.Handle);
- GL.UseProgram(Shader.Handle);
- Matrix2 Transform = Matrix2.Identity;
- int TexUniformLocation = GL.GetUniformLocation(Shader.Handle, "tex");
- GL.Uniform1(TexUniformLocation, 0);
- int WindowSizeUniformLocation = GL.GetUniformLocation(Shader.Handle, "window_size");
- GL.Uniform2(WindowSizeUniformLocation, new Vector2(1280.0f, 720.0f));
- int TransformUniformLocation = GL.GetUniformLocation(Shader.Handle, "transform");
- GL.UniformMatrix2(TransformUniformLocation, false, ref Transform);
- }
- private void SetupVertex()
- {
- VaoHandle = GL.GenVertexArray();
- VboHandle = GL.GenBuffer();
- float[] Buffer = new float[]
- {
- -1, 1, 0, 0,
- 1, 1, 1, 0,
- -1, -1, 0, 1,
- 1, -1, 1, 1
- };
- IntPtr Length = new IntPtr(Buffer.Length * 4);
- GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
- GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
- GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
- GL.BindVertexArray(VaoHandle);
- GL.EnableVertexAttribArray(0);
- GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
- GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 16, 0);
- GL.EnableVertexAttribArray(1);
- GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
- GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 16, 8);
- }
- private void SetupTexture(int Handle, int Width, int Height)
- {
- 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);
- (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);
- }
- }
- }
|