From 48f6570557fc76496936514d94e3ccddf55ec633 Mon Sep 17 00:00:00 2001
From: Mary <me@thog.eu>
Date: Fri, 13 Nov 2020 00:15:34 +0100
Subject: Salieri: shader cache (#1701)

Here come Salieri, my implementation of a disk shader cache!

"I'm sure you know why I named it that."
"It doesn't really mean anything."

This implementation collects shaders at runtime and cache them to be later compiled when starting a game.
---
 Ryujinx.Graphics.OpenGL/Program.cs | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

(limited to 'Ryujinx.Graphics.OpenGL/Program.cs')

diff --git a/Ryujinx.Graphics.OpenGL/Program.cs b/Ryujinx.Graphics.OpenGL/Program.cs
index 17e14df6..d39e181d 100644
--- a/Ryujinx.Graphics.OpenGL/Program.cs
+++ b/Ryujinx.Graphics.OpenGL/Program.cs
@@ -3,6 +3,7 @@ using Ryujinx.Common.Logging;
 using Ryujinx.Graphics.GAL;
 using Ryujinx.Graphics.Shader.CodeGen.Glsl;
 using System;
+using System.Buffers.Binary;
 using System.Collections.Generic;
 using System.Linq;
 
@@ -22,6 +23,8 @@ namespace Ryujinx.Graphics.OpenGL
         {
             Handle = GL.CreateProgram();
 
+            GL.ProgramParameter(Handle, ProgramParameterName.ProgramBinaryRetrievableHint, 1);
+
             for (int index = 0; index < shaders.Length; index++)
             {
                 int shaderHandle = ((Shader)shaders[index]).Handle;
@@ -93,6 +96,27 @@ namespace Ryujinx.Graphics.OpenGL
             ComputeRenderScaleUniform = GL.GetUniformLocation(Handle, "cp_renderScale");
         }
 
+        public Program(ReadOnlySpan<byte> code)
+        {
+            BinaryFormat binaryFormat = (BinaryFormat)BinaryPrimitives.ReadInt32LittleEndian(code.Slice(code.Length - 4, 4));
+
+            Handle = GL.CreateProgram();
+
+            unsafe
+            {
+                fixed (byte* ptr = code)
+                {
+                    GL.ProgramBinary(Handle, binaryFormat, (IntPtr)ptr, code.Length - 4);
+                }
+            }
+
+            CheckProgramLink();
+
+            FragmentIsBgraUniform = GL.GetUniformLocation(Handle, "is_bgra");
+            FragmentRenderScaleUniform = GL.GetUniformLocation(Handle, "fp_renderScale");
+            ComputeRenderScaleUniform = GL.GetUniformLocation(Handle, "cp_renderScale");
+        }
+
         public void Bind()
         {
             GL.UseProgram(Handle);
@@ -113,6 +137,19 @@ namespace Ryujinx.Graphics.OpenGL
             }
         }
 
+        public byte[] GetBinary()
+        {
+            GL.GetProgram(Handle, (GetProgramParameterName)All.ProgramBinaryLength, out int size);
+
+            byte[] data = new byte[size + 4];
+
+            GL.GetProgramBinary(Handle, size, out _, out BinaryFormat binFormat, data);
+
+            BinaryPrimitives.WriteInt32LittleEndian(data.AsSpan().Slice(size, 4), (int)binFormat);
+
+            return data;
+        }
+
         public void Dispose()
         {
             if (Handle != 0)
-- 
cgit v1.2.3-70-g09d2