aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-04-08 16:17:35 -0300
committergdkchan <gab.dark.100@gmail.com>2018-04-08 16:41:38 -0300
commitb9aa3966c00b4bb3ff0292dc28ed53ad26cf284b (patch)
treecd2ab3d65c61ac6c6ceb312116e5d138868a3e18 /Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
parent7acd0e01226d64d05b2675f6ae07507039a31835 (diff)
Merge shader branch, adding support for GLSL decompilation, a macro
interpreter, and a rewrite of the GPU code.
Diffstat (limited to 'Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs')
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs253
1 files changed, 253 insertions, 0 deletions
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
new file mode 100644
index 00000000..6d6ac555
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
@@ -0,0 +1,253 @@
+using OpenTK.Graphics.OpenGL;
+using Ryujinx.Graphics.Gal.Shader;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ class OGLShader
+ {
+ private class ShaderStage : 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 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 OGLShader()
+ {
+ Stages = new ConcurrentDictionary<long, ShaderStage>();
+
+ Programs = new Dictionary<ShaderProgram, int>();
+ }
+
+ public void Create(long Tag, GalShaderType Type, byte[] Data)
+ {
+ Stages.GetOrAdd(Tag, (Key) => ShaderStageFactory(Type, Data));
+ }
+
+ private ShaderStage ShaderStageFactory(GalShaderType Type, byte[] Data)
+ {
+ GlslProgram Program = GetGlslProgram(Data, Type);
+
+ return new ShaderStage(
+ Type,
+ Program.Code,
+ Program.Textures,
+ Program.Uniforms);
+ }
+
+ private GlslProgram GetGlslProgram(byte[] Data, GalShaderType Type)
+ {
+ int[] Code = new int[(Data.Length - 0x50) >> 2];
+
+ using (MemoryStream MS = new MemoryStream(Data))
+ {
+ MS.Seek(0x50, SeekOrigin.Begin);
+
+ BinaryReader Reader = new BinaryReader(MS);
+
+ for (int Index = 0; Index < Code.Length; Index++)
+ {
+ Code[Index] = Reader.ReadInt32();
+ }
+ }
+
+ GlslDecompiler Decompiler = new GlslDecompiler();
+
+ return Decompiler.Decompile(Code, Type);
+ }
+
+ public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Tag)
+ {
+ if (Stages.TryGetValue(Tag, out ShaderStage Stage))
+ {
+ return Stage.TextureUsage;
+ }
+
+ return Enumerable.Empty<ShaderDeclInfo>();
+ }
+
+ public void SetConstBuffer(long Tag, int Cbuf, byte[] Data)
+ {
+ BindProgram();
+
+ if (Stages.TryGetValue(Tag, out ShaderStage Stage))
+ {
+ foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage.Where(x => x.Cbuf == Cbuf))
+ {
+ float Value = BitConverter.ToSingle(Data, DeclInfo.Index * 4);
+
+ int Location = GL.GetUniformLocation(CurrentProgramHandle, DeclInfo.Name);
+
+ GL.Uniform1(Location, Value);
+ }
+ }
+ }
+
+ public void SetUniform1(string UniformName, int Value)
+ {
+ BindProgram();
+
+ int Location = GL.GetUniformLocation(CurrentProgramHandle, UniformName);
+
+ GL.Uniform1(Location, Value);
+ }
+
+ public void Bind(long Tag)
+ {
+ if (Stages.TryGetValue(Tag, out ShaderStage Stage))
+ {
+ Bind(Stage);
+ }
+ }
+
+ private void Bind(ShaderStage Stage)
+ {
+ switch (Stage.Type)
+ {
+ case GalShaderType.Vertex: Current.Vertex = Stage; break;
+ case GalShaderType.TessControl: Current.TessControl = Stage; break;
+ case GalShaderType.TessEvaluation: Current.TessEvaluation = Stage; break;
+ case GalShaderType.Geometry: Current.Geometry = Stage; break;
+ case GalShaderType.Fragment: Current.Fragment = Stage; break;
+ }
+ }
+
+ public void BindProgram()
+ {
+ if (Current.Vertex == null ||
+ Current.Fragment == null)
+ {
+ return;
+ }
+
+ if (!Programs.TryGetValue(Current, out int Handle))
+ {
+ Handle = GL.CreateProgram();
+
+ AttachIfNotNull(Handle, Current.Vertex);
+ AttachIfNotNull(Handle, Current.TessControl);
+ AttachIfNotNull(Handle, Current.TessEvaluation);
+ AttachIfNotNull(Handle, Current.Geometry);
+ AttachIfNotNull(Handle, Current.Fragment);
+
+ GL.LinkProgram(Handle);
+
+ CheckProgramLink(Handle);
+
+ Programs.Add(Current, Handle);
+ }
+
+ GL.UseProgram(Handle);
+
+ CurrentProgramHandle = Handle;
+ }
+
+ private void AttachIfNotNull(int ProgramHandle, ShaderStage Stage)
+ {
+ if (Stage != null)
+ {
+ Stage.Compile();
+
+ GL.AttachShader(ProgramHandle, Stage.Handle);
+ }
+ }
+
+ 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)
+ {
+ int Status = 0;
+
+ GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out Status);
+
+ if (Status == 0)
+ {
+ throw new ShaderException(GL.GetProgramInfoLog(Handle));
+ }
+ }
+ }
+} \ No newline at end of file