2018-02-23 13:48:27 -08:00
|
|
|
using OpenTK;
|
2018-02-04 15:08:20 -08:00
|
|
|
using System;
|
2018-02-28 18:37:40 -08:00
|
|
|
using System.Collections.Concurrent;
|
2018-02-04 15:08:20 -08:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
2018-02-20 12:09:23 -08:00
|
|
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
2018-02-04 15:08:20 -08:00
|
|
|
{
|
|
|
|
public class OpenGLRenderer : IGalRenderer
|
|
|
|
{
|
2018-04-08 12:17:35 -07:00
|
|
|
private OGLBlend Blend;
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
private OGLFrameBuffer FrameBuffer;
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
private OGLRasterizer Rasterizer;
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
private OGLShader Shader;
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
private OGLTexture Texture;
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-02-28 18:37:40 -08:00
|
|
|
private ConcurrentQueue<Action> ActionsQueue;
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-02-23 13:48:27 -08:00
|
|
|
private FrameBuffer FbRenderer;
|
|
|
|
|
2018-02-04 15:08:20 -08:00
|
|
|
public OpenGLRenderer()
|
|
|
|
{
|
2018-04-08 12:17:35 -07:00
|
|
|
Blend = new OGLBlend();
|
|
|
|
|
|
|
|
FrameBuffer = new OGLFrameBuffer();
|
|
|
|
|
|
|
|
Rasterizer = new OGLRasterizer();
|
|
|
|
|
|
|
|
Shader = new OGLShader();
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
Texture = new OGLTexture();
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-02-28 18:37:40 -08:00
|
|
|
ActionsQueue = new ConcurrentQueue<Action>();
|
2018-02-04 15:08:20 -08:00
|
|
|
}
|
|
|
|
|
2018-02-23 13:48:27 -08:00
|
|
|
public void InitializeFrameBuffer()
|
|
|
|
{
|
|
|
|
FbRenderer = new FrameBuffer(1280, 720);
|
|
|
|
}
|
|
|
|
|
2018-03-11 21:04:52 -07:00
|
|
|
public void ResetFrameBuffer()
|
|
|
|
{
|
|
|
|
FbRenderer.Reset();
|
|
|
|
}
|
|
|
|
|
2018-02-04 15:08:20 -08:00
|
|
|
public void QueueAction(Action ActionMthd)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(ActionMthd);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void RunActions()
|
|
|
|
{
|
2018-02-23 13:48:27 -08:00
|
|
|
int Count = ActionsQueue.Count;
|
|
|
|
|
2018-02-28 18:37:40 -08:00
|
|
|
while (Count-- > 0 && ActionsQueue.TryDequeue(out Action RenderAction))
|
2018-02-04 15:08:20 -08:00
|
|
|
{
|
2018-02-28 18:37:40 -08:00
|
|
|
RenderAction();
|
2018-02-04 15:08:20 -08:00
|
|
|
}
|
2018-02-23 16:59:38 -08:00
|
|
|
}
|
2018-02-04 15:08:20 -08:00
|
|
|
|
|
|
|
public void Render()
|
|
|
|
{
|
2018-04-10 12:56:03 -07:00
|
|
|
FbRenderer.Render();
|
2018-02-23 13:48:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
public void SetWindowSize(int Width, int Height)
|
|
|
|
{
|
|
|
|
FbRenderer.WindowWidth = Width;
|
|
|
|
FbRenderer.WindowHeight = Height;
|
|
|
|
}
|
|
|
|
|
|
|
|
public unsafe void SetFrameBuffer(
|
|
|
|
byte* Fb,
|
|
|
|
int Width,
|
|
|
|
int Height,
|
|
|
|
float ScaleX,
|
|
|
|
float ScaleY,
|
2018-02-28 18:37:40 -08:00
|
|
|
float OffsX,
|
|
|
|
float OffsY,
|
2018-02-23 13:48:27 -08:00
|
|
|
float Rotate)
|
|
|
|
{
|
|
|
|
Matrix2 Transform;
|
|
|
|
|
|
|
|
Transform = Matrix2.CreateScale(ScaleX, ScaleY);
|
|
|
|
Transform *= Matrix2.CreateRotation(Rotate);
|
|
|
|
|
2018-02-28 18:37:40 -08:00
|
|
|
Vector2 Offs = new Vector2(OffsX, OffsY);
|
|
|
|
|
|
|
|
FbRenderer.Set(Fb, Width, Height, Transform, Offs);
|
2018-02-04 15:08:20 -08:00
|
|
|
}
|
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
public void SetBlendEnable(bool Enable)
|
2018-02-04 15:08:20 -08:00
|
|
|
{
|
2018-04-08 12:17:35 -07:00
|
|
|
if (Enable)
|
2018-02-04 15:08:20 -08:00
|
|
|
{
|
2018-04-08 12:17:35 -07:00
|
|
|
ActionsQueue.Enqueue(() => Blend.Enable());
|
2018-02-04 15:08:20 -08:00
|
|
|
}
|
2018-04-08 12:17:35 -07:00
|
|
|
else
|
2018-02-04 15:08:20 -08:00
|
|
|
{
|
2018-04-08 12:17:35 -07:00
|
|
|
ActionsQueue.Enqueue(() => Blend.Disable());
|
2018-02-04 15:08:20 -08:00
|
|
|
}
|
2018-04-08 12:17:35 -07:00
|
|
|
}
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
public void SetBlend(
|
|
|
|
GalBlendEquation Equation,
|
|
|
|
GalBlendFactor FuncSrc,
|
|
|
|
GalBlendFactor FuncDst)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => Blend.Set(Equation, FuncSrc, FuncDst));
|
|
|
|
}
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
public void SetBlendSeparate(
|
|
|
|
GalBlendEquation EquationRgb,
|
|
|
|
GalBlendEquation EquationAlpha,
|
|
|
|
GalBlendFactor FuncSrcRgb,
|
|
|
|
GalBlendFactor FuncDstRgb,
|
|
|
|
GalBlendFactor FuncSrcAlpha,
|
|
|
|
GalBlendFactor FuncDstAlpha)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() =>
|
|
|
|
{
|
|
|
|
Blend.SetSeparate(
|
|
|
|
EquationRgb,
|
|
|
|
EquationAlpha,
|
|
|
|
FuncSrcRgb,
|
|
|
|
FuncDstRgb,
|
|
|
|
FuncSrcAlpha,
|
|
|
|
FuncDstAlpha);
|
|
|
|
});
|
|
|
|
}
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
public void SetFb(int FbIndex, int Width, int Height)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => FrameBuffer.Set(FbIndex, Width, Height));
|
|
|
|
}
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
public void BindFrameBuffer(int FbIndex)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => FrameBuffer.Bind(FbIndex));
|
|
|
|
}
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
public void DrawFrameBuffer(int FbIndex)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => FrameBuffer.Draw(FbIndex));
|
|
|
|
}
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => Rasterizer.ClearBuffers(RtIndex, Flags));
|
|
|
|
}
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
public void SetVertexArray(int VbIndex, int Stride, byte[] Buffer, GalVertexAttrib[] Attribs)
|
|
|
|
{
|
|
|
|
if ((uint)VbIndex > 31)
|
2018-02-04 15:08:20 -08:00
|
|
|
{
|
2018-04-08 12:17:35 -07:00
|
|
|
throw new ArgumentOutOfRangeException(nameof(VbIndex));
|
2018-02-04 15:08:20 -08:00
|
|
|
}
|
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
ActionsQueue.Enqueue(() => Rasterizer.SetVertexArray(VbIndex, Stride,
|
|
|
|
Buffer ?? throw new ArgumentNullException(nameof(Buffer)),
|
|
|
|
Attribs ?? throw new ArgumentNullException(nameof(Attribs))));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetIndexArray(byte[] Buffer, GalIndexFormat Format)
|
|
|
|
{
|
|
|
|
if (Buffer == null)
|
2018-02-04 15:08:20 -08:00
|
|
|
{
|
2018-04-08 12:17:35 -07:00
|
|
|
throw new ArgumentNullException(nameof(Buffer));
|
2018-02-04 15:08:20 -08:00
|
|
|
}
|
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
ActionsQueue.Enqueue(() => Rasterizer.SetIndexArray(Buffer, Format));
|
2018-02-04 15:08:20 -08:00
|
|
|
}
|
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
public void DrawArrays(int VbIndex, GalPrimitiveType PrimType)
|
2018-02-04 15:08:20 -08:00
|
|
|
{
|
2018-04-08 12:17:35 -07:00
|
|
|
if ((uint)VbIndex > 31)
|
|
|
|
{
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(VbIndex));
|
|
|
|
}
|
|
|
|
|
|
|
|
ActionsQueue.Enqueue(() => Rasterizer.DrawArrays(VbIndex, PrimType));
|
2018-02-04 15:08:20 -08:00
|
|
|
}
|
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
public void DrawElements(int VbIndex, int First, GalPrimitiveType PrimType)
|
2018-02-04 15:08:20 -08:00
|
|
|
{
|
2018-04-08 12:17:35 -07:00
|
|
|
if ((uint)VbIndex > 31)
|
|
|
|
{
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(VbIndex));
|
|
|
|
}
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
ActionsQueue.Enqueue(() => Rasterizer.DrawElements(VbIndex, First, PrimType));
|
2018-02-04 15:08:20 -08:00
|
|
|
}
|
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
public void CreateShader(long Tag, GalShaderType Type, byte[] Data)
|
2018-02-04 15:08:20 -08:00
|
|
|
{
|
2018-04-08 12:17:35 -07:00
|
|
|
if (Data == null)
|
2018-02-04 15:08:20 -08:00
|
|
|
{
|
2018-04-08 12:17:35 -07:00
|
|
|
throw new ArgumentNullException(nameof(Data));
|
2018-02-04 15:08:20 -08:00
|
|
|
}
|
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
Shader.Create(Tag, Type, Data);
|
|
|
|
}
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
public void SetConstBuffer(long Tag, int Cbuf, byte[] Data)
|
|
|
|
{
|
|
|
|
if (Data == null)
|
2018-02-04 15:08:20 -08:00
|
|
|
{
|
2018-04-08 12:17:35 -07:00
|
|
|
throw new ArgumentNullException(nameof(Data));
|
2018-02-04 15:08:20 -08:00
|
|
|
}
|
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
ActionsQueue.Enqueue(() => Shader.SetConstBuffer(Tag, Cbuf, Data));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetUniform1(string UniformName, int Value)
|
|
|
|
{
|
|
|
|
if (UniformName == null)
|
2018-02-04 15:08:20 -08:00
|
|
|
{
|
2018-04-08 12:17:35 -07:00
|
|
|
throw new ArgumentNullException(nameof(UniformName));
|
2018-02-04 15:08:20 -08:00
|
|
|
}
|
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
ActionsQueue.Enqueue(() => Shader.SetUniform1(UniformName, Value));
|
2018-02-04 15:08:20 -08:00
|
|
|
}
|
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Tag)
|
2018-02-04 15:08:20 -08:00
|
|
|
{
|
2018-04-08 12:17:35 -07:00
|
|
|
return Shader.GetTextureUsage(Tag);
|
|
|
|
}
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
public void BindShader(long Tag)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => Shader.Bind(Tag));
|
|
|
|
}
|
2018-02-04 15:08:20 -08:00
|
|
|
|
2018-04-08 12:17:35 -07:00
|
|
|
public void BindProgram()
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => Shader.BindProgram());
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetTexture(int Index, GalTexture Tex)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => Texture.Set(Index, Tex));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetSampler(int Index, GalTextureSampler Sampler)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => Texture.Set(Index, Sampler));
|
2018-02-04 15:08:20 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|