mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-08-02 19:07:10 +02:00
Merge shader branch, adding support for GLSL decompilation, a macro
interpreter, and a rewrite of the GPU code.
This commit is contained in:
parent
bad6d9b7a0
commit
eacc7689ed
77 changed files with 5301 additions and 766 deletions
|
@ -219,7 +219,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
PixelFormat.Rgba,
|
||||
PixelType.UnsignedByte,
|
||||
Pixels);
|
||||
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
|
||||
GL.BindVertexArray(VaoHandle);
|
||||
|
|
49
Ryujinx.Graphics/Gal/OpenGL/OGLBlend.cs
Normal file
49
Ryujinx.Graphics/Gal/OpenGL/OGLBlend.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
class OGLBlend
|
||||
{
|
||||
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.GetBlendFactorSrc(FuncSrc),
|
||||
OGLEnumConverter.GetBlendFactorDst(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(
|
||||
OGLEnumConverter.GetBlendFactorSrc(FuncSrcRgb),
|
||||
OGLEnumConverter.GetBlendFactorDst(FuncDstRgb),
|
||||
OGLEnumConverter.GetBlendFactorSrc(FuncSrcAlpha),
|
||||
OGLEnumConverter.GetBlendFactorDst(FuncDstAlpha));
|
||||
}
|
||||
}
|
||||
}
|
129
Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
Normal file
129
Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
Normal file
|
@ -0,0 +1,129 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
static class OGLEnumConverter
|
||||
{
|
||||
public static DrawElementsType GetDrawElementsType(GalIndexFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalIndexFormat.Byte: return DrawElementsType.UnsignedByte;
|
||||
case GalIndexFormat.Int16: return DrawElementsType.UnsignedShort;
|
||||
case GalIndexFormat.Int32: return DrawElementsType.UnsignedInt;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Format));
|
||||
}
|
||||
|
||||
public static PrimitiveType GetPrimitiveType(GalPrimitiveType Type)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case GalPrimitiveType.Points: return PrimitiveType.Points;
|
||||
case GalPrimitiveType.Lines: return PrimitiveType.Lines;
|
||||
case GalPrimitiveType.LineLoop: return PrimitiveType.LineLoop;
|
||||
case GalPrimitiveType.LineStrip: return PrimitiveType.LineStrip;
|
||||
case GalPrimitiveType.Triangles: return PrimitiveType.Triangles;
|
||||
case GalPrimitiveType.TriangleStrip: return PrimitiveType.TriangleStrip;
|
||||
case GalPrimitiveType.TriangleFan: return PrimitiveType.TriangleFan;
|
||||
case GalPrimitiveType.Quads: return PrimitiveType.Quads;
|
||||
case GalPrimitiveType.QuadStrip: return PrimitiveType.QuadStrip;
|
||||
case GalPrimitiveType.Polygon: return PrimitiveType.Polygon;
|
||||
case GalPrimitiveType.LinesAdjacency: return PrimitiveType.LinesAdjacency;
|
||||
case GalPrimitiveType.LineStripAdjacency: return PrimitiveType.LineStripAdjacency;
|
||||
case GalPrimitiveType.TrianglesAdjacency: return PrimitiveType.TrianglesAdjacency;
|
||||
case GalPrimitiveType.TriangleStripAdjacency: return PrimitiveType.TriangleStripAdjacency;
|
||||
case GalPrimitiveType.Patches: return PrimitiveType.Patches;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Type));
|
||||
}
|
||||
|
||||
public static ShaderType GetShaderType(GalShaderType Type)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case GalShaderType.Vertex: return ShaderType.VertexShader;
|
||||
case GalShaderType.TessControl: return ShaderType.TessControlShader;
|
||||
case GalShaderType.TessEvaluation: return ShaderType.TessEvaluationShader;
|
||||
case GalShaderType.Geometry: return ShaderType.GeometryShader;
|
||||
case GalShaderType.Fragment: return ShaderType.FragmentShader;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Type));
|
||||
}
|
||||
|
||||
public static PixelInternalFormat GetCompressedTextureFormat(GalTextureFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalTextureFormat.BC1: return PixelInternalFormat.CompressedRgbaS3tcDxt1Ext;
|
||||
case GalTextureFormat.BC2: return PixelInternalFormat.CompressedRgbaS3tcDxt3Ext;
|
||||
case GalTextureFormat.BC3: return PixelInternalFormat.CompressedRgbaS3tcDxt5Ext;
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Format.ToString());
|
||||
}
|
||||
|
||||
public static TextureWrapMode GetTextureWrapMode(GalTextureWrap Wrap)
|
||||
{
|
||||
switch (Wrap)
|
||||
{
|
||||
case GalTextureWrap.Repeat: return TextureWrapMode.Repeat;
|
||||
case GalTextureWrap.MirroredRepeat: return TextureWrapMode.MirroredRepeat;
|
||||
case GalTextureWrap.ClampToEdge: return TextureWrapMode.ClampToEdge;
|
||||
case GalTextureWrap.ClampToBorder: return TextureWrapMode.ClampToBorder;
|
||||
case GalTextureWrap.Clamp: return TextureWrapMode.Clamp;
|
||||
|
||||
//TODO: Those needs extensions (and are currently wrong).
|
||||
case GalTextureWrap.MirrorClampToEdge: return TextureWrapMode.ClampToEdge;
|
||||
case GalTextureWrap.MirrorClampToBorder: return TextureWrapMode.ClampToBorder;
|
||||
case GalTextureWrap.MirrorClamp: return TextureWrapMode.Clamp;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Wrap));
|
||||
}
|
||||
|
||||
public static TextureMinFilter GetTextureMinFilter(
|
||||
GalTextureFilter MinFilter,
|
||||
GalTextureMipFilter MipFilter)
|
||||
{
|
||||
//TODO: Mip (needs mipmap support first).
|
||||
switch (MinFilter)
|
||||
{
|
||||
case GalTextureFilter.Nearest: return TextureMinFilter.Nearest;
|
||||
case GalTextureFilter.Linear: return TextureMinFilter.Linear;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(MinFilter));
|
||||
}
|
||||
|
||||
public static TextureMagFilter GetTextureMagFilter(GalTextureFilter Filter)
|
||||
{
|
||||
switch (Filter)
|
||||
{
|
||||
case GalTextureFilter.Nearest: return TextureMagFilter.Nearest;
|
||||
case GalTextureFilter.Linear: return TextureMagFilter.Linear;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Filter));
|
||||
}
|
||||
|
||||
public static BlendEquationMode GetBlendEquation(GalBlendEquation BlendEquation)
|
||||
{
|
||||
return (BlendEquationMode)BlendEquation;
|
||||
}
|
||||
|
||||
public static BlendingFactorSrc GetBlendFactorSrc(GalBlendFactor BlendFactor)
|
||||
{
|
||||
return (BlendingFactorSrc)(BlendFactor - 0x4000);
|
||||
}
|
||||
|
||||
public static BlendingFactorDest GetBlendFactorDst(GalBlendFactor BlendFactor)
|
||||
{
|
||||
return (BlendingFactorDest)(BlendFactor - 0x4000);
|
||||
}
|
||||
}
|
||||
}
|
182
Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs
Normal file
182
Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs
Normal file
|
@ -0,0 +1,182 @@
|
|||
using OpenTK;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
class OGLFrameBuffer
|
||||
{
|
||||
private struct FrameBuffer
|
||||
{
|
||||
public int FbHandle;
|
||||
public int RbHandle;
|
||||
public int TexHandle;
|
||||
}
|
||||
|
||||
private struct ShaderProgram
|
||||
{
|
||||
public int Handle;
|
||||
public int VpHandle;
|
||||
public int FpHandle;
|
||||
}
|
||||
|
||||
private FrameBuffer[] Fbs;
|
||||
|
||||
private ShaderProgram Shader;
|
||||
|
||||
private bool IsInitialized;
|
||||
|
||||
private int VaoHandle;
|
||||
private int VboHandle;
|
||||
|
||||
public OGLFrameBuffer()
|
||||
{
|
||||
Fbs = new FrameBuffer[16];
|
||||
|
||||
Shader = new ShaderProgram();
|
||||
}
|
||||
|
||||
public void Set(int Index, int Width, int Height)
|
||||
{
|
||||
if (Fbs[Index].FbHandle != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Fbs[Index].FbHandle = GL.GenFramebuffer();
|
||||
Fbs[Index].RbHandle = GL.GenRenderbuffer();
|
||||
Fbs[Index].TexHandle = GL.GenTexture();
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fbs[Index].FbHandle);
|
||||
|
||||
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, Fbs[Index].RbHandle);
|
||||
|
||||
GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Depth24Stencil8, 1280, 720);
|
||||
|
||||
GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthStencilAttachment, RenderbufferTarget.Renderbuffer, Fbs[Index].RbHandle);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Fbs[Index].TexHandle);
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||
|
||||
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, 1280, 720, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
|
||||
|
||||
GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, Fbs[Index].TexHandle, 0);
|
||||
|
||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||
}
|
||||
|
||||
public void Bind(int Index)
|
||||
{
|
||||
if (Fbs[Index].FbHandle == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fbs[Index].FbHandle);
|
||||
}
|
||||
|
||||
public void Draw(int Index)
|
||||
{
|
||||
if (Fbs[Index].FbHandle == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureInitialized();
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Fbs[Index].TexHandle);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
|
||||
GL.BindVertexArray(VaoHandle);
|
||||
|
||||
GL.UseProgram(Shader.Handle);
|
||||
|
||||
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
|
||||
}
|
||||
|
||||
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.CreateScale(1, -1);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
231
Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs
Normal file
231
Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs
Normal file
|
@ -0,0 +1,231 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
class OGLRasterizer
|
||||
{
|
||||
private static Dictionary<GalVertexAttribSize, int> AttribElements =
|
||||
new Dictionary<GalVertexAttribSize, int>()
|
||||
{
|
||||
{ GalVertexAttribSize._32_32_32_32, 4 },
|
||||
{ GalVertexAttribSize._32_32_32, 3 },
|
||||
{ GalVertexAttribSize._16_16_16_16, 4 },
|
||||
{ GalVertexAttribSize._32_32, 2 },
|
||||
{ GalVertexAttribSize._16_16_16, 3 },
|
||||
{ GalVertexAttribSize._8_8_8_8, 4 },
|
||||
{ GalVertexAttribSize._16_16, 2 },
|
||||
{ GalVertexAttribSize._32, 1 },
|
||||
{ GalVertexAttribSize._8_8_8, 3 },
|
||||
{ GalVertexAttribSize._8_8, 2 },
|
||||
{ GalVertexAttribSize._16, 1 },
|
||||
{ GalVertexAttribSize._8, 1 },
|
||||
{ GalVertexAttribSize._10_10_10_2, 4 },
|
||||
{ GalVertexAttribSize._11_11_10, 3 }
|
||||
};
|
||||
|
||||
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> AttribTypes =
|
||||
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
||||
{
|
||||
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Int },
|
||||
{ GalVertexAttribSize._32_32_32, VertexAttribPointerType.Int },
|
||||
{ GalVertexAttribSize._16_16_16_16, VertexAttribPointerType.Short },
|
||||
{ GalVertexAttribSize._32_32, VertexAttribPointerType.Int },
|
||||
{ GalVertexAttribSize._16_16_16, VertexAttribPointerType.Short },
|
||||
{ GalVertexAttribSize._8_8_8_8, VertexAttribPointerType.Byte },
|
||||
{ GalVertexAttribSize._16_16, VertexAttribPointerType.Short },
|
||||
{ GalVertexAttribSize._32, VertexAttribPointerType.Int },
|
||||
{ GalVertexAttribSize._8_8_8, VertexAttribPointerType.Byte },
|
||||
{ GalVertexAttribSize._8_8, VertexAttribPointerType.Byte },
|
||||
{ GalVertexAttribSize._16, VertexAttribPointerType.Short },
|
||||
{ GalVertexAttribSize._8, VertexAttribPointerType.Byte },
|
||||
{ GalVertexAttribSize._10_10_10_2, VertexAttribPointerType.Int }, //?
|
||||
{ GalVertexAttribSize._11_11_10, VertexAttribPointerType.Int } //?
|
||||
};
|
||||
|
||||
private struct VbInfo
|
||||
{
|
||||
public int VaoHandle;
|
||||
public int VboHandle;
|
||||
|
||||
public int PrimCount;
|
||||
}
|
||||
|
||||
private struct IbInfo
|
||||
{
|
||||
public int IboHandle;
|
||||
public int Count;
|
||||
|
||||
public DrawElementsType Type;
|
||||
}
|
||||
|
||||
private VbInfo[] VertexBuffers;
|
||||
|
||||
private IbInfo IndexBuffer;
|
||||
|
||||
public OGLRasterizer()
|
||||
{
|
||||
VertexBuffers = new VbInfo[32];
|
||||
|
||||
IndexBuffer = new IbInfo();
|
||||
}
|
||||
|
||||
public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags)
|
||||
{
|
||||
ClearBufferMask Mask = 0;
|
||||
|
||||
//OpenGL doesn't support clearing just a single color channel,
|
||||
//so we can't just clear all channels...
|
||||
if (Flags.HasFlag(GalClearBufferFlags.ColorRed) &&
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorGreen) &&
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorBlue) &&
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorAlpha))
|
||||
{
|
||||
Mask = ClearBufferMask.ColorBufferBit;
|
||||
}
|
||||
|
||||
if (Flags.HasFlag(GalClearBufferFlags.Depth))
|
||||
{
|
||||
Mask |= ClearBufferMask.DepthBufferBit;
|
||||
}
|
||||
|
||||
if (Flags.HasFlag(GalClearBufferFlags.Stencil))
|
||||
{
|
||||
Mask |= ClearBufferMask.StencilBufferBit;
|
||||
}
|
||||
|
||||
GL.Clear(Mask);
|
||||
}
|
||||
|
||||
public void SetVertexArray(int VbIndex, int Stride, byte[] Buffer, GalVertexAttrib[] Attribs)
|
||||
{
|
||||
EnsureVbInitialized(VbIndex);
|
||||
|
||||
VertexBuffers[VbIndex].PrimCount = Buffer.Length / Stride;
|
||||
|
||||
VbInfo Vb = VertexBuffers[VbIndex];
|
||||
|
||||
IntPtr Length = new IntPtr(Buffer.Length);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle);
|
||||
GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
|
||||
|
||||
GL.BindVertexArray(Vb.VaoHandle);
|
||||
|
||||
for (int Attr = 0; Attr < 16; Attr++)
|
||||
{
|
||||
GL.DisableVertexAttribArray(Attr);
|
||||
}
|
||||
|
||||
for (int Index = 0; Index < Attribs.Length; Index++)
|
||||
{
|
||||
GalVertexAttrib Attrib = Attribs[Index];
|
||||
|
||||
GL.EnableVertexAttribArray(Index);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle);
|
||||
|
||||
bool Unsigned =
|
||||
Attrib.Type == GalVertexAttribType.Unorm ||
|
||||
Attrib.Type == GalVertexAttribType.Uint ||
|
||||
Attrib.Type == GalVertexAttribType.Uscaled;
|
||||
|
||||
bool Normalize =
|
||||
Attrib.Type == GalVertexAttribType.Snorm ||
|
||||
Attrib.Type == GalVertexAttribType.Unorm;
|
||||
|
||||
VertexAttribPointerType Type = 0;
|
||||
|
||||
if (Attrib.Type == GalVertexAttribType.Float)
|
||||
{
|
||||
Type = VertexAttribPointerType.Float;
|
||||
}
|
||||
else
|
||||
{
|
||||
Type = AttribTypes[Attrib.Size] + (Unsigned ? 1 : 0);
|
||||
}
|
||||
|
||||
int Size = AttribElements[Attrib.Size];
|
||||
int Offset = Attrib.Offset;
|
||||
|
||||
GL.VertexAttribPointer(Index, Size, Type, Normalize, Stride, Offset);
|
||||
}
|
||||
|
||||
GL.BindVertexArray(0);
|
||||
}
|
||||
|
||||
public void SetIndexArray(byte[] Buffer, GalIndexFormat Format)
|
||||
{
|
||||
EnsureIbInitialized();
|
||||
|
||||
IndexBuffer.Type = OGLEnumConverter.GetDrawElementsType(Format);
|
||||
|
||||
IndexBuffer.Count = Buffer.Length >> (int)Format;
|
||||
|
||||
IntPtr Length = new IntPtr(Buffer.Length);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, IndexBuffer.IboHandle);
|
||||
GL.BufferData(BufferTarget.ElementArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
|
||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
|
||||
}
|
||||
|
||||
public void DrawArrays(int VbIndex, GalPrimitiveType PrimType)
|
||||
{
|
||||
VbInfo Vb = VertexBuffers[VbIndex];
|
||||
|
||||
if (Vb.PrimCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GL.BindVertexArray(Vb.VaoHandle);
|
||||
|
||||
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), 0, Vb.PrimCount);
|
||||
}
|
||||
|
||||
public void DrawElements(int VbIndex, int First, GalPrimitiveType PrimType)
|
||||
{
|
||||
VbInfo Vb = VertexBuffers[VbIndex];
|
||||
|
||||
if (Vb.PrimCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PrimitiveType Mode = OGLEnumConverter.GetPrimitiveType(PrimType);
|
||||
|
||||
GL.BindVertexArray(Vb.VaoHandle);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, IndexBuffer.IboHandle);
|
||||
|
||||
GL.DrawElements(Mode, IndexBuffer.Count, IndexBuffer.Type, First);
|
||||
}
|
||||
|
||||
private void EnsureVbInitialized(int VbIndex)
|
||||
{
|
||||
VbInfo Vb = VertexBuffers[VbIndex];
|
||||
|
||||
if (Vb.VaoHandle == 0)
|
||||
{
|
||||
Vb.VaoHandle = GL.GenVertexArray();
|
||||
}
|
||||
|
||||
if (Vb.VboHandle == 0)
|
||||
{
|
||||
Vb.VboHandle = GL.GenBuffer();
|
||||
}
|
||||
|
||||
VertexBuffers[VbIndex] = Vb;
|
||||
}
|
||||
|
||||
private void EnsureIbInitialized()
|
||||
{
|
||||
if (IndexBuffer.IboHandle == 0)
|
||||
{
|
||||
IndexBuffer.IboHandle = GL.GenBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
253
Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
Normal file
253
Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
Normal file
|
@ -0,0 +1,253 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Graphics.Gal.Shader;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
class OGLShader
|
||||
{
|
||||
private class ShaderStage : IDisposable
|
||||
{
|
||||
public int Handle { get; private set; }
|
||||
|
||||
public bool IsCompiled { get; private set; }
|
||||
|
||||
public GalShaderType Type { get; private set; }
|
||||
|
||||
public string Code { get; private set; }
|
||||
|
||||
public IEnumerable<ShaderDeclInfo> TextureUsage { get; private set; }
|
||||
public IEnumerable<ShaderDeclInfo> UniformUsage { get; private set; }
|
||||
|
||||
public ShaderStage(
|
||||
GalShaderType Type,
|
||||
string Code,
|
||||
IEnumerable<ShaderDeclInfo> TextureUsage,
|
||||
IEnumerable<ShaderDeclInfo> UniformUsage)
|
||||
{
|
||||
this.Type = Type;
|
||||
this.Code = Code;
|
||||
this.TextureUsage = TextureUsage;
|
||||
this.UniformUsage = UniformUsage;
|
||||
}
|
||||
|
||||
public void Compile()
|
||||
{
|
||||
if (Handle == 0)
|
||||
{
|
||||
Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type));
|
||||
|
||||
CompileAndCheck(Handle, Code);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
{
|
||||
if (Disposing && Handle != 0)
|
||||
{
|
||||
GL.DeleteShader(Handle);
|
||||
|
||||
Handle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct ShaderProgram
|
||||
{
|
||||
public ShaderStage Vertex;
|
||||
public ShaderStage TessControl;
|
||||
public ShaderStage TessEvaluation;
|
||||
public ShaderStage Geometry;
|
||||
public ShaderStage Fragment;
|
||||
}
|
||||
|
||||
private ShaderProgram Current;
|
||||
|
||||
private ConcurrentDictionary<long, ShaderStage> Stages;
|
||||
|
||||
private Dictionary<ShaderProgram, int> Programs;
|
||||
|
||||
public int CurrentProgramHandle { get; private set; }
|
||||
|
||||
public OGLShader()
|
||||
{
|
||||
Stages = new ConcurrentDictionary<long, ShaderStage>();
|
||||
|
||||
Programs = new Dictionary<ShaderProgram, int>();
|
||||
}
|
||||
|
||||
public void Create(long Tag, GalShaderType Type, byte[] Data)
|
||||
{
|
||||
Stages.GetOrAdd(Tag, (Key) => ShaderStageFactory(Type, Data));
|
||||
}
|
||||
|
||||
private ShaderStage ShaderStageFactory(GalShaderType Type, byte[] Data)
|
||||
{
|
||||
GlslProgram Program = GetGlslProgram(Data, Type);
|
||||
|
||||
return new ShaderStage(
|
||||
Type,
|
||||
Program.Code,
|
||||
Program.Textures,
|
||||
Program.Uniforms);
|
||||
}
|
||||
|
||||
private GlslProgram GetGlslProgram(byte[] Data, GalShaderType Type)
|
||||
{
|
||||
int[] Code = new int[(Data.Length - 0x50) >> 2];
|
||||
|
||||
using (MemoryStream MS = new MemoryStream(Data))
|
||||
{
|
||||
MS.Seek(0x50, SeekOrigin.Begin);
|
||||
|
||||
BinaryReader Reader = new BinaryReader(MS);
|
||||
|
||||
for (int Index = 0; Index < Code.Length; Index++)
|
||||
{
|
||||
Code[Index] = Reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
|
||||
GlslDecompiler Decompiler = new GlslDecompiler();
|
||||
|
||||
return Decompiler.Decompile(Code, Type);
|
||||
}
|
||||
|
||||
public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Tag)
|
||||
{
|
||||
if (Stages.TryGetValue(Tag, out ShaderStage Stage))
|
||||
{
|
||||
return Stage.TextureUsage;
|
||||
}
|
||||
|
||||
return Enumerable.Empty<ShaderDeclInfo>();
|
||||
}
|
||||
|
||||
public void SetConstBuffer(long Tag, int Cbuf, byte[] Data)
|
||||
{
|
||||
BindProgram();
|
||||
|
||||
if (Stages.TryGetValue(Tag, out ShaderStage Stage))
|
||||
{
|
||||
foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage.Where(x => x.Cbuf == Cbuf))
|
||||
{
|
||||
float Value = BitConverter.ToSingle(Data, DeclInfo.Index * 4);
|
||||
|
||||
int Location = GL.GetUniformLocation(CurrentProgramHandle, DeclInfo.Name);
|
||||
|
||||
GL.Uniform1(Location, Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUniform1(string UniformName, int Value)
|
||||
{
|
||||
BindProgram();
|
||||
|
||||
int Location = GL.GetUniformLocation(CurrentProgramHandle, UniformName);
|
||||
|
||||
GL.Uniform1(Location, Value);
|
||||
}
|
||||
|
||||
public void Bind(long Tag)
|
||||
{
|
||||
if (Stages.TryGetValue(Tag, out ShaderStage Stage))
|
||||
{
|
||||
Bind(Stage);
|
||||
}
|
||||
}
|
||||
|
||||
private void Bind(ShaderStage Stage)
|
||||
{
|
||||
switch (Stage.Type)
|
||||
{
|
||||
case GalShaderType.Vertex: Current.Vertex = Stage; break;
|
||||
case GalShaderType.TessControl: Current.TessControl = Stage; break;
|
||||
case GalShaderType.TessEvaluation: Current.TessEvaluation = Stage; break;
|
||||
case GalShaderType.Geometry: Current.Geometry = Stage; break;
|
||||
case GalShaderType.Fragment: Current.Fragment = Stage; break;
|
||||
}
|
||||
}
|
||||
|
||||
public void BindProgram()
|
||||
{
|
||||
if (Current.Vertex == null ||
|
||||
Current.Fragment == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Programs.TryGetValue(Current, out int Handle))
|
||||
{
|
||||
Handle = GL.CreateProgram();
|
||||
|
||||
AttachIfNotNull(Handle, Current.Vertex);
|
||||
AttachIfNotNull(Handle, Current.TessControl);
|
||||
AttachIfNotNull(Handle, Current.TessEvaluation);
|
||||
AttachIfNotNull(Handle, Current.Geometry);
|
||||
AttachIfNotNull(Handle, Current.Fragment);
|
||||
|
||||
GL.LinkProgram(Handle);
|
||||
|
||||
CheckProgramLink(Handle);
|
||||
|
||||
Programs.Add(Current, Handle);
|
||||
}
|
||||
|
||||
GL.UseProgram(Handle);
|
||||
|
||||
CurrentProgramHandle = Handle;
|
||||
}
|
||||
|
||||
private void AttachIfNotNull(int ProgramHandle, ShaderStage Stage)
|
||||
{
|
||||
if (Stage != null)
|
||||
{
|
||||
Stage.Compile();
|
||||
|
||||
GL.AttachShader(ProgramHandle, Stage.Handle);
|
||||
}
|
||||
}
|
||||
|
||||
public static void CompileAndCheck(int Handle, string Code)
|
||||
{
|
||||
GL.ShaderSource(Handle, Code);
|
||||
GL.CompileShader(Handle);
|
||||
|
||||
CheckCompilation(Handle);
|
||||
}
|
||||
|
||||
private static void CheckCompilation(int Handle)
|
||||
{
|
||||
int Status = 0;
|
||||
|
||||
GL.GetShader(Handle, ShaderParameter.CompileStatus, out Status);
|
||||
|
||||
if (Status == 0)
|
||||
{
|
||||
throw new ShaderException(GL.GetShaderInfoLog(Handle));
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckProgramLink(int Handle)
|
||||
{
|
||||
int Status = 0;
|
||||
|
||||
GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out Status);
|
||||
|
||||
if (Status == 0)
|
||||
{
|
||||
throw new ShaderException(GL.GetProgramInfoLog(Handle));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
96
Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
Normal file
96
Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
class OGLTexture
|
||||
{
|
||||
private int[] Textures;
|
||||
|
||||
public OGLTexture()
|
||||
{
|
||||
Textures = new int[80];
|
||||
}
|
||||
|
||||
public void Set(int Index, GalTexture Tex)
|
||||
{
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||||
|
||||
int Handle = EnsureTextureInitialized(Index);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
|
||||
int W = Tex.Width;
|
||||
int H = Tex.Height;
|
||||
|
||||
byte[] Data = Tex.Data;
|
||||
|
||||
int Length = Data.Length;
|
||||
|
||||
if (IsCompressedTextureFormat(Tex.Format))
|
||||
{
|
||||
PixelInternalFormat Pif = OGLEnumConverter.GetCompressedTextureFormat(Tex.Format);
|
||||
|
||||
GL.CompressedTexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Length, Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: Get those from Texture format.
|
||||
const PixelInternalFormat Pif = PixelInternalFormat.Rgba;
|
||||
|
||||
const PixelFormat Pf = PixelFormat.Rgba;
|
||||
|
||||
const PixelType Pt = PixelType.UnsignedByte;
|
||||
|
||||
GL.TexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Pf, Pt, Data);
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(int Index, GalTextureSampler Sampler)
|
||||
{
|
||||
int Handle = EnsureTextureInitialized(Index);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
|
||||
int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU);
|
||||
int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV);
|
||||
|
||||
int MinFilter = (int)OGLEnumConverter.GetTextureMinFilter(Sampler.MinFilter, Sampler.MipFilter);
|
||||
int MagFilter = (int)OGLEnumConverter.GetTextureMagFilter(Sampler.MagFilter);
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, WrapS);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, WrapT);
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
|
||||
|
||||
float[] Color = new float[]
|
||||
{
|
||||
Sampler.BorderColor.Red,
|
||||
Sampler.BorderColor.Green,
|
||||
Sampler.BorderColor.Blue,
|
||||
Sampler.BorderColor.Alpha
|
||||
};
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, Color);
|
||||
}
|
||||
|
||||
private static bool IsCompressedTextureFormat(GalTextureFormat Format)
|
||||
{
|
||||
return Format == GalTextureFormat.BC1 ||
|
||||
Format == GalTextureFormat.BC2 ||
|
||||
Format == GalTextureFormat.BC3;
|
||||
}
|
||||
|
||||
private int EnsureTextureInitialized(int TexIndex)
|
||||
{
|
||||
int Handle = Textures[TexIndex];
|
||||
|
||||
if (Handle == 0)
|
||||
{
|
||||
Handle = Textures[TexIndex] = GL.GenTexture();
|
||||
}
|
||||
|
||||
return Handle;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using OpenTK;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
@ -8,22 +7,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
public class OpenGLRenderer : IGalRenderer
|
||||
{
|
||||
private struct VertexBuffer
|
||||
{
|
||||
public int VaoHandle;
|
||||
public int VboHandle;
|
||||
private OGLBlend Blend;
|
||||
|
||||
public int PrimCount;
|
||||
}
|
||||
private OGLFrameBuffer FrameBuffer;
|
||||
|
||||
private struct Texture
|
||||
{
|
||||
public int Handle;
|
||||
}
|
||||
private OGLRasterizer Rasterizer;
|
||||
|
||||
private List<VertexBuffer> VertexBuffers;
|
||||
private OGLShader Shader;
|
||||
|
||||
private Texture[] Textures;
|
||||
private OGLTexture Texture;
|
||||
|
||||
private ConcurrentQueue<Action> ActionsQueue;
|
||||
|
||||
|
@ -31,9 +23,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public OpenGLRenderer()
|
||||
{
|
||||
VertexBuffers = new List<VertexBuffer>();
|
||||
Blend = new OGLBlend();
|
||||
|
||||
Textures = new Texture[8];
|
||||
FrameBuffer = new OGLFrameBuffer();
|
||||
|
||||
Rasterizer = new OGLRasterizer();
|
||||
|
||||
Shader = new OGLShader();
|
||||
|
||||
Texture = new OGLTexture();
|
||||
|
||||
ActionsQueue = new ConcurrentQueue<Action>();
|
||||
}
|
||||
|
@ -66,18 +64,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
public void Render()
|
||||
{
|
||||
FbRenderer.Render();
|
||||
|
||||
for (int Index = 0; Index < VertexBuffers.Count; Index++)
|
||||
{
|
||||
VertexBuffer Vb = VertexBuffers[Index];
|
||||
|
||||
if (Vb.VaoHandle != 0 &&
|
||||
Vb.PrimCount != 0)
|
||||
{
|
||||
GL.BindVertexArray(Vb.VaoHandle);
|
||||
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, Vb.PrimCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetWindowSize(int Width, int Height)
|
||||
|
@ -106,218 +92,161 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
FbRenderer.Set(Fb, Width, Height, Transform, Offs);
|
||||
}
|
||||
|
||||
public void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs)
|
||||
public void SetBlendEnable(bool Enable)
|
||||
{
|
||||
if (Index < 0)
|
||||
if (Enable)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Index));
|
||||
ActionsQueue.Enqueue(() => Blend.Enable());
|
||||
}
|
||||
|
||||
if (Buffer.Length == 0 || Stride == 0)
|
||||
else
|
||||
{
|
||||
return;
|
||||
ActionsQueue.Enqueue(() => Blend.Disable());
|
||||
}
|
||||
|
||||
EnsureVbInitialized(Index);
|
||||
|
||||
VertexBuffer Vb = VertexBuffers[Index];
|
||||
|
||||
Vb.PrimCount = Buffer.Length / Stride;
|
||||
|
||||
VertexBuffers[Index] = Vb;
|
||||
|
||||
IntPtr Length = new IntPtr(Buffer.Length);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle);
|
||||
GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
|
||||
|
||||
GL.BindVertexArray(Vb.VaoHandle);
|
||||
|
||||
for (int Attr = 0; Attr < 16; Attr++)
|
||||
{
|
||||
GL.DisableVertexAttribArray(Attr);
|
||||
}
|
||||
|
||||
foreach (GalVertexAttrib Attrib in Attribs)
|
||||
{
|
||||
if (Attrib.Index >= 3) break;
|
||||
|
||||
GL.EnableVertexAttribArray(Attrib.Index);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle);
|
||||
|
||||
int Size = 0;
|
||||
|
||||
switch (Attrib.Size)
|
||||
{
|
||||
case GalVertexAttribSize._8:
|
||||
case GalVertexAttribSize._16:
|
||||
case GalVertexAttribSize._32:
|
||||
Size = 1;
|
||||
break;
|
||||
case GalVertexAttribSize._8_8:
|
||||
case GalVertexAttribSize._16_16:
|
||||
case GalVertexAttribSize._32_32:
|
||||
Size = 2;
|
||||
break;
|
||||
case GalVertexAttribSize._8_8_8:
|
||||
case GalVertexAttribSize._11_11_10:
|
||||
case GalVertexAttribSize._16_16_16:
|
||||
case GalVertexAttribSize._32_32_32:
|
||||
Size = 3;
|
||||
break;
|
||||
case GalVertexAttribSize._8_8_8_8:
|
||||
case GalVertexAttribSize._10_10_10_2:
|
||||
case GalVertexAttribSize._16_16_16_16:
|
||||
case GalVertexAttribSize._32_32_32_32:
|
||||
Size = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
bool Signed =
|
||||
Attrib.Type == GalVertexAttribType.Snorm ||
|
||||
Attrib.Type == GalVertexAttribType.Sint ||
|
||||
Attrib.Type == GalVertexAttribType.Sscaled;
|
||||
|
||||
bool Normalize =
|
||||
Attrib.Type == GalVertexAttribType.Snorm ||
|
||||
Attrib.Type == GalVertexAttribType.Unorm;
|
||||
|
||||
VertexAttribPointerType Type = 0;
|
||||
|
||||
switch (Attrib.Type)
|
||||
{
|
||||
case GalVertexAttribType.Snorm:
|
||||
case GalVertexAttribType.Unorm:
|
||||
case GalVertexAttribType.Sint:
|
||||
case GalVertexAttribType.Uint:
|
||||
case GalVertexAttribType.Uscaled:
|
||||
case GalVertexAttribType.Sscaled:
|
||||
{
|
||||
switch (Attrib.Size)
|
||||
{
|
||||
case GalVertexAttribSize._8:
|
||||
case GalVertexAttribSize._8_8:
|
||||
case GalVertexAttribSize._8_8_8:
|
||||
case GalVertexAttribSize._8_8_8_8:
|
||||
{
|
||||
Type = Signed
|
||||
? VertexAttribPointerType.Byte
|
||||
: VertexAttribPointerType.UnsignedByte;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GalVertexAttribSize._16:
|
||||
case GalVertexAttribSize._16_16:
|
||||
case GalVertexAttribSize._16_16_16:
|
||||
case GalVertexAttribSize._16_16_16_16:
|
||||
{
|
||||
Type = Signed
|
||||
? VertexAttribPointerType.Short
|
||||
: VertexAttribPointerType.UnsignedShort;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GalVertexAttribSize._10_10_10_2:
|
||||
case GalVertexAttribSize._11_11_10:
|
||||
case GalVertexAttribSize._32:
|
||||
case GalVertexAttribSize._32_32:
|
||||
case GalVertexAttribSize._32_32_32:
|
||||
case GalVertexAttribSize._32_32_32_32:
|
||||
{
|
||||
Type = Signed
|
||||
? VertexAttribPointerType.Int
|
||||
: VertexAttribPointerType.UnsignedInt;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GalVertexAttribType.Float:
|
||||
{
|
||||
Type = VertexAttribPointerType.Float;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GL.VertexAttribPointer(
|
||||
Attrib.Index,
|
||||
Size,
|
||||
Type,
|
||||
Normalize,
|
||||
Stride,
|
||||
Attrib.Offset);
|
||||
}
|
||||
|
||||
GL.BindVertexArray(0);
|
||||
}
|
||||
|
||||
public void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height)
|
||||
public void SetBlend(
|
||||
GalBlendEquation Equation,
|
||||
GalBlendFactor FuncSrc,
|
||||
GalBlendFactor FuncDst)
|
||||
{
|
||||
EnsureTexInitialized(Index);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||
GL.TexImage2D(TextureTarget.Texture2D,
|
||||
0,
|
||||
PixelInternalFormat.Rgba,
|
||||
Width,
|
||||
Height,
|
||||
0,
|
||||
PixelFormat.Rgba,
|
||||
PixelType.UnsignedByte,
|
||||
Buffer);
|
||||
ActionsQueue.Enqueue(() => Blend.Set(Equation, FuncSrc, FuncDst));
|
||||
}
|
||||
|
||||
public void BindTexture(int Index)
|
||||
public void SetBlendSeparate(
|
||||
GalBlendEquation EquationRgb,
|
||||
GalBlendEquation EquationAlpha,
|
||||
GalBlendFactor FuncSrcRgb,
|
||||
GalBlendFactor FuncDstRgb,
|
||||
GalBlendFactor FuncSrcAlpha,
|
||||
GalBlendFactor FuncDstAlpha)
|
||||
{
|
||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle);
|
||||
ActionsQueue.Enqueue(() =>
|
||||
{
|
||||
Blend.SetSeparate(
|
||||
EquationRgb,
|
||||
EquationAlpha,
|
||||
FuncSrcRgb,
|
||||
FuncDstRgb,
|
||||
FuncSrcAlpha,
|
||||
FuncDstAlpha);
|
||||
});
|
||||
}
|
||||
|
||||
private void EnsureVbInitialized(int VbIndex)
|
||||
public void SetFb(int FbIndex, int Width, int Height)
|
||||
{
|
||||
while (VbIndex >= VertexBuffers.Count)
|
||||
{
|
||||
VertexBuffers.Add(new VertexBuffer());
|
||||
}
|
||||
|
||||
VertexBuffer Vb = VertexBuffers[VbIndex];
|
||||
|
||||
if (Vb.VaoHandle == 0)
|
||||
{
|
||||
Vb.VaoHandle = GL.GenVertexArray();
|
||||
}
|
||||
|
||||
if (Vb.VboHandle == 0)
|
||||
{
|
||||
Vb.VboHandle = GL.GenBuffer();
|
||||
}
|
||||
|
||||
VertexBuffers[VbIndex] = Vb;
|
||||
ActionsQueue.Enqueue(() => FrameBuffer.Set(FbIndex, Width, Height));
|
||||
}
|
||||
|
||||
private void EnsureTexInitialized(int TexIndex)
|
||||
public void BindFrameBuffer(int FbIndex)
|
||||
{
|
||||
Texture Tex = Textures[TexIndex];
|
||||
ActionsQueue.Enqueue(() => FrameBuffer.Bind(FbIndex));
|
||||
}
|
||||
|
||||
if (Tex.Handle == 0)
|
||||
public void DrawFrameBuffer(int FbIndex)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => FrameBuffer.Draw(FbIndex));
|
||||
}
|
||||
|
||||
public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => Rasterizer.ClearBuffers(RtIndex, Flags));
|
||||
}
|
||||
|
||||
public void SetVertexArray(int VbIndex, int Stride, byte[] Buffer, GalVertexAttrib[] Attribs)
|
||||
{
|
||||
if ((uint)VbIndex > 31)
|
||||
{
|
||||
Tex.Handle = GL.GenTexture();
|
||||
throw new ArgumentOutOfRangeException(nameof(VbIndex));
|
||||
}
|
||||
|
||||
Textures[TexIndex] = Tex;
|
||||
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)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Buffer));
|
||||
}
|
||||
|
||||
ActionsQueue.Enqueue(() => Rasterizer.SetIndexArray(Buffer, Format));
|
||||
}
|
||||
|
||||
public void DrawArrays(int VbIndex, GalPrimitiveType PrimType)
|
||||
{
|
||||
if ((uint)VbIndex > 31)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(VbIndex));
|
||||
}
|
||||
|
||||
ActionsQueue.Enqueue(() => Rasterizer.DrawArrays(VbIndex, PrimType));
|
||||
}
|
||||
|
||||
public void DrawElements(int VbIndex, int First, GalPrimitiveType PrimType)
|
||||
{
|
||||
if ((uint)VbIndex > 31)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(VbIndex));
|
||||
}
|
||||
|
||||
ActionsQueue.Enqueue(() => Rasterizer.DrawElements(VbIndex, First, PrimType));
|
||||
}
|
||||
|
||||
public void CreateShader(long Tag, GalShaderType Type, byte[] Data)
|
||||
{
|
||||
if (Data == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Data));
|
||||
}
|
||||
|
||||
Shader.Create(Tag, Type, Data);
|
||||
}
|
||||
|
||||
public void SetConstBuffer(long Tag, int Cbuf, byte[] Data)
|
||||
{
|
||||
if (Data == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Data));
|
||||
}
|
||||
|
||||
ActionsQueue.Enqueue(() => Shader.SetConstBuffer(Tag, Cbuf, Data));
|
||||
}
|
||||
|
||||
public void SetUniform1(string UniformName, int Value)
|
||||
{
|
||||
if (UniformName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(UniformName));
|
||||
}
|
||||
|
||||
ActionsQueue.Enqueue(() => Shader.SetUniform1(UniformName, Value));
|
||||
}
|
||||
|
||||
public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Tag)
|
||||
{
|
||||
return Shader.GetTextureUsage(Tag);
|
||||
}
|
||||
|
||||
public void BindShader(long Tag)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => Shader.Bind(Tag));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue