Added support for more primitive types (aka topology), added alpha blending support, added texture wrap/filter support, started frame buffer support (not working properly), added index buffer support
This commit is contained in:
parent
46405f6767
commit
10a00cc796
22 changed files with 1044 additions and 227 deletions
|
@ -680,8 +680,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
||||||
}
|
}
|
||||||
|
|
||||||
Map.CpuAddress = Addr;
|
Map.CpuAddress = Addr;
|
||||||
Map.Align = Align;
|
Map.Align = Align;
|
||||||
Map.Kind = Kind;
|
Map.Kind = Kind;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
||||||
private BufferEntry[] BufferQueue;
|
private BufferEntry[] BufferQueue;
|
||||||
|
|
||||||
private ManualResetEvent WaitBufferFree;
|
private ManualResetEvent WaitBufferFree;
|
||||||
|
|
||||||
private object RenderQueueLock;
|
private object RenderQueueLock;
|
||||||
|
|
||||||
private int RenderQueueCount;
|
private int RenderQueueCount;
|
||||||
|
@ -85,7 +85,7 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
||||||
{ ("android.gui.IGraphicBufferProducer", 0xb), GbpDisconnect },
|
{ ("android.gui.IGraphicBufferProducer", 0xb), GbpDisconnect },
|
||||||
{ ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer }
|
{ ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer }
|
||||||
};
|
};
|
||||||
|
|
||||||
this.Renderer = Renderer;
|
this.Renderer = Renderer;
|
||||||
this.ReleaseEvent = ReleaseEvent;
|
this.ReleaseEvent = ReleaseEvent;
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
||||||
using (MemoryStream MS = new MemoryStream())
|
using (MemoryStream MS = new MemoryStream())
|
||||||
{
|
{
|
||||||
BinaryWriter Writer = new BinaryWriter(MS);
|
BinaryWriter Writer = new BinaryWriter(MS);
|
||||||
|
|
||||||
BufferEntry Entry = BufferQueue[Slot];
|
BufferEntry Entry = BufferQueue[Slot];
|
||||||
|
|
||||||
int BufferCount = 1; //?
|
int BufferCount = 1; //?
|
||||||
|
@ -243,7 +243,7 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
||||||
private long GbpPreallocBuffer(ServiceCtx Context, BinaryReader ParcelReader)
|
private long GbpPreallocBuffer(ServiceCtx Context, BinaryReader ParcelReader)
|
||||||
{
|
{
|
||||||
int Slot = ParcelReader.ReadInt32();
|
int Slot = ParcelReader.ReadInt32();
|
||||||
|
|
||||||
int BufferCount = ParcelReader.ReadInt32();
|
int BufferCount = ParcelReader.ReadInt32();
|
||||||
long BufferSize = ParcelReader.ReadInt64();
|
long BufferSize = ParcelReader.ReadInt64();
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
||||||
NvMapFb MapFb = (NvMapFb)ServiceNvDrv.NvMapsFb.GetData(Context.Process, 0);
|
NvMapFb MapFb = (NvMapFb)ServiceNvDrv.NvMapsFb.GetData(Context.Process, 0);
|
||||||
|
|
||||||
long Address = Map.CpuAddress;
|
long Address = Map.CpuAddress;
|
||||||
|
|
||||||
if (MapFb.HasBufferOffset(Slot))
|
if (MapFb.HasBufferOffset(Slot))
|
||||||
{
|
{
|
||||||
Address += MapFb.GetBufferOffset(Slot);
|
Address += MapFb.GetBufferOffset(Slot);
|
||||||
|
|
11
Ryujinx.Graphics/Gal/GalBlendEquation.cs
Normal file
11
Ryujinx.Graphics/Gal/GalBlendEquation.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public enum GalBlendEquation
|
||||||
|
{
|
||||||
|
FuncAdd = 0x8006,
|
||||||
|
Min = 0x8007,
|
||||||
|
Max = 0x8008,
|
||||||
|
FuncSubtract = 0x800a,
|
||||||
|
FuncReverseSubtract = 0x800b
|
||||||
|
}
|
||||||
|
}
|
25
Ryujinx.Graphics/Gal/GalBlendFactor.cs
Normal file
25
Ryujinx.Graphics/Gal/GalBlendFactor.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public enum GalBlendFactor
|
||||||
|
{
|
||||||
|
Zero = 0x4000,
|
||||||
|
One = 0x4001,
|
||||||
|
SrcColor = 0x4300,
|
||||||
|
OneMinusSrcColor = 0x4301,
|
||||||
|
SrcAlpha = 0x4302,
|
||||||
|
OneMinusSrcAlpha = 0x4303,
|
||||||
|
DstAlpha = 0x4304,
|
||||||
|
OneMinusDstAlpha = 0x4305,
|
||||||
|
DstColor = 0x4306,
|
||||||
|
OneMinusDstColor = 0x4307,
|
||||||
|
SrcAlphaSaturate = 0x4308,
|
||||||
|
ConstantColor = 0xc001,
|
||||||
|
OneMinusConstantColor = 0xc002,
|
||||||
|
ConstantAlpha = 0xc003,
|
||||||
|
OneMinusConstantAlpha = 0xc004,
|
||||||
|
Src1Color = 0xc900,
|
||||||
|
OneMinusSrc1Color = 0xc901,
|
||||||
|
Src1Alpha = 0xc902,
|
||||||
|
OneMinusSrc1Alpha = 0xc903
|
||||||
|
}
|
||||||
|
}
|
22
Ryujinx.Graphics/Gal/GalColorF.cs
Normal file
22
Ryujinx.Graphics/Gal/GalColorF.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public struct GalColorF
|
||||||
|
{
|
||||||
|
public float Red { get; private set; }
|
||||||
|
public float Green { get; private set; }
|
||||||
|
public float Blue { get; private set; }
|
||||||
|
public float Alpha { get; private set; }
|
||||||
|
|
||||||
|
public GalColorF(
|
||||||
|
float Red,
|
||||||
|
float Green,
|
||||||
|
float Blue,
|
||||||
|
float Alpha)
|
||||||
|
{
|
||||||
|
this.Red = Red;
|
||||||
|
this.Green = Green;
|
||||||
|
this.Blue = Blue;
|
||||||
|
this.Alpha = Alpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
Ryujinx.Graphics/Gal/GalIndexFormat.cs
Normal file
9
Ryujinx.Graphics/Gal/GalIndexFormat.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public enum GalIndexFormat
|
||||||
|
{
|
||||||
|
Byte = 0,
|
||||||
|
Int16 = 1,
|
||||||
|
Int32 = 2
|
||||||
|
}
|
||||||
|
}
|
8
Ryujinx.Graphics/Gal/GalTextureFilter.cs
Normal file
8
Ryujinx.Graphics/Gal/GalTextureFilter.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public enum GalTextureFilter
|
||||||
|
{
|
||||||
|
Nearest = 1,
|
||||||
|
Linear = 2
|
||||||
|
}
|
||||||
|
}
|
9
Ryujinx.Graphics/Gal/GalTextureMipFilter.cs
Normal file
9
Ryujinx.Graphics/Gal/GalTextureMipFilter.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public enum GalTextureMipFilter
|
||||||
|
{
|
||||||
|
None = 1,
|
||||||
|
Nearest = 2,
|
||||||
|
Linear = 3
|
||||||
|
}
|
||||||
|
}
|
33
Ryujinx.Graphics/Gal/GalTextureSampler.cs
Normal file
33
Ryujinx.Graphics/Gal/GalTextureSampler.cs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public struct GalTextureSampler
|
||||||
|
{
|
||||||
|
public GalTextureWrap AddressU { get; private set; }
|
||||||
|
public GalTextureWrap AddressV { get; private set; }
|
||||||
|
public GalTextureWrap AddressP { get; private set; }
|
||||||
|
|
||||||
|
public GalTextureFilter MinFilter { get; private set; }
|
||||||
|
public GalTextureFilter MagFilter { get; private set; }
|
||||||
|
public GalTextureMipFilter MipFilter { get; private set; }
|
||||||
|
|
||||||
|
public GalColorF BorderColor { get; private set; }
|
||||||
|
|
||||||
|
public GalTextureSampler(
|
||||||
|
GalTextureWrap AddressU,
|
||||||
|
GalTextureWrap AddressV,
|
||||||
|
GalTextureWrap AddressP,
|
||||||
|
GalTextureFilter MinFilter,
|
||||||
|
GalTextureFilter MagFilter,
|
||||||
|
GalTextureMipFilter MipFilter,
|
||||||
|
GalColorF BorderColor)
|
||||||
|
{
|
||||||
|
this.AddressU = AddressU;
|
||||||
|
this.AddressV = AddressV;
|
||||||
|
this.AddressP = AddressP;
|
||||||
|
this.MinFilter = MinFilter;
|
||||||
|
this.MagFilter = MagFilter;
|
||||||
|
this.MipFilter = MipFilter;
|
||||||
|
this.BorderColor = BorderColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
Ryujinx.Graphics/Gal/GalTextureWrap.cs
Normal file
14
Ryujinx.Graphics/Gal/GalTextureWrap.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public enum GalTextureWrap
|
||||||
|
{
|
||||||
|
Repeat = 0,
|
||||||
|
MirroredRepeat = 1,
|
||||||
|
ClampToEdge = 2,
|
||||||
|
ClampToBorder = 3,
|
||||||
|
Clamp = 4,
|
||||||
|
MirrorClampToEdge = 5,
|
||||||
|
MirrorClampToBorder = 6,
|
||||||
|
MirrorClamp = 7
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal
|
namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
|
@ -21,23 +22,56 @@ namespace Ryujinx.Graphics.Gal
|
||||||
float OffsY,
|
float OffsY,
|
||||||
float Rotate);
|
float Rotate);
|
||||||
|
|
||||||
|
//Blend
|
||||||
|
void SetBlendEnable(bool Enable);
|
||||||
|
|
||||||
|
void SetBlend(
|
||||||
|
GalBlendEquation Equation,
|
||||||
|
GalBlendFactor FuncSrc,
|
||||||
|
GalBlendFactor FuncDst);
|
||||||
|
|
||||||
|
void SetBlendSeparate(
|
||||||
|
GalBlendEquation EquationRgb,
|
||||||
|
GalBlendEquation EquationAlpha,
|
||||||
|
GalBlendFactor FuncSrcRgb,
|
||||||
|
GalBlendFactor FuncDstRgb,
|
||||||
|
GalBlendFactor FuncSrcAlpha,
|
||||||
|
GalBlendFactor FuncDstAlpha);
|
||||||
|
|
||||||
|
//Frame Buffer
|
||||||
|
void SetFb(int FbIndex, int Width, int Height);
|
||||||
|
|
||||||
|
void BindFrameBuffer(int FbIndex);
|
||||||
|
|
||||||
|
void DrawFrameBuffer(int FbIndex);
|
||||||
|
|
||||||
//Rasterizer
|
//Rasterizer
|
||||||
void ClearBuffers(int RtIndex, GalClearBufferFlags Flags);
|
void ClearBuffers(int RtIndex, GalClearBufferFlags Flags);
|
||||||
|
|
||||||
void SetVertexArray(int VbIndex, int Stride, byte[] Buffer, GalVertexAttrib[] Attribs);
|
void SetVertexArray(int VbIndex, int Stride, byte[] Buffer, GalVertexAttrib[] Attribs);
|
||||||
|
|
||||||
void RenderVertexArray(int VbIndex);
|
void SetIndexArray(byte[] Buffer, GalIndexFormat Format);
|
||||||
|
|
||||||
|
void DrawArrays(int VbIndex, GalPrimitiveType PrimType);
|
||||||
|
|
||||||
|
void DrawElements(int VbIndex, int First, GalPrimitiveType PrimType);
|
||||||
|
|
||||||
//Shader
|
//Shader
|
||||||
void CreateShader(long Tag, GalShaderType Type, byte[] Data);
|
void CreateShader(long Tag, GalShaderType Type, byte[] Data);
|
||||||
|
|
||||||
void SetShaderConstBuffer(long Tag, int Cbuf, byte[] Data);
|
IEnumerable<ShaderDeclInfo> GetTextureUsage(long Tag);
|
||||||
|
|
||||||
|
void SetConstBuffer(long Tag, int Cbuf, byte[] Data);
|
||||||
|
|
||||||
|
void SetUniform1(string UniformName, int Value);
|
||||||
|
|
||||||
void BindShader(long Tag);
|
void BindShader(long Tag);
|
||||||
|
|
||||||
void BindProgram();
|
void BindProgram();
|
||||||
|
|
||||||
//Texture
|
//Texture
|
||||||
void UpdateTextures(Func<int, GalShaderType, GalTexture> RequestTextureCallback);
|
void SetTexture(int Index, GalTexture Tex);
|
||||||
|
|
||||||
|
void SetSampler(int Index, GalTextureSampler Sampler);
|
||||||
}
|
}
|
||||||
}
|
}
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,42 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
static class OGLEnumConverter
|
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)
|
public static ShaderType GetShaderType(GalShaderType Type)
|
||||||
{
|
{
|
||||||
switch (Type)
|
switch (Type)
|
||||||
|
@ -30,5 +66,64 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
throw new NotImplementedException(Format.ToString());
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,7 +44,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{ GalVertexAttribSize._11_11_10, VertexAttribPointerType.Int } //?
|
{ GalVertexAttribSize._11_11_10, VertexAttribPointerType.Int } //?
|
||||||
};
|
};
|
||||||
|
|
||||||
private struct VertexBuffer
|
private struct VbInfo
|
||||||
{
|
{
|
||||||
public int VaoHandle;
|
public int VaoHandle;
|
||||||
public int VboHandle;
|
public int VboHandle;
|
||||||
|
@ -52,11 +52,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
public int PrimCount;
|
public int PrimCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
private VertexBuffer[] VertexBuffers;
|
private struct IbInfo
|
||||||
|
{
|
||||||
|
public int IboHandle;
|
||||||
|
public int Count;
|
||||||
|
|
||||||
|
public DrawElementsType Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private VbInfo[] VertexBuffers;
|
||||||
|
|
||||||
|
private IbInfo IndexBuffer;
|
||||||
|
|
||||||
public OGLRasterizer()
|
public OGLRasterizer()
|
||||||
{
|
{
|
||||||
VertexBuffers = new VertexBuffer[32];
|
VertexBuffers = new VbInfo[32];
|
||||||
|
|
||||||
|
IndexBuffer = new IbInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags)
|
public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags)
|
||||||
|
@ -92,7 +104,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
VertexBuffers[VbIndex].PrimCount = Buffer.Length / Stride;
|
VertexBuffers[VbIndex].PrimCount = Buffer.Length / Stride;
|
||||||
|
|
||||||
VertexBuffer Vb = VertexBuffers[VbIndex];
|
VbInfo Vb = VertexBuffers[VbIndex];
|
||||||
|
|
||||||
IntPtr Length = new IntPtr(Buffer.Length);
|
IntPtr Length = new IntPtr(Buffer.Length);
|
||||||
|
|
||||||
|
@ -144,9 +156,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
GL.BindVertexArray(0);
|
GL.BindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RenderVertexArray(int VbIndex)
|
public void SetIndexArray(byte[] Buffer, GalIndexFormat Format)
|
||||||
{
|
{
|
||||||
VertexBuffer Vb = VertexBuffers[VbIndex];
|
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)
|
if (Vb.PrimCount == 0)
|
||||||
{
|
{
|
||||||
|
@ -155,12 +182,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
GL.BindVertexArray(Vb.VaoHandle);
|
GL.BindVertexArray(Vb.VaoHandle);
|
||||||
|
|
||||||
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, Vb.PrimCount);
|
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)
|
private void EnsureVbInitialized(int VbIndex)
|
||||||
{
|
{
|
||||||
VertexBuffer Vb = VertexBuffers[VbIndex];
|
VbInfo Vb = VertexBuffers[VbIndex];
|
||||||
|
|
||||||
if (Vb.VaoHandle == 0)
|
if (Vb.VaoHandle == 0)
|
||||||
{
|
{
|
||||||
|
@ -174,5 +219,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
VertexBuffers[VbIndex] = Vb;
|
VertexBuffers[VbIndex] = Vb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EnsureIbInitialized()
|
||||||
|
{
|
||||||
|
if (IndexBuffer.IboHandle == 0)
|
||||||
|
{
|
||||||
|
IndexBuffer.IboHandle = GL.GenBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using Ryujinx.Graphics.Gal.Shader;
|
using Ryujinx.Graphics.Gal.Shader;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -13,23 +14,37 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
public int Handle { get; private set; }
|
public int Handle { get; private set; }
|
||||||
|
|
||||||
|
public bool IsCompiled { get; private set; }
|
||||||
|
|
||||||
public GalShaderType Type { 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> TextureUsage { get; private set; }
|
||||||
public IEnumerable<ShaderDeclInfo> UniformUsage { get; private set; }
|
public IEnumerable<ShaderDeclInfo> UniformUsage { get; private set; }
|
||||||
|
|
||||||
public ShaderStage(
|
public ShaderStage(
|
||||||
GalShaderType Type,
|
GalShaderType Type,
|
||||||
|
string Code,
|
||||||
IEnumerable<ShaderDeclInfo> TextureUsage,
|
IEnumerable<ShaderDeclInfo> TextureUsage,
|
||||||
IEnumerable<ShaderDeclInfo> UniformUsage)
|
IEnumerable<ShaderDeclInfo> UniformUsage)
|
||||||
{
|
{
|
||||||
Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type));
|
|
||||||
|
|
||||||
this.Type = Type;
|
this.Type = Type;
|
||||||
|
this.Code = Code;
|
||||||
this.TextureUsage = TextureUsage;
|
this.TextureUsage = TextureUsage;
|
||||||
this.UniformUsage = UniformUsage;
|
this.UniformUsage = UniformUsage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Compile()
|
||||||
|
{
|
||||||
|
if (Handle == 0)
|
||||||
|
{
|
||||||
|
Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type));
|
||||||
|
|
||||||
|
CompileAndCheck(Handle, Code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
|
@ -57,7 +72,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
private ShaderProgram Current;
|
private ShaderProgram Current;
|
||||||
|
|
||||||
private Dictionary<long, ShaderStage> Stages;
|
private ConcurrentDictionary<long, ShaderStage> Stages;
|
||||||
|
|
||||||
private Dictionary<ShaderProgram, int> Programs;
|
private Dictionary<ShaderProgram, int> Programs;
|
||||||
|
|
||||||
|
@ -65,49 +80,62 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public OGLShader()
|
public OGLShader()
|
||||||
{
|
{
|
||||||
Stages = new Dictionary<long, ShaderStage>();
|
Stages = new ConcurrentDictionary<long, ShaderStage>();
|
||||||
|
|
||||||
Programs = new Dictionary<ShaderProgram, int>();
|
Programs = new Dictionary<ShaderProgram, int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Create(long Tag, GalShaderType Type, byte[] Data)
|
public void Create(long Tag, GalShaderType Type, byte[] Data)
|
||||||
{
|
{
|
||||||
if (!Stages.ContainsKey(Tag))
|
Stages.GetOrAdd(Tag, (Key) => ShaderStageFactory(Type, Data));
|
||||||
{
|
|
||||||
GlslProgram Program = GetGlslProgram(Data, Type);
|
|
||||||
|
|
||||||
ShaderStage Stage = new ShaderStage(
|
|
||||||
Type,
|
|
||||||
Program.Textures,
|
|
||||||
Program.Uniforms);
|
|
||||||
|
|
||||||
Stages.Add(Tag, Stage);
|
|
||||||
|
|
||||||
CompileAndCheck(Stage.Handle, Program.Code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<ShaderDeclInfo> GetTextureUsage(GalShaderType ShaderType)
|
private ShaderStage ShaderStageFactory(GalShaderType Type, byte[] Data)
|
||||||
{
|
{
|
||||||
switch (ShaderType)
|
GlslProgram Program = GetGlslProgram(Data, Type);
|
||||||
{
|
|
||||||
case GalShaderType.Vertex: return GetTextureUsage(Current.Vertex);
|
|
||||||
case GalShaderType.TessControl: return GetTextureUsage(Current.TessControl);
|
|
||||||
case GalShaderType.TessEvaluation: return GetTextureUsage(Current.TessEvaluation);
|
|
||||||
case GalShaderType.Geometry: return GetTextureUsage(Current.Geometry);
|
|
||||||
case GalShaderType.Fragment: return GetTextureUsage(Current.Fragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return new ShaderStage(
|
||||||
|
Type,
|
||||||
|
Program.Code,
|
||||||
|
Program.Textures,
|
||||||
|
Program.Uniforms);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<ShaderDeclInfo> GetTextureUsage(ShaderStage Stage)
|
private GlslProgram GetGlslProgram(byte[] Data, GalShaderType Type)
|
||||||
{
|
{
|
||||||
return Stage?.TextureUsage ?? Enumerable.Empty<ShaderDeclInfo>();
|
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)
|
public void SetConstBuffer(long Tag, int Cbuf, byte[] Data)
|
||||||
{
|
{
|
||||||
|
BindProgram();
|
||||||
|
|
||||||
if (Stages.TryGetValue(Tag, out ShaderStage Stage))
|
if (Stages.TryGetValue(Tag, out ShaderStage Stage))
|
||||||
{
|
{
|
||||||
foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage.Where(x => x.Cbuf == Cbuf))
|
foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage.Where(x => x.Cbuf == Cbuf))
|
||||||
|
@ -121,18 +149,32 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetUniform1(string UniformName, int Value)
|
||||||
|
{
|
||||||
|
BindProgram();
|
||||||
|
|
||||||
|
int Location = GL.GetUniformLocation(CurrentProgramHandle, UniformName);
|
||||||
|
|
||||||
|
GL.Uniform1(Location, Value);
|
||||||
|
}
|
||||||
|
|
||||||
public void Bind(long Tag)
|
public void Bind(long Tag)
|
||||||
{
|
{
|
||||||
if (Stages.TryGetValue(Tag, out ShaderStage Stage))
|
if (Stages.TryGetValue(Tag, out ShaderStage Stage))
|
||||||
{
|
{
|
||||||
switch (Stage.Type)
|
Bind(Stage);
|
||||||
{
|
}
|
||||||
case GalShaderType.Vertex: Current.Vertex = Stage; break;
|
}
|
||||||
case GalShaderType.TessControl: Current.TessControl = Stage; break;
|
|
||||||
case GalShaderType.TessEvaluation: Current.TessEvaluation = Stage; break;
|
private void Bind(ShaderStage Stage)
|
||||||
case GalShaderType.Geometry: Current.Geometry = Stage; break;
|
{
|
||||||
case GalShaderType.Fragment: Current.Fragment = Stage; break;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,32 +212,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
if (Stage != null)
|
if (Stage != null)
|
||||||
{
|
{
|
||||||
|
Stage.Compile();
|
||||||
|
|
||||||
GL.AttachShader(ProgramHandle, Stage.Handle);
|
GL.AttachShader(ProgramHandle, Stage.Handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private GlslProgram GetGlslProgram(byte[] Data, GalShaderType Type)
|
public static void CompileAndCheck(int Handle, string Code)
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CompileAndCheck(int Handle, string Code)
|
|
||||||
{
|
{
|
||||||
GL.ShaderSource(Handle, Code);
|
GL.ShaderSource(Handle, Code);
|
||||||
GL.CompileShader(Handle);
|
GL.CompileShader(Handle);
|
||||||
|
|
|
@ -1,72 +1,34 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
class OGLTexture
|
class OGLTexture
|
||||||
{
|
{
|
||||||
private OGLShader Shader;
|
|
||||||
|
|
||||||
private int[] Textures;
|
private int[] Textures;
|
||||||
|
|
||||||
private int CurrentTextureIndex;
|
public OGLTexture()
|
||||||
|
|
||||||
public OGLTexture(OGLShader Shader)
|
|
||||||
{
|
{
|
||||||
this.Shader = Shader;
|
|
||||||
|
|
||||||
Textures = new int[80];
|
Textures = new int[80];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateTextures(Func<int, GalShaderType, GalTexture> RequestTextureCallback)
|
public void Set(int Index, GalTexture Tex)
|
||||||
{
|
{
|
||||||
CurrentTextureIndex = 0;
|
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||||||
|
|
||||||
UpdateTextures(RequestTextureCallback, GalShaderType.Vertex);
|
int Handle = EnsureTextureInitialized(Index);
|
||||||
UpdateTextures(RequestTextureCallback, GalShaderType.TessControl);
|
|
||||||
UpdateTextures(RequestTextureCallback, GalShaderType.TessEvaluation);
|
|
||||||
UpdateTextures(RequestTextureCallback, GalShaderType.Geometry);
|
|
||||||
UpdateTextures(RequestTextureCallback, GalShaderType.Fragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateTextures(Func<int, GalShaderType, GalTexture> RequestTextureCallback, GalShaderType ShaderType)
|
|
||||||
{
|
|
||||||
foreach (ShaderDeclInfo DeclInfo in Shader.GetTextureUsage(ShaderType))
|
|
||||||
{
|
|
||||||
GalTexture Texture = RequestTextureCallback(DeclInfo.Index, ShaderType);
|
|
||||||
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0 + CurrentTextureIndex);
|
|
||||||
|
|
||||||
UploadTexture(Texture);
|
|
||||||
|
|
||||||
int Location = GL.GetUniformLocation(Shader.CurrentProgramHandle, DeclInfo.Name);
|
|
||||||
|
|
||||||
GL.Uniform1(Location, CurrentTextureIndex++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UploadTexture(GalTexture Texture)
|
|
||||||
{
|
|
||||||
int Handle = EnsureTextureInitialized(CurrentTextureIndex);
|
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||||
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
|
int W = Tex.Width;
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
|
int H = Tex.Height;
|
||||||
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
byte[] Data = Tex.Data;
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
|
||||||
|
|
||||||
int W = Texture.Width;
|
|
||||||
int H = Texture.Height;
|
|
||||||
|
|
||||||
byte[] Data = Texture.Data;
|
|
||||||
|
|
||||||
int Length = Data.Length;
|
int Length = Data.Length;
|
||||||
|
|
||||||
if (IsCompressedTextureFormat(Texture.Format))
|
if (IsCompressedTextureFormat(Tex.Format))
|
||||||
{
|
{
|
||||||
PixelInternalFormat Pif = OGLEnumConverter.GetCompressedTextureFormat(Texture.Format);
|
PixelInternalFormat Pif = OGLEnumConverter.GetCompressedTextureFormat(Tex.Format);
|
||||||
|
|
||||||
GL.CompressedTexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Length, Data);
|
GL.CompressedTexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Length, Data);
|
||||||
}
|
}
|
||||||
|
@ -83,6 +45,35 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
private static bool IsCompressedTextureFormat(GalTextureFormat Format)
|
||||||
{
|
{
|
||||||
return Format == GalTextureFormat.BC1 ||
|
return Format == GalTextureFormat.BC1 ||
|
||||||
|
@ -90,13 +81,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Format == GalTextureFormat.BC3;
|
Format == GalTextureFormat.BC3;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int EnsureTextureInitialized(int TextureIndex)
|
private int EnsureTextureInitialized(int TexIndex)
|
||||||
{
|
{
|
||||||
int Handle = Textures[TextureIndex];
|
int Handle = Textures[TexIndex];
|
||||||
|
|
||||||
if (Handle == 0)
|
if (Handle == 0)
|
||||||
{
|
{
|
||||||
Handle = Textures[TextureIndex] = GL.GenTexture();
|
Handle = Textures[TexIndex] = GL.GenTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Handle;
|
return Handle;
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
public class OpenGLRenderer : IGalRenderer
|
public class OpenGLRenderer : IGalRenderer
|
||||||
{
|
{
|
||||||
|
private OGLBlend Blend;
|
||||||
|
|
||||||
|
private OGLFrameBuffer FrameBuffer;
|
||||||
|
|
||||||
private OGLRasterizer Rasterizer;
|
private OGLRasterizer Rasterizer;
|
||||||
|
|
||||||
private OGLShader Shader;
|
private OGLShader Shader;
|
||||||
|
@ -18,11 +23,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public OpenGLRenderer()
|
public OpenGLRenderer()
|
||||||
{
|
{
|
||||||
|
Blend = new OGLBlend();
|
||||||
|
|
||||||
|
FrameBuffer = new OGLFrameBuffer();
|
||||||
|
|
||||||
Rasterizer = new OGLRasterizer();
|
Rasterizer = new OGLRasterizer();
|
||||||
|
|
||||||
Shader = new OGLShader();
|
Shader = new OGLShader();
|
||||||
|
|
||||||
Texture = new OGLTexture(Shader);
|
Texture = new OGLTexture();
|
||||||
|
|
||||||
ActionsQueue = new ConcurrentQueue<Action>();
|
ActionsQueue = new ConcurrentQueue<Action>();
|
||||||
}
|
}
|
||||||
|
@ -83,6 +92,61 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
FbRenderer.Set(Fb, Width, Height, Transform, Offs);
|
FbRenderer.Set(Fb, Width, Height, Transform, Offs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetBlendEnable(bool Enable)
|
||||||
|
{
|
||||||
|
if (Enable)
|
||||||
|
{
|
||||||
|
ActionsQueue.Enqueue(() => Blend.Enable());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ActionsQueue.Enqueue(() => Blend.Disable());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBlend(
|
||||||
|
GalBlendEquation Equation,
|
||||||
|
GalBlendFactor FuncSrc,
|
||||||
|
GalBlendFactor FuncDst)
|
||||||
|
{
|
||||||
|
ActionsQueue.Enqueue(() => Blend.Set(Equation, FuncSrc, FuncDst));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetFb(int FbIndex, int Width, int Height)
|
||||||
|
{
|
||||||
|
ActionsQueue.Enqueue(() => FrameBuffer.Set(FbIndex, Width, Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BindFrameBuffer(int FbIndex)
|
||||||
|
{
|
||||||
|
ActionsQueue.Enqueue(() => FrameBuffer.Bind(FbIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawFrameBuffer(int FbIndex)
|
||||||
|
{
|
||||||
|
ActionsQueue.Enqueue(() => FrameBuffer.Draw(FbIndex));
|
||||||
|
}
|
||||||
|
|
||||||
public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags)
|
public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags)
|
||||||
{
|
{
|
||||||
ActionsQueue.Enqueue(() => Rasterizer.ClearBuffers(RtIndex, Flags));
|
ActionsQueue.Enqueue(() => Rasterizer.ClearBuffers(RtIndex, Flags));
|
||||||
|
@ -100,14 +164,34 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Attribs ?? throw new ArgumentNullException(nameof(Attribs))));
|
Attribs ?? throw new ArgumentNullException(nameof(Attribs))));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RenderVertexArray(int VbIndex)
|
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)
|
if ((uint)VbIndex > 31)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(VbIndex));
|
throw new ArgumentOutOfRangeException(nameof(VbIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionsQueue.Enqueue(() => Rasterizer.RenderVertexArray(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)
|
public void CreateShader(long Tag, GalShaderType Type, byte[] Data)
|
||||||
|
@ -117,10 +201,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
throw new ArgumentNullException(nameof(Data));
|
throw new ArgumentNullException(nameof(Data));
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionsQueue.Enqueue(() => Shader.Create(Tag, Type, Data));
|
Shader.Create(Tag, Type, Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetShaderConstBuffer(long Tag, int Cbuf, byte[] Data)
|
public void SetConstBuffer(long Tag, int Cbuf, byte[] Data)
|
||||||
{
|
{
|
||||||
if (Data == null)
|
if (Data == null)
|
||||||
{
|
{
|
||||||
|
@ -130,6 +214,21 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
ActionsQueue.Enqueue(() => Shader.SetConstBuffer(Tag, Cbuf, 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)
|
public void BindShader(long Tag)
|
||||||
{
|
{
|
||||||
ActionsQueue.Enqueue(() => Shader.Bind(Tag));
|
ActionsQueue.Enqueue(() => Shader.Bind(Tag));
|
||||||
|
@ -140,9 +239,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
ActionsQueue.Enqueue(() => Shader.BindProgram());
|
ActionsQueue.Enqueue(() => Shader.BindProgram());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateTextures(Func<int, GalShaderType, GalTexture> RequestTextureCallback)
|
public void SetTexture(int Index, GalTexture Tex)
|
||||||
{
|
{
|
||||||
ActionsQueue.Enqueue(() => Texture.UpdateTextures(RequestTextureCallback));
|
ActionsQueue.Enqueue(() => Texture.Set(Index, Tex));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetSampler(int Index, GalTextureSampler Sampler)
|
||||||
|
{
|
||||||
|
ActionsQueue.Enqueue(() => Texture.Set(Index, Sampler));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -152,7 +152,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
else if (DeclInfo.Name == GlslDecl.FragmentOutputName)
|
else if (DeclInfo.Name == GlslDecl.FragmentOutputName)
|
||||||
{
|
{
|
||||||
Name = "out " + GetDecl(DeclInfo) + ";";
|
Name = "layout (location = 0) out " + GetDecl(DeclInfo) + ";";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,6 +22,8 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private ConstBuffer[] Cbs;
|
private ConstBuffer[] Cbs;
|
||||||
|
|
||||||
|
private bool HasDataToRender;
|
||||||
|
|
||||||
public NvGpuEngine3d(NsGpu Gpu)
|
public NvGpuEngine3d(NsGpu Gpu)
|
||||||
{
|
{
|
||||||
this.Gpu = Gpu;
|
this.Gpu = Gpu;
|
||||||
|
@ -61,34 +63,60 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const long GoodFbAddress = 0x1615b2a00;
|
||||||
|
|
||||||
private void VertexEndGl(AMemory Memory, NsGpuPBEntry PBEntry)
|
private void VertexEndGl(AMemory Memory, NsGpuPBEntry PBEntry)
|
||||||
{
|
{
|
||||||
int TexCbuf = ReadRegister(NvGpuEngine3dReg.TextureCbIndex);
|
SetFrameBuffer(0);
|
||||||
|
|
||||||
int TexHandle = ReadCb(Memory, TexCbuf, 0x20);
|
long[] Tags = UploadShaders(Memory);
|
||||||
|
|
||||||
UploadShaders(Memory);
|
|
||||||
|
|
||||||
Gpu.Renderer.BindProgram();
|
Gpu.Renderer.BindProgram();
|
||||||
|
|
||||||
UploadTextures(Memory);
|
SetAlphaBlending();
|
||||||
|
|
||||||
|
UploadTextures(Memory, Tags);
|
||||||
UploadUniforms(Memory);
|
UploadUniforms(Memory);
|
||||||
UploadVertexArrays(Memory);
|
UploadVertexArrays(Memory);
|
||||||
|
|
||||||
|
HasDataToRender = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClearBuffers(AMemory Memory, NsGpuPBEntry PBEntry)
|
private void ClearBuffers(AMemory Memory, NsGpuPBEntry PBEntry)
|
||||||
{
|
{
|
||||||
|
if (HasDataToRender)
|
||||||
|
{
|
||||||
|
HasDataToRender = false;
|
||||||
|
|
||||||
|
Gpu.Renderer.DrawFrameBuffer(0);
|
||||||
|
}
|
||||||
|
|
||||||
int Arg0 = PBEntry.Arguments[0];
|
int Arg0 = PBEntry.Arguments[0];
|
||||||
|
|
||||||
int Rt = (Arg0 >> 6) & 0xf;
|
int FbIndex = (Arg0 >> 6) & 0xf;
|
||||||
|
|
||||||
|
int Layer = (Arg0 >> 10) & 0x3ff;
|
||||||
|
|
||||||
GalClearBufferFlags Flags = (GalClearBufferFlags)(Arg0 & 0x3f);
|
GalClearBufferFlags Flags = (GalClearBufferFlags)(Arg0 & 0x3f);
|
||||||
|
|
||||||
Gpu.Renderer.ClearBuffers(Rt, Flags);
|
SetFrameBuffer(0);
|
||||||
|
|
||||||
|
Gpu.Renderer.ClearBuffers(Layer, Flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UploadShaders(AMemory Memory)
|
private void SetFrameBuffer(int FbIndex)
|
||||||
{
|
{
|
||||||
|
int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10);
|
||||||
|
int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10);
|
||||||
|
|
||||||
|
Gpu.Renderer.SetFb(FbIndex, Width, Height);
|
||||||
|
Gpu.Renderer.BindFrameBuffer(FbIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long[] UploadShaders(AMemory Memory)
|
||||||
|
{
|
||||||
|
long[] Tags = new long[5];
|
||||||
|
|
||||||
long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
||||||
|
|
||||||
for (int Index = 0; Index < 6; Index++)
|
for (int Index = 0; Index < 6; Index++)
|
||||||
|
@ -115,9 +143,108 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
GalShaderType ShaderType = GetTypeFromProgram(Index);
|
GalShaderType ShaderType = GetTypeFromProgram(Index);
|
||||||
|
|
||||||
|
Tags[(int)ShaderType] = Tag;
|
||||||
|
|
||||||
Gpu.Renderer.CreateShader(Tag, ShaderType, Code);
|
Gpu.Renderer.CreateShader(Tag, ShaderType, Code);
|
||||||
Gpu.Renderer.BindShader(Tag);
|
Gpu.Renderer.BindShader(Tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GalShaderType GetTypeFromProgram(int Program)
|
||||||
|
{
|
||||||
|
switch (Program)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 1: return GalShaderType.Vertex;
|
||||||
|
case 2: return GalShaderType.TessControl;
|
||||||
|
case 3: return GalShaderType.TessEvaluation;
|
||||||
|
case 4: return GalShaderType.Geometry;
|
||||||
|
case 5: return GalShaderType.Fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(Program));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetAlphaBlending()
|
||||||
|
{
|
||||||
|
bool BlendEnableMaster = (ReadRegister(NvGpuEngine3dReg.BlendEnableMaster) & 1) != 0;
|
||||||
|
|
||||||
|
Gpu.Renderer.SetBlendEnable(BlendEnableMaster);
|
||||||
|
|
||||||
|
bool BlendSeparateAlpha = (ReadRegister(NvGpuEngine3dReg.BlendSeparateAlpha) & 1) != 0;
|
||||||
|
|
||||||
|
GalBlendEquation EquationRgb = (GalBlendEquation)ReadRegister(NvGpuEngine3dReg.BlendEquationRgb);
|
||||||
|
|
||||||
|
GalBlendFactor FuncSrcRgb = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.BlendFuncSrcRgb);
|
||||||
|
GalBlendFactor FuncDstRgb = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.BlendFuncDstRgb);
|
||||||
|
|
||||||
|
if (BlendSeparateAlpha)
|
||||||
|
{
|
||||||
|
GalBlendEquation EquationAlpha = (GalBlendEquation)ReadRegister(NvGpuEngine3dReg.BlendEquationAlpha);
|
||||||
|
|
||||||
|
GalBlendFactor FuncSrcAlpha = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.BlendFuncSrcAlpha);
|
||||||
|
GalBlendFactor FuncDstAlpha = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.BlendFuncDstAlpha);
|
||||||
|
|
||||||
|
Gpu.Renderer.SetBlendSeparate(
|
||||||
|
EquationRgb,
|
||||||
|
EquationAlpha,
|
||||||
|
FuncSrcRgb,
|
||||||
|
FuncDstRgb,
|
||||||
|
FuncSrcAlpha,
|
||||||
|
FuncDstAlpha);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Gpu.Renderer.SetBlend(EquationRgb, FuncSrcRgb, FuncDstRgb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UploadTextures(AMemory Memory, long[] Tags)
|
||||||
|
{
|
||||||
|
long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
||||||
|
|
||||||
|
int TextureCbIndex = ReadRegister(NvGpuEngine3dReg.TextureCbIndex);
|
||||||
|
|
||||||
|
long BasePosition = Cbs[TextureCbIndex].Position;
|
||||||
|
|
||||||
|
long Size = (uint)Cbs[TextureCbIndex].Size;
|
||||||
|
|
||||||
|
int TexIndex = 0;
|
||||||
|
|
||||||
|
for (int Index = 0; Index < Tags.Length; Index++)
|
||||||
|
{
|
||||||
|
foreach (ShaderDeclInfo DeclInfo in Gpu.Renderer.GetTextureUsage(Tags[Index]))
|
||||||
|
{
|
||||||
|
long Position = BasePosition + Index * Size;
|
||||||
|
|
||||||
|
UploadTexture(Memory, Position, TexIndex, DeclInfo.Index);
|
||||||
|
|
||||||
|
Gpu.Renderer.SetUniform1(DeclInfo.Name, TexIndex);
|
||||||
|
|
||||||
|
TexIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UploadTexture(AMemory Memory, long BasePosition, int TexIndex, int HndIndex)
|
||||||
|
{
|
||||||
|
long Position = BasePosition + HndIndex * 4;
|
||||||
|
|
||||||
|
int TextureHandle = Memory.ReadInt32(Position);
|
||||||
|
|
||||||
|
int TicIndex = (TextureHandle >> 0) & 0xfffff;
|
||||||
|
int TscIndex = (TextureHandle >> 20) & 0xfff;
|
||||||
|
|
||||||
|
TryGetCpuAddr(NvGpuEngine3dReg.TexHeaderPoolOffset, out long TicPosition);
|
||||||
|
TryGetCpuAddr(NvGpuEngine3dReg.TexSamplerPoolOffset, out long TscPosition);
|
||||||
|
|
||||||
|
TicPosition += TicIndex * 0x20;
|
||||||
|
TscPosition += TscIndex * 0x20;
|
||||||
|
|
||||||
|
Gpu.Renderer.SetTexture(TexIndex, TextureFactory.MakeTexture(Gpu, Memory, TicPosition));
|
||||||
|
Gpu.Renderer.SetSampler(TexIndex, TextureFactory.MakeSampler(Gpu, Memory, TscPosition));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UploadUniforms(AMemory Memory)
|
private void UploadUniforms(AMemory Memory)
|
||||||
|
@ -147,7 +274,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
byte[] Data = AMemoryHelper.ReadBytes(Memory, CbPosition, (uint)Cb.Size);
|
byte[] Data = AMemoryHelper.ReadBytes(Memory, CbPosition, (uint)Cb.Size);
|
||||||
|
|
||||||
Gpu.Renderer.SetShaderConstBuffer(BasePosition + (uint)Offset, Cbuf, Data);
|
Gpu.Renderer.SetConstBuffer(BasePosition + (uint)Offset, Cbuf, Data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,6 +282,32 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private void UploadVertexArrays(AMemory Memory)
|
private void UploadVertexArrays(AMemory Memory)
|
||||||
{
|
{
|
||||||
|
long IndexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress);
|
||||||
|
|
||||||
|
int IndexSize = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat);
|
||||||
|
int IndexFirst = ReadRegister(NvGpuEngine3dReg.IndexBatchFirst);
|
||||||
|
int IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount);
|
||||||
|
|
||||||
|
GalIndexFormat IndexFormat = (GalIndexFormat)IndexSize;
|
||||||
|
|
||||||
|
IndexSize = 1 << IndexSize;
|
||||||
|
|
||||||
|
if (IndexSize > 4)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IndexSize != 0)
|
||||||
|
{
|
||||||
|
IndexPosition = Gpu.GetCpuAddr(IndexPosition);
|
||||||
|
|
||||||
|
int BufferSize = IndexCount * IndexSize;
|
||||||
|
|
||||||
|
byte[] Data = AMemoryHelper.ReadBytes(Memory, IndexPosition, BufferSize);
|
||||||
|
|
||||||
|
Gpu.Renderer.SetIndexArray(Data, IndexFormat);
|
||||||
|
}
|
||||||
|
|
||||||
List<GalVertexAttrib>[] Attribs = new List<GalVertexAttrib>[32];
|
List<GalVertexAttrib>[] Attribs = new List<GalVertexAttrib>[32];
|
||||||
|
|
||||||
for (int Attr = 0; Attr < 16; Attr++)
|
for (int Attr = 0; Attr < 16; Attr++)
|
||||||
|
@ -187,83 +340,36 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4);
|
long VertexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4);
|
||||||
long EndPos = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNEndAddr + Index * 4);
|
long VertexEndPos = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNEndAddr + Index * 4);
|
||||||
|
|
||||||
long Size = (EndPos - Position) + 1;
|
long Size = (VertexEndPos - VertexPosition) + 1;
|
||||||
|
|
||||||
int Stride = Control & 0xfff;
|
int Stride = Control & 0xfff;
|
||||||
|
|
||||||
Position = Gpu.GetCpuAddr(Position);
|
VertexPosition = Gpu.GetCpuAddr(VertexPosition);
|
||||||
|
|
||||||
byte[] Data = AMemoryHelper.ReadBytes(Memory, Position, Size);
|
byte[] Data = AMemoryHelper.ReadBytes(Memory, VertexPosition, Size);
|
||||||
|
|
||||||
GalVertexAttrib[] AttribArray = Attribs[Index]?.ToArray() ?? new GalVertexAttrib[0];
|
GalVertexAttrib[] AttribArray = Attribs[Index]?.ToArray() ?? new GalVertexAttrib[0];
|
||||||
|
|
||||||
Gpu.Renderer.SetVertexArray(Index, Stride, Data, AttribArray);
|
Gpu.Renderer.SetVertexArray(Index, Stride, Data, AttribArray);
|
||||||
Gpu.Renderer.RenderVertexArray(Index);
|
|
||||||
|
int PrimCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl);
|
||||||
|
|
||||||
|
GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff);
|
||||||
|
|
||||||
|
if (IndexCount != 0)
|
||||||
|
{
|
||||||
|
Gpu.Renderer.DrawElements(Index, IndexFirst, PrimType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Gpu.Renderer.DrawArrays(Index, PrimType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UploadTextures(AMemory Memory)
|
|
||||||
{
|
|
||||||
int TextureCbIndex = ReadRegister(NvGpuEngine3dReg.TextureCbIndex);
|
|
||||||
|
|
||||||
long BasePosition = Cbs[TextureCbIndex].Position;
|
|
||||||
|
|
||||||
long Size = (uint)Cbs[TextureCbIndex].Size;
|
|
||||||
|
|
||||||
Gpu.Renderer.UpdateTextures((int Index, GalShaderType ShaderType) =>
|
|
||||||
{
|
|
||||||
long Position = BasePosition + (int)ShaderType * Size;
|
|
||||||
|
|
||||||
return TextureRequestHandler(Memory, Position, Index);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private GalTexture TextureRequestHandler(AMemory Memory, long BasePosition, int Index)
|
|
||||||
{
|
|
||||||
long Position = BasePosition + Index * 4;
|
|
||||||
|
|
||||||
int TextureHandle = Memory.ReadInt32(Position);
|
|
||||||
|
|
||||||
int TicIndex = (TextureHandle >> 0) & 0xfffff;
|
|
||||||
int TscIndex = (TextureHandle >> 20) & 0xfff;
|
|
||||||
|
|
||||||
TryGetCpuAddr(NvGpuEngine3dReg.TexHeaderPoolOffset, out long TicPosition);
|
|
||||||
|
|
||||||
TicPosition += TicIndex * 0x20;
|
|
||||||
|
|
||||||
return TextureFactory.MakeTexture(Gpu, Memory, TicPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int[] ReadWords(AMemory Memory, long Position, int Count)
|
|
||||||
{
|
|
||||||
int[] Words = new int[Count];
|
|
||||||
|
|
||||||
for (int Index = 0; Index < Count; Index++, Position += 4)
|
|
||||||
{
|
|
||||||
Words[Index] = Memory.ReadInt32(Position);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Words;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static GalShaderType GetTypeFromProgram(int Program)
|
|
||||||
{
|
|
||||||
switch (Program)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
case 1: return GalShaderType.Vertex;
|
|
||||||
case 2: return GalShaderType.TessControl;
|
|
||||||
case 3: return GalShaderType.TessEvaluation;
|
|
||||||
case 4: return GalShaderType.Geometry;
|
|
||||||
case 5: return GalShaderType.Fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(Program));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void QueryControl(AMemory Memory, NsGpuPBEntry PBEntry)
|
private void QueryControl(AMemory Memory, NsGpuPBEntry PBEntry)
|
||||||
{
|
{
|
||||||
if (TryGetCpuAddr(NvGpuEngine3dReg.QueryAddress, out long Position))
|
if (TryGetCpuAddr(NvGpuEngine3dReg.QueryAddress, out long Position))
|
||||||
|
|
|
@ -2,23 +2,43 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
enum NvGpuEngine3dReg
|
enum NvGpuEngine3dReg
|
||||||
{
|
{
|
||||||
VertexAttribNFormat = 0x458,
|
FrameBufferNAddress = 0x200,
|
||||||
TexHeaderPoolOffset = 0x55d,
|
FrameBufferNWidth = 0x202,
|
||||||
ShaderAddress = 0x582,
|
FrameBufferNHeight = 0x203,
|
||||||
QueryAddress = 0x6c0,
|
FrameBufferNFormat = 0x204,
|
||||||
QuerySequence = 0x6c2,
|
VertexAttribNFormat = 0x458,
|
||||||
QueryControl = 0x6c3,
|
BlendSeparateAlpha = 0x4cf,
|
||||||
VertexArrayNControl = 0x700,
|
BlendEquationRgb = 0x4d0,
|
||||||
VertexArrayNAddress = 0x701,
|
BlendFuncSrcRgb = 0x4d1,
|
||||||
VertexArrayNDivisor = 0x703,
|
BlendFuncDstRgb = 0x4d2,
|
||||||
VertexArrayNEndAddr = 0x7c0,
|
BlendEquationAlpha = 0x4d3,
|
||||||
ShaderNControl = 0x800,
|
BlendFuncSrcAlpha = 0x4d4,
|
||||||
ShaderNOffset = 0x801,
|
BlendFuncDstAlpha = 0x4d6,
|
||||||
ShaderNMaxGprs = 0x803,
|
BlendEnableMaster = 0x4d7,
|
||||||
ShaderNType = 0x804,
|
VertexArrayElemBase = 0x50d,
|
||||||
ConstBufferNSize = 0x8e0,
|
TexHeaderPoolOffset = 0x55d,
|
||||||
ConstBufferNAddress = 0x8e1,
|
TexSamplerPoolOffset = 0x557,
|
||||||
ConstBufferNOffset = 0x8e3,
|
ShaderAddress = 0x582,
|
||||||
TextureCbIndex = 0x982
|
VertexBeginGl = 0x586,
|
||||||
|
IndexArrayAddress = 0x5f2,
|
||||||
|
IndexArrayEndAddr = 0x5f4,
|
||||||
|
IndexArrayFormat = 0x5f6,
|
||||||
|
IndexBatchFirst = 0x5f7,
|
||||||
|
IndexBatchCount = 0x5f8,
|
||||||
|
QueryAddress = 0x6c0,
|
||||||
|
QuerySequence = 0x6c2,
|
||||||
|
QueryControl = 0x6c3,
|
||||||
|
VertexArrayNControl = 0x700,
|
||||||
|
VertexArrayNAddress = 0x701,
|
||||||
|
VertexArrayNDivisor = 0x703,
|
||||||
|
VertexArrayNEndAddr = 0x7c0,
|
||||||
|
ShaderNControl = 0x800,
|
||||||
|
ShaderNOffset = 0x801,
|
||||||
|
ShaderNMaxGprs = 0x803,
|
||||||
|
ShaderNType = 0x804,
|
||||||
|
ConstBufferNSize = 0x8e0,
|
||||||
|
ConstBufferNAddress = 0x8e1,
|
||||||
|
ConstBufferNOffset = 0x8e3,
|
||||||
|
TextureCbIndex = 0x982
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu
|
namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
|
@ -39,6 +40,34 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
return new GalTexture(Data, Width, Height, Format);
|
return new GalTexture(Data, Width, Height, Format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static GalTextureSampler MakeSampler(NsGpu Gpu, AMemory Memory, long TscPosition)
|
||||||
|
{
|
||||||
|
int[] Tsc = ReadWords(Memory, TscPosition, 8);
|
||||||
|
|
||||||
|
GalTextureWrap AddressU = (GalTextureWrap)((Tsc[0] >> 0) & 7);
|
||||||
|
GalTextureWrap AddressV = (GalTextureWrap)((Tsc[0] >> 3) & 7);
|
||||||
|
GalTextureWrap AddressP = (GalTextureWrap)((Tsc[0] >> 6) & 7);
|
||||||
|
|
||||||
|
GalTextureFilter MagFilter = (GalTextureFilter) ((Tsc[1] >> 0) & 3);
|
||||||
|
GalTextureFilter MinFilter = (GalTextureFilter) ((Tsc[1] >> 4) & 3);
|
||||||
|
GalTextureMipFilter MipFilter = (GalTextureMipFilter)((Tsc[1] >> 6) & 3);
|
||||||
|
|
||||||
|
GalColorF BorderColor = new GalColorF(
|
||||||
|
BitConverter.Int32BitsToSingle(Tsc[4]),
|
||||||
|
BitConverter.Int32BitsToSingle(Tsc[5]),
|
||||||
|
BitConverter.Int32BitsToSingle(Tsc[6]),
|
||||||
|
BitConverter.Int32BitsToSingle(Tsc[7]));
|
||||||
|
|
||||||
|
return new GalTextureSampler(
|
||||||
|
AddressU,
|
||||||
|
AddressV,
|
||||||
|
AddressP,
|
||||||
|
MinFilter,
|
||||||
|
MagFilter,
|
||||||
|
MipFilter,
|
||||||
|
BorderColor);
|
||||||
|
}
|
||||||
|
|
||||||
private static int[] ReadWords(AMemory Memory, long Position, int Count)
|
private static int[] ReadWords(AMemory Memory, long Position, int Count)
|
||||||
{
|
{
|
||||||
int[] Words = new int[Count];
|
int[] Words = new int[Count];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue