Move Uniform binds to GalPipelineState
This commit is contained in:
parent
c9245100a0
commit
3361eb389b
10 changed files with 247 additions and 250 deletions
|
@ -10,17 +10,12 @@
|
||||||
public GalVertexAttrib[] Attribs;
|
public GalVertexAttrib[] Attribs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct GalConstBufferBinding
|
public class GalPipelineState
|
||||||
{
|
|
||||||
public bool Enabled;
|
|
||||||
public long Key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct GalPipelineState
|
|
||||||
{
|
{
|
||||||
|
public const int Stages = 5;
|
||||||
public const int ConstBuffersPerStage = 18;
|
public const int ConstBuffersPerStage = 18;
|
||||||
|
|
||||||
public GalConstBufferBinding[][] ConstBufferKeys;
|
public long[][] ConstBufferKeys;
|
||||||
|
|
||||||
public GalVertexBinding[] VertexBindings;
|
public GalVertexBinding[] VertexBindings;
|
||||||
|
|
||||||
|
@ -63,5 +58,15 @@
|
||||||
|
|
||||||
public bool PrimitiveRestartEnabled;
|
public bool PrimitiveRestartEnabled;
|
||||||
public uint PrimitiveRestartIndex;
|
public uint PrimitiveRestartIndex;
|
||||||
|
|
||||||
|
public GalPipelineState()
|
||||||
|
{
|
||||||
|
ConstBufferKeys = new long[Stages][];
|
||||||
|
|
||||||
|
for (int Stage = 0; Stage < Stages; Stage++)
|
||||||
|
{
|
||||||
|
ConstBufferKeys[Stage] = new long[ConstBuffersPerStage];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,7 +12,5 @@ namespace Ryujinx.Graphics.Gal
|
||||||
bool IsCached(long Key, long Size);
|
bool IsCached(long Key, long Size);
|
||||||
|
|
||||||
void SetData(long Key, long Size, IntPtr HostAddress);
|
void SetData(long Key, long Size, IntPtr HostAddress);
|
||||||
|
|
||||||
void Bind(GalShaderType ShaderType, int Index, long Key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,6 +2,6 @@
|
||||||
{
|
{
|
||||||
public interface IGalPipeline
|
public interface IGalPipeline
|
||||||
{
|
{
|
||||||
void Bind(ref GalPipelineState State);
|
void Bind(GalPipelineState State);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,8 +11,6 @@ namespace Ryujinx.Graphics.Gal
|
||||||
|
|
||||||
IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key);
|
IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key);
|
||||||
|
|
||||||
void BindConstBuffers();
|
|
||||||
|
|
||||||
void EnsureTextureBinding(string UniformName, int Value);
|
void EnsureTextureBinding(string UniformName, int Value);
|
||||||
|
|
||||||
void SetFlip(float X, float Y);
|
void SetFlip(float X, float Y);
|
||||||
|
|
|
@ -5,22 +5,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
class OGLConstBuffer : IGalConstBuffer
|
class OGLConstBuffer : IGalConstBuffer
|
||||||
{
|
{
|
||||||
public const int ConstBuffersPerStage = 18;
|
|
||||||
|
|
||||||
private OGLCachedResource<OGLStreamBuffer> Cache;
|
private OGLCachedResource<OGLStreamBuffer> Cache;
|
||||||
|
|
||||||
private long[][] Keys;
|
|
||||||
|
|
||||||
public OGLConstBuffer()
|
public OGLConstBuffer()
|
||||||
{
|
{
|
||||||
Cache = new OGLCachedResource<OGLStreamBuffer>(DeleteBuffer);
|
Cache = new OGLCachedResource<OGLStreamBuffer>(DeleteBuffer);
|
||||||
|
|
||||||
Keys = new long[5][];
|
|
||||||
|
|
||||||
for (int i = 0; i < Keys.Length; i++)
|
|
||||||
{
|
|
||||||
Keys[i] = new long[ConstBuffersPerStage];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LockCache()
|
public void LockCache()
|
||||||
|
@ -55,19 +44,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Buffer.SetData(Size, HostAddress);
|
Buffer.SetData(Size, HostAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Bind(GalShaderType Stage, int Index, long Key)
|
public bool TryGetUbo(long Key, out int UboHandle)
|
||||||
{
|
{
|
||||||
Keys[(int)Stage][Index] = Key;
|
if (Cache.TryGetValue(Key, out OGLStreamBuffer Buffer))
|
||||||
}
|
|
||||||
|
|
||||||
public void PipelineBind(GalShaderType Stage, int Index, int BindingIndex)
|
|
||||||
{
|
|
||||||
long Key = Keys[(int)Stage][Index];
|
|
||||||
|
|
||||||
if (Key != 0 && Cache.TryGetValue(Key, out OGLStreamBuffer Buffer))
|
|
||||||
{
|
{
|
||||||
GL.BindBufferBase(BufferRangeTarget.UniformBuffer, BindingIndex, Buffer.Handle);
|
UboHandle = Buffer.Handle;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UboHandle = 0;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DeleteBuffer(OGLStreamBuffer Buffer)
|
private static void DeleteBuffer(OGLStreamBuffer Buffer)
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
public class OGLPipeline : IGalPipeline
|
class OGLPipeline : IGalPipeline
|
||||||
{
|
{
|
||||||
private static Dictionary<GalVertexAttribSize, int> AttribElements =
|
private static Dictionary<GalVertexAttribSize, int> AttribElements =
|
||||||
new Dictionary<GalVertexAttribSize, int>()
|
new Dictionary<GalVertexAttribSize, int>()
|
||||||
|
@ -46,13 +46,17 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
private GalPipelineState O;
|
private GalPipelineState O;
|
||||||
|
|
||||||
|
private OGLConstBuffer Buffer;
|
||||||
private OGLRasterizer Rasterizer;
|
private OGLRasterizer Rasterizer;
|
||||||
|
private OGLShader Shader;
|
||||||
|
|
||||||
private int VaoHandle;
|
private int VaoHandle;
|
||||||
|
|
||||||
public OGLPipeline(OGLRasterizer Rasterizer)
|
public OGLPipeline(OGLConstBuffer Buffer, OGLRasterizer Rasterizer, OGLShader Shader)
|
||||||
{
|
{
|
||||||
|
this.Buffer = Buffer;
|
||||||
this.Rasterizer = Rasterizer;
|
this.Rasterizer = Rasterizer;
|
||||||
|
this.Shader = Shader;
|
||||||
|
|
||||||
//These values match OpenGL's defaults
|
//These values match OpenGL's defaults
|
||||||
O = new GalPipelineState
|
O = new GalPipelineState
|
||||||
|
@ -100,58 +104,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Bind(ref GalPipelineState S)
|
public void Bind(GalPipelineState S)
|
||||||
{
|
{
|
||||||
//O stands for Older, S for (current) State
|
//O stands for Older, S for (current) State
|
||||||
|
|
||||||
foreach (GalVertexBinding Binding in S.VertexBindings)
|
BindUniforms(S);
|
||||||
{
|
|
||||||
if (!Binding.Enabled || !Rasterizer.TryGetVbo(Binding.VboKey, out int VboHandle))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VaoHandle == 0)
|
BindVertexLayout(S);
|
||||||
{
|
|
||||||
VaoHandle = GL.GenVertexArray();
|
|
||||||
|
|
||||||
//Vertex arrays shouldn't be used anywhere else in OpenGL's backend
|
|
||||||
//if you want to use it, move this line out of the if
|
|
||||||
GL.BindVertexArray(VaoHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (GalVertexAttrib Attrib in Binding.Attribs)
|
|
||||||
{
|
|
||||||
GL.EnableVertexAttribArray(Attrib.Index);
|
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
|
||||||
|
|
||||||
bool Unsigned =
|
|
||||||
Attrib.Type == GalVertexAttribType.Unorm ||
|
|
||||||
Attrib.Type == GalVertexAttribType.Uint ||
|
|
||||||
Attrib.Type == GalVertexAttribType.Uscaled;
|
|
||||||
|
|
||||||
bool Normalize =
|
|
||||||
Attrib.Type == GalVertexAttribType.Snorm ||
|
|
||||||
Attrib.Type == GalVertexAttribType.Unorm;
|
|
||||||
|
|
||||||
VertexAttribPointerType Type = 0;
|
|
||||||
|
|
||||||
if (Attrib.Type == GalVertexAttribType.Float)
|
|
||||||
{
|
|
||||||
Type = VertexAttribPointerType.Float;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Type = AttribTypes[Attrib.Size] + (Unsigned ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Size = AttribElements[Attrib.Size];
|
|
||||||
int Offset = Attrib.Offset;
|
|
||||||
|
|
||||||
GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Binding.Stride, Offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Note: Uncomment SetFrontFace and SetCullFace when flipping issues are solved
|
//Note: Uncomment SetFrontFace and SetCullFace when flipping issues are solved
|
||||||
|
|
||||||
|
@ -320,6 +279,90 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
O = S;
|
O = S;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void BindUniforms(GalPipelineState S)
|
||||||
|
{
|
||||||
|
int FreeBinding = 0;
|
||||||
|
|
||||||
|
void BindIfNotNull(OGLShaderStage Stage)
|
||||||
|
{
|
||||||
|
if (Stage != null)
|
||||||
|
{
|
||||||
|
foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage)
|
||||||
|
{
|
||||||
|
long Key = S.ConstBufferKeys[(int)Stage.Type][DeclInfo.Cbuf];
|
||||||
|
|
||||||
|
if (Key != 0 && Key != O.ConstBufferKeys[(int)Stage.Type][DeclInfo.Cbuf])
|
||||||
|
{
|
||||||
|
if (Buffer.TryGetUbo(Key, out int UboHandle))
|
||||||
|
{
|
||||||
|
GL.BindBufferBase(BufferRangeTarget.UniformBuffer, FreeBinding, UboHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeBinding++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BindIfNotNull(Shader.Current.Vertex);
|
||||||
|
BindIfNotNull(Shader.Current.TessControl);
|
||||||
|
BindIfNotNull(Shader.Current.TessEvaluation);
|
||||||
|
BindIfNotNull(Shader.Current.Geometry);
|
||||||
|
BindIfNotNull(Shader.Current.Fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BindVertexLayout(GalPipelineState S)
|
||||||
|
{
|
||||||
|
foreach (GalVertexBinding Binding in S.VertexBindings)
|
||||||
|
{
|
||||||
|
if (!Binding.Enabled || !Rasterizer.TryGetVbo(Binding.VboKey, out int VboHandle))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VaoHandle == 0)
|
||||||
|
{
|
||||||
|
VaoHandle = GL.GenVertexArray();
|
||||||
|
|
||||||
|
//Vertex arrays shouldn't be used anywhere else in OpenGL's backend
|
||||||
|
//if you want to use it, move this line out of the if
|
||||||
|
GL.BindVertexArray(VaoHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (GalVertexAttrib Attrib in Binding.Attribs)
|
||||||
|
{
|
||||||
|
GL.EnableVertexAttribArray(Attrib.Index);
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
||||||
|
|
||||||
|
bool Unsigned =
|
||||||
|
Attrib.Type == GalVertexAttribType.Unorm ||
|
||||||
|
Attrib.Type == GalVertexAttribType.Uint ||
|
||||||
|
Attrib.Type == GalVertexAttribType.Uscaled;
|
||||||
|
|
||||||
|
bool Normalize =
|
||||||
|
Attrib.Type == GalVertexAttribType.Snorm ||
|
||||||
|
Attrib.Type == GalVertexAttribType.Unorm;
|
||||||
|
|
||||||
|
VertexAttribPointerType Type = 0;
|
||||||
|
|
||||||
|
if (Attrib.Type == GalVertexAttribType.Float)
|
||||||
|
{
|
||||||
|
Type = VertexAttribPointerType.Float;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Type = AttribTypes[Attrib.Size] + (Unsigned ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Size = AttribElements[Attrib.Size];
|
||||||
|
int Offset = Attrib.Offset;
|
||||||
|
|
||||||
|
GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Binding.Stride, Offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Enable(EnableCap Cap, bool Enabled)
|
private void Enable(EnableCap Cap, bool Enabled)
|
||||||
{
|
{
|
||||||
if (Enabled)
|
if (Enabled)
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
Shader = new OGLShader(Buffer as OGLConstBuffer);
|
Shader = new OGLShader(Buffer as OGLConstBuffer);
|
||||||
|
|
||||||
Pipeline = new OGLPipeline(Rasterizer as OGLRasterizer);
|
Pipeline = new OGLPipeline(Buffer as OGLConstBuffer, Rasterizer as OGLRasterizer, Shader as OGLShader);
|
||||||
|
|
||||||
Texture = new OGLTexture();
|
Texture = new OGLTexture();
|
||||||
|
|
||||||
|
|
|
@ -11,71 +11,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
class OGLShader : IGalShader
|
class OGLShader : IGalShader
|
||||||
{
|
{
|
||||||
private class ShaderStage : IDisposable
|
public OGLShaderProgram Current;
|
||||||
{
|
|
||||||
public int Handle { get; private set; }
|
|
||||||
|
|
||||||
public bool IsCompiled { get; private set; }
|
private ConcurrentDictionary<long, OGLShaderStage> Stages;
|
||||||
|
|
||||||
public GalShaderType Type { get; private set; }
|
private Dictionary<OGLShaderProgram, int> Programs;
|
||||||
|
|
||||||
public string Code { get; private set; }
|
|
||||||
|
|
||||||
public IEnumerable<ShaderDeclInfo> TextureUsage { get; private set; }
|
|
||||||
public IEnumerable<ShaderDeclInfo> UniformUsage { get; private set; }
|
|
||||||
|
|
||||||
public ShaderStage(
|
|
||||||
GalShaderType Type,
|
|
||||||
string Code,
|
|
||||||
IEnumerable<ShaderDeclInfo> TextureUsage,
|
|
||||||
IEnumerable<ShaderDeclInfo> UniformUsage)
|
|
||||||
{
|
|
||||||
this.Type = Type;
|
|
||||||
this.Code = Code;
|
|
||||||
this.TextureUsage = TextureUsage;
|
|
||||||
this.UniformUsage = UniformUsage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Compile()
|
|
||||||
{
|
|
||||||
if (Handle == 0)
|
|
||||||
{
|
|
||||||
Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type));
|
|
||||||
|
|
||||||
CompileAndCheck(Handle, Code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool Disposing)
|
|
||||||
{
|
|
||||||
if (Disposing && Handle != 0)
|
|
||||||
{
|
|
||||||
GL.DeleteShader(Handle);
|
|
||||||
|
|
||||||
Handle = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct ShaderProgram
|
|
||||||
{
|
|
||||||
public ShaderStage Vertex;
|
|
||||||
public ShaderStage TessControl;
|
|
||||||
public ShaderStage TessEvaluation;
|
|
||||||
public ShaderStage Geometry;
|
|
||||||
public ShaderStage Fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ShaderProgram Current;
|
|
||||||
|
|
||||||
private ConcurrentDictionary<long, ShaderStage> Stages;
|
|
||||||
|
|
||||||
private Dictionary<ShaderProgram, int> Programs;
|
|
||||||
|
|
||||||
public int CurrentProgramHandle { get; private set; }
|
public int CurrentProgramHandle { get; private set; }
|
||||||
|
|
||||||
|
@ -85,9 +25,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
this.Buffer = Buffer;
|
this.Buffer = Buffer;
|
||||||
|
|
||||||
Stages = new ConcurrentDictionary<long, ShaderStage>();
|
Stages = new ConcurrentDictionary<long, OGLShaderStage>();
|
||||||
|
|
||||||
Programs = new Dictionary<ShaderProgram, int>();
|
Programs = new Dictionary<OGLShaderProgram, int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Create(IGalMemory Memory, long Key, GalShaderType Type)
|
public void Create(IGalMemory Memory, long Key, GalShaderType Type)
|
||||||
|
@ -100,7 +40,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Stages.GetOrAdd(Key, (Stage) => ShaderStageFactory(Memory, VpAPos, Key, true, Type));
|
Stages.GetOrAdd(Key, (Stage) => ShaderStageFactory(Memory, VpAPos, Key, true, Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ShaderStage ShaderStageFactory(
|
private OGLShaderStage ShaderStageFactory(
|
||||||
IGalMemory Memory,
|
IGalMemory Memory,
|
||||||
long Position,
|
long Position,
|
||||||
long PositionB,
|
long PositionB,
|
||||||
|
@ -129,7 +69,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Program = Decompiler.Decompile(Memory, Position, Type);
|
Program = Decompiler.Decompile(Memory, Position, Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ShaderStage(
|
return new OGLShaderStage(
|
||||||
Type,
|
Type,
|
||||||
Program.Code,
|
Program.Code,
|
||||||
Program.Textures,
|
Program.Textures,
|
||||||
|
@ -138,7 +78,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key)
|
public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key)
|
||||||
{
|
{
|
||||||
if (Stages.TryGetValue(Key, out ShaderStage Stage))
|
if (Stages.TryGetValue(Key, out OGLShaderStage Stage))
|
||||||
{
|
{
|
||||||
return Stage.TextureUsage;
|
return Stage.TextureUsage;
|
||||||
}
|
}
|
||||||
|
@ -146,30 +86,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
return Enumerable.Empty<ShaderDeclInfo>();
|
return Enumerable.Empty<ShaderDeclInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BindConstBuffers()
|
|
||||||
{
|
|
||||||
int FreeBinding = 0;
|
|
||||||
|
|
||||||
void BindIfNotNull(ShaderStage Stage)
|
|
||||||
{
|
|
||||||
if (Stage != null)
|
|
||||||
{
|
|
||||||
foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage)
|
|
||||||
{
|
|
||||||
Buffer.PipelineBind(Stage.Type, DeclInfo.Cbuf, FreeBinding);
|
|
||||||
|
|
||||||
FreeBinding++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BindIfNotNull(Current.Vertex);
|
|
||||||
BindIfNotNull(Current.TessControl);
|
|
||||||
BindIfNotNull(Current.TessEvaluation);
|
|
||||||
BindIfNotNull(Current.Geometry);
|
|
||||||
BindIfNotNull(Current.Fragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EnsureTextureBinding(string UniformName, int Value)
|
public void EnsureTextureBinding(string UniformName, int Value)
|
||||||
{
|
{
|
||||||
BindProgram();
|
BindProgram();
|
||||||
|
@ -190,13 +106,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public void Bind(long Key)
|
public void Bind(long Key)
|
||||||
{
|
{
|
||||||
if (Stages.TryGetValue(Key, out ShaderStage Stage))
|
if (Stages.TryGetValue(Key, out OGLShaderStage Stage))
|
||||||
{
|
{
|
||||||
Bind(Stage);
|
Bind(Stage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Bind(ShaderStage Stage)
|
private void Bind(OGLShaderStage Stage)
|
||||||
{
|
{
|
||||||
if (Stage.Type == GalShaderType.Geometry)
|
if (Stage.Type == GalShaderType.Geometry)
|
||||||
{
|
{
|
||||||
|
@ -262,7 +178,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
CurrentProgramHandle = Handle;
|
CurrentProgramHandle = Handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AttachIfNotNull(int ProgramHandle, ShaderStage Stage)
|
private void AttachIfNotNull(int ProgramHandle, OGLShaderStage Stage)
|
||||||
{
|
{
|
||||||
if (Stage != null)
|
if (Stage != null)
|
||||||
{
|
{
|
||||||
|
@ -276,7 +192,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
int FreeBinding = 0;
|
int FreeBinding = 0;
|
||||||
|
|
||||||
void BindUniformBlocksIfNotNull(ShaderStage Stage)
|
void BindUniformBlocksIfNotNull(OGLShaderStage Stage)
|
||||||
{
|
{
|
||||||
if (Stage != null)
|
if (Stage != null)
|
||||||
{
|
{
|
||||||
|
@ -304,26 +220,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
BindUniformBlocksIfNotNull(Current.Fragment);
|
BindUniformBlocksIfNotNull(Current.Fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CompileAndCheck(int Handle, string Code)
|
|
||||||
{
|
|
||||||
GL.ShaderSource(Handle, Code);
|
|
||||||
GL.CompileShader(Handle);
|
|
||||||
|
|
||||||
CheckCompilation(Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CheckCompilation(int Handle)
|
|
||||||
{
|
|
||||||
int Status = 0;
|
|
||||||
|
|
||||||
GL.GetShader(Handle, ShaderParameter.CompileStatus, out Status);
|
|
||||||
|
|
||||||
if (Status == 0)
|
|
||||||
{
|
|
||||||
throw new ShaderException(GL.GetShaderInfoLog(Handle));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CheckProgramLink(int Handle)
|
private static void CheckProgramLink(int Handle)
|
||||||
{
|
{
|
||||||
int Status = 0;
|
int Status = 0;
|
||||||
|
|
86
Ryujinx.Graphics/Gal/OpenGL/OGLShaderProgram.cs
Normal file
86
Ryujinx.Graphics/Gal/OpenGL/OGLShaderProgram.cs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
{
|
||||||
|
struct OGLShaderProgram
|
||||||
|
{
|
||||||
|
public OGLShaderStage Vertex;
|
||||||
|
public OGLShaderStage TessControl;
|
||||||
|
public OGLShaderStage TessEvaluation;
|
||||||
|
public OGLShaderStage Geometry;
|
||||||
|
public OGLShaderStage Fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
class OGLShaderStage : IDisposable
|
||||||
|
{
|
||||||
|
public int Handle { get; private set; }
|
||||||
|
|
||||||
|
public bool IsCompiled { get; private set; }
|
||||||
|
|
||||||
|
public GalShaderType Type { get; private set; }
|
||||||
|
|
||||||
|
public string Code { get; private set; }
|
||||||
|
|
||||||
|
public IEnumerable<ShaderDeclInfo> TextureUsage { get; private set; }
|
||||||
|
public IEnumerable<ShaderDeclInfo> UniformUsage { get; private set; }
|
||||||
|
|
||||||
|
public OGLShaderStage(
|
||||||
|
GalShaderType Type,
|
||||||
|
string Code,
|
||||||
|
IEnumerable<ShaderDeclInfo> TextureUsage,
|
||||||
|
IEnumerable<ShaderDeclInfo> UniformUsage)
|
||||||
|
{
|
||||||
|
this.Type = Type;
|
||||||
|
this.Code = Code;
|
||||||
|
this.TextureUsage = TextureUsage;
|
||||||
|
this.UniformUsage = UniformUsage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Compile()
|
||||||
|
{
|
||||||
|
if (Handle == 0)
|
||||||
|
{
|
||||||
|
Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type));
|
||||||
|
|
||||||
|
CompileAndCheck(Handle, Code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool Disposing)
|
||||||
|
{
|
||||||
|
if (Disposing && Handle != 0)
|
||||||
|
{
|
||||||
|
GL.DeleteShader(Handle);
|
||||||
|
|
||||||
|
Handle = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CompileAndCheck(int Handle, string Code)
|
||||||
|
{
|
||||||
|
GL.ShaderSource(Handle, Code);
|
||||||
|
GL.CompileShader(Handle);
|
||||||
|
|
||||||
|
CheckCompilation(Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CheckCompilation(int Handle)
|
||||||
|
{
|
||||||
|
int Status = 0;
|
||||||
|
|
||||||
|
GL.GetShader(Handle, ShaderParameter.CompileStatus, out Status);
|
||||||
|
|
||||||
|
if (Status == 0)
|
||||||
|
{
|
||||||
|
throw new ShaderException(GL.GetShaderInfoLog(Handle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,10 +27,6 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
|
|
||||||
private List<long>[] UploadedKeys;
|
private List<long>[] UploadedKeys;
|
||||||
|
|
||||||
private GalPipelineState State;
|
|
||||||
|
|
||||||
private bool ConstBufferBindingsChanged;
|
|
||||||
|
|
||||||
public NvGpuEngine3d(NvGpu Gpu)
|
public NvGpuEngine3d(NvGpu Gpu)
|
||||||
{
|
{
|
||||||
this.Gpu = Gpu;
|
this.Gpu = Gpu;
|
||||||
|
@ -70,8 +66,6 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
{
|
{
|
||||||
UploadedKeys[i] = new List<long>();
|
UploadedKeys[i] = new List<long>();
|
||||||
}
|
}
|
||||||
|
|
||||||
State = new GalPipelineState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||||
|
@ -90,32 +84,26 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
{
|
{
|
||||||
LockCaches();
|
LockCaches();
|
||||||
|
|
||||||
|
GalPipelineState State = new GalPipelineState();
|
||||||
|
|
||||||
SetFrameBuffer(Vmm, 0);
|
SetFrameBuffer(Vmm, 0);
|
||||||
|
|
||||||
long[] Keys = UploadShaders(Vmm);
|
long[] Keys = UploadShaders(Vmm);
|
||||||
|
|
||||||
Gpu.Renderer.Shader.BindProgram();
|
Gpu.Renderer.Shader.BindProgram();
|
||||||
|
|
||||||
if (ConstBufferBindingsChanged)
|
SetFrontFace(State);
|
||||||
{
|
SetCullFace(State);
|
||||||
ConstBufferBindingsChanged = false;
|
SetDepth(State);
|
||||||
|
SetStencil(State);
|
||||||
|
SetAlphaBlending(State);
|
||||||
|
SetPrimitiveRestart(State);
|
||||||
|
|
||||||
Gpu.Renderer.Shader.BindConstBuffers();
|
UploadTextures(Vmm, State, Keys);
|
||||||
}
|
UploadConstBuffers(Vmm, State);
|
||||||
|
UploadVertexArrays(Vmm, State);
|
||||||
|
|
||||||
//Note: Uncomment SetFrontFace and SetCullFace when flipping issues are solved
|
DispatchRender(Vmm, State);
|
||||||
//SetFrontFace();
|
|
||||||
//SetCullFace();
|
|
||||||
SetDepth();
|
|
||||||
SetStencil();
|
|
||||||
SetAlphaBlending();
|
|
||||||
SetPrimitiveRestart();
|
|
||||||
|
|
||||||
UploadTextures(Vmm, Keys);
|
|
||||||
UploadConstBuffers(Vmm);
|
|
||||||
UploadVertexArrays(Vmm);
|
|
||||||
|
|
||||||
DispatchRender(Vmm);
|
|
||||||
|
|
||||||
UnlockCaches();
|
UnlockCaches();
|
||||||
}
|
}
|
||||||
|
@ -256,7 +244,7 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
throw new ArgumentOutOfRangeException(nameof(Program));
|
throw new ArgumentOutOfRangeException(nameof(Program));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetFrontFace()
|
private void SetFrontFace(GalPipelineState State)
|
||||||
{
|
{
|
||||||
float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX);
|
float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX);
|
||||||
float SignY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY);
|
float SignY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY);
|
||||||
|
@ -281,7 +269,7 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
State.FrontFace = FrontFace;
|
State.FrontFace = FrontFace;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetCullFace()
|
private void SetCullFace(GalPipelineState State)
|
||||||
{
|
{
|
||||||
State.CullFaceEnabled = (ReadRegister(NvGpuEngine3dReg.CullFaceEnable) & 1) != 0;
|
State.CullFaceEnabled = (ReadRegister(NvGpuEngine3dReg.CullFaceEnable) & 1) != 0;
|
||||||
|
|
||||||
|
@ -291,7 +279,7 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetDepth()
|
private void SetDepth(GalPipelineState State)
|
||||||
{
|
{
|
||||||
State.DepthTestEnabled = (ReadRegister(NvGpuEngine3dReg.DepthTestEnable) & 1) != 0;
|
State.DepthTestEnabled = (ReadRegister(NvGpuEngine3dReg.DepthTestEnable) & 1) != 0;
|
||||||
|
|
||||||
|
@ -303,7 +291,7 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetStencil()
|
private void SetStencil(GalPipelineState State)
|
||||||
{
|
{
|
||||||
State.StencilTestEnabled = (ReadRegister(NvGpuEngine3dReg.StencilEnable) & 1) != 0;
|
State.StencilTestEnabled = (ReadRegister(NvGpuEngine3dReg.StencilEnable) & 1) != 0;
|
||||||
|
|
||||||
|
@ -329,7 +317,7 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetAlphaBlending()
|
private void SetAlphaBlending(GalPipelineState State)
|
||||||
{
|
{
|
||||||
//TODO: Support independent blend properly.
|
//TODO: Support independent blend properly.
|
||||||
State.BlendEnabled = (ReadRegister(NvGpuEngine3dReg.IBlendNEnable) & 1) != 0;
|
State.BlendEnabled = (ReadRegister(NvGpuEngine3dReg.IBlendNEnable) & 1) != 0;
|
||||||
|
@ -347,7 +335,7 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetPrimitiveRestart()
|
private void SetPrimitiveRestart(GalPipelineState State)
|
||||||
{
|
{
|
||||||
State.PrimitiveRestartEnabled = (ReadRegister(NvGpuEngine3dReg.PrimRestartEnable) & 1) != 0;
|
State.PrimitiveRestartEnabled = (ReadRegister(NvGpuEngine3dReg.PrimRestartEnable) & 1) != 0;
|
||||||
|
|
||||||
|
@ -357,7 +345,7 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UploadTextures(NvGpuVmm Vmm, long[] Keys)
|
private void UploadTextures(NvGpuVmm Vmm, GalPipelineState State, long[] Keys)
|
||||||
{
|
{
|
||||||
long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
||||||
|
|
||||||
|
@ -451,30 +439,29 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
Gpu.Renderer.Texture.SetSampler(Sampler);
|
Gpu.Renderer.Texture.SetSampler(Sampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UploadConstBuffers(NvGpuVmm Vmm)
|
private void UploadConstBuffers(NvGpuVmm Vmm, GalPipelineState State)
|
||||||
{
|
{
|
||||||
for (int Stage = 0; Stage < 5; Stage++)
|
for (int Stage = 0; Stage < State.ConstBufferKeys.Length; Stage++)
|
||||||
{
|
{
|
||||||
for (int Index = 0; Index < 18; Index++)
|
for (int Index = 0; Index < State.ConstBufferKeys[Stage].Length; Index++)
|
||||||
{
|
{
|
||||||
ConstBuffer Cb = ConstBuffers[Stage][Index];
|
ConstBuffer Cb = ConstBuffers[Stage][Index];
|
||||||
|
|
||||||
if (Cb.Enabled)
|
long Key = Cb.Position;
|
||||||
|
|
||||||
|
if (Cb.Enabled && QueryKeyUpload(Vmm, Key, Cb.Size, NvGpuBufferType.ConstBuffer))
|
||||||
{
|
{
|
||||||
long Key = Cb.Position;
|
IntPtr Source = Vmm.GetHostAddress(Key, Cb.Size);
|
||||||
|
|
||||||
if (QueryKeyUpload(Vmm, Key, Cb.Size, NvGpuBufferType.ConstBuffer))
|
Gpu.Renderer.Buffer.SetData(Key, Cb.Size, Source);
|
||||||
{
|
|
||||||
IntPtr Source = Vmm.GetHostAddress(Key, Cb.Size);
|
|
||||||
|
|
||||||
Gpu.Renderer.Buffer.SetData(Key, Cb.Size, Source);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
State.ConstBufferKeys[Stage][Index] = Key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UploadVertexArrays(NvGpuVmm Vmm)
|
private void UploadVertexArrays(NvGpuVmm Vmm, GalPipelineState State)
|
||||||
{
|
{
|
||||||
long IndexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress);
|
long IndexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress);
|
||||||
|
|
||||||
|
@ -573,14 +560,14 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DispatchRender(NvGpuVmm Vmm)
|
private void DispatchRender(NvGpuVmm Vmm, GalPipelineState State)
|
||||||
{
|
{
|
||||||
int IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount);
|
int IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount);
|
||||||
int PrimCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl);
|
int PrimCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl);
|
||||||
|
|
||||||
GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff);
|
GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff);
|
||||||
|
|
||||||
Gpu.Renderer.Pipeline.Bind(ref State);
|
Gpu.Renderer.Pipeline.Bind(State);
|
||||||
|
|
||||||
if (IndexCount != 0)
|
if (IndexCount != 0)
|
||||||
{
|
{
|
||||||
|
@ -665,10 +652,6 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
|
|
||||||
if (Cb.Position != Position || Cb.Enabled != Enabled || Cb.Size != Size)
|
if (Cb.Position != Position || Cb.Enabled != Enabled || Cb.Size != Size)
|
||||||
{
|
{
|
||||||
Gpu.Renderer.Buffer.Bind((GalShaderType)Stage, Index, Enabled ? Position : 0);
|
|
||||||
|
|
||||||
ConstBufferBindingsChanged = true;
|
|
||||||
|
|
||||||
ConstBuffers[Stage][Index].Position = Position;
|
ConstBuffers[Stage][Index].Position = Position;
|
||||||
ConstBuffers[Stage][Index].Enabled = Enabled;
|
ConstBuffers[Stage][Index].Enabled = Enabled;
|
||||||
ConstBuffers[Stage][Index].Size = Size;
|
ConstBuffers[Stage][Index].Size = Size;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue