|
|
@@ -69,6 +69,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|
|
public ShaderStage Fragment;
|
|
|
}
|
|
|
|
|
|
+ const int ConstBuffersPerStage = 18;
|
|
|
+
|
|
|
private ShaderProgram Current;
|
|
|
|
|
|
private ConcurrentDictionary<long, ShaderStage> Stages;
|
|
|
@@ -77,11 +79,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|
|
|
|
|
public int CurrentProgramHandle { get; private set; }
|
|
|
|
|
|
+ private OGLStreamBuffer[][] ConstBuffers;
|
|
|
+
|
|
|
public OGLShader()
|
|
|
{
|
|
|
Stages = new ConcurrentDictionary<long, ShaderStage>();
|
|
|
|
|
|
Programs = new Dictionary<ShaderProgram, int>();
|
|
|
+
|
|
|
+ ConstBuffers = new OGLStreamBuffer[5][];
|
|
|
+
|
|
|
+ for (int i = 0; i < 5; i++)
|
|
|
+ {
|
|
|
+ ConstBuffers[i] = new OGLStreamBuffer[ConstBuffersPerStage];
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
public void Create(IGalMemory Memory, long Key, GalShaderType Type)
|
|
|
@@ -119,27 +130,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|
|
|
|
|
public void SetConstBuffer(long Key, int Cbuf, byte[] Data)
|
|
|
{
|
|
|
- BindProgram();
|
|
|
-
|
|
|
if (Stages.TryGetValue(Key, out ShaderStage Stage))
|
|
|
{
|
|
|
foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage.Where(x => x.Cbuf == Cbuf))
|
|
|
{
|
|
|
- int Location = GL.GetUniformLocation(CurrentProgramHandle, DeclInfo.Name);
|
|
|
+ OGLStreamBuffer Buffer = GetConstBuffer(Stage.Type, Cbuf);
|
|
|
|
|
|
- int Count = Data.Length >> 2;
|
|
|
+ int Size = Math.Min(Data.Length, Buffer.Size);
|
|
|
|
|
|
- //The Index is the index of the last element,
|
|
|
- //so we can add 1 to get the uniform array size.
|
|
|
- Count = Math.Min(Count, DeclInfo.Index + 1);
|
|
|
+ byte[] Destiny = Buffer.Map(Size);
|
|
|
|
|
|
- unsafe
|
|
|
- {
|
|
|
- fixed (byte* Ptr = Data)
|
|
|
- {
|
|
|
- GL.Uniform1(Location, Count, (float*)Ptr);
|
|
|
- }
|
|
|
- }
|
|
|
+ Array.Copy(Data, Destiny, Size);
|
|
|
+
|
|
|
+ Buffer.Unmap(Size);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -204,11 +207,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|
|
|
|
|
CheckProgramLink(Handle);
|
|
|
|
|
|
+ BindUniformBlocks(Handle);
|
|
|
+
|
|
|
Programs.Add(Current, Handle);
|
|
|
}
|
|
|
|
|
|
GL.UseProgram(Handle);
|
|
|
|
|
|
+ BindUniformBuffers(Handle);
|
|
|
+
|
|
|
CurrentProgramHandle = Handle;
|
|
|
}
|
|
|
|
|
|
@@ -222,6 +229,87 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private void BindUniformBlocks(int ProgramHandle)
|
|
|
+ {
|
|
|
+ int FreeBinding = 0;
|
|
|
+
|
|
|
+ int BindUniformBlocksIfNotNull(ShaderStage Stage)
|
|
|
+ {
|
|
|
+ if (Stage != null)
|
|
|
+ {
|
|
|
+ foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage)
|
|
|
+ {
|
|
|
+ int BlockIndex = GL.GetUniformBlockIndex(ProgramHandle, DeclInfo.Name);
|
|
|
+
|
|
|
+ if (BlockIndex < 0)
|
|
|
+ {
|
|
|
+ //It is expected that its found, if it's not then driver might be in a malfunction
|
|
|
+ throw new InvalidOperationException();
|
|
|
+ }
|
|
|
+
|
|
|
+ GL.UniformBlockBinding(ProgramHandle, BlockIndex, FreeBinding);
|
|
|
+
|
|
|
+ FreeBinding++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return FreeBinding;
|
|
|
+ }
|
|
|
+
|
|
|
+ BindUniformBlocksIfNotNull(Current.Vertex);
|
|
|
+ BindUniformBlocksIfNotNull(Current.TessControl);
|
|
|
+ BindUniformBlocksIfNotNull(Current.TessEvaluation);
|
|
|
+ BindUniformBlocksIfNotNull(Current.Geometry);
|
|
|
+ BindUniformBlocksIfNotNull(Current.Fragment);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void BindUniformBuffers(int ProgramHandle)
|
|
|
+ {
|
|
|
+ int FreeBinding = 0;
|
|
|
+
|
|
|
+ int BindUniformBuffersIfNotNull(ShaderStage Stage)
|
|
|
+ {
|
|
|
+ if (Stage != null)
|
|
|
+ {
|
|
|
+ foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage)
|
|
|
+ {
|
|
|
+ OGLStreamBuffer Buffer = GetConstBuffer(Stage.Type, DeclInfo.Cbuf);
|
|
|
+
|
|
|
+ GL.BindBufferBase(BufferRangeTarget.UniformBuffer, FreeBinding, Buffer.Handle);
|
|
|
+
|
|
|
+ FreeBinding++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return FreeBinding;
|
|
|
+ }
|
|
|
+
|
|
|
+ BindUniformBuffersIfNotNull(Current.Vertex);
|
|
|
+ BindUniformBuffersIfNotNull(Current.TessControl);
|
|
|
+ BindUniformBuffersIfNotNull(Current.TessEvaluation);
|
|
|
+ BindUniformBuffersIfNotNull(Current.Geometry);
|
|
|
+ BindUniformBuffersIfNotNull(Current.Fragment);
|
|
|
+ }
|
|
|
+
|
|
|
+ private OGLStreamBuffer GetConstBuffer(GalShaderType StageType, int Cbuf)
|
|
|
+ {
|
|
|
+ int StageIndex = (int)StageType;
|
|
|
+
|
|
|
+ OGLStreamBuffer Buffer = ConstBuffers[StageIndex][Cbuf];
|
|
|
+
|
|
|
+ if (Buffer == null)
|
|
|
+ {
|
|
|
+ //Allocate a maximum of 64 KiB
|
|
|
+ int Size = Math.Min(GL.GetInteger(GetPName.MaxUniformBlockSize), 64 * 1024);
|
|
|
+
|
|
|
+ Buffer = OGLStreamBuffer.Create(BufferTarget.UniformBuffer, Size);
|
|
|
+
|
|
|
+ ConstBuffers[StageIndex][Cbuf] = Buffer;
|
|
|
+ }
|
|
|
+
|
|
|
+ return Buffer;
|
|
|
+ }
|
|
|
+
|
|
|
public static void CompileAndCheck(int Handle, string Code)
|
|
|
{
|
|
|
GL.ShaderSource(Handle, Code);
|