Merge shader branch, adding support for GLSL decompilation, a macro
interpreter, and a rewrite of the GPU code.
This commit is contained in:
parent
7acd0e0122
commit
b9aa3966c0
77 changed files with 5301 additions and 766 deletions
253
Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
Normal file
253
Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
Normal file
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue