Quads, QuadStrip, const attributes and half-float attributes support (#447)
* Quads, QuadStrip and const attributes support * Add support for half float attributes and fix texture pitch alignment * Throw when an unsupported float type is used as const attribute aswell
This commit is contained in:
parent
dd3cb33c9f
commit
aa1cd849cf
12 changed files with 420 additions and 53 deletions
|
@ -1,17 +1,5 @@
|
||||||
namespace Ryujinx.Graphics.Gal
|
namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
public struct GalVertexBinding
|
|
||||||
{
|
|
||||||
//VboKey shouldn't be here, but ARB_vertex_attrib_binding is core since 4.3
|
|
||||||
|
|
||||||
public bool Enabled;
|
|
||||||
public int Stride;
|
|
||||||
public long VboKey;
|
|
||||||
public bool Instanced;
|
|
||||||
public int Divisor;
|
|
||||||
public GalVertexAttrib[] Attribs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GalPipelineState
|
public class GalPipelineState
|
||||||
{
|
{
|
||||||
public const int Stages = 5;
|
public const int Stages = 5;
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal
|
namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
public struct GalVertexAttrib
|
public struct GalVertexAttrib
|
||||||
{
|
{
|
||||||
public int Index { get; private set; }
|
public int Index { get; private set; }
|
||||||
public bool IsConst { get; private set; }
|
public bool IsConst { get; private set; }
|
||||||
public int Offset { get; private set; }
|
public int Offset { get; private set; }
|
||||||
|
public IntPtr Pointer { get; private set; }
|
||||||
|
|
||||||
public GalVertexAttribSize Size { get; private set; }
|
public GalVertexAttribSize Size { get; private set; }
|
||||||
public GalVertexAttribType Type { get; private set; }
|
public GalVertexAttribType Type { get; private set; }
|
||||||
|
@ -15,12 +18,14 @@ namespace Ryujinx.Graphics.Gal
|
||||||
int Index,
|
int Index,
|
||||||
bool IsConst,
|
bool IsConst,
|
||||||
int Offset,
|
int Offset,
|
||||||
|
IntPtr Pointer,
|
||||||
GalVertexAttribSize Size,
|
GalVertexAttribSize Size,
|
||||||
GalVertexAttribType Type,
|
GalVertexAttribType Type,
|
||||||
bool IsBgra)
|
bool IsBgra)
|
||||||
{
|
{
|
||||||
this.Index = Index;
|
this.Index = Index;
|
||||||
this.IsConst = IsConst;
|
this.IsConst = IsConst;
|
||||||
|
this.Pointer = Pointer;
|
||||||
this.Offset = Offset;
|
this.Offset = Offset;
|
||||||
this.Size = Size;
|
this.Size = Size;
|
||||||
this.Type = Type;
|
this.Type = Type;
|
||||||
|
|
14
Ryujinx.Graphics/Gal/GalVertexBinding.cs
Normal file
14
Ryujinx.Graphics/Gal/GalVertexBinding.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public struct GalVertexBinding
|
||||||
|
{
|
||||||
|
//VboKey shouldn't be here, but ARB_vertex_attrib_binding is core since 4.3
|
||||||
|
|
||||||
|
public bool Enabled;
|
||||||
|
public int Stride;
|
||||||
|
public long VboKey;
|
||||||
|
public bool Instanced;
|
||||||
|
public int Divisor;
|
||||||
|
public GalVertexAttrib[] Attribs;
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ namespace Ryujinx.Graphics.Gal
|
||||||
void CreateVbo(long Key, int DataSize, IntPtr HostAddress);
|
void CreateVbo(long Key, int DataSize, IntPtr HostAddress);
|
||||||
|
|
||||||
void CreateIbo(long Key, int DataSize, IntPtr HostAddress);
|
void CreateIbo(long Key, int DataSize, IntPtr HostAddress);
|
||||||
|
void CreateIbo(long Key, int DataSize, byte[] Buffer);
|
||||||
|
|
||||||
void SetIndexArray(int Size, GalIndexFormat Format);
|
void SetIndexArray(int Size, GalIndexFormat Format);
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalFrontFace.CCW: return FrontFaceDirection.Ccw;
|
case GalFrontFace.CCW: return FrontFaceDirection.Ccw;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(FrontFace));
|
throw new ArgumentException(nameof(FrontFace) + " \"" + FrontFace + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CullFaceMode GetCullFace(GalCullFace CullFace)
|
public static CullFaceMode GetCullFace(GalCullFace CullFace)
|
||||||
|
@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalCullFace.FrontAndBack: return CullFaceMode.FrontAndBack;
|
case GalCullFace.FrontAndBack: return CullFaceMode.FrontAndBack;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(CullFace));
|
throw new ArgumentException(nameof(CullFace) + " \"" + CullFace + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StencilOp GetStencilOp(GalStencilOp Op)
|
public static StencilOp GetStencilOp(GalStencilOp Op)
|
||||||
|
@ -42,7 +42,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalStencilOp.DecrWrap: return StencilOp.DecrWrap;
|
case GalStencilOp.DecrWrap: return StencilOp.DecrWrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Op));
|
throw new ArgumentException(nameof(Op) + " \"" + Op + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DepthFunction GetDepthFunc(GalComparisonOp Func)
|
public static DepthFunction GetDepthFunc(GalComparisonOp Func)
|
||||||
|
@ -66,7 +66,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalComparisonOp.Always: return DepthFunction.Always;
|
case GalComparisonOp.Always: return DepthFunction.Always;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Func));
|
throw new ArgumentException(nameof(Func) + " \"" + Func + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StencilFunction GetStencilFunc(GalComparisonOp Func)
|
public static StencilFunction GetStencilFunc(GalComparisonOp Func)
|
||||||
|
@ -84,7 +84,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalIndexFormat.Int32: return DrawElementsType.UnsignedInt;
|
case GalIndexFormat.Int32: return DrawElementsType.UnsignedInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Format));
|
throw new ArgumentException(nameof(Format) + " \"" + Format + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PrimitiveType GetPrimitiveType(GalPrimitiveType Type)
|
public static PrimitiveType GetPrimitiveType(GalPrimitiveType Type)
|
||||||
|
@ -98,8 +98,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalPrimitiveType.Triangles: return PrimitiveType.Triangles;
|
case GalPrimitiveType.Triangles: return PrimitiveType.Triangles;
|
||||||
case GalPrimitiveType.TriangleStrip: return PrimitiveType.TriangleStrip;
|
case GalPrimitiveType.TriangleStrip: return PrimitiveType.TriangleStrip;
|
||||||
case GalPrimitiveType.TriangleFan: return PrimitiveType.TriangleFan;
|
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.Polygon: return PrimitiveType.Polygon;
|
||||||
case GalPrimitiveType.LinesAdjacency: return PrimitiveType.LinesAdjacency;
|
case GalPrimitiveType.LinesAdjacency: return PrimitiveType.LinesAdjacency;
|
||||||
case GalPrimitiveType.LineStripAdjacency: return PrimitiveType.LineStripAdjacency;
|
case GalPrimitiveType.LineStripAdjacency: return PrimitiveType.LineStripAdjacency;
|
||||||
|
@ -108,7 +106,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalPrimitiveType.Patches: return PrimitiveType.Patches;
|
case GalPrimitiveType.Patches: return PrimitiveType.Patches;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Type));
|
throw new ArgumentException(nameof(Type) + " \"" + Type + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderType GetShaderType(GalShaderType Type)
|
public static ShaderType GetShaderType(GalShaderType Type)
|
||||||
|
@ -122,7 +120,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalShaderType.Fragment: return ShaderType.FragmentShader;
|
case GalShaderType.Fragment: return ShaderType.FragmentShader;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Type));
|
throw new ArgumentException(nameof(Type) + " \"" + Type + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (PixelInternalFormat, PixelFormat, PixelType) GetImageFormat(GalImageFormat Format)
|
public static (PixelInternalFormat, PixelFormat, PixelType) GetImageFormat(GalImageFormat Format)
|
||||||
|
@ -211,7 +209,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalTextureSource.OneFloat: return All.One;
|
case GalTextureSource.OneFloat: return All.One;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Source));
|
throw new ArgumentException(nameof(Source) + " \"" + Source + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextureWrapMode GetTextureWrapMode(GalTextureWrap Wrap)
|
public static TextureWrapMode GetTextureWrapMode(GalTextureWrap Wrap)
|
||||||
|
@ -245,7 +243,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Wrap));
|
throw new ArgumentException(nameof(Wrap) + " \"" + Wrap + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextureMinFilter GetTextureMinFilter(
|
public static TextureMinFilter GetTextureMinFilter(
|
||||||
|
@ -259,7 +257,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalTextureFilter.Linear: return TextureMinFilter.Linear;
|
case GalTextureFilter.Linear: return TextureMinFilter.Linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(MinFilter));
|
throw new ArgumentException(nameof(MinFilter) + " \"" + MinFilter + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextureMagFilter GetTextureMagFilter(GalTextureFilter Filter)
|
public static TextureMagFilter GetTextureMagFilter(GalTextureFilter Filter)
|
||||||
|
@ -270,7 +268,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalTextureFilter.Linear: return TextureMagFilter.Linear;
|
case GalTextureFilter.Linear: return TextureMagFilter.Linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Filter));
|
throw new ArgumentException(nameof(Filter) + " \"" + Filter + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlendEquationMode GetBlendEquation(GalBlendEquation BlendEquation)
|
public static BlendEquationMode GetBlendEquation(GalBlendEquation BlendEquation)
|
||||||
|
@ -284,7 +282,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalBlendEquation.Max: return BlendEquationMode.Max;
|
case GalBlendEquation.Max: return BlendEquationMode.Max;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(BlendEquation));
|
throw new ArgumentException(nameof(BlendEquation) + " \"" + BlendEquation + "\" is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlendingFactor GetBlendFactor(GalBlendFactor BlendFactor)
|
public static BlendingFactor GetBlendFactor(GalBlendFactor BlendFactor)
|
||||||
|
@ -315,7 +313,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
return BlendingFactor.ConstantColor;
|
return BlendingFactor.ConstantColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(BlendFactor));
|
throw new ArgumentException(nameof(BlendFactor) + " \"" + BlendFactor + "\" is not valid!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{ GalVertexAttribSize._11_11_10, 3 }
|
{ GalVertexAttribSize._11_11_10, 3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> FloatAttribTypes =
|
||||||
|
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
||||||
|
{
|
||||||
|
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Float },
|
||||||
|
{ GalVertexAttribSize._32_32_32, VertexAttribPointerType.Float },
|
||||||
|
{ GalVertexAttribSize._16_16_16_16, VertexAttribPointerType.HalfFloat },
|
||||||
|
{ GalVertexAttribSize._32_32, VertexAttribPointerType.Float },
|
||||||
|
{ GalVertexAttribSize._16_16_16, VertexAttribPointerType.HalfFloat },
|
||||||
|
{ GalVertexAttribSize._16_16, VertexAttribPointerType.HalfFloat },
|
||||||
|
{ GalVertexAttribSize._32, VertexAttribPointerType.Float },
|
||||||
|
{ GalVertexAttribSize._16, VertexAttribPointerType.HalfFloat }
|
||||||
|
};
|
||||||
|
|
||||||
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> SignedAttribTypes =
|
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> SignedAttribTypes =
|
||||||
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
||||||
{
|
{
|
||||||
|
@ -356,8 +369,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.EnableVertexAttribArray(Attrib.Index);
|
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
||||||
|
|
||||||
bool Unsigned =
|
bool Unsigned =
|
||||||
|
@ -373,35 +384,50 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
if (Attrib.Type == GalVertexAttribType.Float)
|
if (Attrib.Type == GalVertexAttribType.Float)
|
||||||
{
|
{
|
||||||
Type = VertexAttribPointerType.Float;
|
Type = GetType(FloatAttribTypes, Attrib);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Unsigned)
|
if (Unsigned)
|
||||||
{
|
{
|
||||||
Type = UnsignedAttribTypes[Attrib.Size];
|
Type = GetType(UnsignedAttribTypes, Attrib);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Type = SignedAttribTypes[Attrib.Size];
|
Type = GetType(SignedAttribTypes, Attrib);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Size = AttribElements[Attrib.Size];
|
if (!AttribElements.TryGetValue(Attrib.Size, out int Size))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Invalid attribute size \"" + Attrib.Size + "\"!");
|
||||||
|
}
|
||||||
|
|
||||||
int Offset = Attrib.Offset;
|
int Offset = Attrib.Offset;
|
||||||
|
|
||||||
if (Attrib.Type == GalVertexAttribType.Sint ||
|
if (Binding.Stride != 0)
|
||||||
Attrib.Type == GalVertexAttribType.Uint)
|
|
||||||
{
|
{
|
||||||
IntPtr Pointer = new IntPtr(Offset);
|
GL.EnableVertexAttribArray(Attrib.Index);
|
||||||
|
|
||||||
VertexAttribIntegerType IType = (VertexAttribIntegerType)Type;
|
if (Attrib.Type == GalVertexAttribType.Sint ||
|
||||||
|
Attrib.Type == GalVertexAttribType.Uint)
|
||||||
|
{
|
||||||
|
IntPtr Pointer = new IntPtr(Offset);
|
||||||
|
|
||||||
GL.VertexAttribIPointer(Attrib.Index, Size, IType, Binding.Stride, Pointer);
|
VertexAttribIntegerType IType = (VertexAttribIntegerType)Type;
|
||||||
|
|
||||||
|
GL.VertexAttribIPointer(Attrib.Index, Size, IType, Binding.Stride, Pointer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Binding.Stride, Offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Binding.Stride, Offset);
|
GL.DisableVertexAttribArray(Attrib.Index);
|
||||||
|
|
||||||
|
SetConstAttrib(Attrib);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Binding.Instanced && Binding.Divisor != 0)
|
if (Binding.Instanced && Binding.Divisor != 0)
|
||||||
|
@ -416,6 +442,149 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static VertexAttribPointerType GetType(Dictionary<GalVertexAttribSize, VertexAttribPointerType> Dict, GalVertexAttrib Attrib)
|
||||||
|
{
|
||||||
|
if (!Dict.TryGetValue(Attrib.Size, out VertexAttribPointerType Type))
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("Unsupported size \"" + Attrib.Size + "\" on type \"" + Attrib.Type + "\"!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe static void SetConstAttrib(GalVertexAttrib Attrib)
|
||||||
|
{
|
||||||
|
void Unsupported()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("Constant attribute " + Attrib.Size + " not implemented!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Attrib.Size == GalVertexAttribSize._10_10_10_2 ||
|
||||||
|
Attrib.Size == GalVertexAttribSize._11_11_10)
|
||||||
|
{
|
||||||
|
Unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Attrib.Type == GalVertexAttribType.Unorm)
|
||||||
|
{
|
||||||
|
switch (Attrib.Size)
|
||||||
|
{
|
||||||
|
case GalVertexAttribSize._8:
|
||||||
|
case GalVertexAttribSize._8_8:
|
||||||
|
case GalVertexAttribSize._8_8_8:
|
||||||
|
case GalVertexAttribSize._8_8_8_8:
|
||||||
|
GL.VertexAttrib4N((uint)Attrib.Index, (byte*)Attrib.Pointer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GalVertexAttribSize._16:
|
||||||
|
case GalVertexAttribSize._16_16:
|
||||||
|
case GalVertexAttribSize._16_16_16:
|
||||||
|
case GalVertexAttribSize._16_16_16_16:
|
||||||
|
GL.VertexAttrib4N((uint)Attrib.Index, (ushort*)Attrib.Pointer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GalVertexAttribSize._32:
|
||||||
|
case GalVertexAttribSize._32_32:
|
||||||
|
case GalVertexAttribSize._32_32_32:
|
||||||
|
case GalVertexAttribSize._32_32_32_32:
|
||||||
|
GL.VertexAttrib4N((uint)Attrib.Index, (uint*)Attrib.Pointer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Attrib.Type == GalVertexAttribType.Snorm)
|
||||||
|
{
|
||||||
|
switch (Attrib.Size)
|
||||||
|
{
|
||||||
|
case GalVertexAttribSize._8:
|
||||||
|
case GalVertexAttribSize._8_8:
|
||||||
|
case GalVertexAttribSize._8_8_8:
|
||||||
|
case GalVertexAttribSize._8_8_8_8:
|
||||||
|
GL.VertexAttrib4N((uint)Attrib.Index, (sbyte*)Attrib.Pointer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GalVertexAttribSize._16:
|
||||||
|
case GalVertexAttribSize._16_16:
|
||||||
|
case GalVertexAttribSize._16_16_16:
|
||||||
|
case GalVertexAttribSize._16_16_16_16:
|
||||||
|
GL.VertexAttrib4N((uint)Attrib.Index, (short*)Attrib.Pointer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GalVertexAttribSize._32:
|
||||||
|
case GalVertexAttribSize._32_32:
|
||||||
|
case GalVertexAttribSize._32_32_32:
|
||||||
|
case GalVertexAttribSize._32_32_32_32:
|
||||||
|
GL.VertexAttrib4N((uint)Attrib.Index, (int*)Attrib.Pointer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Attrib.Type == GalVertexAttribType.Uint)
|
||||||
|
{
|
||||||
|
switch (Attrib.Size)
|
||||||
|
{
|
||||||
|
case GalVertexAttribSize._8:
|
||||||
|
case GalVertexAttribSize._8_8:
|
||||||
|
case GalVertexAttribSize._8_8_8:
|
||||||
|
case GalVertexAttribSize._8_8_8_8:
|
||||||
|
GL.VertexAttribI4((uint)Attrib.Index, (byte*)Attrib.Pointer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GalVertexAttribSize._16:
|
||||||
|
case GalVertexAttribSize._16_16:
|
||||||
|
case GalVertexAttribSize._16_16_16:
|
||||||
|
case GalVertexAttribSize._16_16_16_16:
|
||||||
|
GL.VertexAttribI4((uint)Attrib.Index, (ushort*)Attrib.Pointer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GalVertexAttribSize._32:
|
||||||
|
case GalVertexAttribSize._32_32:
|
||||||
|
case GalVertexAttribSize._32_32_32:
|
||||||
|
case GalVertexAttribSize._32_32_32_32:
|
||||||
|
GL.VertexAttribI4((uint)Attrib.Index, (uint*)Attrib.Pointer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Attrib.Type == GalVertexAttribType.Sint)
|
||||||
|
{
|
||||||
|
switch (Attrib.Size)
|
||||||
|
{
|
||||||
|
case GalVertexAttribSize._8:
|
||||||
|
case GalVertexAttribSize._8_8:
|
||||||
|
case GalVertexAttribSize._8_8_8:
|
||||||
|
case GalVertexAttribSize._8_8_8_8:
|
||||||
|
GL.VertexAttribI4((uint)Attrib.Index, (sbyte*)Attrib.Pointer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GalVertexAttribSize._16:
|
||||||
|
case GalVertexAttribSize._16_16:
|
||||||
|
case GalVertexAttribSize._16_16_16:
|
||||||
|
case GalVertexAttribSize._16_16_16_16:
|
||||||
|
GL.VertexAttribI4((uint)Attrib.Index, (short*)Attrib.Pointer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GalVertexAttribSize._32:
|
||||||
|
case GalVertexAttribSize._32_32:
|
||||||
|
case GalVertexAttribSize._32_32_32:
|
||||||
|
case GalVertexAttribSize._32_32_32_32:
|
||||||
|
GL.VertexAttribI4((uint)Attrib.Index, (int*)Attrib.Pointer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Attrib.Type == GalVertexAttribType.Float)
|
||||||
|
{
|
||||||
|
switch (Attrib.Size)
|
||||||
|
{
|
||||||
|
case GalVertexAttribSize._32:
|
||||||
|
case GalVertexAttribSize._32_32:
|
||||||
|
case GalVertexAttribSize._32_32_32:
|
||||||
|
case GalVertexAttribSize._32_32_32_32:
|
||||||
|
GL.VertexAttrib4(Attrib.Index, (float*)Attrib.Pointer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: Unsupported(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Enable(EnableCap Cap, bool Enabled)
|
private void Enable(EnableCap Cap, bool Enabled)
|
||||||
{
|
{
|
||||||
if (Enabled)
|
if (Enabled)
|
||||||
|
|
|
@ -119,6 +119,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
GL.BufferData(BufferTarget.ElementArrayBuffer, Length, HostAddress, BufferUsageHint.StreamDraw);
|
GL.BufferData(BufferTarget.ElementArrayBuffer, Length, HostAddress, BufferUsageHint.StreamDraw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CreateIbo(long Key, int DataSize, byte[] Buffer)
|
||||||
|
{
|
||||||
|
int Handle = GL.GenBuffer();
|
||||||
|
|
||||||
|
IboCache.AddOrUpdate(Key, Handle, (uint)DataSize);
|
||||||
|
|
||||||
|
IntPtr Length = new IntPtr(Buffer.Length);
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle);
|
||||||
|
GL.BufferData(BufferTarget.ElementArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetIndexArray(int Size, GalIndexFormat Format)
|
public void SetIndexArray(int Size, GalIndexFormat Format)
|
||||||
{
|
{
|
||||||
IndexBuffer.Type = OGLEnumConverter.GetDrawElementsType(Format);
|
IndexBuffer.Type = OGLEnumConverter.GetDrawElementsType(Format);
|
||||||
|
@ -135,7 +147,26 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, Count);
|
if (PrimType == GalPrimitiveType.Quads)
|
||||||
|
{
|
||||||
|
for (int Offset = 0; Offset < Count; Offset += 4)
|
||||||
|
{
|
||||||
|
GL.DrawArrays(PrimitiveType.TriangleFan, First + Offset, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (PrimType == GalPrimitiveType.QuadStrip)
|
||||||
|
{
|
||||||
|
GL.DrawArrays(PrimitiveType.TriangleFan, First, 4);
|
||||||
|
|
||||||
|
for (int Offset = 2; Offset < Count; Offset += 2)
|
||||||
|
{
|
||||||
|
GL.DrawArrays(PrimitiveType.TriangleFan, First + Offset, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, Count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType)
|
public void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType)
|
||||||
|
|
|
@ -568,12 +568,15 @@ namespace Ryujinx.Graphics
|
||||||
|
|
||||||
private void UploadVertexArrays(NvGpuVmm Vmm, GalPipelineState State)
|
private void UploadVertexArrays(NvGpuVmm Vmm, GalPipelineState State)
|
||||||
{
|
{
|
||||||
long IndexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress);
|
long IbPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress);
|
||||||
|
|
||||||
long IboKey = Vmm.GetPhysicalAddress(IndexPosition);
|
long IboKey = Vmm.GetPhysicalAddress(IbPosition);
|
||||||
|
|
||||||
int IndexEntryFmt = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat);
|
int IndexEntryFmt = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat);
|
||||||
int IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount);
|
int IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount);
|
||||||
|
int PrimCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl);
|
||||||
|
|
||||||
|
GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff);
|
||||||
|
|
||||||
GalIndexFormat IndexFormat = (GalIndexFormat)IndexEntryFmt;
|
GalIndexFormat IndexFormat = (GalIndexFormat)IndexEntryFmt;
|
||||||
|
|
||||||
|
@ -590,14 +593,50 @@ namespace Ryujinx.Graphics
|
||||||
|
|
||||||
bool IboCached = Gpu.Renderer.Rasterizer.IsIboCached(IboKey, (uint)IbSize);
|
bool IboCached = Gpu.Renderer.Rasterizer.IsIboCached(IboKey, (uint)IbSize);
|
||||||
|
|
||||||
|
bool UsesLegacyQuads =
|
||||||
|
PrimType == GalPrimitiveType.Quads ||
|
||||||
|
PrimType == GalPrimitiveType.QuadStrip;
|
||||||
|
|
||||||
if (!IboCached || QueryKeyUpload(Vmm, IboKey, (uint)IbSize, NvGpuBufferType.Index))
|
if (!IboCached || QueryKeyUpload(Vmm, IboKey, (uint)IbSize, NvGpuBufferType.Index))
|
||||||
{
|
{
|
||||||
IntPtr DataAddress = Vmm.GetHostAddress(IndexPosition, IbSize);
|
if (!UsesLegacyQuads)
|
||||||
|
{
|
||||||
|
IntPtr DataAddress = Vmm.GetHostAddress(IbPosition, IbSize);
|
||||||
|
|
||||||
Gpu.Renderer.Rasterizer.CreateIbo(IboKey, IbSize, DataAddress);
|
Gpu.Renderer.Rasterizer.CreateIbo(IboKey, IbSize, DataAddress);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
byte[] Buffer = Vmm.ReadBytes(IbPosition, IbSize);
|
||||||
|
|
||||||
|
if (PrimType == GalPrimitiveType.Quads)
|
||||||
|
{
|
||||||
|
Buffer = QuadHelper.ConvertIbQuadsToTris(Buffer, IndexEntrySize, IndexCount);
|
||||||
|
}
|
||||||
|
else /* if (PrimType == GalPrimitiveType.QuadStrip) */
|
||||||
|
{
|
||||||
|
Buffer = QuadHelper.ConvertIbQuadStripToTris(Buffer, IndexEntrySize, IndexCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
Gpu.Renderer.Rasterizer.CreateIbo(IboKey, IbSize, Buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Gpu.Renderer.Rasterizer.SetIndexArray(IbSize, IndexFormat);
|
if (!UsesLegacyQuads)
|
||||||
|
{
|
||||||
|
Gpu.Renderer.Rasterizer.SetIndexArray(IbSize, IndexFormat);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (PrimType == GalPrimitiveType.Quads)
|
||||||
|
{
|
||||||
|
Gpu.Renderer.Rasterizer.SetIndexArray(QuadHelper.ConvertIbSizeQuadsToTris(IbSize), IndexFormat);
|
||||||
|
}
|
||||||
|
else /* if (PrimType == GalPrimitiveType.QuadStrip) */
|
||||||
|
{
|
||||||
|
Gpu.Renderer.Rasterizer.SetIndexArray(QuadHelper.ConvertIbSizeQuadStripToTris(IbSize), IndexFormat);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<GalVertexAttrib>[] Attribs = new List<GalVertexAttrib>[32];
|
List<GalVertexAttrib>[] Attribs = new List<GalVertexAttrib>[32];
|
||||||
|
@ -613,10 +652,19 @@ namespace Ryujinx.Graphics
|
||||||
Attribs[ArrayIndex] = new List<GalVertexAttrib>();
|
Attribs[ArrayIndex] = new List<GalVertexAttrib>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long VertexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + ArrayIndex * 4);
|
||||||
|
|
||||||
|
int Offset = (Packed >> 7) & 0x3fff;
|
||||||
|
|
||||||
|
//Note: 16 is the maximum size of an attribute,
|
||||||
|
//having a component size of 32-bits with 4 elements (a vec4).
|
||||||
|
IntPtr Pointer = Vmm.GetHostAddress(VertexPosition + Offset, 16);
|
||||||
|
|
||||||
Attribs[ArrayIndex].Add(new GalVertexAttrib(
|
Attribs[ArrayIndex].Add(new GalVertexAttrib(
|
||||||
Attr,
|
Attr,
|
||||||
((Packed >> 6) & 0x1) != 0,
|
((Packed >> 6) & 0x1) != 0,
|
||||||
(Packed >> 7) & 0x3fff,
|
Offset,
|
||||||
|
Pointer,
|
||||||
(GalVertexAttribSize)((Packed >> 21) & 0x3f),
|
(GalVertexAttribSize)((Packed >> 21) & 0x3f),
|
||||||
(GalVertexAttribType)((Packed >> 27) & 0x7),
|
(GalVertexAttribType)((Packed >> 27) & 0x7),
|
||||||
((Packed >> 31) & 0x1) != 0));
|
((Packed >> 31) & 0x1) != 0));
|
||||||
|
@ -722,6 +770,27 @@ namespace Ryujinx.Graphics
|
||||||
|
|
||||||
long IboKey = Vmm.GetPhysicalAddress(IndexPosition);
|
long IboKey = Vmm.GetPhysicalAddress(IndexPosition);
|
||||||
|
|
||||||
|
//Quad primitive types were deprecated on OpenGL 3.x,
|
||||||
|
//they are converted to a triangles index buffer on IB creation,
|
||||||
|
//so we should use the triangles type here too.
|
||||||
|
if (PrimType == GalPrimitiveType.Quads ||
|
||||||
|
PrimType == GalPrimitiveType.QuadStrip)
|
||||||
|
{
|
||||||
|
PrimType = GalPrimitiveType.Triangles;
|
||||||
|
|
||||||
|
//Note: We assume that index first points to the first
|
||||||
|
//vertex of a quad, if it points to the middle of a
|
||||||
|
//quad (First % 4 != 0 for Quads) then it will not work properly.
|
||||||
|
if (PrimType == GalPrimitiveType.Quads)
|
||||||
|
{
|
||||||
|
IndexFirst = QuadHelper.ConvertIbSizeQuadsToTris(IndexFirst);
|
||||||
|
}
|
||||||
|
else /* if (PrimType == GalPrimitiveType.QuadStrip) */
|
||||||
|
{
|
||||||
|
IndexFirst = QuadHelper.ConvertIbSizeQuadStripToTris(IndexFirst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Gpu.Renderer.Rasterizer.DrawElements(IboKey, IndexFirst, VertexBase, PrimType);
|
Gpu.Renderer.Rasterizer.DrawElements(IboKey, IndexFirst, VertexBase, PrimType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
81
Ryujinx.Graphics/QuadHelper.cs
Normal file
81
Ryujinx.Graphics/QuadHelper.cs
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics
|
||||||
|
{
|
||||||
|
static class QuadHelper
|
||||||
|
{
|
||||||
|
public static int ConvertIbSizeQuadsToTris(int Size)
|
||||||
|
{
|
||||||
|
return Size <= 0 ? 0 : (Size / 4) * 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ConvertIbSizeQuadStripToTris(int Size)
|
||||||
|
{
|
||||||
|
return Size <= 1 ? 0 : ((Size - 2) / 2) * 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] ConvertIbQuadsToTris(byte[] Data, int EntrySize, int Count)
|
||||||
|
{
|
||||||
|
int PrimitivesCount = Count / 4;
|
||||||
|
|
||||||
|
int QuadPrimSize = 4 * EntrySize;
|
||||||
|
int TrisPrimSize = 6 * EntrySize;
|
||||||
|
|
||||||
|
byte[] Output = new byte[PrimitivesCount * 6 * EntrySize];
|
||||||
|
|
||||||
|
for (int Prim = 0; Prim < PrimitivesCount; Prim++)
|
||||||
|
{
|
||||||
|
void AssignIndex(int Src, int Dst, int CopyCount = 1)
|
||||||
|
{
|
||||||
|
Src = Prim * QuadPrimSize + Src * EntrySize;
|
||||||
|
Dst = Prim * TrisPrimSize + Dst * EntrySize;
|
||||||
|
|
||||||
|
Buffer.BlockCopy(Data, Src, Output, Dst, CopyCount * EntrySize);
|
||||||
|
}
|
||||||
|
|
||||||
|
//0 1 2 -> 0 1 2.
|
||||||
|
AssignIndex(0, 0, 3);
|
||||||
|
|
||||||
|
//2 3 -> 3 4.
|
||||||
|
AssignIndex(2, 3, 2);
|
||||||
|
|
||||||
|
//0 -> 5.
|
||||||
|
AssignIndex(0, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] ConvertIbQuadStripToTris(byte[] Data, int EntrySize, int Count)
|
||||||
|
{
|
||||||
|
int PrimitivesCount = (Count - 2) / 2;
|
||||||
|
|
||||||
|
int QuadPrimSize = 2 * EntrySize;
|
||||||
|
int TrisPrimSize = 6 * EntrySize;
|
||||||
|
|
||||||
|
byte[] Output = new byte[PrimitivesCount * 6 * EntrySize];
|
||||||
|
|
||||||
|
for (int Prim = 0; Prim < PrimitivesCount; Prim++)
|
||||||
|
{
|
||||||
|
void AssignIndex(int Src, int Dst, int CopyCount = 1)
|
||||||
|
{
|
||||||
|
Src = Prim * QuadPrimSize + Src * EntrySize + 2 * EntrySize;
|
||||||
|
Dst = Prim * TrisPrimSize + Dst * EntrySize;
|
||||||
|
|
||||||
|
Buffer.BlockCopy(Data, Src, Output, Dst, CopyCount * EntrySize);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-2 -1 0 -> 0 1 2.
|
||||||
|
AssignIndex(-2, 0, 3);
|
||||||
|
|
||||||
|
//0 1 -> 3 4.
|
||||||
|
AssignIndex(0, 3, 2);
|
||||||
|
|
||||||
|
//-2 -> 5.
|
||||||
|
AssignIndex(-2, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -289,7 +289,11 @@ namespace Ryujinx.Graphics.Texture
|
||||||
{
|
{
|
||||||
ImageDescriptor Desc = GetImageDescriptor(Format);
|
ImageDescriptor Desc = GetImageDescriptor(Format);
|
||||||
|
|
||||||
return Desc.BytesPerPixel * DivRoundUp(Width, Desc.BlockWidth);
|
int Pitch = Desc.BytesPerPixel * DivRoundUp(Width, Desc.BlockWidth);
|
||||||
|
|
||||||
|
Pitch = (Pitch + 0x1f) & ~0x1f;
|
||||||
|
|
||||||
|
return Pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetBlockWidth(GalImageFormat Format)
|
public static int GetBlockWidth(GalImageFormat Format)
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Texture
|
||||||
int Width = (Tic[4] & 0xffff) + 1;
|
int Width = (Tic[4] & 0xffff) + 1;
|
||||||
int Height = (Tic[5] & 0xffff) + 1;
|
int Height = (Tic[5] & 0xffff) + 1;
|
||||||
|
|
||||||
return new GalImage(
|
GalImage Image = new GalImage(
|
||||||
Width,
|
Width,
|
||||||
Height,
|
Height,
|
||||||
TileWidth,
|
TileWidth,
|
||||||
|
@ -51,6 +51,13 @@ namespace Ryujinx.Graphics.Texture
|
||||||
YSource,
|
YSource,
|
||||||
ZSource,
|
ZSource,
|
||||||
WSource);
|
WSource);
|
||||||
|
|
||||||
|
if (Layout == GalMemoryLayout.Pitch)
|
||||||
|
{
|
||||||
|
Image.Pitch = (Tic[3] & 0xffff) << 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GalTextureSampler MakeSampler(NvGpu Gpu, NvGpuVmm Vmm, long TscPosition)
|
public static GalTextureSampler MakeSampler(NvGpu Gpu, NvGpuVmm Vmm, long TscPosition)
|
||||||
|
|
Reference in a new issue