Move Uniform binds to GalPipelineState

This commit is contained in:
ReinUsesLisp 2018-08-01 02:04:10 -03:00
commit 3361eb389b
10 changed files with 247 additions and 250 deletions

View file

@ -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];
}
}
} }
} }

View file

@ -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);
} }
} }

View file

@ -2,6 +2,6 @@
{ {
public interface IGalPipeline public interface IGalPipeline
{ {
void Bind(ref GalPipelineState State); void Bind(GalPipelineState State);
} }
} }

View file

@ -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);

View file

@ -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)

View file

@ -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)

View file

@ -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();

View file

@ -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;

View 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));
}
}
}
}

View file

@ -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;