aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
diff options
context:
space:
mode:
authorReinUsesLisp <reinuseslisp@airmail.cc>2018-06-26 02:10:54 -0300
committergdkchan <gab.dark.100@gmail.com>2018-06-26 02:10:54 -0300
commit09dfefed1f84585e2b305cd16482f899b93fe629 (patch)
tree2e24e24f969376056228e8679020f459f4f68dc1 /Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
parentb8be89ab2dad2e2ba5145f64425fa49526f81596 (diff)
Implementation of UBOs instead of uniform constant arrays (#186)
* Sort uniform binding to avoid possible failures in drivers fewer bindings * Throw exception for Cbuf overflow * Search for free bindings instead of using locked ones * EnsureAllocated when binding buffers * Fix uniform bindings * Remove spaces * Use 64 KiB UBOs when available * Remove double colon * Use IdentationStr and avoid division in Cbuf offset * Add spaces
Diffstat (limited to 'Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs')
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs116
1 files changed, 102 insertions, 14 deletions
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
index 5760d172..28fa8728 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
@@ -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);