diff options
| author | ReinUsesLisp <reinuseslisp@airmail.cc> | 2018-06-26 02:10:54 -0300 |
|---|---|---|
| committer | gdkchan <gab.dark.100@gmail.com> | 2018-06-26 02:10:54 -0300 |
| commit | 09dfefed1f84585e2b305cd16482f899b93fe629 (patch) | |
| tree | 2e24e24f969376056228e8679020f459f4f68dc1 /Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs | |
| parent | b8be89ab2dad2e2ba5145f64425fa49526f81596 (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.cs | 116 |
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); |
