2018-02-23 22:48:27 +01:00
|
|
|
using OpenTK;
|
2018-02-05 00:08:20 +01:00
|
|
|
using System;
|
2018-03-01 03:37:40 +01:00
|
|
|
using System.Collections.Concurrent;
|
2018-02-05 00:08:20 +01:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
2018-02-20 21:09:23 +01:00
|
|
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
2018-02-05 00:08:20 +01:00
|
|
|
{
|
|
|
|
public class OpenGLRenderer : IGalRenderer
|
|
|
|
{
|
2018-04-08 21:17:35 +02:00
|
|
|
private OGLBlend Blend;
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-04-08 21:17:35 +02:00
|
|
|
private OGLFrameBuffer FrameBuffer;
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-04-08 21:17:35 +02:00
|
|
|
private OGLRasterizer Rasterizer;
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-04-08 21:17:35 +02:00
|
|
|
private OGLShader Shader;
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-04-08 21:17:35 +02:00
|
|
|
private OGLTexture Texture;
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-03-01 03:37:40 +01:00
|
|
|
private ConcurrentQueue<Action> ActionsQueue;
|
2018-02-05 00:08:20 +01:00
|
|
|
|
|
|
|
public OpenGLRenderer()
|
|
|
|
{
|
2018-04-08 21:17:35 +02:00
|
|
|
Blend = new OGLBlend();
|
|
|
|
|
|
|
|
FrameBuffer = new OGLFrameBuffer();
|
|
|
|
|
|
|
|
Rasterizer = new OGLRasterizer();
|
|
|
|
|
|
|
|
Shader = new OGLShader();
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-04-08 21:17:35 +02:00
|
|
|
Texture = new OGLTexture();
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-03-01 03:37:40 +01:00
|
|
|
ActionsQueue = new ConcurrentQueue<Action>();
|
2018-02-05 00:08:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public void QueueAction(Action ActionMthd)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(ActionMthd);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void RunActions()
|
|
|
|
{
|
2018-02-23 22:48:27 +01:00
|
|
|
int Count = ActionsQueue.Count;
|
|
|
|
|
2018-03-01 03:37:40 +01:00
|
|
|
while (Count-- > 0 && ActionsQueue.TryDequeue(out Action RenderAction))
|
2018-02-05 00:08:20 +01:00
|
|
|
{
|
2018-03-01 03:37:40 +01:00
|
|
|
RenderAction();
|
2018-02-05 00:08:20 +01:00
|
|
|
}
|
2018-02-24 01:59:38 +01:00
|
|
|
}
|
2018-02-05 00:08:20 +01:00
|
|
|
|
|
|
|
public void Render()
|
|
|
|
{
|
2018-04-13 20:12:58 +02:00
|
|
|
FrameBuffer.Render();
|
2018-02-23 22:48:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public void SetWindowSize(int Width, int Height)
|
|
|
|
{
|
2018-04-14 06:14:42 +02:00
|
|
|
FrameBuffer.SetWindowSize(Width, Height);
|
2018-02-05 00:08:20 +01:00
|
|
|
}
|
|
|
|
|
2018-04-08 21:17:35 +02:00
|
|
|
public void SetBlendEnable(bool Enable)
|
2018-02-05 00:08:20 +01:00
|
|
|
{
|
2018-04-08 21:17:35 +02:00
|
|
|
if (Enable)
|
2018-02-05 00:08:20 +01:00
|
|
|
{
|
2018-04-08 21:17:35 +02:00
|
|
|
ActionsQueue.Enqueue(() => Blend.Enable());
|
2018-02-05 00:08:20 +01:00
|
|
|
}
|
2018-04-08 21:17:35 +02:00
|
|
|
else
|
2018-02-05 00:08:20 +01:00
|
|
|
{
|
2018-04-08 21:17:35 +02:00
|
|
|
ActionsQueue.Enqueue(() => Blend.Disable());
|
2018-02-05 00:08:20 +01:00
|
|
|
}
|
2018-04-08 21:17:35 +02:00
|
|
|
}
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-04-08 21:17:35 +02:00
|
|
|
public void SetBlend(
|
|
|
|
GalBlendEquation Equation,
|
|
|
|
GalBlendFactor FuncSrc,
|
|
|
|
GalBlendFactor FuncDst)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => Blend.Set(Equation, FuncSrc, FuncDst));
|
|
|
|
}
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-04-08 21:17:35 +02: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-05 00:08:20 +01:00
|
|
|
|
2018-04-13 20:12:58 +02:00
|
|
|
public void CreateFrameBuffer(long Tag, int Width, int Height)
|
2018-04-08 21:17:35 +02:00
|
|
|
{
|
2018-04-13 20:12:58 +02:00
|
|
|
ActionsQueue.Enqueue(() => FrameBuffer.Create(Tag, Width, Height));
|
2018-04-08 21:17:35 +02:00
|
|
|
}
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-04-13 20:12:58 +02:00
|
|
|
public void BindFrameBuffer(long Tag)
|
2018-04-08 21:17:35 +02:00
|
|
|
{
|
2018-04-13 20:12:58 +02:00
|
|
|
ActionsQueue.Enqueue(() => FrameBuffer.Bind(Tag));
|
2018-04-08 21:17:35 +02:00
|
|
|
}
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-04-13 20:12:58 +02:00
|
|
|
public void BindFrameBufferTexture(long Tag, int Index, GalTextureSampler Sampler)
|
2018-04-08 21:17:35 +02:00
|
|
|
{
|
2018-04-13 20:12:58 +02:00
|
|
|
ActionsQueue.Enqueue(() =>
|
|
|
|
{
|
|
|
|
FrameBuffer.BindTexture(Tag, Index);
|
|
|
|
|
|
|
|
OGLTexture.Set(Sampler);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetFrameBuffer(long Tag)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => FrameBuffer.Set(Tag));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetFrameBuffer(byte[] Data, int Width, int Height)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => FrameBuffer.Set(Data, Width, Height));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetFrameBufferTransform(float SX, float SY, float Rotate, float TX, float TY)
|
|
|
|
{
|
|
|
|
Matrix2 Transform;
|
|
|
|
|
|
|
|
Transform = Matrix2.CreateScale(SX, SY);
|
|
|
|
Transform *= Matrix2.CreateRotation(Rotate);
|
|
|
|
|
|
|
|
Vector2 Offs = new Vector2(TX, TY);
|
|
|
|
|
|
|
|
ActionsQueue.Enqueue(() => FrameBuffer.SetTransform(Transform, Offs));
|
2018-04-08 21:17:35 +02:00
|
|
|
}
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-04-14 05:39:24 +02:00
|
|
|
public void SetViewport(int X, int Y, int Width, int Height)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => FrameBuffer.SetViewport(X, Y, Width, Height));
|
|
|
|
}
|
|
|
|
|
2018-04-26 04:11:26 +02:00
|
|
|
public void GetFrameBufferData(long Tag, Action<byte[]> Callback)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => FrameBuffer.GetBufferData(Tag, Callback));
|
|
|
|
}
|
|
|
|
|
2018-04-08 21:17:35 +02:00
|
|
|
public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => Rasterizer.ClearBuffers(RtIndex, Flags));
|
|
|
|
}
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-06-09 02:15:56 +02:00
|
|
|
public bool IsVboCached(long Tag, long DataSize)
|
2018-04-08 21:17:35 +02:00
|
|
|
{
|
2018-06-09 02:15:56 +02:00
|
|
|
return Rasterizer.IsVboCached(Tag, DataSize);
|
|
|
|
}
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-06-09 02:15:56 +02:00
|
|
|
public bool IsIboCached(long Tag, long DataSize)
|
|
|
|
{
|
|
|
|
return Rasterizer.IsIboCached(Tag, DataSize);
|
2018-04-08 21:17:35 +02:00
|
|
|
}
|
|
|
|
|
2018-06-09 02:15:56 +02:00
|
|
|
public void CreateVbo(long Tag, byte[] Buffer)
|
2018-04-08 21:17:35 +02:00
|
|
|
{
|
2018-06-09 02:15:56 +02:00
|
|
|
ActionsQueue.Enqueue(() => Rasterizer.CreateVbo(Tag, Buffer));
|
|
|
|
}
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-06-09 02:15:56 +02:00
|
|
|
public void CreateIbo(long Tag, byte[] Buffer)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => Rasterizer.CreateIbo(Tag, Buffer));
|
2018-02-05 00:08:20 +01:00
|
|
|
}
|
|
|
|
|
2018-06-09 02:15:56 +02:00
|
|
|
public void SetVertexArray(int VbIndex, int Stride, long VboTag, GalVertexAttrib[] Attribs)
|
2018-02-05 00:08:20 +01:00
|
|
|
{
|
2018-04-08 21:17:35 +02:00
|
|
|
if ((uint)VbIndex > 31)
|
|
|
|
{
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(VbIndex));
|
|
|
|
}
|
|
|
|
|
2018-06-09 02:15:56 +02:00
|
|
|
if (Attribs == null)
|
|
|
|
{
|
|
|
|
throw new ArgumentNullException(nameof(Attribs));
|
|
|
|
}
|
|
|
|
|
|
|
|
ActionsQueue.Enqueue(() => Rasterizer.SetVertexArray(VbIndex, Stride, VboTag, Attribs));
|
2018-02-05 00:08:20 +01:00
|
|
|
}
|
|
|
|
|
2018-06-09 02:15:56 +02:00
|
|
|
public void SetIndexArray(long Tag, int Size, GalIndexFormat Format)
|
2018-02-05 00:08:20 +01:00
|
|
|
{
|
2018-06-09 02:15:56 +02:00
|
|
|
ActionsQueue.Enqueue(() => Rasterizer.SetIndexArray(Tag, Size, Format));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void DrawArrays(int First, int PrimCount, GalPrimitiveType PrimType)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => Rasterizer.DrawArrays(First, PrimCount, PrimType));
|
|
|
|
}
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-06-09 02:15:56 +02:00
|
|
|
public void DrawElements(long IboTag, int First, GalPrimitiveType PrimType)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => Rasterizer.DrawElements(IboTag, First, PrimType));
|
2018-02-05 00:08:20 +01:00
|
|
|
}
|
|
|
|
|
2018-05-23 03:43:31 +02:00
|
|
|
public void CreateShader(IGalMemory Memory, long Tag, GalShaderType Type)
|
2018-02-05 00:08:20 +01:00
|
|
|
{
|
2018-05-23 03:43:31 +02:00
|
|
|
if (Memory == null)
|
2018-02-05 00:08:20 +01:00
|
|
|
{
|
2018-05-23 03:43:31 +02:00
|
|
|
throw new ArgumentNullException(nameof(Memory));
|
2018-02-05 00:08:20 +01:00
|
|
|
}
|
|
|
|
|
2018-05-23 03:43:31 +02:00
|
|
|
Shader.Create(Memory, Tag, Type);
|
2018-04-08 21:17:35 +02:00
|
|
|
}
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-04-08 21:17:35 +02:00
|
|
|
public void SetConstBuffer(long Tag, int Cbuf, byte[] Data)
|
|
|
|
{
|
|
|
|
if (Data == null)
|
2018-02-05 00:08:20 +01:00
|
|
|
{
|
2018-04-08 21:17:35 +02:00
|
|
|
throw new ArgumentNullException(nameof(Data));
|
2018-02-05 00:08:20 +01:00
|
|
|
}
|
|
|
|
|
2018-04-08 21:17:35 +02:00
|
|
|
ActionsQueue.Enqueue(() => Shader.SetConstBuffer(Tag, Cbuf, Data));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetUniform1(string UniformName, int Value)
|
|
|
|
{
|
|
|
|
if (UniformName == null)
|
2018-02-05 00:08:20 +01:00
|
|
|
{
|
2018-04-08 21:17:35 +02:00
|
|
|
throw new ArgumentNullException(nameof(UniformName));
|
2018-02-05 00:08:20 +01:00
|
|
|
}
|
|
|
|
|
2018-04-08 21:17:35 +02:00
|
|
|
ActionsQueue.Enqueue(() => Shader.SetUniform1(UniformName, Value));
|
2018-02-05 00:08:20 +01:00
|
|
|
}
|
|
|
|
|
2018-04-14 05:39:24 +02:00
|
|
|
public void SetUniform2F(string UniformName, float X, float Y)
|
|
|
|
{
|
|
|
|
if (UniformName == null)
|
|
|
|
{
|
|
|
|
throw new ArgumentNullException(nameof(UniformName));
|
|
|
|
}
|
|
|
|
|
|
|
|
ActionsQueue.Enqueue(() => Shader.SetUniform2F(UniformName, X, Y));
|
|
|
|
}
|
|
|
|
|
2018-04-08 21:17:35 +02:00
|
|
|
public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Tag)
|
2018-02-05 00:08:20 +01:00
|
|
|
{
|
2018-04-08 21:17:35 +02:00
|
|
|
return Shader.GetTextureUsage(Tag);
|
|
|
|
}
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-04-08 21:17:35 +02:00
|
|
|
public void BindShader(long Tag)
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => Shader.Bind(Tag));
|
|
|
|
}
|
2018-02-05 00:08:20 +01:00
|
|
|
|
2018-04-08 21:17:35 +02:00
|
|
|
public void BindProgram()
|
|
|
|
{
|
|
|
|
ActionsQueue.Enqueue(() => Shader.BindProgram());
|
|
|
|
}
|
|
|
|
|
2018-06-09 02:15:56 +02:00
|
|
|
public void SetTextureAndSampler(long Tag, byte[] Data, GalTexture Texture, GalTextureSampler Sampler)
|
2018-04-08 21:17:35 +02:00
|
|
|
{
|
2018-04-13 20:12:58 +02:00
|
|
|
ActionsQueue.Enqueue(() =>
|
|
|
|
{
|
2018-06-09 02:15:56 +02:00
|
|
|
this.Texture.Create(Tag, Data, Texture);
|
2018-04-13 20:12:58 +02:00
|
|
|
|
|
|
|
OGLTexture.Set(Sampler);
|
|
|
|
});
|
2018-04-08 21:17:35 +02:00
|
|
|
}
|
|
|
|
|
2018-06-09 02:15:56 +02:00
|
|
|
public bool TryGetCachedTexture(long Tag, long DataSize, out GalTexture Texture)
|
|
|
|
{
|
|
|
|
return this.Texture.TryGetCachedTexture(Tag, DataSize, out Texture);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void BindTexture(long Tag, int Index)
|
2018-04-08 21:17:35 +02:00
|
|
|
{
|
2018-06-09 02:15:56 +02:00
|
|
|
ActionsQueue.Enqueue(() => Texture.Bind(Tag, Index));
|
2018-02-05 00:08:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|