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
36f85260bb
commit
bcec123330
22 changed files with 1052 additions and 235 deletions
|
@ -98,7 +98,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
{
|
||||
int Fd = Context.RequestData.ReadInt32();
|
||||
int Cmd = Context.RequestData.ReadInt32() & 0xffff;
|
||||
|
||||
|
||||
NvFd FdData = Fds.GetData<NvFd>(Context.Process, Fd);
|
||||
|
||||
long Position = Context.Request.GetSendBuffPtr();
|
||||
|
@ -206,7 +206,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
int Flags = Reader.ReadInt32();
|
||||
int Kind = Reader.ReadInt32();
|
||||
int Handle = Reader.ReadInt32();
|
||||
int PageSize = Reader.ReadInt32();
|
||||
int PageSize = Reader.ReadInt32();
|
||||
long BuffAddr = Reader.ReadInt64();
|
||||
long MapSize = Reader.ReadInt64();
|
||||
long Offset = Reader.ReadInt64();
|
||||
|
@ -226,7 +226,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
if (Map == null)
|
||||
{
|
||||
Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
|
||||
|
||||
|
||||
return -1; //TODO: Corrent error code.
|
||||
}
|
||||
|
||||
|
@ -590,7 +590,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
if (Map == null)
|
||||
{
|
||||
Logging.Warn($"Trying to use invalid NvMap Id {Id}!");
|
||||
|
||||
|
||||
return -1; //TODO: Corrent error code.
|
||||
}
|
||||
|
||||
|
@ -617,13 +617,13 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
if (Map == null)
|
||||
{
|
||||
Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
|
||||
|
||||
|
||||
return -1; //TODO: Corrent error code.
|
||||
}
|
||||
|
||||
Map.CpuAddress = Addr;
|
||||
Map.Align = Align;
|
||||
Map.Kind = Kind;
|
||||
Map.Align = Align;
|
||||
Map.Kind = Kind;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -643,7 +643,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
if (Map == null)
|
||||
{
|
||||
Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
|
||||
|
||||
|
||||
return -1; //TODO: Corrent error code.
|
||||
}
|
||||
|
||||
|
@ -668,7 +668,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
if (Map == null)
|
||||
{
|
||||
Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
|
||||
|
||||
|
||||
return -1; //TODO: Corrent error code.
|
||||
}
|
||||
|
||||
|
@ -698,7 +698,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
if (Map == null)
|
||||
{
|
||||
Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
|
||||
|
||||
|
||||
return -1; //TODO: Corrent error code.
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
private BufferEntry[] BufferQueue;
|
||||
|
||||
private ManualResetEvent WaitBufferFree;
|
||||
|
||||
|
||||
private object RenderQueueLock;
|
||||
|
||||
private int RenderQueueCount;
|
||||
|
@ -85,7 +85,7 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
{ ("android.gui.IGraphicBufferProducer", 0xb), GbpDisconnect },
|
||||
{ ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer }
|
||||
};
|
||||
|
||||
|
||||
this.Renderer = Renderer;
|
||||
this.ReleaseEvent = ReleaseEvent;
|
||||
|
||||
|
@ -139,7 +139,7 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
|
||||
BufferEntry Entry = BufferQueue[Slot];
|
||||
|
||||
int BufferCount = 1; //?
|
||||
|
@ -243,7 +243,7 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
private long GbpPreallocBuffer(ServiceCtx Context, BinaryReader ParcelReader)
|
||||
{
|
||||
int Slot = ParcelReader.ReadInt32();
|
||||
|
||||
|
||||
int BufferCount = ParcelReader.ReadInt32();
|
||||
long BufferSize = ParcelReader.ReadInt64();
|
||||
|
||||
|
@ -293,7 +293,7 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
NvMapFb MapFb = (NvMapFb)ServiceNvDrv.NvMapsFb.GetData(Context.Process, 0);
|
||||
|
||||
long Address = Map.CpuAddress;
|
||||
|
||||
|
||||
if (MapFb.HasBufferOffset(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.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
|
@ -21,23 +22,56 @@ namespace Ryujinx.Graphics.Gal
|
|||
float OffsY,
|
||||
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
|
||||
void ClearBuffers(int RtIndex, GalClearBufferFlags Flags);
|
||||
|
||||
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
|
||||
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 BindProgram();
|
||||
|
||||
//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
|
||||
{
|
||||
public static DrawElementsType GetDrawElementsType(GalIndexFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalIndexFormat.Byte: return DrawElementsType.UnsignedByte;
|
||||
case GalIndexFormat.Int16: return DrawElementsType.UnsignedShort;
|
||||
case GalIndexFormat.Int32: return DrawElementsType.UnsignedInt;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Format));
|
||||
}
|
||||
|
||||
public static PrimitiveType GetPrimitiveType(GalPrimitiveType Type)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case GalPrimitiveType.Points: return PrimitiveType.Points;
|
||||
case GalPrimitiveType.Lines: return PrimitiveType.Lines;
|
||||
case GalPrimitiveType.LineLoop: return PrimitiveType.LineLoop;
|
||||
case GalPrimitiveType.LineStrip: return PrimitiveType.LineStrip;
|
||||
case GalPrimitiveType.Triangles: return PrimitiveType.Triangles;
|
||||
case GalPrimitiveType.TriangleStrip: return PrimitiveType.TriangleStrip;
|
||||
case GalPrimitiveType.TriangleFan: return PrimitiveType.TriangleFan;
|
||||
case GalPrimitiveType.Quads: return PrimitiveType.Quads;
|
||||
case GalPrimitiveType.QuadStrip: return PrimitiveType.QuadStrip;
|
||||
case GalPrimitiveType.Polygon: return PrimitiveType.Polygon;
|
||||
case GalPrimitiveType.LinesAdjacency: return PrimitiveType.LinesAdjacency;
|
||||
case GalPrimitiveType.LineStripAdjacency: return PrimitiveType.LineStripAdjacency;
|
||||
case GalPrimitiveType.TrianglesAdjacency: return PrimitiveType.TrianglesAdjacency;
|
||||
case GalPrimitiveType.TriangleStripAdjacency: return PrimitiveType.TriangleStripAdjacency;
|
||||
case GalPrimitiveType.Patches: return PrimitiveType.Patches;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Type));
|
||||
}
|
||||
|
||||
public static ShaderType GetShaderType(GalShaderType Type)
|
||||
{
|
||||
switch (Type)
|
||||
|
@ -30,5 +66,64 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
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 } //?
|
||||
};
|
||||
|
||||
private struct VertexBuffer
|
||||
private struct VbInfo
|
||||
{
|
||||
public int VaoHandle;
|
||||
public int VboHandle;
|
||||
|
@ -52,11 +52,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
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()
|
||||
{
|
||||
VertexBuffers = new VertexBuffer[32];
|
||||
VertexBuffers = new VbInfo[32];
|
||||
|
||||
IndexBuffer = new IbInfo();
|
||||
}
|
||||
|
||||
public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags)
|
||||
|
@ -92,7 +104,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
VertexBuffers[VbIndex].PrimCount = Buffer.Length / Stride;
|
||||
|
||||
VertexBuffer Vb = VertexBuffers[VbIndex];
|
||||
VbInfo Vb = VertexBuffers[VbIndex];
|
||||
|
||||
IntPtr Length = new IntPtr(Buffer.Length);
|
||||
|
||||
|
@ -144,9 +156,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
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)
|
||||
{
|
||||
|
@ -155,12 +182,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
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)
|
||||
{
|
||||
VertexBuffer Vb = VertexBuffers[VbIndex];
|
||||
VbInfo Vb = VertexBuffers[VbIndex];
|
||||
|
||||
if (Vb.VaoHandle == 0)
|
||||
{
|
||||
|
@ -174,5 +219,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
VertexBuffers[VbIndex] = Vb;
|
||||
}
|
||||
|
||||
private void EnsureIbInitialized()
|
||||
{
|
||||
if (IndexBuffer.IboHandle == 0)
|
||||
{
|
||||
IndexBuffer.IboHandle = GL.GenBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Graphics.Gal.Shader;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
@ -13,23 +14,37 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
public int Handle { get; private set; }
|
||||
|
||||
public bool IsCompiled { get; private set; }
|
||||
|
||||
public GalShaderType Type { get; private set; }
|
||||
|
||||
public string Code { get; private set; }
|
||||
|
||||
public IEnumerable<ShaderDeclInfo> TextureUsage { get; private set; }
|
||||
public IEnumerable<ShaderDeclInfo> UniformUsage { get; private set; }
|
||||
|
||||
public ShaderStage(
|
||||
GalShaderType Type,
|
||||
string Code,
|
||||
IEnumerable<ShaderDeclInfo> TextureUsage,
|
||||
IEnumerable<ShaderDeclInfo> UniformUsage)
|
||||
{
|
||||
Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type));
|
||||
|
||||
this.Type = Type;
|
||||
this.Code = Code;
|
||||
this.TextureUsage = TextureUsage;
|
||||
this.UniformUsage = UniformUsage;
|
||||
}
|
||||
|
||||
public void Compile()
|
||||
{
|
||||
if (Handle == 0)
|
||||
{
|
||||
Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type));
|
||||
|
||||
CompileAndCheck(Handle, Code);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
@ -57,7 +72,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
private ShaderProgram Current;
|
||||
|
||||
private Dictionary<long, ShaderStage> Stages;
|
||||
private ConcurrentDictionary<long, ShaderStage> Stages;
|
||||
|
||||
private Dictionary<ShaderProgram, int> Programs;
|
||||
|
||||
|
@ -65,49 +80,62 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public OGLShader()
|
||||
{
|
||||
Stages = new Dictionary<long, ShaderStage>();
|
||||
Stages = new ConcurrentDictionary<long, ShaderStage>();
|
||||
|
||||
Programs = new Dictionary<ShaderProgram, int>();
|
||||
}
|
||||
|
||||
public void Create(long Tag, GalShaderType Type, byte[] Data)
|
||||
{
|
||||
if (!Stages.ContainsKey(Tag))
|
||||
{
|
||||
GlslProgram Program = GetGlslProgram(Data, Type);
|
||||
|
||||
ShaderStage Stage = new ShaderStage(
|
||||
Type,
|
||||
Program.Textures,
|
||||
Program.Uniforms);
|
||||
|
||||
Stages.Add(Tag, Stage);
|
||||
|
||||
CompileAndCheck(Stage.Handle, Program.Code);
|
||||
}
|
||||
Stages.GetOrAdd(Tag, (Key) => ShaderStageFactory(Type, Data));
|
||||
}
|
||||
|
||||
public IEnumerable<ShaderDeclInfo> GetTextureUsage(GalShaderType ShaderType)
|
||||
private ShaderStage ShaderStageFactory(GalShaderType Type, byte[] Data)
|
||||
{
|
||||
switch (ShaderType)
|
||||
{
|
||||
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);
|
||||
}
|
||||
GlslProgram Program = GetGlslProgram(Data, Type);
|
||||
|
||||
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)
|
||||
{
|
||||
BindProgram();
|
||||
|
||||
if (Stages.TryGetValue(Tag, out ShaderStage Stage))
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (Stages.TryGetValue(Tag, out ShaderStage Stage))
|
||||
{
|
||||
switch (Stage.Type)
|
||||
{
|
||||
case GalShaderType.Vertex: Current.Vertex = Stage; break;
|
||||
case GalShaderType.TessControl: Current.TessControl = Stage; break;
|
||||
case GalShaderType.TessEvaluation: Current.TessEvaluation = Stage; break;
|
||||
case GalShaderType.Geometry: Current.Geometry = Stage; break;
|
||||
case GalShaderType.Fragment: Current.Fragment = Stage; break;
|
||||
}
|
||||
Bind(Stage);
|
||||
}
|
||||
}
|
||||
|
||||
private void Bind(ShaderStage Stage)
|
||||
{
|
||||
switch (Stage.Type)
|
||||
{
|
||||
case GalShaderType.Vertex: Current.Vertex = Stage; break;
|
||||
case GalShaderType.TessControl: Current.TessControl = Stage; break;
|
||||
case GalShaderType.TessEvaluation: Current.TessEvaluation = Stage; break;
|
||||
case GalShaderType.Geometry: Current.Geometry = Stage; break;
|
||||
case GalShaderType.Fragment: Current.Fragment = Stage; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,32 +212,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
if (Stage != null)
|
||||
{
|
||||
Stage.Compile();
|
||||
|
||||
GL.AttachShader(ProgramHandle, Stage.Handle);
|
||||
}
|
||||
}
|
||||
|
||||
private GlslProgram GetGlslProgram(byte[] Data, GalShaderType Type)
|
||||
{
|
||||
int[] Code = new int[(Data.Length - 0x50) >> 2];
|
||||
|
||||
using (MemoryStream MS = new MemoryStream(Data))
|
||||
{
|
||||
MS.Seek(0x50, SeekOrigin.Begin);
|
||||
|
||||
BinaryReader Reader = new BinaryReader(MS);
|
||||
|
||||
for (int Index = 0; Index < Code.Length; Index++)
|
||||
{
|
||||
Code[Index] = Reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
|
||||
GlslDecompiler Decompiler = new GlslDecompiler();
|
||||
|
||||
return Decompiler.Decompile(Code, Type);
|
||||
}
|
||||
|
||||
private static void CompileAndCheck(int Handle, string Code)
|
||||
public static void CompileAndCheck(int Handle, string Code)
|
||||
{
|
||||
GL.ShaderSource(Handle, Code);
|
||||
GL.CompileShader(Handle);
|
||||
|
|
|
@ -1,72 +1,34 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
class OGLTexture
|
||||
{
|
||||
private OGLShader Shader;
|
||||
|
||||
private int[] Textures;
|
||||
|
||||
private int CurrentTextureIndex;
|
||||
|
||||
public OGLTexture(OGLShader Shader)
|
||||
public OGLTexture()
|
||||
{
|
||||
this.Shader = Shader;
|
||||
|
||||
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);
|
||||
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);
|
||||
int Handle = EnsureTextureInitialized(Index);
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
|
||||
int W = Tex.Width;
|
||||
int H = Tex.Height;
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||
|
||||
int W = Texture.Width;
|
||||
int H = Texture.Height;
|
||||
|
||||
byte[] Data = Texture.Data;
|
||||
byte[] Data = Tex.Data;
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
return Format == GalTextureFormat.BC1 ||
|
||||
|
@ -90,13 +81,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
Format == GalTextureFormat.BC3;
|
||||
}
|
||||
|
||||
private int EnsureTextureInitialized(int TextureIndex)
|
||||
private int EnsureTextureInitialized(int TexIndex)
|
||||
{
|
||||
int Handle = Textures[TextureIndex];
|
||||
int Handle = Textures[TexIndex];
|
||||
|
||||
if (Handle == 0)
|
||||
{
|
||||
Handle = Textures[TextureIndex] = GL.GenTexture();
|
||||
Handle = Textures[TexIndex] = GL.GenTexture();
|
||||
}
|
||||
|
||||
return Handle;
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
using OpenTK;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
public class OpenGLRenderer : IGalRenderer
|
||||
{
|
||||
private OGLBlend Blend;
|
||||
|
||||
private OGLFrameBuffer FrameBuffer;
|
||||
|
||||
private OGLRasterizer Rasterizer;
|
||||
|
||||
private OGLShader Shader;
|
||||
|
@ -18,11 +23,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public OpenGLRenderer()
|
||||
{
|
||||
Blend = new OGLBlend();
|
||||
|
||||
FrameBuffer = new OGLFrameBuffer();
|
||||
|
||||
Rasterizer = new OGLRasterizer();
|
||||
|
||||
Shader = new OGLShader();
|
||||
|
||||
Texture = new OGLTexture(Shader);
|
||||
Texture = new OGLTexture();
|
||||
|
||||
ActionsQueue = new ConcurrentQueue<Action>();
|
||||
}
|
||||
|
@ -83,6 +92,61 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
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)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => Rasterizer.ClearBuffers(RtIndex, Flags));
|
||||
|
@ -100,14 +164,34 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
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)
|
||||
{
|
||||
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)
|
||||
|
@ -117,10 +201,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
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)
|
||||
{
|
||||
|
@ -130,6 +214,21 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
ActionsQueue.Enqueue(() => Shader.SetConstBuffer(Tag, Cbuf, Data));
|
||||
}
|
||||
|
||||
public void SetUniform1(string UniformName, int Value)
|
||||
{
|
||||
if (UniformName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(UniformName));
|
||||
}
|
||||
|
||||
ActionsQueue.Enqueue(() => Shader.SetUniform1(UniformName, Value));
|
||||
}
|
||||
|
||||
public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Tag)
|
||||
{
|
||||
return Shader.GetTextureUsage(Tag);
|
||||
}
|
||||
|
||||
public void BindShader(long Tag)
|
||||
{
|
||||
ActionsQueue.Enqueue(() => Shader.Bind(Tag));
|
||||
|
@ -140,9 +239,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
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)
|
||||
{
|
||||
Name = "out " + GetDecl(DeclInfo) + ";";
|
||||
Name = "layout (location = 0) out " + GetDecl(DeclInfo) + ";";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -22,6 +22,8 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
private ConstBuffer[] Cbs;
|
||||
|
||||
private bool HasDataToRender;
|
||||
|
||||
public NvGpuEngine3d(NsGpu Gpu)
|
||||
{
|
||||
this.Gpu = Gpu;
|
||||
|
@ -61,34 +63,60 @@ namespace Ryujinx.Graphics.Gpu
|
|||
}
|
||||
}
|
||||
|
||||
private const long GoodFbAddress = 0x1615b2a00;
|
||||
|
||||
private void VertexEndGl(AMemory Memory, NsGpuPBEntry PBEntry)
|
||||
{
|
||||
int TexCbuf = ReadRegister(NvGpuEngine3dReg.TextureCbIndex);
|
||||
SetFrameBuffer(0);
|
||||
|
||||
int TexHandle = ReadCb(Memory, TexCbuf, 0x20);
|
||||
|
||||
UploadShaders(Memory);
|
||||
long[] Tags = UploadShaders(Memory);
|
||||
|
||||
Gpu.Renderer.BindProgram();
|
||||
|
||||
UploadTextures(Memory);
|
||||
SetAlphaBlending();
|
||||
|
||||
UploadTextures(Memory, Tags);
|
||||
UploadUniforms(Memory);
|
||||
UploadVertexArrays(Memory);
|
||||
|
||||
HasDataToRender = true;
|
||||
}
|
||||
|
||||
private void ClearBuffers(AMemory Memory, NsGpuPBEntry PBEntry)
|
||||
{
|
||||
if (HasDataToRender)
|
||||
{
|
||||
HasDataToRender = false;
|
||||
|
||||
Gpu.Renderer.DrawFrameBuffer(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);
|
||||
|
||||
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);
|
||||
|
||||
for (int Index = 0; Index < 6; Index++)
|
||||
|
@ -115,9 +143,108 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
GalShaderType ShaderType = GetTypeFromProgram(Index);
|
||||
|
||||
Tags[(int)ShaderType] = Tag;
|
||||
|
||||
Gpu.Renderer.CreateShader(Tag, ShaderType, Code);
|
||||
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)
|
||||
|
@ -147,7 +274,7 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
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)
|
||||
{
|
||||
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];
|
||||
|
||||
for (int Attr = 0; Attr < 16; Attr++)
|
||||
|
@ -187,83 +340,36 @@ namespace Ryujinx.Graphics.Gpu
|
|||
continue;
|
||||
}
|
||||
|
||||
long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4);
|
||||
long EndPos = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNEndAddr + Index * 4);
|
||||
long VertexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4);
|
||||
long VertexEndPos = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNEndAddr + Index * 4);
|
||||
|
||||
long Size = (EndPos - Position) + 1;
|
||||
long Size = (VertexEndPos - VertexPosition) + 1;
|
||||
|
||||
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];
|
||||
|
||||
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)
|
||||
{
|
||||
if (TryGetCpuAddr(NvGpuEngine3dReg.QueryAddress, out long Position))
|
||||
|
|
|
@ -2,23 +2,43 @@ namespace Ryujinx.Graphics.Gpu
|
|||
{
|
||||
enum NvGpuEngine3dReg
|
||||
{
|
||||
VertexAttribNFormat = 0x458,
|
||||
TexHeaderPoolOffset = 0x55d,
|
||||
ShaderAddress = 0x582,
|
||||
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
|
||||
FrameBufferNAddress = 0x200,
|
||||
FrameBufferNWidth = 0x202,
|
||||
FrameBufferNHeight = 0x203,
|
||||
FrameBufferNFormat = 0x204,
|
||||
VertexAttribNFormat = 0x458,
|
||||
BlendSeparateAlpha = 0x4cf,
|
||||
BlendEquationRgb = 0x4d0,
|
||||
BlendFuncSrcRgb = 0x4d1,
|
||||
BlendFuncDstRgb = 0x4d2,
|
||||
BlendEquationAlpha = 0x4d3,
|
||||
BlendFuncSrcAlpha = 0x4d4,
|
||||
BlendFuncDstAlpha = 0x4d6,
|
||||
BlendEnableMaster = 0x4d7,
|
||||
VertexArrayElemBase = 0x50d,
|
||||
TexHeaderPoolOffset = 0x55d,
|
||||
TexSamplerPoolOffset = 0x557,
|
||||
ShaderAddress = 0x582,
|
||||
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 Ryujinx.Graphics.Gal;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
|
@ -39,6 +40,34 @@ namespace Ryujinx.Graphics.Gpu
|
|||
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)
|
||||
{
|
||||
int[] Words = new int[Count];
|
||||
|
|
Loading…
Add table
Reference in a new issue